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

莒县住房和城乡规划建设局网站网站建设包括哪些内容

莒县住房和城乡规划建设局网站,网站建设包括哪些内容,哈尔滨公共资源网,图片二维码生成器在线制作游戏角色 详细教程 一、准备工作 1、场景重命名为Farm 2、导入资源 (1) 新建文件夹。Import Asset (2) 导入:人物、走、跑、休息 3、设置摄像机 二、制作角色预制体 1、增加角色,命名为Player,设置材质、人类角色 2、设置角色的空闲…

游戏角色

详细教程

一、准备工作

1、场景重命名为Farm

2、导入资源

(1) 新建文件夹。Import Asset

(2) 导入:人物、走、跑、休息

3、设置摄像机

二、制作角色预制体

1、增加角色,命名为Player,设置材质、人类角色

2、设置角色的空闲、走、跑的材质等

3、添加Rigidbody组件,约束Position上的Y轴AZ,Rotation上的X、Z轴

4、设置Update Mode

5、新建Prefabs文件夹,将角色制成预制体

三、设置角色动画

1、新建文件夹Animation,在Animation文件夹下新建文件夹Controllers

2、在Controller文件夹下Create Animator Controller,命名为Player

3、选中Hierarchy中的人物,在Inspector面板中给Animator中的Controller选择Player

4、打开Controller文件夹下的Player,设置动画

(1) 复制mixano.com,分别重命名为Walking、Running和Idle

(2) 将复制的Walking、Running和Idle转移到Animation文件夹

(3) 分别选择Walking、Running和Idle,设置循环播放(Loop Pose也勾选上)

(4) 打开Controller文件夹下的Player,依次将Idle(默认)、Walking、Running拖入新界面

(5) 选择Parameters,添加Bool,Bool,分别命名为IsWalking,Running。不勾选(默认状态)

(6) 选中Idle到Walk的箭头,右侧点加号,出现IsWalking true,取消勾选Hash Exit Time

(7) 同样的方法设定Walking转换为Idle。将IsWalking设置为false。取消勾选Hash Exit Time

(8) 选中动画编辑器中的Idle、Walking、Running,将Speed改为2

(9) 同样的方法设置Running

四、控制角色行走

1、给角色预制体,添加Character Controller(角色控制器)组件,调节参数至笼罩全身

2、给角色预制体添加PlayerController.cs组件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayerController : MonoBehaviour
{public float turnSpeed = 20f;Animator animator;Rigidbody rb;Vector3 movement;Quaternion rotation = Quaternion.identity;[Header("Movement System")]public float walkSpeed = 1f;public float runSpeed = 3f;private void Start(){animator = GetComponent<Animator>();rb = GetComponent<Rigidbody>();}private void FixedUpdate(){float horizontal = Input.GetAxis("Horizontal");float vertical = Input.GetAxis("Vertical");movement.Set(horizontal, 0f, vertical);bool hasHorizontalInput = !Mathf.Approximately(horizontal, 0);bool hasVerticalInput = !Mathf.Approximately(vertical, 0);float movementSpeed = walkSpeed;movement.Normalize();Vector3 desiredForward = Vector3.RotateTowards(transform.forward, movement, turnSpeed * Time.deltaTime, 0f);rotation = Quaternion.LookRotation(desiredForward);rb.MovePosition(rb.position + movement * movementSpeed * Time.deltaTime);}private void OnAnimatorMove(){animator.SetBool("IsWalking", movement.magnitude > 0);rb.MoveRotation(rotation);}
}

3、增加奔跑

(1) 添加加速键Sprint(left shift            right shift)

(2) 回到PlayerController.cs,设置加速和奔跑

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayerController : MonoBehaviour
{public float turnSpeed = 20f;Animator animator;Rigidbody rb;Vector3 movement;Quaternion rotation = Quaternion.identity;[Header("Movement System")]public float walkSpeed = 1.5f;public float runSpeed = 3f;private void Start(){animator = GetComponent<Animator>();rb = GetComponent<Rigidbody>();}private void FixedUpdate(){float horizontal = Input.GetAxis("Horizontal");float vertical = Input.GetAxis("Vertical");movement.Set(horizontal, 0f, vertical);bool hasHorizontalInput = !Mathf.Approximately(horizontal, 0);bool hasVerticalInput = !Mathf.Approximately(vertical, 0);float movementSpeed = walkSpeed;if (Input.GetButton("Sprint") && (hasHorizontalInput || hasVerticalInput)){movementSpeed = runSpeed;}movement.Normalize();Vector3 desiredForward = Vector3.RotateTowards(transform.forward, movement, turnSpeed * Time.deltaTime, 0f);rotation = Quaternion.LookRotation(desiredForward);rb.MovePosition(rb.position + movement * movementSpeed * Time.deltaTime);}private void OnAnimatorMove(){animator.SetBool("IsWalking", movement.magnitude > 0);animator.SetBool("IsRunning", Input.GetButton("Sprint") && (movement.magnitude > 0));rb.MoveRotation(rotation);}
}

(3) AI提供的优化

using UnityEngine;public class PlayerController : MonoBehaviour
{public float turnSpeed = 20f;public Animator animator;public Rigidbody rb;public Vector3 movement;public Quaternion rotation = Quaternion.identity;private float speed;private bool isInputUpdated;[Header("Movement System")]public float walkSpeed = 6f;public float runSpeed = 12f;void Start(){animator = GetComponent<Animator>();rb = GetComponent<Rigidbody>();}private void FixedUpdate(){float horizontal = Input.GetAxis("Horizontal");float vertical = Input.GetAxis("Vertical");movement.Set(horizontal, 0f, vertical);movement.Normalize();bool hasHorizontalInput = !Mathf.Approximately(horizontal, 0f);bool hasVerticalInput = !Mathf.Approximately(vertical, 0f);if (Input.GetButton("Sprint")){speed = runSpeed;animator.SetBool("IsRunning", true);}else if (hasHorizontalInput || hasVerticalInput){speed = walkSpeed;animator.SetBool("IsWalking", true);}else{speed = 0f;animator.SetBool("IsWalking", false);animator.SetBool("IsRunning", false);}Vector3 desireForward = Vector3.RotateTowards(transform.forward, movement, turnSpeed * Time.fixedDeltaTime, 0f);rotation = Quaternion.LookRotation(desireForward);isInputUpdated = true;}private void OnAnimatorMove(){if (isInputUpdated){Vector3 movementSpeed = movement * speed;rb.MovePosition(rb.position + movementSpeed * Time.fixedDeltaTime);rb.MoveRotation(rotation);isInputUpdated = false; // Reset the flag after applying the input}}
}
五、相机跟随

1、调整相机的Transform

2、给Main Camera增加CameraController.cs组件 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CameraController : MonoBehaviour
{public float offsetz = 6f;public float smoothing = 8f;Transform playerPos;void Start(){playerPos = FindObjectOfType<PlayerController>().transform;}void Update(){FollowPlayer();}void FollowPlayer(){Vector3 targetPos = new Vector3(playerPos.position.x, 
transform.position.y, playerPos.position.z-offsetz);transform.position = Vector3.Lerp(transform.position, targetPos, smoothing*Time.deltaTime);}
}

农田处理

详细教程

一、准备工作

1、导入资源:在Import Asset文件夹下新建文件夹Farmland

(1) 新建文件夹Dirt,移入aerial_ground相关文件

(2) 新建文件夹Tilled land,移入 brown_mud_dry相关文件

(3) 新建文件夹Watered land,移入brown_mud相关文件

2、设置一块耕地 Land

3、制备预制体 Land(标签Land)

4、在Scripts文件夹下新建Farming 文件夹,其下新建Land.cs

二、制作农田

1、设置三种状态的耕地

(1) 打开Land预制体,给它添加Land.cs组件,使不同类型的土地渲染不同的材质,赋值

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Land : MonoBehaviour
{public enum LandStatus { Soil, Farmland, Watered }public LandStatus landStatus;public Material soilMat, farmlandMat, wateredMat;new Renderer renderer;void Start(){renderer = GetComponent<Renderer>();SwitchLandStatus(LandStatus.Soil);}public void SwitchLandStatus(LandStatus statusToSwitch){landStatus = statusToSwitch;Material materialToSwitch = soilMat;switch (statusToSwitch){case LandStatus.Soil: materialToSwitch = soilMat; break;case LandStatus.Farmland: materialToSwitch = farmlandMat; break;case LandStatus.Watered: materialToSwitch = wateredMat; break;}renderer.material = materialToSwitch;}
}

2、设置选中的土地块的形态

(1) 以Land为父物体,3D Object-Cube,命名Select,设置transform,移除Collider组件。

(2) 给Select制作并导入贴图,放在UI文件夹(新建)

(3) 打开Land预制体,选中Select,将贴图拖放到Select上,UI文件夹中出现新的文件夹Materials

(4) 打开文件夹Materials,选中新生成的材质球,将Rendering Mode更改为Transparent,更改Albedo的颜色,Smoothness设置为1

(5) 隐藏Select或在Land.cs的Start方法中添加select.SetActive(false);或Select(false);

3、回到Unity,复制这个Land,平铺这些田地,并转入FarmingArea空物体中

4、创建陆地:3D Object-Quad

三、人与耕地的交互

1、创建和设置检测射线

(1) 打开Player预制体,以Player为父物体,Create Empty,命名为 Interactor(发出射线方)

(2) 给Interactor添加PlayerInteraction.cs组件,设置检测射线

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayerInteraction : MonoBehaviour
{PlayerController playerController;void Start(){playerController = transform.parent.GetComponent<PlayerController>();}void Update(){RaycastHit hit;if(Physics.Raycast(transform.position, Vector3.down, out hit, 1)){OnInteractableHit(hit);}}void OnInteractableHit(RaycastHit hit){Collider other = hit.collider;Debug.Log(other.name);}
}

2、设置选中耕地时,出现选中状态

(1) 编辑Land.cs,增加是否被选中的方法

public GameObject select;void Start()
{renderer = GetComponent<Renderer>();SwitchLandStatus(LandStatus.Soil);Select(false);
}public void Select(bool toggle)
{select.SetActive(toggle);
}

(2) 赋值

(3) 编辑 PlayerInteraction.cs,区分农田和其他土地、设置选中框的显示

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayerInteraction : MonoBehaviour
{PlayerController playerController;Land selectLand = null;void Start(){playerController = transform.parent.GetComponent<PlayerController>();}void Update(){RaycastHit hit;if (Physics.Raycast(transform.position, Vector3.down, out hit, 1)){OnInteractableHit(hit);}}void OnInteractableHit(RaycastHit hit){Collider other = hit.collider;if (other != null && other.CompareTag("Land")){Land land = other.GetComponent<Land>();if (land != null){SelectLand(land); return;}else { Debug.Log("未选中任何田地"); }}if (selectLand != null){DeselectLand(selectLand);}}void SelectLand(Land land){if (land == null) { Debug.Log("你未选择田地"); return; }if (selectLand != null) { selectLand.Select(false); }selectLand = land;land.Select(true);}void DeselectLand(Land land){if(land == null) { Debug.Log("你没有选择田地");return; }land.Select(false);selectLand = null;}
}

3、建立交互系统 

(1) 编辑 Land.cs,添加 Interact 方法

public void Interact()
{SwitchLandStatus(LandStatus.Farmland);
}

(2) 编辑 PlayerInteraction.cs,添加 Interact 方法,调用Land中的Inseract方法

public void Interact()
{if(selectLand != null){selectLand.Interact();return;}Debug.Log("未站在田地上");
}

(3) 编辑 PlayerController.cs,添加 Interact 方法:当点击鼠标或按下左Ctrl键时,调用PlayerInteraction.cs中的Interact方法

PlayerInteraction playerInteraction;
void Start()
{animator = GetComponent<Animator>();rb = GetComponent<Rigidbody>();playerInteraction = GetComponentInChildren<PlayerInteraction>();
}
public void Update()
{Interact();
}
public void Interact()
{if (Input.GetButtonDown("Fire1")){playerInteraction.Interact();}
}

农具管理 

详细教程 标题四

水壶 标题一

一、准备工作

1、点击Windows- Package Manager,安装2D Sprite(标题四)

2、导入农具资源到UI 文件夹

3、拆分蔬菜和工具

4、在Scripts下创Inventory文件夹,在该文件夹下新建ItemData.cs

5、在Assets文件下创建Data文件夹,在Data下创建两个文件夹:Items和Tools

6、在Tools文件夹新建文件夹Seeds

二、准备农具模型

1、模型下载

官网资源

模型下载

模型下载

(1) Watering Can  https://www.cgtrader.com/free-3d-models/household/other/watering-can-c76fe658-8352-4ed8-8d08-b2bc0b0af9e6

(2) hoe   https://www.cgtrader.com/items/4145952/download-page

(3) axe  https://www.cgtrader.com/free-3d-models/industrial/tool/axe-lowpoly-pbr-simple

(4) pickaxe https://www.cgtrader.com/free-3d-models/various/various-models/pickaxe-5903c86c-f84f-44bd-af34-8f7ce07666b9

(5) shovel  https://www.cgtrader.com/free-3d-models/household/household-tools/shovel-b4035fae-6192-4afe-a238-1c4ec2877a5f

2、改变轴心点的简易方法:

使用Empty GameObject作为容器:在Unity中创建一个空的GameObject,将预制体作为其子对象。然后,在父对象的Transform组件中调整其Position属性,将其移动到期望的位置。父对象的轴心点即是预制体的轴心点

3、导入模型资源

(1) 注意:下载后在各自的文件夹中将需要导入的文件夹名改为Texture

(2) 在Import Asset 文件夹分别新建Tools和Items文件夹

(3) 在Tools文件夹中分别创建WarteringCan,Axe,Pickaxe,Shovel,Hoe文件夹

(4) 导入相应农具(将含有下列资源的Textures文件夹直接拖入相应文件夹)

4、制作模型预制体

(1) Create Empty,命名工具

(2) 以步骤(1) 的物体为父物体,添加子物体农具

(3) 制作预制体

三、创建农具的类(ItemData对象)

1、编辑 ItemData.cs,设置所有农具都具备的节点

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[CreateAssetMenu(menuName = "Items/Item")]
public class ItemData : ScriptableObject
{public string description;public Sprite thumbnail;public GameObject gameModel;
}

2、创建ItemData对象——卷心菜

(1) 在Items文件夹下Create-Item,命名为Cabbage

(2) 选中Cabbage,设置description为A leafy Green vegetable

3、创建工具

(1) 打开Scripts下的Inventory文件夹,新建EquipmentData.cs

using System.Collections;
using System.Collections.Generic;
using UnityEditor.Search;
using UnityEngine;[CreateAssetMenu(menuName = ("Items/Equipment"))]
public class EquipmentData : ItemData
{public enum ToolType { Hoe, WateringCan, Axe, Pickaxt, Shovel}public ToolType Type;
}

(2) Tools文件夹Create-Items-Equipment,命名为Hoe,

(3) 同样的方法创建WarteringCan,Axe,Pickaxe,Shovel

(4) 设置它们的description

Axe:For cleaning wood obstacles

Hoe:For tilling the land

Pickaxe:For cleaning rock obstacles

Watering Can:For watering the plants to make them grow

Shovel:Clear plant material

(4) 设置它们的thumbnail:Axe:12;Hoe:13;Pickaxe:11;Shovel:10

4、设置ItemData的Game Model

5、创建种子

(1) 在Scripts下的Inventory文件夹下创建SeedData.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[CreateAssetMenu(menuName =("Items/Seed"))]public class SeedData : ItemData
{public int daysToGrow;public ItemData cropToYield;
}

(2) Seed文件夹下创建Seed文件,命名为Cabbage Seed。description为Seeds to grow cabbages 

(3) 设置Cabbage Seed的各节点

UI面板

 

详细教程 标题六

一、准备工作

1、Create Empty,命名为Manager

(1) 打开Scripts文件夹,新建UI文件夹

(2) 在UI文件夹中,添加InventoryManager.cs和UIManager.cs

(3) 给 Manager 添加UIManager.cs组件

2、新建Canvas:以Manager为父物体,UI-Canvas,设置UI Scale Mode和Reference Resolution

3、创建背包按钮:以Canvas为父物体,创建按钮,命名为InventoryButton,大小160,144

4、以Canvas为父物体,Create Empty。命名为InventoryPanel。Alt+Strech

5、工具栏

(1) 工具栏背景:以InventoryPanel为父物体,UI-Image,命名为ToolsPanel

(2) 工具栏名称:以ToolsPanel为父物体,UI-Text,命名为Header

(3) 选中的工具槽:以ToolsPanel为父物体,UI-Image,命名为HandSlot。

(4) 工具槽预制体:

① 工具槽区域:

以ToolsPanel为父物体,Create Empty。命名为InventorySlots

添加Grid Layout Group组件

② 工具槽背景:

以InventorySlots为父物体,UI-Image

复制得到 8 个工具槽。选中InventorySlots,设置Grid Layout Group,使工具槽均匀分列两行

③ 工具槽预制体

删除复制出的Image,保留的Image重命名为InventorySlot,设置颜色AF8E60,

打开Prefabs文件夹,新建UI 文件夹,将InventorySlot制成预制体

④ 工具槽中工具缩略图

以InventorySlot(物品背景)为父物体,UI-Image,命名为ItemDisplay(物品缩略图)。

设置大小位置图片,勾选Preserve Aspect

⑤ 工具槽中的工具位:复制InventorySlot,得到8个工具位

6、物品栏(收获的物品)

(1) 复制ToolsPanel,重命名为ItemsPanel,调整到适当位置

(2) 更改文本Tools为Items

7、说明面板

(1) 背景:以InventoryPanel为父物体,UI-Image。命名为ItemInfo

(2) 说明文本(名称):以ItemInfo为父物体,UI-text,命名为ItemName

(3) 说明文本(描述):复制ItemName,命名为ItemDescription,设置大小字号等

8、隐藏InventoryPanel面板

9、创建返回按钮:复制背包按钮,重命名为ExitBtn。放入InventoryPanel面板,设置大小颜色等

10、设置按钮

(1) 编辑UIManager.cs,设置UI面板显示或隐藏

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class UIManager : MonoBehaviour
{public static UIManager Instance { get; private set; }public GameObject inventoryPanle;private void Awake(){if (Instance != null && Instance != this) { Destroy(gameObject); }else { Instance = this; }}private void OnDestroy(){if (Instance == this) { Instance = null; }}public void ToggleInventoryPanel(){inventoryPanle.SetActive(!inventoryPanle.activeSelf);}
}

(2) 赋值

(3) 设置按钮:背包、返回两个按钮

二、显示物品缩略图

1、管理一个物品槽中的物品的属性和数量

(1) 打开Scripts-Inventory文件新建 ItemSlotData.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[System.Serializable]
public class ItemSlotData
{public ItemData itemData;public int quantity;public ItemSlotData(ItemData itemData, int quantity){this.itemData = itemData;this.quantity = quantity;ValidateQuantity();}public ItemSlotData(ItemData itemData){this.itemData = itemData;quantity = 1;ValidateQuantity();}public void AddQuantity(){AddQuantity(1);}public void AddQuantity(int amountToAdd){quantity += amountToAdd;}public void Remove(){quantity--;ValidateQuantity();}public void ValidateQuantity(){if (quantity <= 0 || itemData ==null){Empty();}}public void Empty(){itemData = null;quantity = 0;}
}

(2) 作用:根据传入的参数不同,创建不同的ItemSlotData对象,并设置该对象的数量 

2、显示物品槽中物品的缩略图的方法

(1) 在UI文件夹下新建InventorySlot.cs,给打开预制体InventorySlot,添加这个组件

(2) 编辑InventorySlot.cs,通过Display方法显示物品缩略图

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class InventorySlot : MonoBehaviour
{ItemData itemToDisplay;public Image itemDisplayImage;public enum InventoryType { Item, Tool }public InventoryType inventoryType;public void Display(ItemSlotData itemSlot){itemToDisplay = itemSlot.itemData;if (itemToDisplay != null && itemToDisplay.thumbnail != null){itemDisplayImage.sprite = itemToDisplay.thumbnail;itemDisplayImage.gameObject.SetActive(true);return;}itemDisplayImage.gameObject.SetActive(false);this.itemToDisplay = null;}
}

(3) 打开InventorySlot 预制体,赋值

(4) 在Hierarchy面板,赋值Type

3、编辑InventoryManager.cs

(1) 初始化工具槽数组和工具槽,检查选中物体类型

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class InventoryManager : MonoBehaviour
{public static InventoryManager Instance { get; private set; }[Header("Tools")][SerializeField] private ItemSlotData[] toolSlots = new ItemSlotData[8];[SerializeField] private ItemSlotData equippedToolSlot = null;[Header("Items")][SerializeField] private ItemSlotData[] itemSlots = new ItemSlotData[8];[SerializeField] private ItemSlotData equippedItemSlot = null;private void Awake(){if (Instance != null && Instance != this) { Destroy(gameObject); }else { Instance = this; }}private void OnDestroy(){if(Instance == this) { Instance = null; }}#region Gets and Checkspublic ItemSlotData[] GetInventorySlots(InventorySlot.InventoryType inventoryType){if(inventoryType == InventorySlot.InventoryType.Item) {  return itemSlots; }return toolSlots;}#endregion
}

(2) 赋值

4、编辑UIManager.cs

(1) 显示工具栏中工具的缩略图

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class UIManager : MonoBehaviour
{public static UIManager Instance { get; private set; }public GameObject inventoryPanle;public InventorySlot[] toolSlots;private void Awake(){if (Instance != null && Instance != this) { Destroy(gameObject); }else { Instance = this; }}private void OnDestroy(){if (Instance == this) { Instance = null; }}void Start(){RenderInventory();}public void RenderInventory(){ItemSlotData[] inventoryToolSlots =InventoryManager.Instance.
GetInventorySlots(InventorySlot.InventoryType.Tool);RenderInventoryPanel(inventoryToolSlots,toolSlots);}void RenderInventoryPanel(ItemSlotData[] slots, InventorySlot[] uiSlots){for (int i = 0; i < uiSlots.Length; i++){uiSlots[i].Display(slots[i]);}}public void ToggleInventoryPanel(){inventoryPanle.SetActive(!inventoryPanle.activeSelf);//注意增加更新物品栏内容的方法RenderInventory();}
}

(2) 赋值

5、显示物品栏(收获物品)缩略图

(1) 编辑UIManager.cs,显示物品栏的缩略图

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class UIManager : MonoBehaviour
{public static UIManager Instance { get; private set; }//归类管理Unity编辑器的Inspector面板[Header("Inventory System")]public GameObject inventoryPanle;public InventorySlot[] toolSlots;//物品槽public InventorySlot[] itemSlots;private void Awake(){if (Instance != null && Instance != this) { Destroy(gameObject); }else { Instance = this; }}private void OnDestroy(){if (Instance == this) { Instance = null; }}void Start(){RenderInventory();}public void RenderInventory(){ItemSlotData[] inventoryToolSlots = InventoryManager.Instance.GetInventorySlots(InventorySlot.InventoryType.Tool);//物品槽ItemSlotData[] inventoryItemSlots = InventoryManager.Instance.GetInventorySlots(InventorySlot.InventoryType.Item);RenderInventoryPanel(inventoryToolSlots, toolSlots);//物品槽RenderInventoryPanel(inventoryItemSlots, itemSlots);}void RenderInventoryPanel(ItemSlotData[] slots, InventorySlot[] uiSlots){for (int i = 0; i < uiSlots.Length; i++){uiSlots[i].Display(slots[i]);}}public void ToggleInventoryPanel(){inventoryPanle.SetActive(!inventoryPanle.activeSelf);RenderInventory();}
}

(2) 赋值

三、显示物品名称和描述

1、设置文本

(1) 编辑UIManager.cs,设置文本应该显示的信息

//物品名称和描述文本
public Text itemNameText;
public Text itemDescriptionText;
public void DisplayItemInfo(ItemData data)
{if (data == null){itemNameText.text = "";itemDescriptionText.text = "";return;}itemNameText.text = data.name;itemDescriptionText.text = data.description;
}

(2) 赋值

2、编辑InventorySlot.cs, 增加鼠标悬停事件

//增加接口
public class InventorySlot : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler
{public void OnPointerEnter(PointerEventData eventData){UIManager.Instance.DisplayItemInfo(itemToDisplay);}public void OnPointerExit(PointerEventData eventData){UIManager.Instance.DisplayItemInfo(null);}
}
四、显示物品数量

详细教程步骤二

1、添加物品数量文本

(1) 以HandSlot为父物体,UI-Text,重命名为QuantityText,设置大小位置文本字体段落颜色

(2) Apply 预制体InventorySlot的更改

2、验证物品栏槽位的有效性

(1) 编辑InventoryManager.cs

#region Inventory Slot validation
//在Unity编辑器中当脚本发生变化时自动调用,用于验证物品栏槽位的有效性
public void OnValidate()
{ValidateInventorySlots(itemSlots);ValidateInventorySlots(toolSlots);
}
//验证单个物品栏槽位的有效性。如果物品栏槽位中的物品存在但数量为0,则将数量设置为1
void ValidateInventorySlots(ItemSlotData slot)
{if(slot.itemData != null && slot.quantity == 0){slot.quantity = 1;}
}
//用于验证物品栏槽位数组中的所有槽位的有效性。
//通过循环调用ValidateInventorySlots(ItemSlotData slot)方法来验证每个槽位的有效性
void ValidateInventorySlots(ItemSlotData[] array)
{foreach(ItemSlotData slot in array){ValidateInventorySlots(slot);}
}
#endregion

(2) 假设各物品的初始数量(用于后续测试)

3、显示物品数量

(1) 编辑InventorySlot.cs, 增加需要显示物品的数量

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;public class InventorySlot : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler
{ItemData itemToDisplay;public Image itemDisplayImage;//物品数量int quantity;//数量文本public Text quantityText;public enum InventoryType { Item, Tool }public InventoryType inventoryType;public void Display(ItemSlotData itemSlot){itemToDisplay = itemSlot.itemData;//初始化数量quantity = itemSlot.quantity;//初始的数量文本quantityText.text = "";if (itemToDisplay != null && itemToDisplay.thumbnail != null){itemDisplayImage.sprite = itemToDisplay.thumbnail;//数量文本if (quantity > 1){quantityText.text = quantity.ToString();}itemDisplayImage.gameObject.SetActive(true);return;}itemDisplayImage.gameObject.SetActive(false);this.itemToDisplay = null;}public void OnPointerEnter(PointerEventData eventData){UIManager.Instance.DisplayItemInfo(itemToDisplay);}public void OnPointerExit(PointerEventData eventData){UIManager.Instance.DisplayItemInfo(null);}
}

 (2) 赋值

物品槽和状态栏UI

详细教程 步骤十一、步骤十四

一、准备工作

1、状态栏背景:UI-Image,命名为StatusBar,调整大小、位置等。颜色F4DDB7

2、手持物品:复制一个HandSlot,作为StatusBar的子物体

3、时间框:以StatusBar为父物体,Create Empty,命名为TimeInfo

4、天气位:复制步骤 2 中的HandSlot,作为TimeInfo的子物体,命名为Weather

5、季节和星期:以TimeInfo为父物体UI-Text,重命名为Date

6、时间:以TimeInfo为父物体UI-Text,重命名为Time

7、在UI文件夹新建 HandInventorySlot.cs 作为InventorySlot.cs的子类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class HandInventorySlot : InventorySlot
{}

8、装备物品槽缩略图和数量:

(1) 复制InventorySlot下的ItemDisplay,作为子物体粘贴到ToolPanel下的 HandSlot下

(2) 复制InventorySlot下的QuantityText,作为子物体粘贴到ToolPanel下的 HandSlot下

(3) 给ToolPanel下的 HandSlot  添加HandInventorySlot.cs组件,赋值,更改Inventory Type

(4) 同样的方法设置ItemPanel下的 HandSlot 

9、手持物品缩略图和数量:

(1) 以步骤2的HandSlot为父物体,UI-Image,命名为HandSlotImage

(2) 复制InventorySlot下的QuantityText,作为子物体粘贴到StatusBar下的 HandSlot下,调整大小

(3) 给StatusBar下的 HandSlot  添加HandInventorySlot.cs组件,赋值(注意更改Inventory Type)

二、装备物品槽缩略图

1、设定装备物品槽的类型

(1) 编辑 InventoryManager.cs

#region Gets and Checks
//待装备物品的类型
public ItemSlotData GetEquippedSlot(InventorySlot.InventoryType inventoryType)
{if(inventoryType == InventorySlot.InventoryType.Item){return equippedItemSlot;}return equippedToolSlot;
}
public ItemSlotData[] GetInventorySlots(InventorySlot.InventoryType inventoryType)
{if(inventoryType == InventorySlot.InventoryType.Item) {  return itemSlots; }return toolSlots;
}
#endregion

(2) 赋值

 

2、显示装备槽中的物品

(1) 编辑UIManager.cs

//装备物品槽中的待装备物品
public HandInventorySlot toolHandSlot;
public HandInventorySlot itemHandSlot;
public void RenderInventory()
{ItemSlotData[] inventoryToolSlots = InventoryManager.Instance.GetInventorySlots(InventorySlot.InventoryType.Tool);RenderInventoryPanel(inventoryToolSlots, toolSlots);ItemSlotData[] inventoryItemSlots = InventoryManager.Instance.GetInventorySlots(InventorySlot.InventoryType.Item);RenderInventoryPanel(inventoryItemSlots, itemSlots);//待装备物品toolHandSlot.Display(InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Tool));itemHandSlot.Display(InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Item));
}

(2) 赋值

三、手持槽物品缩略图

1、设定和检查手持物品槽的类型: 编辑 InventoryManager.cs

    #region Gets and Checks//手持槽的类型public ItemData GetEquippedSlotItem(InventorySlot.InventoryType inventoryType){if (inventoryType == InventorySlot.InventoryType.Item){return equippedItemSlot.itemData;}return equippedToolSlot.itemData;}//装备槽的类型public ItemSlotData GetEquippedSlot(InventorySlot.InventoryType inventoryType){if(inventoryType == InventorySlot.InventoryType.Item){return equippedItemSlot;}return equippedToolSlot;}//物品栏中物品槽的类型public ItemSlotData[] GetInventorySlots(InventorySlot.InventoryType inventoryType){if(inventoryType == InventorySlot.InventoryType.Item) {  return itemSlots; }return toolSlots;}//工具还是种子public bool IsTool(ItemData item){EquipmentData equipment = item as EquipmentData;if (equipment != null) { return true; }SeedData seed = item as SeedData;return seed != null;}#endregion

2、显示手持槽中的物品

(1) 编辑UIManager.cs

//手持物品
public Image toolEquipSlotImage;
public void RenderInventory()
{ItemSlotData[] inventoryToolSlots = InventoryManager.Instance.GetInventorySlots(InventorySlot.InventoryType.Tool);RenderInventoryPanel(inventoryToolSlots, toolSlots);ItemSlotData[] inventoryItemSlots = InventoryManager.Instance.GetInventorySlots(InventorySlot.InventoryType.Item);RenderInventoryPanel(inventoryItemSlots, itemSlots);toolHandSlot.Display(InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Tool));itemHandSlot.Display(InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Item));//手持槽物品ItemData equippedTool = InventoryManager.Instance.GetEquippedSlotItem(InventorySlot.InventoryType.Tool);if (equippedTool != null){toolEquipSlotImage.sprite = equippedTool.thumbnail;toolEquipSlotImage.gameObject.SetActive(true);return;}toolEquipSlotImage.gameObject.SetActive(false);
}

(2) 赋值

物品交换
一、为物品分配索引值

1、分配被点击物品的索引:编辑InventorySlot.cs,把被点击物品的索引分配给this.slotIndex

//点击的物品槽的索引
int slotIndex;
//把被点击物品的索引分配给this.slotIndex
public void AssignIndex(int slotIndex)
{this.slotIndex = slotIndex;
}

2、为物品栏中的每一个物品分配一个索引值:

(1) 编辑UIManager.cs,创建并在Start方法中调用AssignSlotIndex()方法

void Start()
{RenderInventory();//调用方法AssignSlotIndex();
}
//遍历……数组,并为数组中的每个 InventorySlot 对象分配一个索引值
public void AssignSlotIndex()
{for(int i = 0; i < toolSlots.Length; i++){toolSlots[i].AssignIndex(i);itemSlots[i].AssignIndex(i);}
}

(2) 索引值被传递给InventorySlot.cs中的AssignIndex(int slotIndex)方法,并在slotIndex中显示出来

二、物品槽到装备槽

1、编辑 ItemSlotData.cs

(1) 比较两个物体的itemData属性是否相同(是不是同一种物体——用于堆叠物品)

(2) 判断某itemData是否为空,可结合Empty方法,用于清空物品槽中的物品

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[System.Serializable]
public class ItemSlotData
{public ItemData itemData;public int quantity;public ItemSlotData(ItemData itemData, int quantity){this.itemData = itemData;this.quantity = quantity;ValidateQuantity();}public ItemSlotData(ItemData itemData){this.itemData = itemData;quantity = 1;ValidateQuantity();}public ItemSlotData(ItemSlotData slotToClone){itemData = slotToClone.itemData;quantity = slotToClone.quantity;}public void AddQuantity(){AddQuantity(1);}public void AddQuantity(int amountToAdd){quantity += amountToAdd;}public void Remove(){quantity--;ValidateQuantity();}//比较传入的参数slotToCompare和当前ItemSlotData对象(this)的的itemData属性是否相同//并返回一个布尔值//具体作用:判断二者是否可以叠加//调用方法:A.Stackalbe(B);public bool Stackable(ItemSlotData slotToCompare){return slotToCompare.itemData == itemData;}public void ValidateQuantity(){if (quantity <= 0 || itemData == null){Empty();}}public void Empty(){itemData = null;quantity = 0;}//判断ItemSlotData对象的itemData属性是否为空(null)public bool IsEmpty(){return itemData == null;}
}

2、编辑 InventoryManager.cs

(1) 增加两个物品转移的方法

public void InventoryToHand(int slotIndex,InventorySlot.InventoryType inventoryType)
{Debug.Log("装备物品");
}
public void HandToInventory(InventorySlot.InventoryType inventoryType)
{Debug.Log("收回物品");
}

(2) 检查装备槽位

public void OnValidate()
{//检查装备槽位ValidateInventorySlots(equippedToolSlot);ValidateInventorySlots(equippedItemSlot);//检查物品栏中的物品槽位ValidateInventorySlots(itemSlots);ValidateInventorySlots(toolSlots);
}

(3) 依据选中槽所属的类型,将选中槽赋值给变量handToEquip

    public void InventoryToHand(int slotIndex,InventorySlot.InventoryType inventoryType){ItemSlotData handToEquip;ItemSlotData[] inventoryToAlter;if (inventoryType == InventorySlot.InventoryType.Item){handToEquip = equippedItemSlot;inventoryToAlter = itemSlots;}else{handToEquip = equippedToolSlot;inventoryToAlter = toolSlots;}}

(3) 增加将物品槽中的物品复制到装备槽的方法

public void EquipHandSlot(ItemData item)
{if (IsTool(item)){equippedToolSlot = new ItemSlotData(item);}else{equippedItemSlot = new ItemSlotData(item);}
}
//根据物品类型将选中物品由物品槽复制到装备槽
public void EquipHandSlot(ItemSlotData itemSlot)
{//获取选中物品槽的物品数据ItemData item = itemSlot.itemData;//调用IsTool方法检查物品类型if (IsTool(item)){//(物品是工具类型)将 itemSlot 中的物品数据复制到 equippedToolSlot 中equippedToolSlot = new ItemSlotData(itemSlot);}else{//如果物品不是工具类型,将 itemSlot 中的物品数据复制到 equippedItemSlot 中equippedItemSlot = new ItemSlotData(itemSlot);}
}

(4)  工具槽中的物品转移到装备槽(堆叠或转移)

    public void InventoryToHand(int slotIndex,InventorySlot.InventoryType inventoryType){ItemSlotData handToEquip;ItemSlotData[] inventoryToAlter;if (inventoryType == InventorySlot.InventoryType.Item){handToEquip = equippedItemSlot;inventoryToAlter = itemSlots;}else{handToEquip = equippedToolSlot;inventoryToAlter = toolSlots;}//(选中槽与装备槽物品相同)可以堆叠,同时清空选中槽物品if (handToEquip.Stackable(inventoryToAlter[slotIndex])){ItemSlotData slotToAlter = inventoryToAlter[slotIndex];handToEquip.AddQuantity(slotToAlter.quantity);slotToAlter.Empty();}//不能堆叠,选中槽物品转移到装备槽,同时清空选中槽物品else{//将 inventoryToAlter 数组中的指定索引 slotIndex 的值赋给临时变量 slotToEquipItemSlotData slotToEquip = new ItemSlotData(inventoryToAlter[slotIndex]);//将 handToEquip 的值赋给 inventoryToAlter 数组中的指定索引 slotIndexinventoryToAlter[slotIndex] = new ItemSlotData(handToEquip);//临时变量中的物品复制到装备槽EquipHandSlot(slotToEquip);//清空handToEquip 的值handToEquip.Empty();}UIManager.Instance.RenderInventory();}

 

3、编辑 InventorySlot.cs,实现物品转移

(1) 增加鼠标点击事件,调用InventoryManager.cs方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;//增加点击事件接口
public class InventorySlot : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler,IPointerClickHandler
{ItemData itemToDisplay;public Image itemDisplayImage;//点击的物品槽的索引int slotIndex;int quantity;public Text quantityText;public enum InventoryType { Item, Tool }public InventoryType inventoryType;public void Display(ItemSlotData itemSlot){itemToDisplay = itemSlot.itemData;quantity = itemSlot.quantity;quantityText.text = "";if (itemToDisplay != null && itemToDisplay.thumbnail != null){itemDisplayImage.sprite = itemToDisplay.thumbnail;if (quantity > 1){quantityText.text = quantity.ToString();}itemDisplayImage.gameObject.SetActive(true);return;}itemDisplayImage.gameObject.SetActive(false);this.itemToDisplay = null;}public void AssignIndex(int slotIndex){this.slotIndex = slotIndex;}public void OnPointerEnter(PointerEventData eventData){UIManager.Instance.DisplayItemInfo(itemToDisplay);}public void OnPointerExit(PointerEventData eventData){UIManager.Instance.DisplayItemInfo(null);}//点击事件(注意可重写)public virtual void OnPointerClick(PointerEventData eventData){InventoryManager.Instance.InventoryToHand(slotIndex, inventoryType);}
}

(2) 解析:调用InventoryManager.cs方法。传入的参数:点击的物品槽索引,所处的物品栏类型

 4、重写点击事件:

(1) 目的:点击已装备槽时,调用InventoryMagager类中的HandToInventory方法

(2) 编辑HandInventorySlot.cs,传入参数为点击选中槽所属的类型

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;public class HandInventorySlot : InventorySlot
{public override void OnPointerClick(PointerEventData eventData){InventoryManager.Instance.HandToInventory(inventoryType);}
}
三、装备槽到物品槽

1、编辑 InventoryManager.cs

(1) 增加装备槽复制到物品槽的方法

    #region 物品交换的方法//根据物品类型将装备槽中的物品由装备槽复制到物品槽public bool StackItemToInventory(ItemSlotData itemSlot, ItemSlotData[] inventoryArray){//遍历inventoryArray(某类物品栏的物品槽数组)for (int i = 0; i < inventoryArray.Length; i++){//可以堆叠(装备槽物品与物品栏中的某种物品是同种物品)if (inventoryArray[i].Stackable(itemSlot)){inventoryArray[i].AddQuantity(itemSlot.quantity);itemSlot.Empty();return true;}}return false;}public void EquipHandSlot(ItemSlotData itemSlot){ItemData item = itemSlot.itemData;if (IsTool(item)){equippedToolSlot = new ItemSlotData(itemSlot);}else{equippedItemSlot = new ItemSlotData(itemSlot);}}#endregion

(2) 编辑物品由装备槽转移到物品槽的方法

    public void HandToInventory(InventorySlot.InventoryType inventoryType){ItemSlotData handSlot;ItemSlotData[] inventoryToAlter;//确定点击物品的类型并赋值if(inventoryType == InventorySlot.InventoryType.Item){handSlot = equippedItemSlot;inventoryToAlter = itemSlots;}else{handSlot = equippedToolSlot;inventoryToAlter = toolSlots;}if(!StackItemToInventory(handSlot, inventoryToAlter)){for(int i = 0; i < inventoryToAlter.Length; i++){if (inventoryToAlter[i].IsEmpty()){inventoryToAlter[i] = new ItemSlotData(handSlot);handSlot.Empty();break;}}}UIManager.Instance.RenderInventory();}

if (!StackItemToInventory(handSlot, inventoryToAlter)){}

① 先执行StackItemToInventory() 方法,返回一个bool值

② 若物品可以堆叠,则StackItemToInventory() 方法返回的值为true,

if (!StackItemToInventory(handSlot, inventoryToAlter)){}该语句不能执行

③ 若物品不能堆叠,则StackItemToInventory() 方法返回的值为false,

执行 if (!StackItemToInventory(handSlot, inventoryToAlter)){}

2、InventoryManager.cs 的完整代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class InventoryManager : MonoBehaviour
{public static InventoryManager Instance { get; private set; }[Header("Tools")][SerializeField] private ItemSlotData[] toolSlots = new ItemSlotData[8];[SerializeField] private ItemSlotData equippedToolSlot = null;[Header("Items")][SerializeField] private ItemSlotData[] itemSlots = new ItemSlotData[8];[SerializeField] private ItemSlotData equippedItemSlot = null;private void Awake(){if (Instance != null && Instance != this) { Destroy(gameObject); }else { Instance = this; }}private void OnDestroy(){if(Instance == this) { Instance = null; }}public void InventoryToHand(int slotIndex,InventorySlot.InventoryType inventoryType){ItemSlotData handToEquip;ItemSlotData[] inventoryToAlter;if (inventoryType == InventorySlot.InventoryType.Item){handToEquip = equippedItemSlot;inventoryToAlter = itemSlots;}else{handToEquip = equippedToolSlot;inventoryToAlter = toolSlots;}if (handToEquip.Stackable(inventoryToAlter[slotIndex])){ItemSlotData slotToAlter = inventoryToAlter[slotIndex];handToEquip.AddQuantity(slotToAlter.quantity);slotToAlter.Empty();}else{ItemSlotData slotToEquip = new ItemSlotData(inventoryToAlter[slotIndex]);inventoryToAlter[slotIndex] = new ItemSlotData(handToEquip);EquipHandSlot(slotToEquip);handToEquip.Empty();}UIManager.Instance.RenderInventory();}public void HandToInventory(InventorySlot.InventoryType inventoryType){ItemSlotData handSlot;ItemSlotData[] inventoryToAlter;if(inventoryType == InventorySlot.InventoryType.Item){handSlot = equippedItemSlot;inventoryToAlter = itemSlots;}else{handSlot = equippedToolSlot;inventoryToAlter = toolSlots;}//将装备槽中的物品堆叠到相应的物品槽中if (!StackItemToInventory(handSlot, inventoryToAlter)){for(int i = 0; i < inventoryToAlter.Length; i++){if (inventoryToAlter[i].IsEmpty()){inventoryToAlter[i] = new ItemSlotData(handSlot);handSlot.Empty();break;}}}UIManager.Instance.RenderInventory();}#region Gets and Checks//手持物品槽的类型public ItemData GetEquippedSlotItem(InventorySlot.InventoryType inventoryType){if (inventoryType == InventorySlot.InventoryType.Item){return equippedItemSlot.itemData;}return equippedToolSlot.itemData;}//选中物品槽的类型public ItemSlotData GetEquippedSlot(InventorySlot.InventoryType inventoryType){if(inventoryType == InventorySlot.InventoryType.Item){return equippedItemSlot;}return equippedToolSlot;}//物品栏中物品槽的类型public ItemSlotData[] GetInventorySlots(InventorySlot.InventoryType inventoryType){if(inventoryType == InventorySlot.InventoryType.Item) {  return itemSlots; }return toolSlots;}//检查特定类型的槽位是否已经装备了物品public bool SlotEquipped(InventorySlot.InventoryType inventoryType){if (inventoryType == InventorySlot.InventoryType.Item){return !equippedItemSlot.IsEmpty();}return !equippedToolSlot.IsEmpty();}//检查给定的物品是否为工具,若为工具或种子,返回为true,否则返回falsepublic bool IsTool(ItemData item){//将 item 强制转换为 EquipmentData 类型,并将结果赋值给 equipment 变量EquipmentData equipment = item as EquipmentData;if (equipment != null){return true;}SeedData seed = item as SeedData;return seed != null;}#endregion#region 物品交换的方法//根据物品类型将装备槽中的物品由装备槽复制到物品槽public bool StackItemToInventory(ItemSlotData itemSlot, ItemSlotData[] inventoryArray){//遍历inventoryArray(某类物品栏的物品槽数组)for (int i = 0; i < inventoryArray.Length; i++){//可以堆叠(装备槽物品与物品栏中的某种物品是同种物品)if (inventoryArray[i].Stackable(itemSlot)){inventoryArray[i].AddQuantity(itemSlot.quantity);itemSlot.Empty();return true;}}return false;}//根据物品类型将选中物品由物品槽复制到装备槽public void EquipHandSlot(ItemSlotData itemSlot){//获取选中物品槽的物品数据ItemData item = itemSlot.itemData;//调用IsTool方法检查物品类型if (IsTool(item)){//(物品是工具类型)将 itemSlot 中的物品数据复制到 equippedToolSlot 中equippedToolSlot = new ItemSlotData(itemSlot);}else{//如果物品不是工具类型,将 itemSlot 中的物品数据复制到 equippedItemSlot 中equippedItemSlot = new ItemSlotData(itemSlot);}}#endregion#region Inventory Slot validation(验证物品栏槽位的有效性)public void OnValidate(){//检查装备槽位ValidateInventorySlots(equippedToolSlot);ValidateInventorySlots(equippedItemSlot);ValidateInventorySlots(itemSlots);ValidateInventorySlots(toolSlots);}void ValidateInventorySlots(ItemSlotData slot){if(slot.itemData != null && slot.quantity == 0){slot.quantity = 1;}}void ValidateInventorySlots(ItemSlotData[] array){foreach(ItemSlotData slot in array){ValidateInventorySlots(slot);}}#endregion
}
状态栏物品和数量

1、编辑UIManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class UIManager : MonoBehaviour
{public static UIManager Instance { get; private set; }[Header("Inventory System")]public GameObject inventoryPanle;public InventorySlot[] toolSlots;public InventorySlot[] itemSlots;public HandInventorySlot toolHandSlot;public HandInventorySlot itemHandSlot;public Text itemNameText;public Text itemDescriptionText;//状态栏工具数量public Text toolQuantityText;public Image toolEquipSlotImage;private void Awake(){if (Instance != null && Instance != this) { Destroy(gameObject); }else { Instance = this; }}private void OnDestroy(){if (Instance == this) { Instance = null; }}void Start(){RenderInventory();AssignSlotIndex();}public void AssignSlotIndex(){for(int i = 0; i < toolSlots.Length; i++){toolSlots[i].AssignIndex(i);itemSlots[i].AssignIndex(i);}}public void RenderInventory(){ItemSlotData[] inventoryToolSlots = InventoryManager.Instance.GetInventorySlots
(InventorySlot.InventoryType.Tool);RenderInventoryPanel(inventoryToolSlots, toolSlots);ItemSlotData[] inventoryItemSlots = InventoryManager.Instance.GetInventorySlots
(InventorySlot.InventoryType.Item);RenderInventoryPanel(inventoryItemSlots, itemSlots);toolHandSlot.Display(InventoryManager.Instance.GetEquippedSlot
(InventorySlot.InventoryType.Tool));itemHandSlot.Display(InventoryManager.Instance.GetEquippedSlot
(InventorySlot.InventoryType.Item));//手持槽物品ItemData equippedTool = InventoryManager.Instance.GetEquippedSlotItem
(InventorySlot.InventoryType.Tool);//状态栏工具数量的文本toolQuantityText.text = "";if (equippedTool != null){toolEquipSlotImage.sprite = equippedTool.thumbnail;toolEquipSlotImage.gameObject.SetActive(true);//显示状态栏上的工具的数量int quantity = InventoryManager.Instance.GetEquippedSlot
(InventorySlot.InventoryType.Tool).quantity;if (quantity > 1){toolQuantityText.text = quantity.ToString();}return;}toolEquipSlotImage.gameObject.SetActive(false);}void RenderInventoryPanel(ItemSlotData[] slots, InventorySlot[] uiSlots){for (int i = 0; i < uiSlots.Length; i++){uiSlots[i].Display(slots[i]);}}public void DisplayItemInfo(ItemData data){if (data == null){itemNameText.text = "";itemDescriptionText.text = "";return;}itemNameText.text = data.name;itemDescriptionText.text = data.description;}public void ToggleInventoryPanel(){inventoryPanle.SetActive(!inventoryPanle.activeSelf);RenderInventory();}
}

2、赋值

更换土壤状态

详细教程步骤六、2

一、手持农具

1、编辑Player预制体,添加手持物体的位置

     以mixamorig6:RightHand为父物体,Create Empty,重命名为Hand Point

2、添加农具模型

(1) 编辑InventoryManager.cs,创建并调用手持农具的方法

//手持物体的位置
public Transform handPoint;
public void InventoryToHand(int slotIndex,InventorySlot.InventoryType inventoryType)
{//其它代码//手持农具if (inventoryType == InventorySlot.InventoryType.Tool){RenderHand();}UIManager.Instance.RenderInventory();
}
//手持农具的方法
public void RenderHand()
{if (handPoint.childCount > 0){Destroy(handPoint.GetChild(0).gameObject);}if (SlotEquipped(InventorySlot.InventoryType.Tool)){Instantiate(GetEquippedSlotItem(InventorySlot.InventoryType.Tool).gameModel, handPoint);}
}
//检查手持的槽位是否已经装备了物品public bool SlotEquipped(InventorySlot.InventoryType inventoryType){if (inventoryType == InventorySlot.InventoryType.Item){return !equippedItemSlot.IsEmpty();}return !equippedToolSlot.IsEmpty();}

(2) 解析

public bool IsEmpty()
{return itemData == null;
}

equippedToolSlot.IsEmpty() :判断 equippedToolSlot 是否为空,如果为空,IsEmpty()返回 true

public bool SlotEquipped(InventorySlot.InventoryType inventoryType)
{return !equippedToolSlot.IsEmpty();
}

!equippedToolSlot.IsEmpty() :取反。

如果equippedToolSlot为空,IsEmpty()返回 true,SlotEquipped()返回false,即:槽位未装备物品

if (SlotEquipped(InventorySlot.InventoryType.Tool))
{Instantiate(GetEquippedSlotItem(InventorySlot.InventoryType.Tool).gameModel,handPoint);
}

if (SlotEquipped(InventorySlot.InventoryType.Tool)) :如果槽位装备物品,在手持位生成该物品模型

(3) 赋值

3、装备和卸下农具

(1) 编辑InventoryManager.cs

    public void HandToInventory(InventorySlot.InventoryType inventoryType){//其它代码//卸下农具if(inventoryType == InventorySlot.InventoryType.Tool){RenderHand();}UIManager.Instance.RenderInventory();}
二、更改土壤状态

1、编辑Land.cs

    public void Interact(){//根据点击事件决定土壤状态ItemData toolSlot = InventoryManager.Instance.GetEquippedSlotItem(InventorySlot.InventoryType.Tool);if (!InventoryManager.Instance.SlotEquipped(InventorySlot.InventoryType.Tool)){return;}EquipmentData equipmentTool = toolSlot as EquipmentData;if (equipmentTool != null){EquipmentData.ToolType toolType = equipmentTool.Type;switch (toolType){case EquipmentData.ToolType.Hoe: SwitchLandStatus(LandStatus.Farmland); break;case EquipmentData.ToolType.WateringCan: if (landStatus == LandStatus.Farmland||landStatus ==LandStatus.Watered){SwitchLandStatus(LandStatus.Watered);}break;}}}

时间管理系统

详细教程 步骤二

一、设置时间逻辑

1、设定年季周、日时分:Scripts文件夹下创建Time 文件夹,其下创建GameTimestamp.cs,

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class GameTimestamp
{public int year;public enum Season { Spring, Summer, Fall, Winter }public Season season;public enum DayOfTheWeek { Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday }public int day, hour, minute;public GameTimestamp(int year, Season season, int day, int hour, int minute){this.year = year;this.season = season;this.day = day;this.hour = hour;this.minute = minute;}public void UpdateClock(){minute++;if (minute >= 60) { minute = 0; hour++; }if (hour >= 24) { hour = 0; day++; }if (day > 30){day = 1;if (season == Season.Winter){season = Season.Spring;year++;}else{season++;}}}public GameTimestamp(GameTimestamp timestamp){this.year = timestamp.year;this.season = timestamp.season;this.day = timestamp.day;this.hour = timestamp.hour;this.minute = timestamp.minute;}public static int HoursToMinutes(int hour) { return hour * 60; }public static int DaysToHours(int day) { return day * 24; }public static int SeasonsToDays(Season season){int seasonIndex = (int)season;return seasonIndex * 30;}public static int YearsToDays(int year) { return year * 4 * 30; }public DayOfTheWeek GetDayOfTheWeek(){int daysPassed = YearsToDays(year) + SeasonsToDays(season) + day;int dayIndex = daysPassed % 7;return (DayOfTheWeek)dayIndex;}
}

AI的建议

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;[Serializable]
public class GameTimestamp
{// 时间的定义public enum Season { Spring, Summer, Autumn, Winter }public int hour;public Season season;public int day;public int month;public int year;public int minute;public GameTimestamp(int hour, Season season, int day, int month, int year){this.hour = hour;this.season = season;this.day = day;this.month = month;this.year = year;}public void UpdateClock(){minute++;if (minute >= 60){minute = 0;hour++;if (hour >= 24){hour = 0;day++;if (day > GetDaysInMonth(month)){day = 1;month++;if (month > 12){ month = 1;year++; }}}}}private int GetDaysInMonth(int month){switch (month){case 2:return 28;case 4:case 6:case 9:case 11:return 30;default:return 31;}}public static int HoursToMinutes(int hours){return hours * 60;}
}public class TimeManager : MonoBehaviour
{public static TimeManager Instance { get; private set; }[SerializeField]private GameTimestamp timestamp;public float timeScale = 1.0f;//太阳的位置[Header("Day and Night cycle")]public Transform sunTransform;private void Awake(){if (Instance != null && Instance != this){ Destroy(gameObject); }else { Instance = this; }}private void OnDestroy(){if (Instance == this) { Instance = null; }}void Start(){timestamp = new GameTimestamp(0, GameTimestamp.Season.Spring, 1, 6, 0);StartCoroutine(TimeUpdate());}IEnumerator TimeUpdate(){while (true){Tick();yield return new WaitForSeconds(1f / timeScale);}}public void Tick(){timestamp.UpdateClock();//游戏运行的时间转换成分钟数int timeInminutes = GameTimestamp.HoursToMinutes(timestamp.hour) + timestamp.minute;//太阳与地平线间的夹角float sunAngle = 360f / (24f * 60f) * timeInminutes - 90;//设置太阳的欧拉角(在三维空间中旋转的向量)sunTransform.eulerAngles = new Vector3(sunAngle, 0, 0);}
}

2、时间流逝

(1) 给Manager添加TimeManager.cs组件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TimeManager : MonoBehaviour
{public static TimeManager Instance { get; private set; }[SerializeField]public GameTimestamp timestamp;public float timeScale = 1.0f;private void Awake(){if (Instance != null && Instance != this) { Destroy(gameObject); }else { Instance = this; }}private void OnDestroy(){if (Instance == this) { Instance = null; }}void Start(){timestamp = new GameTimestamp(0, GameTimestamp.Season.Spring, 1, 6, 0);StartCoroutine(TimeUpdate());}IEnumerator TimeUpdate(){while (true){Tick();yield return new WaitForSeconds(1 / timeScale);}}public void Tick(){timestamp.UpdateClock();}
}

(2) 流逝逻辑:每隔1秒钟,minute ++;

二、时间与光照

1、编辑TimeManager.cs,设置太阳旋转

//太阳的位置
[Header("Day and Night cycle")]
public Transform sunTransform;void UpdateSunMovement()
{//游戏运行的时间转换成分钟数int timeInminutes = GameTimestamp.HoursToMinutes(timestamp.hour) + timestamp.minute;//太阳与地平线间的夹角float sunAngle = 360f / (24f * 60f) * timeInminutes - 90;//设置太阳的欧拉角(在三维空间中旋转的向量)sunTransform.eulerAngles = new Vector3(sunAngle, 0, 0);
}
public void Tick()
{timestamp.UpdateClock();UpdateSunMovement();
}

2、赋值

3、测试

(1) 编辑PlayerController.cs

public void Update()
{Interact();//时间加速if(Input.GetKey(KeyCode.RightBracket)){TimeManager.Instance.Tick();}
}

(2) 测试:按下右方括号,时间加速

三、时间管理

1、时间接口:新建ITimeTracker.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public interface ITimeTracker
{void ClockUpdate(GameTimestamp timestamp);
}

2、实时更新时间,并将时间信息传递给已注册的时间跟踪器:编辑TimeManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TimeManager : MonoBehaviour
{public static TimeManager Instance { get; private set; }//内部时钟[Header("Internal Clock")][SerializeField]GameTimestamp timestamp;public float timeScale = 1.0f;[Header("Day and Night cycle")]public Transform sunTransform;//存储所有已注册的时间跟踪器List<ITimeTracker> listeners = new List<ITimeTracker>();public void Tick(){timestamp.UpdateClock();//遍历所有已注册的时间跟踪器foreach(ITimeTracker listener in listeners){listener.ClockUpdate(timestamp);}UpdateSunMovement();}//注册时间跟踪器,并添加到listerns列表中public void RegisterTracker(ITimeTracker listener){listeners.Add(listener);}//注销时间跟踪器,并从列表移除public void UnregisterTracker(ITimeTracker listener){listeners.Remove(listener);}
}
四、显示时间

1、编辑UIManager.cs,更新状态栏上的时间

//接口
public class UIManager : MonoBehaviour, ITimeTracker
//状态栏
[Header("Status Bar")]
public Image toolEquipSlotImage;
public Text toolQuantityText;
//时间文本
public Text timeText;
public Text dateText;
void Start()
{RenderInventory();AssignSlotIndex();//注册时间跟踪器TimeManager.Instance.RegisterTracker(this);
}
//处理UI时间回调
public void ClockUpdate(GameTimestamp timestamp)
{int hours = timestamp.hour;int minutes = timestamp.minute;string prefix = "AM";if (hours > 12) { prefix = "PM"; hours -= 12; }//timeText.text = $"{prefix} {hours:00} :{minutes:00}";timeText.text = prefix + hours + ":" + minutes.ToString("00");int day = timestamp.day;string season = timestamp.season.ToString();string dayOfTheWeek = timestamp.GetDayOfTheWeek().ToString();//dateText.text = $"{season} {day} ({dayOfTheWeek})";dateText.text = season + " " + day + " (" + dayOfTheWeek + ")";
}

2、赋值

五、土壤状态随时间改变

1、比较两个时间戳:编辑GameTimestamp.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;[Serializable]
public class GameTimestamp
{public int year;public enum Season { Spring, Summer, Fall, Winter }public Season season;public enum DayOfTheWeek { Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday }public int day, hour, minute;public GameTimestamp(int year, Season season, int day, int hour, int minute){this.year = year;this.season = season;this.day = day;this.hour = hour;this.minute = minute;}public void UpdateClock(){minute++;if (minute >= 60) { minute = 0; hour++; }if (hour >= 24) { hour = 0; day++; }if (day > 30){day = 1;if (season == Season.Winter){season = Season.Spring;year++;}else{ season++; }}}public GameTimestamp(GameTimestamp timestamp){this.year = timestamp.year;this.season = timestamp.season;this.day = timestamp.day;this.hour = timestamp.hour;this.minute = timestamp.minute;}public static int HoursToMinutes(int hour) { return hour * 60; }public static int DaysToHours(int day) { return day * 24; }public static int SeasonsToDays(Season season){int seasonIndex = (int)season;return seasonIndex * 30;}public static int YearsToDays(int year) { return year * 4 * 30; }public DayOfTheWeek GetDayOfTheWeek(){int daysPassed = YearsToDays(year) + SeasonsToDays(season) + day;int dayIndex = daysPassed % 7;return (DayOfTheWeek)dayIndex;}//比较两个时间戳public static int CompareTimestamp(GameTimestamp timestamp1, GameTimestamp timestamp2){int timestamp1Hours = DaysToHours(YearsToDays(timestamp1.year))+ DaysToHours(SeasonsToDays(timestamp1.season))+ DaysToHours(timestamp1.day) + timestamp1.hour;int timestamp2Hours = DaysToHours(YearsToDays(timestamp2.year))+ DaysToHours(SeasonsToDays(timestamp2.season))+ DaysToHours(timestamp2.day)+ timestamp2.hour;int differnce = timestamp2Hours - timestamp1Hours;//返回 difference 的绝对值return Mathf.Abs(differnce);}
}

2、获取时间戳(timestamp):编辑TimeManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TimeManager : MonoBehaviour
{public static TimeManager Instance { get; private set; }[SerializeField][Header("Internal Clock")]GameTimestamp timestamp;public float timeScale = 1.0f;[Header("Day and Night cycle")]public Transform sunTransform;List<ITimeTracker> listeners = new List<ITimeTracker>();private void Awake(){if (Instance != null && Instance != this) { Destroy(gameObject); }else { Instance = this; }}private void OnDestroy(){if (Instance == this) { Instance = null; }}void Start(){timestamp = new GameTimestamp(0, GameTimestamp.Season.Spring, 1, 6, 0);StartCoroutine(TimeUpdate());}IEnumerator TimeUpdate(){while (true){Tick();yield return new WaitForSeconds(1 / timeScale);}}void UpdateSunMovement(){int timeInminutes = GameTimestamp.HoursToMinutes(timestamp.hour) + timestamp.minute;float sunAngle = 360f / (24f * 60f) * timeInminutes - 90;sunTransform.eulerAngles = new Vector3(sunAngle, 0, 0);}public void Tick(){timestamp.UpdateClock();foreach(ITimeTracker listener in listeners){listener.ClockUpdate(timestamp);}UpdateSunMovement();}public void RegisterTracker(ITimeTracker listener){listeners.Add(listener);}public void UnregisterTracker(ITimeTracker listener){listeners.Remove(listener);}//获取新的时间戳public GameTimestamp GetGameTimestamp(){return new GameTimestamp(timestamp);}
}

3、土壤状态的改变

(1) 编辑Land.cs,

//接口
public class Land : MonoBehaviour,ITimeTracker
{//灌溉时间GameTimestamp timeWatered;void Start(){renderer = GetComponent<Renderer>();SwitchLandStatus(LandStatus.Soil);Select(false);//注册时间戳TimeManager.Instance.RegisterTracker(this);}public void SwitchLandStatus(LandStatus statusToSwitch){landStatus = statusToSwitch;Material materialToSwitch = soilMat;switch (statusToSwitch){case LandStatus.Soil: materialToSwitch = soilMat; break;case LandStatus.Farmland: materialToSwitch = farmlandMat; break;case LandStatus.Watered: materialToSwitch = wateredMat; //灌溉的时间戳timeWatered = TimeManager.Instance.GetGameTimestamp();break;}renderer.material = materialToSwitch;}//灌溉后土壤状态的变化public void ClockUpdate(GameTimestamp timestamp){if(landStatus == LandStatus.Watered){int hoursElapsed = GameTimestamp.CompareTimestamp(timeWatered, timestamp);if(hoursElapsed > 24){SwitchLandStatus(LandStatus.Farmland);}}}
}

作物管理

详细教程

一、准备工作

1、制作Cabbage预制体,并给预制体Cabbage添加Mesh Collider,勾选Convex和Is Trigger

2、打开Asset-Data-Items,选择Cabbage,设置GameModle

3、素材准备

(1) 导入Cartoon_Farm_Crops(来自Unity官网)

(2) 把Standard Asset文件夹拖到Cartoon_Farm_Crops文件夹中

(3) 把Cartoon_Farm_Crops文件夹转移到Assets-Import Assets文件夹中

3、准备幼苗预制体

(1) 打开Assets-Import Assets-Cartoon_Farm_Crops-Prefabs-Standard文件夹

(2) 复制Carrot_Plant粘贴到Asset-Prefabs文件夹中。重命名为Cabbage Seedling

二、制作卷心菜

1、制作种子预制体

(1) Create Empty,重命名为Crop,Reset它的Transform

(2) 给Crop添加子物体Dirt_Pile、Cabbage Seeding和Cabbage,表示卷心菜的三个阶段

(3) 将Dirt_Pile重命名为Seed,将Crop制成预制体,把相关的预制体都放在新建的文件夹Crops中

(4) 打开Crop预制体,删除子物体Seed的Mesh Collider组件

(5) 删除Hierarchy面板上的Crop

2、设置Item对象Cabbage Seed(卷心菜)

(1) 编辑SeedData.cs,增加卷心菜的幼苗状态

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[CreateAssetMenu(menuName =("Items/Seed"))]public class SeedData : ItemData
{public int daysToGrow;public ItemData cropToYield;//幼苗public GameObject seedling;
}

(2) 保留预制体Crop的子物体中的Seed,删除预制体Crop下的其他子物体

3、作物生长的状态

(1) 给预制体Crop添加CropBehaviour.cs组件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CropBehaviour : MonoBehaviour
{SeedData seedToGrow;[Header("Stages of Life")]public GameObject seed;private GameObject seedling;private GameObject harvestable;public CropStage cropStage;public enum CropStage { Seed, Seedling, Havestable }public void Plant(SeedData seedToGrow){this.seedToGrow = seedToGrow;seedling = Instantiate(seedToGrow.seedling, transform);ItemData CropToYield = seedToGrow.cropToYield;harvestable = Instantiate(CropToYield.gameModel, transform);SwitchState(CropStage.Seed);}void SwitchState(CropStage stateToSwitch){seed.SetActive(false);seedling.SetActive(false);harvestable.SetActive(false);switch (stateToSwitch){case CropStage.Seed: seed.SetActive(true); break;case CropStage.Seedling: seedling.SetActive(true); break;case CropStage.Havestable: harvestable.SetActive(true); break;}cropStage = stateToSwitch;}
}

(2) 赋值

三、制作番茄

1、ItemData对象——番茄种子

(1) 打开Data-Tools-Seeds文件夹,Create-Items-Seed。命名为Tomato Seed

(2) 编辑 SeedData.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName =("Items/Seed"))]
public class SeedData : ItemData
{public int daysToGrow;public ItemData cropToVield;public GameObject seedling;//重新生长[Header("Regrowable")]public bool regrowable;public int daysTogrow;
}

(3) 设置ItemData对象番茄种子的属性(Seeds to grow Tomato)

2、果实

(1) 预制体

① 将Tomato_Fruit拖放到Hierarchy,更改标签为Item,Layer为Item,

     重置Transform,旋转 x=-90。 名Tomato

② 将Tomato制成预制体,删除Hierarchy面板上的Tomato

③ 勾选Mesh Collide中的 Convex和Is Trigger

(2) ItemData对象 :

① 打开Data-Item文件夹,Create-Items-Item ,创建一个新项目 Tomato Crop,

The crop the player will harvest first

② 打开Data-Item文件夹,Create-Items-Item ,创建 Tomato(Technically a fruit)

③ 打开Data-Tools-Seed文件夹,设置Tomato Seed

(3) 编辑 Tomato预制体,添加InteractableObject.cs组件,赋值

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class InteractableObject : MonoBehaviour
{public ItemData item;public virtual void Pickup(){InventoryManager.Instance.EquipHandSlot(item);InventoryManager.Instance.RenderHand();Destroy(gameObject);}
}

3、幼苗预制体

(1) 打开Import Asset/Cartoon_Farm_Crops/Prefabs/Standard文件夹

(2) 将Tomato_Plant拖放到Hierarchy,重命名为Tomato Seedling

(3) 移除Tomato_Seedling上的Mesh Collider。制成预制体

(4) 设置ItemData对象 Tomato Seed(番茄种子)的幼苗属性

4、成熟植株预制体

(1) 复制Hierarchy面板上的Tomato_Seedling,重命名为Tomato Harvestable,制成预制体

(2) 编辑Tomato Harvestable预制体

① 添加子物体Tomato

② 更改标签和Layer为 Item

(3) 为Tomato Harvestable预制体添加 Mesh Collider组件

(4) 删除面板上的幼苗植株果实

5、设置ItemData对象番茄种子和番茄

四、播种

1、编辑Land.cs

//种子
[Header("Crops")]
public GameObject cropPrefab;
CropBehaviour cropPlanted = null;
public void Interact()
{ItemData toolSlot = InventoryManager.Instance.GetEquippedSlotItem(InventorySlot.InventoryType.Tool);if (!InventoryManager.Instance.SlotEquipped(InventorySlot.InventoryType.Tool)){return;}EquipmentData equipmentTool = toolSlot as EquipmentData;if (equipmentTool != null){EquipmentData.ToolType toolType = equipmentTool.Type;switch (toolType){case EquipmentData.ToolType.Hoe: SwitchLandStatus(LandStatus.Farmland); break;case EquipmentData.ToolType.WateringCan: SwitchLandStatus(LandStatus.Watered); break;}//返回return;}//播种SeedData seedTool = toolSlot as SeedData;if (seedTool != null && landStatus != LandStatus.Soil && cropPlanted == null){GameObject cropObject = Instantiate(cropPrefab, transform);cropObject.transform.position =new Vector3(transform.position.x, 0f, transform.position.z);cropPlanted = cropObject.GetComponent<CropBehaviour>();cropPlanted.Plant(seedTool);}
}

2、赋值

五、生长

1、编辑CropBehaviour.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CropBehaviour : MonoBehaviour
{SeedData seedToGrow;[Header("Stages of Life")]public GameObject seed;private GameObject seedling;private GameObject harvestable;public CropStage cropStage;public enum CropStage { Seed, Seedling, Havestable }//生长int growth;int maxGrowth;public void Plant(SeedData seedToGrow){this.seedToGrow = seedToGrow;seedling = Instantiate(seedToGrow.seedling, transform);ItemData CropToYield = seedToGrow.cropToYield;harvestable = Instantiate(CropToYield.gameModel, transform);//生长时间int hoursToGrow = GameTimestamp.DaysToHours(seedToGrow.daysToGrow);maxGrowth = GameTimestamp.HoursToMinutes(hoursToGrow);SwitchState(CropStage.Seed);}void SwitchState(CropStage stateToSwitch){seed.SetActive(false);seedling.SetActive(false);harvestable.SetActive(false);switch (stateToSwitch){case CropStage.Seed: seed.SetActive(true); break;case CropStage.Seedling: seedling.SetActive(true); break;case CropStage: harvestable.SetActive(true); break;}cropStage = stateToSwitch;}//生长public void Grow(){growth++;//幼苗if (growth >= maxGrowth / 2 && cropStage == CropStage.Seed){SwitchState(CropStage.Seedling);}//成熟if (growth >= maxGrowth && cropStage == CropStage.Seedling){SwitchState(CropStage.Havestable);}}
}

2、 编辑Land.cs,灌溉后作物生长

    public void ClockUpdate(GameTimestamp timestamp){if (landStatus == LandStatus.Watered){int hoursElapsed = GameTimestamp.CompareTimestamp(timeWatered, timestamp);//作物生长if (cropPlanted != null){cropPlanted.Grow();}if (hoursElapsed > 24){SwitchLandStatus(LandStatus.Farmland);}}}
六、收获果实后幼苗再生

1、创建一个具有可重生收获行为的对象

(1) 打开Farming文件夹,新建RegrowableHarvestBehaviour.cs

(2) 编辑Tomato Harvestable预制体,添加RegrowableHarvestBehaviour.cs组件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class RegrowableHarvestBehaviour : InteractableObject
{CropBehaviour parentCrop;public void SetParent(CropBehaviour parentCrop){this.parentCrop = parentCrop;}public override void Pickup(){InventoryManager.Instance.EquipHandSlot(item);InventoryManager.Instance.RenderHand();}
}

(3) 赋值

2、将植株重置为幼苗状态

(1) 编辑CropBehaviour.cs

    public void Plant(SeedData seedToGrow){//其他代码//第一次种植时,检查它是否能生长if (seedToGrow.regrowable){RegrowableHarvestBehaviour regrowableHarvest = harvestable.GetComponent<RegrowableHarvestBehaviour>();// 将可再生收获行为的父物体设置为当前物体 regrowableHarvest.SetParent(this);}SwitchStage(CropStage.Seed);}void SwitchStage(CropStage stateToSwitch){seed.SetActive(false);seedling.SetActive(false);harvestable.SetActive(false);//其他代码switch (stateToSwitch){         case CropStage.Havestable:harvestable.SetActive(true);//如果种子不可再生,将可收获的种子与该作物游戏对象分离并销毁它if (!seedToGrow.regrowable){harvestable.transform.parent = null;Destroy(gameObject);}break;}cropStage = stateToSwitch;}//当玩家收获可再生作物时调用。将植物状态重置为幼苗public void Regrow(){int hoursToRegrow = GameTimestamp.DaysToHours(seedToGrow.daysToGrow);growth = maxGrowth -GameTimestamp.HoursToMinutes(hoursToRegrow);//切换回幼苗状态SwitchStage(CropStage.Seedling);}

(2) 编辑RegrowableHarvestBehaviour.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class RegrowableHarvestBehaviour : InteractableObject
{CropBehaviour parentCrop;public void SetParent(CropBehaviour parentCrop){this.parentCrop = parentCrop;}public override void Pickup(){InventoryManager.Instance.EquipHandSlot(item);InventoryManager.Instance.RenderHand();//将亲本作物重置为幼苗状态parentCrop.Regrow();}
}
七、枯萎

详细教程 步骤十一

1、制作枯萎的植物的材质

(1) 打开Assets-Import Assets-Farmland-Dirt-Materials,复制Dirt材质,重命名为Wilted Plant

(2) 更改Wilted Plant材质的颜色9A2603,去掉光滑度

2、制作枯萎的植物:编辑Crop预制体

(1) 打开Assets-Import Assets-Cartoon_Farm_Crops-Prefabs-Standard文件夹,将Pumpkin_Plant作为子物体拖放到Crop下,重命名为wilted,将Wilted Plant材质设置给Wilted

(2) 设置它的transform

3、设置枯萎系统:

(1) 编辑CropBehaviour.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class CropBehaviour : MonoBehaviour
{SeedData seedToGrow;[Header("Stages of Life")]public GameObject seed;private GameObject seedling;private GameObject harvestable;//枯萎状态的植株public GameObject wilted;//枯萎状态public enum CropStage { Seed, Seedling, Havestable, Wilted }public CropStage cropStage;int growth;int maxGrowth;//正常生长的最大时间(48小时)int maxHealth = GameTimestamp.HoursToMinutes(48);int health;public void Plant(SeedData seedToGrow){this.seedToGrow = seedToGrow;seedling = Instantiate(seedToGrow.seedling, transform);ItemData cropToYield = seedToGrow.cropToVield;harvestable = Instantiate(cropToYield.gameModel, transform);int hoursToGrow = GameTimestamp.DaysToHours(seedToGrow.daysToGrow);maxGrowth = GameTimestamp.HoursToMinutes(hoursToGrow);//第一次种植时,检查它是否能生长if (seedToGrow.regrowable){RegrowableHarvestBehaviour regrowableHarvest = harvestable.GetComponent<RegrowableHarvestBehaviour>();// 将可再生收获行为的父物体设置为当前物体 regrowableHarvest.SetParent(this);}SwitchStage(CropStage.Seed);}void SwitchStage(CropStage stateToSwitch){seed.SetActive(false);seedling.SetActive(false);harvestable.SetActive(false);//枯萎状态wilted.SetActive(false);switch (stateToSwitch){case CropStage.Seed: seed.SetActive(true); break;case CropStage.Seedling:seedling.SetActive(true);//48小时的正常生长时间health = maxHealth;break;case CropStage.Havestable:harvestable.SetActive(true);//如果种子不可再生,将可收获的种子与该作物游戏对象分离并销毁它if (!seedToGrow.regrowable){harvestable.transform.parent = null;Destroy(gameObject);}break;//枯萎植株选择case CropStage Wilted: wilted.SetActive(true); break;}cropStage = stateToSwitch;}public void Grow(){growth++;//枯萎前的健康时长if (health < maxHealth){health++;}if (growth >= maxGrowth / 2 && cropStage == CropStage.Seed){SwitchStage(CropStage.Seedling);}if (growth >= maxGrowth && cropStage == CropStage.Seedling){SwitchStage(CropStage.Havestable);}}//枯萎逻辑public void Wilted(){health--;if (health <= 0 && cropStage != CropStage.Seed){SwitchStage(CropStage.Wilted);}}//当玩家收获可再生作物时调用。将植物状态重置为幼苗public void Regrow(){int hoursToRegrow = GameTimestamp.DaysToHours(seedToGrow.daysToGrow);growth = maxGrowth -GameTimestamp.HoursToMinutes(hoursToRegrow);//切换回幼苗状态SwitchStage(CropStage.Seedling);}
}

(2) 赋值

4、编辑Land.cs

    public void ClockUpdate(GameTimestamp timestamp){if (landStatus == LandStatus.Watered){int hoursElapsed = GameTimestamp.CompareTimestamp(timeWatered, timestamp);if (cropPlanted != null){cropPlanted.Grow();}if (hoursElapsed > 24){SwitchLandStatus(LandStatus.Farmland);}}//枯萎if (landStatus != LandStatus.Watered && cropPlanted != null){if(cropPlanted.cropStage !=CropBehaviour.CropStage.Seed){cropPlanted.Wilted();}}}
八、收割后重新生长

1、编辑SeedData.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;[CreateAssetMenu(menuName =("Items/Seed"))]public class SeedData : ItemData
{public int daysToGrow;public ItemData cropToYield;public GameObject seedling;//重新生长[Header("Regrowable")]public bool regrowable;public int daysTogrow;
}

农田交互

一、收获

1、增加提示文本

2、编辑PlayerInteraction.cs

六、收割

1、销毁作物:编辑CropBehaviour.cs

    void SwitchState(CropStage stateToSwitch){seed.SetActive(false);seedling.SetActive(false);harvestable.SetActive(false);switch (stateToSwitch){case CropStage.Seed: seed.SetActive(true); break;case CropStage.Seedling: seedling.SetActive(true); break;case CropStage: harvestable.SetActive(true);//收割harvestable.transform.parent = null;Destroy(gameObject);break;}cropStage = stateToSwitch;}

 2、收获作物:编辑InventoryManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class InventoryManager : MonoBehaviour
{    public void InventoryToHand(int slotIndex,InventorySlot.InventoryType inventoryType){//其他代码##//手持收获物if(inventoryType == InventorySlot.InventoryType.Item){RenderHand();}UIManager.Instance.RenderInventory();}public void HandToInventory(InventorySlot.InventoryType inventoryType){//其他代码##//手持收获物if(inventoryType == InventorySlot.InventoryType.Item){RenderHand();}UIManager.Instance.RenderInventory();}public void RenderHand(){//其他代码//收获物if (SlotEquipped(InventorySlot.InventoryType.Item)){Instantiate(GetEquippedSlotItem(InventorySlot.InventoryType.Item).gameModel, handPoint);}}
}

3、拾起作物

(1) 编辑InventoryManager.cs,复制物体

#region 物品交换的方法
//根据物品类型将选中物体复制到对应位置
public void EquipHandSlot(ItemData item)
{if (IsTool(item)){equippedToolSlot = new ItemSlotData(item);}else{equippedItemSlot = new ItemSlotData(item);}
}
//其他代码
#endregion

 (2) 创建拾取方法:

① 在Scripts-Inventory文件夹下新建InteractableObject.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class InteractableObject : MonoBehaviour
{public ItemData item;public virtual void Pickup(){InventoryManager.Instance.EquipHandSlot(item);}
}

② 给预制体Cabbage和Tomato,添加InteractableObject.cs组件,赋值,添加标签Item

农田交互

:编辑SeedData.cs

一、收获

1、增加提示文本

2、编辑PlayerInteraction.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class PlayerInteraction : MonoBehaviour
{PlayerController playerController;Land selectLand = null;//选中的待收获作物InteractableObject selectInteractable = null;//提示文本public Text textComponent;void Start(){playerController = transform.parent.GetComponent<PlayerController>();}void Update(){RaycastHit hit;if (Physics.Raycast(transform.position, Vector3.down, out hit, 1)){OnInteractableHit(hit);}}void OnInteractableHit(RaycastHit hit){Collider other = hit.collider;if (other != null && other.CompareTag("Land")){Land land = other.GetComponent<Land>();if (land != null){SelectLand(land); return;}else { Debug.Log("未选中任何田地"); }}//选中的待收获作物if (other.CompareTag("Item")){selectInteractable = other.GetComponent<InteractableObject>();return;}if (selectInteractable != null){selectInteractable = null;}if (selectLand != null){DeselectLand(selectLand);}}public void Interact(){textComponent.text = "";//禁用工具if (InventoryManager.Instance.SlotEquipped(InventorySlot.InventoryType.Item)){textComponent.text = "你腾不出手来!";return;}if (selectLand != null){selectLand.Interact(); return;}Debug.Log("未站在田地上");}void SelectLand(Land land){if (land == null) { Debug.Log("你未选择田地"); return; }if (selectLand != null) { selectLand.Select(false); }selectLand = land;land.Select(true);}void DeselectLand(Land land){if (land == null) { Debug.Log("你没有选择田地"); return; }land.Select(false);selectLand = null;}//收割交互public void ItemIneract(){if (InventoryManager.Instance.SlotEquipped(InventorySlot.InventoryType.Item)){InventoryManager.Instance.HandToInventory(InventorySlot.InventoryType.Item);return;}//拾取作物if (selectInteractable != null){selectInteractable.Pickup();}}
}

2、编辑PlayerController.cs,点击 左Alt键,物品返回物品栏

using UnityEngine;public class PlayerController : MonoBehaviour
{PlayerInteraction playerInteraction;public float turnSpeed = 20f;Animator animator;bool isWalking = false;bool isRunning = false;Rigidbody rb;Vector3 movement;Quaternion rotation = Quaternion.identity;private float speed;[Header("Movement System")]public float walkSpeed = 6f;public float runSpeed = 12f;void Start(){animator = GetComponent<Animator>();rb = GetComponent<Rigidbody>();playerInteraction = GetComponentInChildren<PlayerInteraction>();}private void FixedUpdate(){float horizontal = Input.GetAxis("Horizontal");float vertical = Input.GetAxis("Vertical");movement.Set(horizontal, 0f, vertical);movement.Normalize();bool hasHorizontalInput = !Mathf.Approximately(horizontal, 0f);bool hasVerticalInput = !Mathf.Approximately(vertical, 0f);if (Input.GetButton("Sprint")){speed = runSpeed;isRunning = true;}else if (hasHorizontalInput || hasVerticalInput){isWalking = true;isRunning = false;speed = walkSpeed;}else{isWalking = false;isRunning = false;speed = 0f;}Vector3 desireForward = Vector3.RotateTowards(transform.forward, movement, turnSpeed * Time.deltaTime, 0f);rotation = Quaternion.LookRotation(desireForward);}public void Update(){Interact();if (Input.GetKey(KeyCode.RightBracket)){TimeManager.Instance.Tick();}}public void Interact(){if (Input.GetButtonDown("Fire1")){playerInteraction.Interact();}//左Altif (Input.GetButtonDown("Fire2")){playerInteraction.ItemIneract();}}private void OnAnimatorMove(){animator.SetBool("IsWalking", isWalking);animator.SetBool("IsRunning", isRunning);Vector3 movementSpeed = movement * speed;rb.MovePosition(rb.position + movementSpeed * animator.deltaPosition.magnitude);rb.MoveRotation(rotation);}
}
二、禁止角色上升

1、编辑预制体Cabbage和Player,分别为二者添加新Layer

2、禁用Item与Player层的交互

(1) 

(2)

(3)

(4)

(1) 

(2)

(3)

(4)

(4)

(4)

http://www.dtcms.com/wzjs/68924.html

相关文章:

  • 网站优化的意义最好用的搜索神器
  • 公众号可以做分类信息网站吗怎么创建个人网站
  • 长沙网站推广优化电商运营怎么做如何从零开始
  • 网站建设百度认证图片惠州网站营销推广
  • 使用网站新网站怎么做优化
  • 程序员给传销做网站浏览器下载安装
  • 做暧暧视频免费视频老司机网站郑州建网站的公司
  • 日照住房和城乡建设厅网站上海网络推广培训学校
  • 增加收录网站网店代运营骗局流程
  • 一般网站建设用什么样的代码外贸网站平台
  • 攻略类型网站如何做产品营销国际外贸网络交易平台
  • 做网站公司常熟今日热点头条
  • 视频拍摄脚本怎么写百度优化是什么意思
  • 搜索引擎营销策略有哪些温州seo按天扣费
  • 织梦网站管理系统二十四个关键词
  • 长沙做网站a微联讯点很好长尾关键词快速排名软件
  • 宝安电子厂做网站sem优化师是做什么的
  • 杭州网站建设 网站设计网络营销环境分析主要包括
  • 如何利用网站做demo吉安seo网站快速排名
  • 51源码之家seo关键词排名优化官网
  • 建设学校网站需要具备自有品牌如何推广
  • 网站的要素是什么热门seo推广排名稳定
  • 公司网站名词解释网站建设制作
  • 手机兼职百度关键词相关性优化软件
  • 湘潭做网站价格 磐石网络广州网站营销推广
  • 中国保密在线网站培训可以搜索国外网站的搜索引擎
  • 图门市建设局网站怎样优化标题关键词
  • 安徽网站建设优化推广html期末大作业个人网站制作
  • 便捷的邢台做网站网络站点推广的方法有哪些
  • 网站建设发票税点如何进行网站性能优化?