【Unity项目实战】从零手戳一个背包系统

前言

首先我们下载我们的人物和背景资源,因为主要是背包系统,所以人物的移动和场景的搭建这里我们就不多讲了,我这里直接提供基础项目源码给大家去使用就行

基础项目下载地址:
链接: https://pan.baidu.com/s/1o7_RW_QQ1rrAbDzT69ApRw 提取码: 8s95

顺带说一下,这里用到了unity的几个免费资源包,有兴趣的也可以自己去unity资源商店下载使用
人物资源:Tiny RPG-Forest
背包ui资源:SIMPLE FANTASY GUI
物品资源:Free Pixel Gear

导入基础项目界面效果
【Unity项目实战】从零手戳一个背包系统_第1张图片

开始

1新建一个面板物体,命名为Bag,剧中,设置合适的宽高,我这里是500x400
【Unity项目实战】从零手戳一个背包系统_第2张图片
2.不需要任何代码,实现按×关闭菜单界面
【Unity项目实战】从零手戳一个背包系统_第3张图片
新建网格布局组件(Grid Layout Group)
【Unity项目实战】从零手戳一个背包系统_第4张图片
写代码控制,如果我按下键盘tab按钮,打开和关闭背包

//背包
public GameObject myBag;
//控制背包打开关闭
bool isOpen;

//...

private void Update()
{
    OpenMyBag();
}

void OpenMyBag(){
   //如果我按下键盘tab按钮,打开和关闭背包
    if (Input.GetKeyDown(KeyCode.Tab))
    {
        isOpen = !isOpen;
        myBag.SetActive(isOpen);
    }
}

用ScriptableObject存储数据

ScriptableObject是一种本地文件存储,游戏停止运行数据不会丢失

1.新建一个Iteam代码,存储物品类,可以实例化为不同的实例,鞋子,剑,药水等
【Unity项目实战】从零手戳一个背包系统_第5张图片
编写代码

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

// 通过以下方式控制程序集的一般信息 文件名 菜单目录名
[CreateAssetMenu(fileName = "Item", menuName = "InventroyTutorial/Item", order = 0)]
public class Item : ScriptableObject {
    
}

实例化使用
【Unity项目实战】从零手戳一个背包系统_第6张图片
完善代码

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

// 通过以下方式控制程序集的一般信息 文件名 菜单目录名
[CreateAssetMenu(fileName = "Item", menuName = "InventroyTutorial/Item", order = 0)]
public class Item : ScriptableObject {
    public string itemName; // 物品名
    public Sprite itemImage; //图片
    public int itemNum; //数量
    [TextArea]
    public string itemInfo;//物品介绍
    public bool isEquipment;//是否可装备
}

实例化使用实例
【Unity项目实战】从零手戳一个背包系统_第7张图片
2.新增背包类Bag脚本,好处就是可以实例化为多个背包,比如玩家背包,铁匠铺背包,药品店背包等

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

[CreateAssetMenu(fileName = "Bag", menuName = "InventroyTutorial/Bag", order = 0)]
public class Bag : ScriptableObject {
    public List<Item> items = new List<Item>();
    
}

实例化背包

【Unity项目实战】从零手戳一个背包系统_第8张图片

添加物品脚本,实现拾取物品效果

拖入一个物品,加入碰撞体触发器
【Unity项目实战】从零手戳一个背包系统_第9张图片
编写物品脚本

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

public class Goods : MonoBehaviour
{
    //绑定实例物品类
    public Item thisItem;
    //绑定物品实例背包类
    public Bag thisBag;
    
    //如果碰到玩家player就把物品放到背包里
    private void OnTriggerEnter2D(Collider2D other) {
        if (other.gameObject.CompareTag("Player")){
            AddNewItem();
            //销毁物品
            Destroy(gameObject);
        }
    }

    public void AddNewItem() {
        //背包是否已经包含物品
        if (!thisBag.items.Contains(thisItem)){
            thisBag.items.Add(thisItem);
        }else{
            thisItem.itemNum += 1;
        }
    }
}

【Unity项目实战】从零手戳一个背包系统_第10张图片
运行效果
【Unity项目实战】从零手戳一个背包系统_第11张图片

编写人物背包脚本

玩家背包挂载脚本

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

public class PlayerBag : MonoBehaviour
{
    //哪个物品
    public Item item;
    //物品图片
    public Image image;
    //物品数量
    public Text num;
}

绑定
【Unity项目实战】从零手戳一个背包系统_第12张图片
新增背包管理类单例模式

using System.ComponentModel.Design.Serialization;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class BagManager : MonoBehaviour
{
    static BagManager instance;
    //人物背包
    public Bag myBag;
    //背包网格
    public GameObject grid;
    //人物背包每个物品预设体
    public PlayerBag playerBag;
    //物品介绍
    public Text itemInfromation;

    void Awake()
    {
        if(instance != null) Destroy(this);
        instance = this;
    }

    private void OnEnable() {
        RefreshItem();
        //默认清空描述
        instance.itemInfromation.text = "";
    }

    //展示描述
    public static void UpdateItemInfo(string itemInfo) {
        instance.itemInfromation.text = itemInfo;
    }

    //生成背包网格物品 物品
    public static void CreateNewItem(Item item){
        UnityEngine.Debug.Log("生成背包网格物品");
        //物品 在哪个位置生成 角度不变
        PlayerBag newItem = Instantiate(instance.playerBag, instance.grid.transform.position, Quaternion.identity);
        //生成
        newItem.gameObject.transform.SetParent(instance.grid.transform);
        //挂载数据
        newItem.item = item;
        newItem.image.sprite = item.itemImage;
        newItem.num.text = item.itemNum.ToString();
    }

    //已存在物品,修改数量
    public static void RefreshItem(){
        //销毁背包所有的物品
        for (int i = 0; i < instance.grid.transform.childCount; i++)
        {
            if(instance.grid.transform.childCount == 0){
                break;
            }
            Destroy(instance.grid.transform.GetChild(i).gameObject);
        }
        //将我的背包列表数据生成背包网格物品
        for (int i = 0; i < instance.myBag.items.Count; i++)
        {
            CreateNewItem(instance.myBag.items[i]);
        }
    }
}

物品预设体添加组件canvas group,控制拖拽物体的射线检测
【Unity项目实战】从零手戳一个背包系统_第13张图片

实现物品的拖拽

// 导入必要的Unity库
using UnityEngine;
using UnityEngine.EventSystems;

// 定义可拖动物品的类
public class DraggableItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    // 定义物品的起始位置和拖动偏移量的变量
    private Vector3 startPosition;
    private Vector3 offset;

    //父级
    public Transform originalParent;

    //eventData点击的地方 transform物体的
    // 定义拖动开始时的方法
    public void OnBeginDrag(PointerEventData eventData)
    {
        
        originalParent = transform.parent;
        // 保存起始位置
        startPosition = transform.position;
        //拖动下面的会覆盖上面的问题
        transform.SetParent(transform.parent.parent);
        //关闭goods物体(也就是拖拽物体)的射线检测
        GetComponent<CanvasGroup>().blocksRaycasts = false;
        Debug.Log("拖动开始");
    }

    // 定义物品正在被拖动时的方法
    public void OnDrag(PointerEventData eventData)
    {
        //跟着鼠标移动
        transform.position = Input.mousePosition;
        //射线检测鼠标下的物体
        Debug.Log(eventData.pointerCurrentRaycast.gameObject.name);
    }

    // 定义拖动结束时的方法
    public void OnEndDrag(PointerEventData eventData)
    {
       
        Debug.Log("拖动结束");

        // 获取拖拽结束时鼠标下的物体
        GameObject endObject = eventData.pointerCurrentRaycast.gameObject;

        //放回原来位置
        transform.position = startPosition;

        GetComponent<CanvasGroup>().blocksRaycasts = true;
    }
}

问题

拖拽时,如果把物体设置到父级上,会出现物体闪烁问题优化,主要就是父级格子Grid物体上加了网格布局组件(Grid Layout Group),默认前面排列已满,物体会闪烁继续排到下面
解决:在背包物体goods预设体上加忽略布局组件(Layout Element),勾选忽略布局即可
【Unity项目实战】从零手戳一个背包系统_第14张图片

存储物品信息

这里我直接就给代码了,注释我写的很详细

using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

// GameSaveManager类用于保存和加载背包信息
public class GameSaveManager : MonoBehaviour
{
    public Inventory myInventory; // 背包信息
    public void SaveGame() // 保存背包信息
    {
        Debug.Log(Application.persistentDataPath); // 输出保存路径
        if (!Directory.Exists(Application.persistentDataPath + "/game_SaveData")) // 如果路径不存在,则创建路径
        {
            Directory.CreateDirectory(Application.persistentDataPath + "/game_SaveData");
        }

        BinaryFormatter formatter = new BinaryFormatter(); // 创建二进制转化器
        FileStream file = File.Create(Application.persistentDataPath + "/game_SaveData/inventory.txt"); // 创建文件流
        var json = JsonUtility.ToJson(myInventory); // 将背包信息转化为json格式
        formatter.Serialize(file, json); // 将json格式的背包信息序列化到文件流中
        file.Close(); // 关闭文件流
    }

    public void LoadGame() // 加载背包信息
    {
        BinaryFormatter bf = new BinaryFormatter(); // 创建二进制转化器
        if (File.Exists(Application.persistentDataPath + "/game_SaveData/inventory.txt")) // 如果文件存在
        {
            FileStream file = File.Open(Application.persistentDataPath + "/game_SaveData/inventory.txt", FileMode.Open); // 打开文件流
            JsonUtility.FromJsonOverwrite((string)bf.Deserialize(file), myInventory); // 将文件流中的背包信息反序列化到myInventory中
            file.Close(); // 关闭文件流
        }
    }
}

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。点赞越多,更新越快哦!当然,如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

你可能感兴趣的:(#,unity实战,unity,游戏引擎,游戏)