当前位置: 首页 > article >正文

Unity3D仿星露谷物语开发43之农作物生长

1、目标

把防风草种子种在地里,并展示植物种子,防风草种子将随着时间变化而生长成植株。

2、创建Crop.cs脚本

在Assets -> Scripts下创建新的目录命名为Crop,在其下创建新的脚本命名为Crop.cs。

代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Crop : MonoBehaviour
{[HideInInspector]public Vector2Int cropGridPosition;
}

3、创建CropDetails.cs脚本

在Assets -> Scripts -> Crop下创建CropDetails.cs脚本。

代码如下:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;[System.Serializable]
public class CropDetails 
{[ItemCodeDescription]public int seedItemCode; // this is the item code for the corresponding seedpublic int[] growthDays; // days growth for each stagepublic int totalGrowthDays; // total growth dayspublic GameObject[] growthPrefab; // prefab to use when instantiating growth stagespublic Sprite[] growthSprite; // growth spritepublic Season[] seasons; // growth seasonspublic Sprite harvestedSprite; // sprite used once harvested[ItemCodeDescription]public int harvestedTransformItemCode; // if the item transform into another item when harvested this item code will be populatedpublic bool hideCropBeforeHarvestedAnimation; // if the crop should be disabled before the harvested animationpublic bool disableCropCollidersBeforeHarvestedAnimation; // if colliders on crop should be disabled to avoid the harvested animation effecting any other game objectspublic bool isHarvestedAnimation; // true if harvested animation to be played on final growth stage prefabpublic bool isHarvestActionEffect = false; // flag to determine whether there is a harvest action effectpublic bool spawnCropProducedAtPlayerPosition;public HarvestActionEffect harvestActionEffect; // the harvest action effect for the crop[ItemCodeDescription]public int[] harvestToolItemCode; // array of item codes for the tools that can harvest or 0 array elements if no tool requiredpublic int[] requiredHarvestActions; // number of harvest actions required for corresponding tool in harvest tool item code array[ItemCodeDescription]public int[] cropProducedItemCode; // array of item codes produced for the harvested croppublic int[] cropProducedMinQuantity; // array of minimum quantities produced for the harvested croppublic int[] cropProducedMaxQuantity; // if max quantity is > min quantity then a random number of crops between min and max are producedpublic int daysToRegrow; // days to regrow next crop or -1 if a single crop/// <summary>/// returns true if the tool item code can be used to harvest this crop, else returns false/// </summary>/// <param name="toolItemCode"></param>/// <returns></returns>public bool CanUseToolToHarvestCrop(int toolItemCode){if(RequiredHarvestActionsForTool(toolItemCode) == -1){return false;}else{return true;}}/// <summary>/// returns -1 if the tool can't be used to harvest this crop, else returns thhe number of harvest actions required by this tool/// </summary>/// <param name="toolItemCode"></param>/// <returns></returns>public int RequiredHarvestActionsForTool(int toolItemCode){for(int i = 0; i < harvestToolItemCode.Length; i++){if (harvestToolItemCode[i] == toolItemCode){return requiredHarvestActions[i];}}return -1;}}

4、创建SO_CropDetailsList.cs脚本

在Assets -> Scripts -> Crop下创建SO_CropDetailsList.cs脚本。

代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[CreateAssetMenu(fileName ="CropDetailsList", menuName ="Scriptable Objects/Crop/Crop Details List")]
public class SO_CropDetailList : ScriptableObject
{[SerializeField]public List<CropDetails> cropDetails;public CropDetails GetCropDetails(int seedItemCode){return cropDetails.Find(x => x.seedItemCode == seedItemCode);}
}

5、填充防风草作物的数据

(1)制作Crop预制体

第1步,在Hierarchy -> PersistentScene下创建新的物体命名为CropStandard。

第2步,给该物体添加Box Collider 2D组件,并设置参数如下:

第3步,添加Crop组件和Item Nudge组件。

第4步,在CropStandard下创建子物体命名为CropSprite。

第5步,给CropSprite添加Sprite Renderer组件,并且设置参数如下:

如果Sorting Layer未设置未Instances,将导致seed无法正确显示(因为优先级不够)。

第6步,将Hierarchy下的CropStandard拖到Assets -> Prefabs -> Crop目录下,并且删除Hierarchy下的CropStandard。

(2)创建Crop的Scriptable资源

第1步,在Assets -> Scriptable Object Assets 下创建新的目录命名为Crop。

第2步,右击Crop目录,选择Scriptable Objects -> Crop -> Crop Details List,命名为so_CropDetailsList。

第3步,配置so_CropDetailsList的信息如下:

6、防风草生长

(1)优化Tags.cs脚本

添加一个变量:

public const string CropsParentTransform = "CropsParentTransform";

(2)添加Crops对象

首先,加载Scene1_Farm场景

然后,在Hierarchy -> Scene1_Farm下创建新的物体命名为Crops

接着,在Inspector界面下创建新的Tag:CropsParentTransform,并且指定Crops的Tag为新Tag。

最后,Unload Scene1_Farm场景。

对Scene2_Field场景进行同样的操作

(3)优化EventHandler.cs脚本

添加新的事件如下:

// Remove selected item from inventory
public static event Action RemoveSelectedItemFromInventoryEvent;public static void CallRemoveSelectedItemFromInventoryEvent()
{if(RemoveSelectedItemFromInventoryEvent != null){RemoveSelectedItemFromInventoryEvent();}
}

(4)优化GridPropertiesManager.cs脚本

添加变量1:

private Transform cropParentTransform;

修改AfterSceneLoaded函数,添加如下代码:

if(GameObject.FindGameObjectWithTag(Tags.CropsParentTransform) != null)
{cropParentTransform = GameObject.FindGameObjectWithTag(Tags.CropsParentTransform).transform;
}
else
{cropParentTransform = null;
}

添加变量2:

[SerializeField] private SO_CropDetailList so_CropDetailList = null;

修改ClearDisplayGridPropertyDetails函数,添加如下代码:

private void ClearDisplayAllPlantedCrops()
{// Destory all crops in sceneCrop[] cropArray;cropArray = FindObjectsOfType<Crop>();   foreach(Crop crop in cropArray){Destroy(crop.gameObject);}}private void ClearDisplayGridPropertyDetails()
{ClearDisplayGroundDecorations();ClearDisplayAllPlantedCrops();
}

修改DisplayGridPropertyDetails函数,代码如下:

private void DisplayGridPropertyDetails()
{// Loop throught all grid itemsforeach(KeyValuePair<string, GridPropertyDetails> item in gridPropertyDictionary){GridPropertyDetails gridPropertyDetails = item.Value;DisplayDugGround(gridPropertyDetails);DisplayWateredGround(gridPropertyDetails);DisplayPlantedCrop(gridPropertyDetails);}
}public void DisplayPlantedCrop(GridPropertyDetails gridPropertyDetails)
{if(gridPropertyDetails.seedItemCode > -1){// get crop detailsCropDetails cropDetails = so_CropDetailList.GetCropDetails(gridPropertyDetails.seedItemCode);// prefab to useGameObject cropPrefab;// instantiate crop prefab at grid locationint growthStages = cropDetails.growthDays.Length;int currentGrowthStage = 0;int daysCounter = cropDetails.totalGrowthDays;// 找出目前所处的成长阶段for(int i = growthStages - 1; i >= 0; i--){if(gridPropertyDetails.growthDays >= daysCounter){currentGrowthStage = i;break;}daysCounter = daysCounter - cropDetails.growthDays[i];}cropPrefab = cropDetails.growthPrefab[currentGrowthStage];Sprite growthSprite = cropDetails.growthSprite[currentGrowthStage];Vector3 worldPosition = groundDecoration2.CellToWorld(new Vector3Int(gridPropertyDetails.gridX, gridPropertyDetails.gridY, 0));worldPosition = new Vector3(worldPosition.x + Settings.gridCellSize / 2, worldPosition.y, worldPosition.z);GameObject cropInstance = Instantiate(cropPrefab, worldPosition, Quaternion.identity);cropInstance.GetComponentInChildren<SpriteRenderer>().sprite = growthSprite;cropInstance.transform.SetParent(cropParentTransform);cropInstance.GetComponent<Crop>().cropGridPosition = new Vector2Int(gridPropertyDetails.gridX, gridPropertyDetails.gridY);}
}

修改AdvanceDay函数,代码如下:

private void AdvanceDay(int gameYear, Season gameSeason, int gameDay, string gameDayyOfWeek, int gameHour, int gameMinute, int gameSecond)
{// Clear Display All Grid Property DetailsClearDisplayGridPropertyDetails();// loop through all scenes - by looping through all gridproperty in the arrayforeach(SO_GridProperties so_GridProperties in so_gridPropertiesArray){// Get gridpropertydetails dictionary for sceneif(GameObjectSave.sceneData.TryGetValue(so_GridProperties.sceneName.ToString(), out SceneSave sceneSave)){if(sceneSave.gridPropertyDetailsDictionary != null){for(int i = sceneSave.gridPropertyDetailsDictionary.Count - 1; i >= 0; i--){KeyValuePair<string, GridPropertyDetails> item = sceneSave.gridPropertyDetailsDictionary.ElementAt(i);GridPropertyDetails gridPropertyDetails = item.Value;#region Update all grid properties to reflect the advance in the day// if a crop is plantedif(gridPropertyDetails.growthDays > -1){gridPropertyDetails.growthDays += 1;}// if ground is watered, then clear waterif(gridPropertyDetails.daysSinceWatered > -1){gridPropertyDetails.daysSinceWatered = -1;}// Set gridpropertydetailsSetGridPropertyDetails(gridPropertyDetails.gridX, gridPropertyDetails.gridY, gridPropertyDetails, sceneSave.gridPropertyDetailsDictionary);#endregion Update all grid properties to reflect the advance in the day}}}}// Display grid property details to reflect changed valuesDisplayGridPropertyDetails();
}

(5)优化Player.cs脚本

优化ProcessPlayerClickInput函数,代码如下:

修改ProcessPlayerClickInputSeed函数如下:

private void ProcessPlayerClickInputSeed(GridPropertyDetails gridPropertyDetails, ItemDetails itemDetails)
{if(itemDetails.canBeDropped && gridCursor.CursorPositionIsValid && gridPropertyDetails.daysSinceDug > -1 && gridPropertyDetails.seedItemCode == -1){PlantSeedAtCursor(gridPropertyDetails, itemDetails);}else if (itemDetails.canBeDropped && gridCursor.CursorPositionIsValid){EventHandler.CallDropSelectedItemEvent();}
}

添加PlantSeedAtCursor函数如下:

 private void PlantSeedAtCursor(GridPropertyDetails gridPropertyDetails, ItemDetails itemDetails){// update grid properties with seed detailsgridPropertyDetails.seedItemCode = itemDetails.itemCode;gridPropertyDetails.growthDays = 0;// Display planted crop at grid property detailsGridPropertiesManager.Instance.DisplayPlantedCrop(gridPropertyDetails);// Remove item from inventoryEventHandler.CallRemoveSelectedItemFromInventoryEvent();}

(6)优化UIInventorySlot.cs脚本

修改OnEnable代码,

 private void OnEnable(){EventHandler.AfterSceneLoadEvent += SceneLoaded;EventHandler.RemoveSelectedItemFromInventoryEvent += RemoveSelectedItemFromInventory;EventHandler.DropSelectedItemEvent += DropSelectedItemAtMousePosition;}

修改OnDisable代码:

private void OnDisable()
{EventHandler.AfterSceneLoadEvent -= SceneLoaded;EventHandler.RemoveSelectedItemFromInventoryEvent -= RemoveSelectedItemFromInventory;EventHandler.DropSelectedItemEvent -= DropSelectedItemAtMousePosition;
}

添加RemoveSelectedItemFromInventory函数代码:

 private void RemoveSelectedItemFromInventory(){if(itemDetails != null && isSelected){int itemCode = itemDetails.itemCode;// Remove item from players inventoryInventoryManager.Instance.RemoveItem(InventoryLocation.player, itemCode);// If no more of iitem then clear selectedif(InventoryManager.Instance.FindItemInInventory(InventoryLocation.player, itemCode) == -1){ClearSelectedItem();}}}

(7)补充配置信息

配置GridPropertiesManager的So_Crop Detail List信息如下:

7、运行游戏

先用Hoe挖一块地

然后洒下Parsnip的种子

按下G键可以加速时间,此时就可以看到防风草生长的过程。

http://www.lryc.cn/news/2378889.html

相关文章:

  • 从0到1上手Kafka:开启分布式消息处理之旅
  • GTS-400 系列运动控制器板卡介绍(三十四)---运动程序多线程累加求和
  • Python爬虫如何应对网站的反爬加密策略?
  • 第一次经历项目上线
  • Conda配置完全指南——Windows系统Anaconda/Miniconda的安装、配置、基础使用、清理缓存空间和Pycharm/VSCode配置指南
  • Quasar组件 Carousel走马灯
  • AI日报 - 2024年5月17日
  • R语言数据框(datafram)数据的构建及简单分析
  • 风控域——风控决策引擎系统设计
  • CAPL Class: TcpSocket (此类用于实现 TCP 网络通信 )
  • 数据分析 —— 数据预处理
  • 软件架构风格系列(4):事件驱动架构
  • windows系统各版本下载
  • arduino平台读取鼠标光电传感器
  • 【Linux网络】网络层
  • 力扣-98.验证二叉搜索树
  • 5.17本日总结
  • 大模型学习:Deepseek+dify零成本部署本地运行实用教程(超级详细!建议收藏)
  • VSCode launch.json 配置参数详解
  • pytest多种断言类型封装为自动化断言规则库
  • Oracle数据库如何进行冷备份和恢复
  • LeetCode Hot100 (2、3、4、5、6、8、9、12)
  • FastMCP:为大语言模型构建强大的上下文和工具服务
  • 数据结构(3)线性表-链表-单链表
  • Java Solon v3.3.0 发布(国产优秀应用开发基座)
  • 23种设计模式概述详述(C#代码示例)
  • 数字化工厂升级引擎:Modbus TCP转Profinet网关助力打造柔性生产系统
  • FPGA生成随机数的方法
  • 【Linux C/C++开发】轻量级关系型数据库SQLite开发(包含性能测试代码)
  • 2025认证杯第二阶段数学建模B题:谣言在社交网络上的传播思路+模型+代码