「模组:常用方法」修訂間的差異

出自Stardew Valley Wiki
跳至導覽 跳至搜尋
行 241: 行 241:
 
Game1.activeClickableMenu = new DialogueBox(message);
 
Game1.activeClickableMenu = new DialogueBox(message);
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
==邮件 (Mail)==
 +
// 未翻译
 +
===概述===
 +
// 未翻译
 +
===注入静态内容 (Inject static content)===
 +
// 未翻译
 +
===客户端调用静态内容 (Send a letter with static content)===
 +
// 未翻译
 +
===注入动态内容 (Inject dynamic content)===
 +
// 未翻译
 +
===客户端调用动态内容 (Send a letter with dynamic content)===
 +
// 未翻译
 +
 +
==其他 (Other)==
 +
===简单动画(animation) 的添加===
 +
<syntaxhighlight lang='c#'>
 +
location.temporarySprites.Add(new TemporaryAnimatedSprite(...));
 +
</syntaxhighlight>
 +
详见<tt>TemporaryAnimatedSprite</tt>类。
 +
 +
===播放一段声音===
 +
<syntaxhighlight lang='c#'>
 +
location.playSound("SOUND");  // "SOUND"为声音的名字
 +
</syntaxhighlight>
 +
详见[https://docs.google.com/spreadsheets/d/1CpDrw23peQiq-C7F2FjYOMePaYe0Rc9BwQsj3h6sjyo/edit#gid=239695361 声音名字一览]。
  
 
[[en:Modding:Common tasks]]
 
[[en:Modding:Common tasks]]
 
[[ru:Модификации:Основные возможности]]
 
[[ru:Модификации:Основные возможности]]

於 2021年6月11日 (五) 01:06 的修訂

目錄

Robin building.png
“我這裡還有很多事情需要處理。”
— 羅賓

不完整的翻譯

本文或部分尚未完全翻譯成中文。 歡迎您通過編輯幫助其建設。
最後編輯臭美香噴噴於2021-06-11 01:06:38.

此頁面展示了製作SMAPI模組時常見的任務。在閱讀時,請結合參考模組製作入門遊戲基本架構

基礎技巧

追蹤一個值的變化

在寫模組時,你可能常常需要了解一個值的變化(什麼時候變,變化前後的值分別是多少,等等)。如果該值沒有包括在SMAPI內置的事件 (event)中,那麼你可以為該值創建一個私有變量,然後在SMAPI的update tick事件中刷新此變量,以達到追蹤值變化的目的。

示例見:[模組:製作指南/APIs/Events#變化監控]

物品 (Items)

物品 代表那些能夠放在背包里的東西,比如說工具、農作物等等。

創建一個物品 (Object) 的實例

Object中所有的構造函數:

 public Object(Vector2 tileLocation, int parentSheetIndex, int initialStack);
 public Object(Vector2 tileLocation, int parentSheetIndex, bool isRecipe = false);
 public Object(int parentSheetIndex, int initialStack, bool isRecipe = false, int price = -1, int quality = 0);
 public Object(Vector2 tileLocation, int parentSheetIndex, string Givenname, bool canBeSetDown, bool canBeGrabbed, bool isHoedirt, bool isSpawnedObject);

參數parentSheetIndex表示該物品的ID(儲存在 ObjectInformation.xnb 文件中)。

在地上生成物品

public virtual bool dropObject(Object obj, Vector2 dropLocation, xTile.Dimensions.Rectangle viewport, bool initialPlacement, Farmer who = null);

 // 调用:
 Game1.getLocationFromName("Farm").dropObject(new StardewValley.Object(itemId, 1, false, -1, 0), new Vector2(x, y) * 64f, Game1.viewport, true, (Farmer)null);

添加物品到背包 (Inventory)

// You can add items found in ObjectInformation using:
    Game1.player.addItemByMenuIfNecessary((Item)new StardewValley.Object(int parentSheetIndex, int initialStack, [bool isRecipe = false], [int price = -1], [int quality = 0]));

例2:

// Add a weapon directly into player's inventory
    const int WEAP_ID = 19;                  // Shadow Dagger -- see Data/weapons
    Item weapon = new MeleeWeapon(WEAP_ID);  // MeleeWeapon is a class in StardewValley.Tools
    Game1.player.addItemByMenuIfNecessary(weapon);

    // Note: This code WORKS.

從背包移除物品

取決於你背包的具體情況。很少有情況需要你親自來調用,因為相關的方法在Farmer類中已經有了。

在大多數情況下,僅需調用 .removeItemFromInventory(Item) 方法。

地點 (Locations)

遊戲基本架構#地點

獲取所有地點

Game1.locations屬性中雖然儲存著主要的地點,但是不包括建築的室內(constructed building interiors)。以下這個方法提供了主玩家的所有地點。

/// <summary>Get all game locations.</summary>
public static IEnumerable<GameLocation> GetLocations()
{
    return Game1.locations
        .Concat(
            from location in Game1.locations.OfType<BuildableGameLocation>()
            from building in location.buildings
            where building.indoors.Value != null
            select building.indoors.Value
        );
}

遍歷:

foreach (GameLocation location in this.GetLocations())
{
   // ...
}

注意:在聯機模式中,客機是拿不到上述所有地點的。要解決這一問題,見獲取有效的地點

編輯地圖

模組:地圖數據

玩家 (Player)

自定義精靈 (Custom Sprite)

位置 (Position)

角色(Character) 的位置(Position) 表示他在當前地點(Location) 的坐標。

相對於地圖 (Map)

每個地點(location) 都有一個對應的xTile地圖(map)。如果以像素(pixel) 為單位,地圖左上角坐標代表(0, 0),坐下角則代表(location.Map.DisplayWidth, location.Map.DisplayHeight)。 角色在當前地點的位置有兩種表達方式:

  • 以像素(pixel) 為單位的絕對(absoulte) 坐標:Position.XPosition.Y
  • 以圖塊(tile) 為單位的圖塊(tile) 坐標:getTileX()getTileY()

常量Game1.tileSize規定,遊戲內每個圖塊(tile) 大小為64x64像素。於是有以下單位換算:

// 绝对坐标 → 图块坐标
Math.Floor(Game1.player.Position.X / Game1.tileSize)
Math.Floor(Game1.player.Position.Y / Game1.tileSize)

// 图块坐标 → 绝对坐标
Game1.player.getTileX() * Game1.tileSize
Game1.player.getTileY() * Game1.tileSize

// 地图大小(以图块为单位)
Math.Floor(Game1.player.currentLocation.Map.DisplayWidth / Game1.tileSize)
Math.Floor(Game1.player.currentLocation.Map.DisplayHeight / Game1.tileSize)

相對於視野 (Viewport)

視野、視口、視窗(Viewport) 代表在當前屏幕上的區域。若以像素計算,其寬高應該與遊戲的屏幕解析度相等,分別為Game1.viewport.WidthGame1.viewport.Height

玩家相對於視野的位置(像素)可表示為:

Game1.player.Position.X - Game1.viewport.X
Game1.player.Position.Y - Game1.viewport.Y

NPC

自定義NPC

想要自定義NPC,你得修改或添加以下文件:

格式: 具體操作(往)目標文件夾或文件名

  • 添加新文件:Characters\Dialogue\<文件名>
  • 添加新文件:Characters\schedules\<文件名>
  • 添加新文件:Portraits\<文件名>
  • 添加新文件:Characters\<文件名>
  • 在已有文件中添加新的條目:Data\EngagementDialogue(可結婚NPC)
  • 在已有文件中添加新的條目:Data\NPCDispositions
  • 在已有文件中添加新的條目:Data\NPCGiftTastes
  • 在已有文件中添加新的條目:Characters\Dialogue\rainy
  • 在已有文件中添加新的條目:Data\animationDescriptions(在行程(schedule) 中增加自定義的動畫)

以上所有的操作都可以通過IAssetLoaders/IAssetEditors或者Content Patcher做到。

最後,你需要調用NPC的構造器來創建實例。

 public NPC(AnimatedSprite sprite, Vector2 position, int facingDir, string name, LocalizedContentManager content = null);
 public NPC(AnimatedSprite sprite, Vector2 position, string defaultMap, int facingDir, string name, Dictionary<int, int[]> schedule, Texture2D portrait, bool eventActor);
 public NPC(AnimatedSprite sprite, Vector2 position, string defaultMap, int facingDirection, string name, bool datable, Dictionary<int, int[]> schedule, Texture2D portrait);

 // 调用:
 Game1.getLocationFromName("Town").addCharacter(npc);

用戶界面 (UI)

用戶界面(User-interface、UI) 是指一系列有關界面元素(如按鈕、列表框、下拉框等等)以及它們組合起來呈現的畫面(如菜單、HUD等等)。

//TODO:歡迎補充UI方面的內容。

HUD消息

HUD消息是指你屏幕左下角時常彈出來的消息框。以下是它的構造函數(不包括一部分無關的):

 public HUDMessage(string message);
 public HUDMessage(string message, int whatType);
 public HUDMessage(string type, int number, bool add, Color color, Item messageSubject = null);
 public HUDMessage(string message, string leaveMeNull)
 public HUDMessage(string message, Color color, float timeLeft, bool fadeIn)
樣式一覽

可選的樣式(type):

  1. 成就 HUDMessage.achievement_type
  2. 新任務 HUDMessage.newQuest_type
  3. 錯誤 HUDMessage.error_type
  4. 體力值 HUDMessage.stamina_type
  5. 生命值 HUDMessage.health_type

顏色(color):

第1、2個構造器並沒有給出表示顏色的參數,此時顏色默認為Color.OrangeRed。 若使用第4個構造器,顏色則與遊戲內文字顏色一樣。

特別:

  • public HUDMessage(string type, int number, bool add, Color color, Item messageSubject = null); 支持消息內容擴展。常用於金錢相關。
  • public HUDMessage(string message, string leaveMeNull); 左側沒有圖標框。
  • public HUDMessage(string message, Color color, float timeLeft, bool fadeIn); 文字漸入效果。


示例1: 彈出一個帶有Error-image-ingame.png的消息框。

 Game1.addHUDMessage(new HUDMessage("MESSAGE", 3));

示例2: 彈出一個純文字的消息框。

 Game1.addHUDMessage(new HUDMessage("MESSAGE", ""));  // second parameter is the 'leaveMeNull' parameter

菜單 (Active clickable menu)

菜單指繪製於最頂層的UI,能夠接受用戶輸入。比方說,當你按下ESCB鍵時呈現的GameMenu就是一個菜單。 菜單的值儲存在Game1.activeClickableMenu,當該欄位不為null時,其值便能呈現出一個菜單了。

每個菜單不盡相同,請閱讀代碼來了解其運作方式。你可能經常需要了解GameMenu的當前欄目 (tab),這是一個示例:

if (Game1.activeClickableMenu is GameMenu menu)
{
  // 获取栏目页
  IList<IClickableMenu> pages = this.Helper.Reflection.GetField<List<IClickableMenu>>(menu, "pages").GetValue();

  // 方法1:比较栏目的ID
  if (menu.currentTab == GameMenu.mapTab)
  {
     ...
  }

  // 方法2:比较菜单类型
  switch (pages[menu.currentTab])
  {
    case MapPage mapPage:
       ...
       break;
  }
}

如果你想要自定義菜單,請繼承自IClickableMenu,將對象分配給Game1.activeClickableMenu。 一個菜單基本上重寫了一些方法,如drawreceiveLeftClick 等等。 draw方法繪製屏幕上的元素;receiveLeftClick 方法處理左鍵點擊事件。 你通常可以使用一些遊戲封裝好的類作為菜單元素,如ClickableTextureButton

這裡提供了一個簡單的例子,這是Birthday Mod的菜單。

對話框 (DialogueBox)

不帶選項的對話框示例。

對話框有許多變種,比如有種對話框能夠選擇想要的對話內容。

如果想換行,請輸入"^"。

下面是一種不帶選項的對話框示例:

using StardewValley.Menus;  // 引用DialogueBox类的命名空间

string message = "This looks like a typewriter ... ^But it's not ...^It's a computer.^";
Game1.activeClickableMenu = new DialogueBox(message);

郵件 (Mail)

// 未翻譯

概述

// 未翻譯

注入靜態內容 (Inject static content)

// 未翻譯

客戶端調用靜態內容 (Send a letter with static content)

// 未翻譯

注入動態內容 (Inject dynamic content)

// 未翻譯

客戶端調用動態內容 (Send a letter with dynamic content)

// 未翻譯

其他 (Other)

簡單動畫(animation) 的添加

location.temporarySprites.Add(new TemporaryAnimatedSprite(...));

詳見TemporaryAnimatedSprite類。

播放一段聲音

location.playSound("SOUND");  // "SOUND"为声音的名字

詳見聲音名字一覽