种田RPG游戏(二)

农田

一、获取土地资源并制作耕地

1、获取资源

资源获取

2、在Import Asset文件夹下新建文件夹Farmland,导入资源。

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

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

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

3、制作材质球

(1) 3D Object-Cube,重命名为Land

(2) 打开Dirt文件夹,把aerial_ground_rock_diff_4k材质拖放到Cube上,此时出现Materials文件夹。

(3) 打开Import Asset的Materials文件夹,将材质球重命名为Dirt

(4) 选中Import Asset的Materials文件夹下Dirt材质球,将Farmland文件夹下的aerial_ground_rock_nor_gl_4k拖放到Normal Map上,点击Fix Now

也可以直接在材质球Dirt的Inspector面板点击Nomal Map左侧圆虚线,选择aerial_ground_rock_nor_gl_4k,点击Fix Now

(5) 选中Hierarchy面板中的 Land,设置Inspector面板中的Height Map(选择aerial_ground_rock_disp_4k)

(6) 用同样的方法制作另外两种材质,重命名材质球与文件夹名称一致

Tilled land中和Watered land中设置如下

4、制作并编辑土地预制体Land

(1) 制作预制体Land,增加标签Land

(2) 打开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;//声明一个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;
    }
}

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

 

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

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

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

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

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

二、设置人与耕地交互(点击鼠标或左Ctrl耕种)

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

2、给Interactor添加PlayerInteractor.cs组件,设置检测射线

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerInteractor : 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);
    }
}

Physics.Raycast(transform.position, Vector3.down, out hit,1) :

执行一次射线投射,并将投射结果储存在 hit 这个输出参数中

Physics.Raycast() :执行射线投射。该方法接受4个参数

transform.position :射线发射的原点

Vector3.down :射线的方向(Vector3.down,表示朝向下方)

out hit :射线的输出结果(用于检测是否与其他物体碰撞,如果投射成功返回true并执行{}内的代码)

out:关键字。将hit标记为输出参数

hit :将投射结果储存在 hit 中后,

           通过{OnInteractableHit(hit);}投射结果被输出到OnInteractableHit(RaycastHit hit)这个方法中。

          在 OnInteractableHit 方法内部,使用 hit 变量可以访问射线的投射结果,以便对结果进行进一步的操作和处理

1 :射线的长度。

3、Hierarchy中新建3D Object-Quad

4、设置农田

(1) 打开Land.cs,设置选中时出现的土地框

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Land : MonoBehaviour
{
    public enum LandStatus { Soil, Farmland, Wartered }
    public LandStatus landStatus;
    public Material soilMat,farmlandMat,warteredMat;
    new Renderer renderer;

    public GameObject select;//选中框
    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.Wartered:materialToSwitch = warteredMat; break;
        }
        renderer.material = materialToSwitch;
    }
    public void Select(bool toggle)
    {
        select.SetActive(toggle);
    }
}

(2) 打开PlayerInteractor.cs,区分农田和其他土地、设置选中框的显示

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerInteractor : 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;
        if (other.CompareTag("Land"))
        {
            Land land =other.GetComponent<Land>();
            Debug.Log("我站在田地里");
            land.Select(true);
        }
        Debug.Log(other.name);
    }
}

(3) 创建一个单独的选中田地的方法,并运用到OnInteractableHit()方法中

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerInteractor : 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.CompareTag("Land"))
        {
            Land land =other.GetComponent<Land>();
            //Debug.Log("我站在田地里");
            SelectLand(land);
            return;//符合other.CompareTag("Land")时,后面代码全都不会被执行而是返回(这个方法执行完毕)
        }
        //Debug.Log(other.name);
        if(selectLand != null)
        {
            selectLand.Select(false);
            selectLand = null;
        }
    }

    //取消之前选择的田地,选择当前的田地
    void SelectLand(Land land)
    {
        if (selectLand !=null)
        {
            selectLand.Select(false);
        }
        selectLand = land;
        land.Select(true );
    }
}

 或创建单独的方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerInteractor : 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.CompareTag("Land"))
        {
            Land land =other.GetComponent<Land>();
            //Debug.Log("我站在田地里");
            SelectLand(land);
            return;
        }
        //Debug.Log(other.name);
        if(selectLand != null)
        {
            DeselectLand(selectLand);
        }
    }

    //取消之前选择的田地,选择当前的田地
    void SelectLand(Land land)
    {
        if (selectLand !=null)
        {
            selectLand.Select(false);
        }
        selectLand = land;
        land.Select(true );
    }
    //取消选择当前田地
    void DeselectLand(Land land)
    {
        selectLand.Select(false );
        selectLand = null;
    }
}

AI的建议

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerInteractor : 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)
            {
                //Debug.Log("我站在田地里");
                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;
    }
}

5、玩家交互——建立完整的交互系统

(1) 打开Land.cs,添加 Interact 方法

public void Interact()
{
    Debug.Log("Interact");
}

(2) 打开PlayerInteractor.cs,添加 Interact 方法,调用Land中的Inseract方法

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

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

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    //引用PlayerInteractor.cs
    PlayerInteractor playerInteractor;
    private CharacterController controller;
    private Animator animator;

    private float moveSpeed = 1f;

    [Header("Movement System")]
    public float walkSpeed = 1f;
    public float runSpeed = 3f;
    void Start()
    {
        controller = GetComponent<CharacterController>();
        animator = GetComponent<Animator>();
        //从当前脚本挂载的物体的子物体上获取PlayerInteractor.cs组件
        playerInteractor = GetComponentInChildren<PlayerInteractor>();
    }

    void Update()
    {
        Move();
        //持续运行Interact方法
        Interact();
    }

    public void Interact()
    {
        //按下鼠标或left Ctrl(在Unity中的默认设置)——选择工具的按钮
        if (Input.GetButtonDown("Fire1"))
        {
            playerInteractor.Interact();
        }
    }
    public void Move()
    {
        float horizontal = Input.GetAxisRaw("Horizontal");
        float vertical = Input.GetAxisRaw("Vertical");

        Vector3 dir = new Vector3(horizontal, 0, vertical).normalized;
        Vector3 velocity = moveSpeed * Time.deltaTime * dir;

        if (Input.GetButton("Sprint"))
        {
            moveSpeed = runSpeed;
            animator.SetBool("Running",true);
        }
        else
        {
            moveSpeed = walkSpeed;
            animator.SetBool("Running", false);
        }
        if (dir.magnitude > 0.1f)
        {
            transform.rotation = Quaternion.LookRotation(dir);
            controller.Move(velocity);
        }
        animator.SetFloat("Speed", velocity.magnitude);
    }
}

 (4) 小结:通过套娃实现:点击鼠标或左Ctrl时,选中的田地块显示选中状态,同时输出"Interact“

点击鼠标或左Ctrl时——由PlayerController.cs实现

选中的田地块显示选中状态——由PlayerInteractor.cs实现

同时输出"Interact“——由Land.cs实现(注意是对应选中状态的田地块)

(5) 打开Land.cs,改变(4)中的输出文字为显示耕作过的土地

    public void Interact()
    {
        SwitchLandStatus (LandStatus.Farmland);
    }
三、管理游戏中的数据——农具

1、在Scripts下创Inventory文件夹,在该文件夹下创建ItemData.cs。

[CreateAssetMenu(menuName ="Items/Item")]
public class ItemData : ScriptableObject

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

3、在Items文件夹下Create-Item,命名为Cabbage

4、打开ItemData.cs

using UnityEngine;

[CreateAssetMenu(menuName ="Items/Item")]
public class ItemData : ScriptableObject
{
    public string description;//描述特征
    public Sprite thumbnail;//图标
    public GameObject gameModel;//游戏模型
}

5、回到Unity,选中Cabbage,设置description为A leafy Green vegetable

6、打开Scripts下的Inventory文件夹,新建EquipmentData.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(menuName = "Items/Equipment")]
public class EquipmentData : ItemData
{
    public enum ToolType
    {
        Hoe,WarteringCan,Axe,Pickaxe
    }
    public ToolType Type;
}

7、在Tools文件夹下Create-Items-Equipment,命名为Hoe

8、选中Hoe,设置description为 For tilling the land

9、同样的方法创建WarteringCan,Axe和Pickaxe

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

四、物品管理——设置图标

1、安装2D Sprite

2、资源下载: 农具蔬菜

3、导入资源到UI 文件夹

3、选中Vegetable,更改Texture Type,Sprite Mode。点击Sprite Editor(打开Sprite编辑器)

4、放大编辑器,选择Type为Automatic,点击Slice,点击Apply

结果

5、对农具进行同样的操作

6、回到Asset/Data/Tools文件夹,选中Axe,设置

7、同样的方法设置卷心菜

五、物品管理——种子

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

using UnityEngine;

[CreateAssetMenu(menuName ="Items/Seed")]
public class SeedData : ItemData
{
    public int daysToGrow;
    public ItemData cropToYield;//作物产量
}

2、在Tools文件夹新建文件夹Seed,在该文件夹下创建一个Seed文件,命名为Cabbage Seed

Seeds to grow cabbages 

3、Create Empty,命名为Manager,添加InventoryManager.cs组件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InventoryManager : MonoBehaviour
{   
    //设置单例
    public static InventoryManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(this);
        }
        else
        {
            Instance = this;
        }
    }
    //在Unity中,InventoryManager组件的标题下方显示一个标题为"Tools"的子标题
    [Header("Tools")]
    //声明并定义数组,分配ItemData对象(斧头等)
    public ItemData[] tools = new ItemData[8];
    //初始化equippedTool(被装备的工具)
    public ItemData equippedTool = null;
    
    [Header("Items")]
    public ItemData[] items = new ItemData[8];
    public ItemData equippedItem = null;
}

解析

public static InventoryManager Instance { get; private set; }

定义一个公共的静态属性Instance,用于访问InventoryManager的单例实例。

由于set是私有的,所以只有InventoryManager类内部才能设置Instance的值

 private void Awake()
 {
     if (Instance != null && Instance != this)
     {
         Destroy(this);
     }
     else
     {
         Instance = this;
     }
 }

当Unity加载一个对象并调用其Awake方法时,这段代码会检查Instance是否已经被设置为另一个InventoryManager的实例。如果是,它会销毁当前对象(即this),以确保在整个游戏中只有一个InventoryManager实例。否则,它会将Instance设置为当前对象。

六、设置UI面板

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

2、创建按钮:以Canvas为父物体,创建按钮,命名为InventoryButton

3、创建UI面板

(1) 创建UI面板:以Canvas为父物体,Create Empty。命名为InventoryPanel。Alt+Strech

(2) 创建Tools面板:

① 物品栏背景:以InventoryPanel为父物体,UI-Image,命名为ToolsPanel,颜色为F4DDB7

② 物品栏名称:以ToolsPanel为父物体,UI-Text,命名为Header

③ 物品栏外的选中物品:以ToolsPanel为父物体,UI-Image,命名为HandSlot。

      Source Image设置为UISprite(圆角)颜色:AF8E60

④ 物品栏:

A. 创建物品栏:以ToolsPanel为父物体,Create Empty。命名为InventorySlots,添加Grid Layout Group组件

B. 创建物品栏中的物品背景,并设置物品背景的摆放:

以InventorySlots为父物体,UI-Image。复制。选中InventorySlots,设置Grid Layout Group

C. 创建物品预制体:删除复制出的Image,保留的Image重命名为InventorySlot,设置颜色AF8E60,打开Prefabs文件夹,新建UI 文件夹,将InventorySlot制成预制体

D. 编辑预制体:以InventorySlot(物品背景)为父物体,UI-Image,命名为ItemDisplay(物品缩略图)。设置大小位置图片

勾选Preserve Aspect

⑤ 编辑Tools面板中的物品: 复制InventorySlot,得到下图

(3) 创建物品面板:

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

② 更改文本Tools为Items

(4) 创建物品说明面板:

① 说明背景:以InventoryPanel为父物体,UI-Image。命名为ItemInfo,设置颜色大小位置(高222)

② 观察InventoryButton的位置,需要被ItemInfo遮挡

③ 说明文本(名称):以ItemInfo为父物体,UI-text,命名为ItemName,设置大小字号等

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

(5) 隐藏InventoryPanel面板

(6) 设置按钮改变InventoryPanel面板的状态(后续用脚本控制)

4、设置返回按钮:

(1) 复制按钮,重命名为ExitBtn。放入InventoryPanel面板,

(2) 更改按钮图片、颜色(009D7E)、大小,及按钮下文本的文字

(3) 设置按钮行为

七、创建一个单例

1、打开Scripts文件夹下的UI文件夹,新建UIManager.cs,为Manager添加这个组件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager : MonoBehaviour
{
    public static UIManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this)
        {            Destroy(this);        }
        else
        {            Instance = this;        }
    }
}

2、AI 关于单例的建议

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager : MonoBehaviour
{
    public static UIManager Instance { get; private set; }

    [Header("Inventoty System")]
    public InventorySlot[] toolSlots;
    public InventorySlot[] itemSlots;


    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
        }
        else
        {
            Instance = this;
        }
    }

    //MonoBehaviour 组件的一个回调方法,当游戏对象被销毁时,Unity 引擎自动调用该方法
    //防止在 UIManager 重新创建实例时检查到一个已经被销毁的实例,从而避免潜在的错误
    private void OnDestroy()
    {
        if (Instance == this)
        {
            Instance = null;
        }
    }
}
 八、显示物品栏Tools中物品的缩略图

1、设置物品栏中的物品ItemDisplay是否显示

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

     创建Display方法,调用这个方法时显示物品的缩略图

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class InventorySlot : MonoBehaviour
{
    //需要显示的物品
    ItemData itemToDisplay;
    public Image itemDisplayImage;
    public void Display(ItemData itemToDisplay)
    {
        if (itemToDisplay != null)
        {
            itemDisplayImage.sprite = itemToDisplay.thumbnail;
            this.itemToDisplay = itemToDisplay;
            itemDisplayImage.gameObject.SetActive(true);
            return;
        }
        itemDisplayImage.gameObject.SetActive(false);
    }
}

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

(3) InventorySlot.cs的注释

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class InventorySlot : MonoBehaviour
{
    ItemData itemToDisplay;//引用一个ItemData对象,该对象包含了物品的各种数据

    public Image itemDisplayImage;//引用一个在Unity中存储的物品缩略图的Image组件

    //在插槽中显示指定的物品
    public void Display(ItemData itemToDisplay)
    {
        if (item != null)
        {
            // 更新itemToDisplay以存储当前显示的物品数据
            this.itemToDisplay = item;
            // 更新Image组件的sprite以显示物品的缩略图
            itemDisplayImage.sprite = itemToDisplay.thumbnail;

            itemDisplayImage.gameObject.SetActive(true);
            return;//可以删除
        }
        else
        {
            itemDisplayImage.gameObject.SetActive(false);
            // 清除itemToDisplay以避免旧的引用
            this.itemToDisplay = null;
        }
    }
}

(3) InventorySlot.cs 的改进

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class InventorySlot : MonoBehaviour
{
    ItemData itemToDisplay;
    public Image itemDisplayImage;

    public void Display(ItemData itemDataToDisplay)
    {
        if (itemDataToDisplay != null && itemDataToDisplay.thumbnail != null)
        {
            this.itemToDisplay = itemDataToDisplay;
            itemDisplayImage.sprite = itemToDisplay.thumbnail;

            itemDisplayImage.gameObject.SetActive(true);
        }
        else
        {
            itemDisplayImage.gameObject.SetActive(false);
            this.itemToDisplay = null;
        }
    }
}

2、打开UIManager.cs,声明由多个物品槽组成的数组,显示物品缩略图

(1)  创建RenderInventory()方法,用于显示物品栏中的物品显示缩略图

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager : MonoBehaviour
{
    public static UIManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this)
        { Destroy(this);}
        else{ Instance = this;}
    }
    //由单个物品槽(物品背景+物品图片)组成的数组,该数组中的元素可以通过元素.Display(),调用Display方法
    [Header("Inventory System")]
    public InventorySlot[] toolSlots;//声明数组并引用InventorySlot对toolSlots的定义
    public InventorySlot[] itemSlots;

    public void RenderInventory()
    {
        //引用InventoryManager.cs中分配的ItemData对象(斧头等)组成一个数组
        ItemData[] inventorytoolSlot =InventoryManager.Instance.tools;

        //通过遍历数组,依次将每个元素传递给Display方法,显示对应的缩略图
        for (int i = 0; i < toolSlots.Length; i++)
        {
            toolSlots[i].Display(inventorytoolSlot[i]);
        }
    }
}

(2) 在 UIManager.cs 中创建一个单独的方法用于遍历数组,将数组中的每一个元素传递给Display方法,从而显示对应的缩略图

public class UIManager : MonoBehaviour
{
    public static UIManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this)
        { Destroy(this);}
        else{ Instance = this;}
    }

    [Header("Inventory System")]
    public InventorySlot[] toolSlots;
    public InventorySlot[] itemSlots;

    public void RenderInventory()
    {
        //该数组作为参数传递给RenderInventoryPanel()
        ItemData[] inventoryToolSlot =InventoryManager.Instance.tools;
        RenderInventoryPanel(inventoryToolSlot,toolSlots);
    }
    void RenderInventoryPanel(ItemData[] slots, InventorySlot[] uiSlots )
    {
        //通过遍历数组,依次将每个元素传递给Display方法,显示对应的缩略图
        for (int i = 0; i < uiSlots.Length; i++)
        { uiSlots[i].Display(slots[i]); }
    }
}

 解析

void RenderInventoryPanel(ItemData[] slots, InventorySlot[] uiSlots)
{
    for (int i = 0; i < uiSlots.Length; i++)
    {
        //DisPlay():InventorySlot.cs中的方法用于显示插槽中的缩略图
        uiSlots[i].Display(slots[i]);
    }
}

[1] void RenderInventoryPanel(ItemData[] slots, InventorySlot[] uiSlots)

这个方法需要两个参数ItemData类的数组和InventorySlot类的数组

[2] ItemData类和InventorySlot类:两个脚本

ItemData类:设定工具和物品总的属性

InventorySlot类:设定ItemData类中的工具和物品对应的插槽中的缩略图

[3] uiSlots[i].Display(slots[i]);

使uiSlots 数组中索引为 i 的 InventorySlot 对象uiSlots显示 slots 数组中对应索引的 ItemData 对象的内容

uiSlots[i]:从 uiSlots 数组中取出索引为 i 的 InventorySlot 对象。

slots[i]:从 slots 数组中取出索引为 i 的 ItemData 对象。

                  是 Display(ItemData item)方法的参数

Display(ItemData item): InventorySlot 类中的一个方法,显示给定 ItemData 对象的缩略图

[4] uiSlots 是Slots (ItemData对象)的某个元素,在InventorySlot 中被定义

(3) 赋值

3、同样的方法设置物品栏中Item物品的显示,并在Start方法中调用

(1) 编辑 UIManager.cs,

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager : MonoBehaviour
{
    public static UIManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this)
        { Destroy(this); }
        else { Instance = this; }
    }

    [Header("Inventory System")]
    public InventorySlot[] toolSlots;
    public InventorySlot[] itemSlots;

    private void Start()
    {
        RenderInventory();
    }

    public void RenderInventory()
    {
        ItemData[] inventoryToolSlot = InventoryManager.Instance.tools;
        RenderInventoryPanel(inventoryToolSlot, toolSlots);

        //Items物品栏中物品槽数组
        ItemData[] inventoryItemSlots = InventoryManager.Instance.items;
        RenderInventoryPanel(inventoryItemSlots, itemSlots);
    }
    public void RenderInventoryPanel(ItemData[] slots, InventorySlot[] uiSlots)
    {
        for (int i = 0; i < uiSlots.Length; i++)
        {
            uiSlots[i].Display(slots[i]);
        }
    }
}

(2) 赋值

4、分配Item对象

九、设置按钮

1、编辑UIManager.cs,设置物品栏面板显示与隐藏

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager : MonoBehaviour
{
    public static UIManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this)
        { Destroy(this);}
        else {Instance = this;}
    }

    [Header("Inventory System")]
    public InventorySlot[] toolSlots;
    public InventorySlot[] itemSlots;

    //物品栏面板
    public GameObject inventoryPanel;

    private void Start()
    {
        RenderInventory();
    }

    public void RenderInventory()
    {
        ItemData[] inventoryToolSlot = InventoryManager.Instance.tools;
        RenderInventoryPanel(inventoryToolSlot, toolSlots);

        ItemData[] inventoryItemSlots = InventoryManager.Instance.items;
        RenderInventoryPanel(inventoryItemSlots, itemSlots);
    }
    void RenderInventoryPanel(ItemData[] slots, InventorySlot[] uiSlots)
    {
        for (int i = 0; i < uiSlots.Length; i++)
        {
            uiSlots[i].Display(slots[i]);
        }
    }
    //设置物品栏面板
    public void ToggleInventoryPanel()
    {
        inventoryPanel.SetActive(!inventoryPanel.activeSelf);
        //显示缩略图
        RenderInventory();
    }
}

2、赋值

3、设置按钮:背包和返回按钮

十、物品名称和描述

1、设置物品文本信息

(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; }
    private void Awake()
    {
        if (Instance != null && Instance != this)
        { Destroy(this); }
        else{ Instance = this; }
    }

    [Header("Inventory System")]

    public GameObject inventoryPanel;

    public InventorySlot[] toolSlots;
    public InventorySlot[] itemSlots;

    //物品信息文本
    public Text itemNameText;
    public Text itemDescriptionText;

    private void Start()
    {
        RenderInventory();
    }

    public void RenderInventory()
    {
        ItemData[] inventoryToolSlot = InventoryManager.Instance.tools;
        RenderInventoryPanel(inventoryToolSlot, toolSlots);

        ItemData[] inventoryItemSlots = InventoryManager.Instance.items;
        RenderInventoryPanel(inventoryItemSlots, itemSlots);
    }
    void RenderInventoryPanel(ItemData[] slots, InventorySlot[] uiSlots)
    {
        for (int i = 0; i < uiSlots.Length; i++)
        {
            uiSlots[i].Display(slots[i]);
        }
    }
    public void ToggleInventoryPanel()
    {
        inventoryPanel.SetActive(!inventoryPanel.activeSelf);
        RenderInventory();
    }

    //物品文本信息
    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,增加鼠标悬停事件

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;
    public void Display(ItemData itemToDisplay)
    {
        if (itemToDisplay != null && itemToDisplay.thumbnail != null)
        {
            itemDisplayImage.sprite = itemToDisplay.thumbnail;
            this.itemToDisplay = itemToDisplay;
            itemDisplayImage.gameObject.SetActive(true);
            return;
        }
        itemDisplayImage.gameObject.SetActive(false);
        this.itemToDisplay = null;
    }

    //鼠标悬停事件
    // 当鼠标或触摸指针进入某个UI元素时触发
    public void OnPointerEnter(PointerEventData eventData)
    {
        //调用UIManager的DisplayerItemInfo方法,并传入当前要显示的ItemData实例
        UIManager.Instance.DisplayItemInfo(itemToDisplay);
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        UIManager.Instance.DisplayItemInfo(null);
    }
}
 十一、设置已装备工具和时间信息UI

1、UI-Image,命名为StatusBar,调整大小、位置等。颜色F4DDB7

2、复制一个HandSlot,作为StatusBar的子物体,变更StatusBar在Hierarchy上的位置。如上图

      使打开背包按钮时被物品栏面板遮挡

3、变更复制的HandSlot的位置和大小

4、以StatusBar为父物体,Create Empty,命名为TimeInfo。调整位置(锚定right middle)、大小。

5、复制步骤3中的HandSlot,作为TimeInfo的子物体,命名为Weather。更改位置和颜色FF9500

6、以TimeInfo为父物体UI-Text,重命名为Time,设置大小位置和文字

7、以TimeInfo为父物体UI-Text,重命名为Date,设置大小位置和文字

8、以步骤3的HandSlot为父物体,UI-Image,命名为HandSlotImage,拉伸,选择一个缩略图

勾选Preserve Aspect

 十二、在StatusBar下的HandSlot显示已装备物品的缩略图

1、编辑UIManager.cs,声明已装备的物品需要显示的图像(此位置显示的物品与物品栏旁边已装备物品一致)

public class UIManager : MonoBehaviour
{
    public static UIManager Instance { get; private set; }
    private void Awake() {……}
    //添加显示标题,声明已装备物品的图像
    [Header("Startas Bar")] 
    public Image toolEquipSlotImage;   
    ……
}

赋值

2、显示和隐藏装备物品的缩略图

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIManager : MonoBehaviour
{
    public static UIManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this)……………………
    }

    //添加显示标题,声明已装备物品的图像
    [Header("Startas Bar")]
    public Image toolEquipSlotImage;

    [Header("Inventory System")]

    public GameObject inventoryPanel;

    public InventorySlot[] toolSlots;
    public InventorySlot[] itemSlots;

    public Text itemNameText;
    public Text itemDescriptionText;

    private void Start()
    {
        RenderInventory();
    }

    public void RenderInventory()
    {
        ItemData[] inventoryToolSlot = InventoryManager.Instance.tools;
        RenderInventoryPanel(inventoryToolSlot, toolSlots);

        ItemData[] inventoryItemSlots = InventoryManager.Instance.items;
        RenderInventoryPanel(inventoryItemSlots, itemSlots);

        //引用InventoryManager.cs的ItemData对象equippedTool(已装备的物品)
        ItemData equippedTool = InventoryManager.Instance.equippedTool;
        //显示缩略图
        if(equippedTool != null)
        {
            //将已装备物品的缩略图赋值给toolEquipSlotImage的sprite组件
            toolEquipSlotImage.sprite = equippedTool.thumbnail;
            toolEquipSlotImage.gameObject.SetActive(true);
            return;
        }
        toolEquipSlotImage.gameObject.SetActive(false);
    }
    void RenderInventoryPanel(ItemData[] slots, InventorySlot[] uiSlots)
    {
        for (int i = 0; i < uiSlots.Length; i++)
        {
            uiSlots[i].Display(slots[i]);
        }
    }
    public void ToggleInventoryPanel()
    {
        inventoryPanel.SetActive(!inventoryPanel.activeSelf);
        RenderInventory();
    }

    public void DisplayItemInfo(ItemData data)
    {
        if(data == null)
        {
            itemNameText.text = "";
            itemDescriptionText.text = "";
            return;
        }
        itemNameText.text = data.name;
        itemDescriptionText.text = data.description;
    }
}

3、赋值(InventoryManager.cs下的Equipped Tool)

 十三、进行物品交换
1、设置物品栏的两种类型(UI中的ToolPanel和ItemsPanel)

(1) 编辑InventorySlot.cs

public class InventorySlot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
    ItemData itemToDisplay;
    public Image itemDisplayImage;

    //物品栏两种类型
    public enum InventoryType
    {
        Item, Tool
    }
    public InventoryType inventoryType;
    …………………………
}

(2) 赋值

2、设置物品栏中的物品与装备物品的交换

(1) 编辑 InventoryManager.cs,增加两个物品转移的方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InventoryManager : MonoBehaviour
{
    //装备物品(由物品栏转移到装备栏)
    public void InventoryToHand()
    {

    }
    //卸下装备物品
    public void HandToInventory()
    {

    }
}

(2) 编辑 InventorySlot.cs,增加接口,增加鼠标点击事件(装备物品事件)

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

//实现三个接口,IPointerClickHandler接口定义了当鼠标在此物体上点击时调用的方法
public class InventorySlot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler,IPointerClickHandler//增加
{
    ItemData itemToDisplay;

    public Image itemDisplayImage;

    public enum InventoryType
    {
        Item,Tool
    }
    public InventoryType type;

    public void Display(ItemData item)
    {
        if (item != null && item.thumbnail != null)
        {
            this.itemToDisplay = item;
            itemDisplayImage.sprite = itemToDisplay.thumbnail;

            itemDisplayImage.gameObject.SetActive(true);
        }
        else
        {
            itemDisplayImage.gameObject.SetActive(false);
            this.itemToDisplay = null;
        }
    }
    //点击事件
    //virtual: 允许继承类对父类的方法进行修改或扩展
    //该方法可以在子类中进行重写
    public virtual void OnPointerClick(PointerEventData eventData)
    {
        //调用InventoryManager.cs中的InventoryToHand()方法(装备物品的方法)
        InventoryManager.Instance.InventoryToHand();
    }

    public void OnPointerEnter(PointerEventData  eventData)
    {
        UIManager.Instance.DisplayerItemInfo(itemToDisplay);
    }
    public void OnPointerExit(PointerEventData eventData)
    {
        UIManager.Instance.DisplayerItemInfo(null);
    }
}

(3) 在UI文件夹新建 HandInventorySlot.cs 作为InventorySlot.cs的子类,设置卸下装备事件

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UIElements;

//继承InventorySlot
public class HandInventorySlot : InventorySlot
{
    //再次点击时调用HandToInventory()方法,输入的参数是inventoryType(点击物品所属的类型)
    public override void OnPointerClick(PointerEventData eventData)
    {
        InventoryManager.Instance.HandToInventory(inventoryType);
    }
}
3、为物品栏中的每一个物品分配一个索引值

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

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class InventorySlot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler,IPointerClickHandler//增加
{
    ItemData itemToDisplay;
    public Image itemDisplayImage;
    public enum InventoryType
    {        Item,Tool    }
    public InventoryType inventoryType;

    int slotIndex;//被选中点击的物品插槽的索引

    public void Display(ItemData item)
    {
        if (item != null)
        {
            this.itemToDisplay = item;
            itemDisplayImage.sprite = itemToDisplay.thumbnail;

            itemDisplayImage.gameObject.SetActive(true);
            return;
        }
        else
        {
            itemDisplayImage.gameObject.SetActive(false);
            this.itemToDisplay = null;
        }
    }

    public virtual void  OnPointerClick(PointerEventData eventData)
    {
        InventoryManager.Instance.InventoryToHand();
    }
    //接收一个参数slotIndex,并将slotIndex的值赋给slotIndex

    public void AssignIndex(int slotIndex)
    {
        this.slotIndex = slotIndex;
    }

    public void OnPointerEnter(PointerEventData  eventData)
    {
        UIManager.Instance.DisplayerItemInfo(itemToDisplay);
    }
    public void OnPointerExit(PointerEventData eventData)
    {
        UIManager.Instance.DisplayerItemInfo(null);
    }
}

(2) 编辑UIManager.cs,创建并在Start方法中调用AssignSlotIndex()方法,分配索引值,这个索引值被传递给InventorySlot.cs中的AssignIndex(int slotIndex)方法,并在slotIndex中显示出来

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIManager : MonoBehaviour
{
    public static UIManager Instance { get; private set; }
    private void Awake()
    {
        if (Instance != null && Instance != this)
        { Destroy(this); }
        else { Instance = this; }
    }

    [Header("Startas Bar")]
    public Image toolEquipSlotImage;

    [Header("Inventory System")]
    public GameObject inventoryPanel;

    public InventorySlot[] toolSlots;
    public InventorySlot[] itemSlots;

    public Text itemNameText;
    public Text itemDescriptionText;

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

    public void RenderInventory()
    {
        ItemData[] inventoryToolSlot = InventoryManager.Instance.tools;
        RenderInventoryPanel(inventoryToolSlot, toolSlots);

        ItemData[] inventoryItemSlots = InventoryManager.Instance.items;
        RenderInventoryPanel(inventoryItemSlots, itemSlots);

        ItemData equippedTool = InventoryManager.Instance.equippedTool;
        if(equippedTool != null)
        {
            toolEquipSlotImage.sprite = equippedTool.thumbnail;
            toolEquipSlotImage.gameObject.SetActive(true);
            return;
        }
        toolEquipSlotImage.gameObject.SetActive(false);
    }
    void RenderInventoryPanel(ItemData[] slots, InventorySlot[] uiSlots)
    {
        for (int i = 0; i < uiSlots.Length; i++)
        {
            uiSlots[i].Display(slots[i]);
        }
    }
    public void ToggleInventoryPanel()
    {
        inventoryPanel.SetActive(!inventoryPanel.activeSelf);
        RenderInventory();
    }

    public void DisplayItemInfo(ItemData data)
    {
        if(data == null)
        {
            itemNameText.text = "";
            itemDescriptionText.text = "";
            return;
        }
        itemNameText.text = data.name;
        itemDescriptionText.text = data.description;
    }
}

解析

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

toolSlots[i] toolSlots 数组中的第 i 个元素(即一个 InventorySlot 对象)

toolSlots[i].AssignIndex(i) :为每一个物品分配一个索引值

调用了当前 InventorySlot 对象的 AssignIndex 方法,并将循环变量 i 作为参数传递给该方法。这样,每个 InventorySlot 对象都会接收到一个唯一的索引值,这个索引值对应了它在 toolSlots 数组中的位置

最终将 toolSlots 数组中每个 InventorySlot 对象的索引位置(即数组中的位置)赋值给它们各自的 slotIndex 成员变量

(3) 调试效果

A. 运行游戏,选中InventoryPanel下ToolsPanel下的InventorySlot,在Inspector面板右上角点击三白点,选择Debug

 B. 可见在Hierarchy面板选择InventorySlot时,Inspector面板的InventorySlot.cs组件中的SlotIndex显示为0,而选择InventorySlot (1)时,索引值为1

4、进行物品位置交换

(1) 编辑InventoryManager.cs,在物品转移的方法中增加两个参数,分配插槽

//增加参数,确定选择的物品处于哪种类型,第几个个索引值
public void InventoryToHand(int slotIndex,InventorySlot.InventoryType inventoryType)
{

}
//增加参数,确定物品返回到哪种类型的物品栏中
public void HandToInventory(InventorySlot.InventoryType inventoryType)
{

}

(2) 编辑HandInventorySlot.cs,增加传入参数,确定物品返回到哪个物品栏

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using static InventorySlot;
public class HandInventorySlot : InventorySlot
{
    public override void OnPointerClick(PointerEventData eventData)
    {
        //增加传入参数
        InventoryManager.Instance.HandToInventory(inventoryType);
    }
}

(3) 编辑InventorySlot.cs,增加传入参数,确定选中的物品索引值是多少,属于哪个物品栏

public class InventorySlot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler,IPointerClickHandler
{
    public virtual void OnPointerClick(PointerEventData eventData)
    {
        InventoryManager.Instance.InventoryToHand(slotIndex,inventoryType);
    }
}

(4) 编辑InventoryManager.cs,进行物品位置交换

public class InventoryManager : MonoBehaviour
{
    public void InventoryToHand(int slotIndex,InventorySlot.InventoryType inventoryType)
    {
        if(inventoryType == InventorySlot.InventoryType.Item)
        {
            //取出物品栏中的物品(在位置A)缓存到itemToEquip这个临时变量(临时位置)中
            ItemData itemToEquip = items[slotIndex];
            //把已装备的物品转移到移出的物品的位置(位置A)上
            items[slotIndex] = equippedItem;
            //把临时变量中的物品从临时位置转移到装备物品的位置上
            equippedItem = itemToEquip;
        }
        else
        {
            //取出物品栏中的物品(在位置A)缓存到itemToEquip这个临时变量(临时位置)中
            ItemData toolToEquip = tools[slotIndex];
            //把已装备的物品转移到移出的物品的位置(位置A)上
            tools[slotIndex] = equippedTool;
            //把临时变量中的物品从临时位置转移到装备物品的位置上
            equippedTool = toolToEquip;
        }
        //更新缩略图
        UIManager.Instance.RenderInventory();
    }
}
 十四、设置物品栏旁边的装备物品槽
1、设置装备物品的图片

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

(2) 在Inspector面板右上角点击三白点,由Debug改回为Normal

(3) 选中步骤(1) 中ItemDisplay的父物体HandSlot,添加HandInventorySlot.cs组件,赋值

(4) 复制步骤(1) 中的ItemDisplay,作为子物体粘贴到HandSlot下(ItemPanel下),同样的方法修改它的Rect Transform。

(5) 选中步骤(4) 中的HandSlot,添加HandInventorySlot.cs组件,赋值——用它自己的ItemDisplay,Inventory Type为Item

2、显示装备物品的缩略图

(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; }
    private void Awake()
    {  …………  }

    [Header("Startas Bar")]
    public Image toolEquipSlotImage;

    [Header("Inventory System")]

    public GameObject inventoryPanel;

    //装备物品(物品栏旁边的装备栏)
    public HandInventorySlot toolHandSlot;

    public InventorySlot[] toolSlots;

    //装备物品
    public HandInventorySlot itemHandSlot;

    public InventorySlot[] itemSlots;

    public Text itemNameText;
    public Text itemDescriptionText;

    private 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()
    {
        ItemData[] inventoryToolSlot = InventoryManager.Instance.tools;
        RenderInventoryPanel(inventoryToolSlot, toolSlots);

        ItemData[] inventoryItemSlots = InventoryManager.Instance.items;
        RenderInventoryPanel(inventoryItemSlots, itemSlots);

        //显示缩略图
        toolHandSlot.Display(InventoryManager.Instance.equippedTool);
        itemHandSlot.Display(InventoryManager.Instance.equippedItem);

        ItemData equippedTool = InventoryManager.Instance.equippedTool;
        if(equippedTool != null)
        {
            toolEquipSlotImage.sprite = equippedTool.thumbnail;
            toolEquipSlotImage.gameObject.SetActive(true);
            return;
        }
        toolEquipSlotImage.gameObject.SetActive(false);
    }
    void RenderInventoryPanel(ItemData[] slots, InventorySlot[] uiSlots)
    {
        for (int i = 0; i < uiSlots.Length; i++)
        {
            uiSlots[i].Display(slots[i]);
        }
    }
    public void ToggleInventoryPanel()
    {
        inventoryPanel.SetActive(!inventoryPanel.activeSelf);
        RenderInventory();
    }

    public void DisplayItemInfo(ItemData data)
    {
        if(data == null)
        {
            itemNameText.text = "";
            itemDescriptionText.text = "";
            return;
        }
        itemNameText.text = data.name;
        itemDescriptionText.text = data.description;
    }
}

(2) 赋值:选中Manager,注意Tool下和Item下的HandSlot 要对应

3、设置装备物品返回物品栏

(1) 编辑InventoryManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static InventorySlot;

public class InventoryManager : MonoBehaviour
{
    public static InventoryManager Instance { get; private set; }
    private void Awake()
    { ………… }

    //分配ItemData对象(斧头等)
    [Header("Tools")]
    public ItemData[] tools = new ItemData[8];
    public ItemData equippedTool = null;

    [Header("Items")]
    public ItemData[] items = new ItemData[8];
    public ItemData equippedItem = null;

    public void InventoryToHand(int slotIndex, InventorySlot.InventoryType inventoryType)
    {
        …………
    }
    //转移装备物品到物品栏的空余位置
    public void HandToInventory(InventorySlot.InventoryType inventoryType)
    {
        if (inventoryType == InventorySlot.InventoryType.Item)
        {
            for (int i = 0; i < items.Length; i++)
            {
                if (items[i] == null)
                {
                    items[i] = equippedItem;
                    equippedItem = null; 
                    break;
                }
            }
        }
        else
        {
            for(int i = 0;i < tools.Length; i++)
            {
                if(tools[i] == null)
                {
                    tools[i] = equippedTool;
                    equippedTool = null;
                    break;
                }
            }
        }
        UIManager.Instance.RenderInventory();
    }
}
4、选中Manager,设置Item对象

十五、改变土地状态
1、编辑Land.cs

注意:这里更改了一个拼写错误Warter改为Water

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;

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

    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;
    }
    public void Select(bool toggle)
    {
        select.SetActive(toggle);
    }

    public void Interact()
    {
        //引用由InventoryManager.cs定义的equippedTool,存储在toolSlot中。(已装备物品)
        ItemData toolSlot = InventoryManager.Instance.equippedTool;
        //将toolSlot的类型转换为EquipmentData类型,并将结果赋值给equipmentTool
        EquipmentData equipmentTool = toolSlot as EquipmentData;
        if (equipmentTool != null)
        {
            //获取工具类型
            EquipmentData.ToolType toolType = equipmentTool.toolType;

            //根据工具类型设置土壤状态
            switch(toolType)
            {
                case EquipmentData.ToolType.Hoe:
                    SwitchLandStatus(LandStatus.Farmland);break;
                case EquipmentData.ToolType.WateringCan:
                    SwitchLandStatus(LandStatus.Watered);break;
            }
        }
    }
}
2、设置Tool Type

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值