Unity:类塔科夫,塔防网格构建

类塔科夫,塔防网格构建

前往我的博客免费查看

这个项目中实现了一个通用背包系统,主要应用于物品管理,可以在多个游戏类型中灵活运用。它的核心功能包含:

  • 网格容量系统:类似塔科夫(Tarkov)和生化危机(Resident Evil),通过二维网格管理背包中的物品位置和大小。

    实际为三维

  • 负重系统:可选加入负重指标,类似绝地求生(PUBG)中的背包容量管理,限制玩家携带物品的总重量。
  • 堆叠机制:支持物品堆叠,采用最大堆叠容量和当前容量的逻辑,灵活处理物品的数量管理。
  • 预览功能:物品的预览和实际形态分离,允许为同一物品设置不同的模型以提高显示和渲染效率。
  • 实例化物品:支持在背包中放置独立的实例化物品,每个物品都有独立的逻辑和行为。
  • 通用性和扩展性:系统采用了双层泛型封装,底层框架可以用作塔防、即时战略或模拟经营类游戏的核心物品管理系统。

底层框架构建

底层网格系统构建使用泛型类 GridXY<TGridObject>,它提供了背包的核心管理功能。以下是该系统的核心实现:

// 泛型,满足扩展需求;
public class GridXY<TGridObject>
{
    
    
	// 定义基本信息大小
	private int width;  
	private int height;  
	private float cellSize;  
	private Vector3 originPosition;  
	private TGridObject[,] gridArray;
	
	// 背包内容管理器,提供物品查询支持
	private Dictionary<string, int> Bag;

	public GridXY(******)
	{
    
    
		// 初始化背包
	}

	// 提供基础操作
	public int GetWidth() 
	{
    
      
	    return width;  
	}  
	public int GetHeight() 
	{
    
      
	    return height;  
	}
	//.......
	
	// 提供底层核心操作
	// 设置物品
	public void SetGridObject(int x, int y, TGridObject value) 
	{
    
      
	    if (x >= 0 && y >= 0 && x < width && y < height) 
	    {
    
      
	        gridArray[x, y] = value;
	    }
    }
    // 获取物品
    public TGridObject GetGridObject(int x, int y) 
    {
    
      
	    if (x >= 0 && y >= 0 && x < width && y < height) 
	    {
    
      
	        return gridArray[x, y];  
	    } 
	    else 
	    {
    
      
	        return default(TGridObject);  
	    }
    }
    // 取出物品
    public int OutObjectCount(String name, int number)  
	{
    
      
	    if (Bag.ContainsKey(name))  
	    {
    
            
		    int tem = Bag[name];  
	        if (tem > number)  
	        {
    
                
		        Bag[name] -= number;  
	            return number;  
	        }        
		    Bag.Remove(name);  
	        return tem;  
	    }    
	    return 0;  
	}
	// 放入物品
	public void InObjectCount(String name, int number)  
	{
    
      
	    if (Bag.ContainsKey(name))  
	    {
    
            
		    Bag[name] += number;  
	        Debug.LogWarning(name + "还有" + Bag[name]);  
	        return;  
	    }    
	    Bag.Add(name, number);  
	}
	
}

物品泛型的实现

系统中的物品通过 PlacedObjectTypeSO 实现,允许物品以脚本化对象(ScriptableObject)的形式进行定义,从而方便管理物品的属性和行为。

public class PlacedObjectTypeSO : ScriptableObject
{
    
    
	public string nameString;  
	
	// 分别为背包外实例,背包内实例,预览放置实例;
	// 解决部分模型过于精细或背包过大造成的卡顿;
	public Transform usePrefab;  
	public Transform prefab;  
	public Transform visual;  
	public int width;  
	public int height;  

	public int number;  
	public int maxNumber;  
	  
	public int ID;
	
	//物品的放置位置相关
	public List<Vector2Int> GetGridPositionList(Vector2Int offset, Dir dir){
    
    };
	public Vector2Int GetRotationOffset(Dir dir){
    
    };
}


public class PlacedObject_Done : MonoBehaviour
{
    
    
	// 部分信息
	private Vector2Int origin;  
	private PlacedObjectTypeSO.Dir dir;  

	// 堆叠相关信息
	private bool canStack; // 疑似冗余信息
	private int number = 1;  
	private int maxNumber = 1;
	
	// 创建物品
	public static PlacedObject_Done Create()
	{
    
    
		Transform placedObjectTransform = Instantiate(*****){
    
    };
		PlacedObject_Done placedObject = placedObjectTransform.GetCom<>();
		// 从SO文件创建
		placedObject.Setup(placedObjectTypeSO, origin, dir);
		
		return placedObject;
	}
	
	// 信息初始化
	private void Setup(****)  
	{
    
      
	
	    this.placedObjectTypeSO = placedObjectTypeSO;  
	    this.origin = origin;  
	    this.dir = dir;  
	  
	    // 堆叠内容  
	    this.number = placedObjectTypeSO.number;  
	    this.maxNumber = placedObjectTypeSO.maxNumber;  
	  
	    if (maxNumber != number)  
	    {
    
            
		    canStack = true;  
	    }
	}
	
	// 物品的核心信息
	// 根据选择判断占地信息;
	public List<Vector2Int> GetGridPositionList() 
	{
    
      
	    return placedObjectTypeSO.GetGridPositionList(origin, dir);  
	}

	// 物品的特定操作
	// 堆叠,且尝试返回剩余值
	public int Stack(int number)  
	{
    
      
	    this.number += number;  
	    Debug.Log(this.number);  
	    if (this.number > maxNumber)  
	    {
    
            
		    int temp = this.number - maxNumber;  
	        this.number = maxNumber;  
	        return temp;  
	    }    
		    return 0;  
	}
	// 设置数值等
	public int GetNumber()  
	{
    
      
	    return number;  
	}  
	public void SetNumber(int number)  
	{
    
      
	    this.number = number;  
	}
}

核心控制层实现

GridSystemXY 负责控制背包网格的运作。它提供了多个核心操作,例如放置物品、堆叠物品等。


public class GridSystemXY : MonoBehaviour
{
    
    
	// 具体放置的类型,如不习惯,可以解耦独立。
	public class GridObject
	{
    
    
		private GridXY<GridObject> grid;  
		private int x;  
		private int y;  
		public PlacedObject_Done placedObject;  

		// 物品构建时,物品持有当前所在背包的引用;
		public GridObject(GridXY<GridObject> grid, int x, int y) 
		{
    
      
		    this.grid = grid;  
		    this.x = x;  
		    this.y = y;  
		    placedObject = null;  
		}
		// 提供配套的操作
		public void SetPlacedObject(PlacedObject_Done placedObject) 
		{
    
      
		    this.placedObject = placedObject;  
		}
		public bool CanBuild(PlacedObjectTypeSO placedObjectTypeSO){
    
    };
		public bool CanStack(PlacedObjectTypeSO placedObjectTypeSO){
    
    };
		public int Stack(){
    
    };
		
	}

	public static GridSystemXY Instance {
    
     get; private set; }

	// 背包管理器,应对多个背包;
	public Dictionary<int, GridXY<GridSystemXY.GridObject>> gridDictionary;
	
	// 当前操作的背包
	private GridXY<GridObject> grid;
	
	// 当前操作的物品
	private PlacedObjectTypeSO.Dir dir; 
	private PlacedObjectTypeSO placedObjectTypeSO;

	// 移动位置时的逻辑。  
	private bool isSwitchingMode = false;  
	private List<Vector2Int> tempGridPositionList = null;
	
	// 备份数据  
	private int number;

	// 初始化
	private void Awake() 
	{
    
      
	    Instance = this;  
	  
	    gridDictionary = new Dictionary<int, GridXY<GridSystemXY.GridObject>>();  
	    int gridWidth = 3;  
	    int gridHeight = 4;  
	    float cellSize = 10f;  
	    AddGrid(1, grid);  
	    AddGrid(2, grid);  
	  
	    placedObjectTypeSO = null;  
	}

	// 部分系统
	// 放置系统
	private void Build()
	{
    
    
		foreach(var ID in gridDictionary)
		{
    
    
			//获取鼠标位置,查看是否可以放置
		}
		if (canBuild)
		{
    
    
			// 堆叠放置
			if(canStack)
			{
    
    
				int tem = targetGridObject.Stack(number);
				if(tem > 0)
				{
    
    
					//未完全放置,仅更新当前数量
					return;
				}
			}
			
			// 放置
			{
    
    
				// 指定位置创建物品
				placedObject = PlacedObject_Done.Create(****);
			}
			
			// 松开;
			DeselectObjectType();
		}
	}

}