RTS游戏关于建筑物放置的测试Demo(Unity)

一.准备一个建筑物

1,创建一个立方体Cube,改名为Mesh

2,创建一个空物体,起名叫Building

3,将Mesh放到Building下,将Mesh的BoxCollider组件删除,在Building的组件中新加BoxCollider和Rigidbody组件

4,创建Building.cs,将脚本挂载到Building下

 

 

注意点:因为BoxCollider没有挂载到Mesh上,所以在调整碰撞器大小时,应该调整到和Mesh原来BoxCollider大小位置一样 (使用导入资源如果涉及到旋转等,注意做好调整)

5,在Assets创建Resources文件夹,在Resources文件夹下创建Prefabs文件夹,在Prefabs文件夹下创建Buildings文件夹,将Building拖入保存为预制件

 

二.配置环境

1,创建一个地形Terrain(Layer为第八层,可以自己设置,不过在Globals 里面自己改)

2,创建一个空物体,改名为Game,创建一个BuildingPlacer.cs,将脚本挂载到Game上

3,在Resources文件夹下创建Materials文件夹,然后创建2个Material,将名字改为下面的,然后将颜色改一下

三.创建建筑物数据和脚本

public class BuildingData
{
    private string _name;
    private int _hp;
    public BuildingData(string name, int hp)
    {
        _name = name;
        _hp = hp;
    }
    public string Name { get { return _name; } }
    public int HP { get { return _hp; } }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BuildingPlacer : MonoBehaviour
{
    //作为建筑放置类,手里必须拿着建筑
    private Building _building;
    private Ray _ray;
    private RaycastHit _raycastHit;
    //这个点的作用主要就是为了判断是否鼠标发生了移动,这个时候就可以更改值了
    private Vector3 SavePoint;

    private void Start()
    {
        _prepareBuilding(0);
    }
    private void Update()
    {
        if (_building != null)
        {
            //如果按下esc就取消建筑物
            if (Input.GetKeyDown(KeyCode.Escape))
            {
                _cancelBuilding();
                return;
            }
            
            _ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if(Physics.Raycast(_ray,out _raycastHit, 1000f, Globals.TERRAIN_LAYER_MASK))
            {
                _building.gameObject.transform.position = _raycastHit.point;
                //只要一动就检查建筑的状态,随时进行切换
                if(SavePoint != _raycastHit.point)
                {
                    _building.ChangeState();
                }
                SavePoint = _raycastHit.point;
                if (_building.HasValidPlace && Input.GetMouseButtonDown(0))
                {
                    _PlaceBuilding();
                }
            }

        }
    }

    /// <summary>
    /// 准备建筑物
    /// </summary>
    public void _prepareBuilding(int index)
    {
        if(_building != null)
        {
            Destroy(_building.gameObject);
        }
        else
        {
            GameObject _gameObject = (GameObject)GameObject.Instantiate(Resources.Load($"Prefabs/Buildings/{Globals.buildingDatas[index].Name}"));
            _building = _gameObject.GetComponent<Building>();
            _building.setvaults(Globals.buildingDatas[index]);
        }
        SavePoint = Vector3.zero;
    }
    /// <summary>
    /// 取消建筑物
    /// </summary>
    void _cancelBuilding()
    {
        Destroy(_building.gameObject);
        _building = null;
    }
    /// <summary>
    /// 放置建筑物
    /// </summary>
    void _PlaceBuilding()
    {
        _building.place();
        _building = null;
        _prepareBuilding(0);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum BuildingPlacementState
{
    VALID,
    INVALID,
    FIXED
};

[RequireComponent(typeof(BoxCollider))]
public class Building : MonoBehaviour
{
    private BuildingData _buildingData;
    private int currentHp;   
    private BuildingPlacementState _state;
    private List<Material> _materials;
    private int _nCollisions = 0;

    public void setvaults(BuildingData buildingData)
    {
        this._buildingData = buildingData;
        this.currentHp = buildingData.HP;
    }
    public string Name { get { return _buildingData.Name; } }
    public int CurrentHp { get { return currentHp; } }
    public int Hp { get { return _buildingData.HP; } }
    public int DataIndex
    {
        get
        {
            for (int i = 0; i < Globals.buildingDatas.Length; i++)
            {
                if (Globals.buildingDatas[i].Name == _buildingData.Name)
                {
                    return i;
                }
            }
            return -1;
        }
    }
    private void Awake()
    {
        _materials = new List<Material>();
        _state = BuildingPlacementState.VALID;
        foreach (Material material in gameObject.transform.Find("Mesh").GetComponent<Renderer>().materials)
        {
            _materials.Add(new Material(material));
        }
        SetMaterials(_state);
    }
    /// <summary>
    /// 根据状态改变颜色
    /// </summary>
    /// <param name="buildingState"></param>
    public void SetMaterials(BuildingPlacementState buildingState)
    {
        List<Material> materials;
        if (buildingState == BuildingPlacementState.VALID)
        {
            materials = new List<Material>();
            for (int i = 0; i < _materials.Count; i++)
            {
                materials.Add(Globals.Valid);
            }
        }
        else if (buildingState == BuildingPlacementState.INVALID)
        {
            materials = new List<Material>();
            for (int i = 0; i < _materials.Count; i++)
            {
                materials.Add(Globals.Invalid);
            }
        }
        else if (buildingState == BuildingPlacementState.FIXED)
        {
            materials = _materials;
        }
        else
        {
            return;
        }
        gameObject.transform.Find("Mesh").GetComponent<Renderer>().materials = materials.ToArray();
    }
    /// <summary>
    /// 触发进入
    /// </summary>
    /// <param name="other"></param>
    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Terrain") return;
        _nCollisions++;
        ChangeState();
    }
    /// <summary>
    /// 触发离开
    /// </summary>
    /// <param name="other"></param>
    private void OnTriggerExit(Collider other)
    {
        if (other.tag == "Terrain") return;
        _nCollisions--;
        ChangeState();
    }
    /// <summary>
    /// 根据自身的触发检测来改变状态
    /// </summary>
    public void ChangeState()
    {
        if (_state == BuildingPlacementState.FIXED)
        {
            return;
        };
        if (_nCollisions > 0)
        {
            _state = BuildingPlacementState.INVALID;
            SetMaterials(_state);
        }
        else
        {
            _state = BuildingPlacementState.VALID;
            SetMaterials(_state);
        }
    }
    /// <summary>
    /// 放置建筑物,改变建筑物状态和恢复颜色
    /// </summary>
    public void place()
    {
        _state = BuildingPlacementState.FIXED;
        SetMaterials(_state);
        gameObject.GetComponent<BoxCollider>().isTrigger = false;
    }
    public bool HasValidPlace{ get => _state == BuildingPlacementState.VALID; }

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

public class Globals : MonoBehaviour
{
    public static BuildingData[] buildingDatas = new BuildingData[]
    {
        new BuildingData("Building",100)
    };
    //这里只保留地面的检测
    public static int TERRAIN_LAYER_MASK = 1 << 8;

    public static Material Valid = Resources.Load("Materials/Valid") as Material;
    public static Material Invalid = Resources.Load("Materials/Invalid") as Material;
}

4.总结

项目运行起来后,就可以进行Building实体的放置了,当放置时碰到已经放置的实体时会显示红色,点击鼠标左键也是没有效果的,如果是绿色,则可以直接左键放置。本博客只是一个小Demo,只是提供一个学习思路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值