大家好,我是Zander,我们接着来开发Rts3D即时战略游戏开发。这一节我们来讲在地图上哪些区域可以建造建筑,哪些地方不可以。
建筑在地形上跟随鼠标,但是并没有标记指示在哪里可以建造,我们希望,如果不能建造就显示红色,如果能建造就显示绿色。
首先在RTSManager中添加一个特别的函数 ,进入RTSManager并编辑这个脚本,添加一个新的方法:
public bool IsGameObjectSafeToPlace(GameObject go)
{
return true;
}
这里暂时不实现这个函数,只是看它的表现;
接着在FindBuildingSite脚本中能让物体显示为红或绿,这里我们需要定义一些变量,来实现功能:如下:
using UnityEngine;
using System.Collections;
public class FindbuildingSite : MonoBehaviour {
Renderer rend; //存储Render 这样可以改变颜色并恢复
Color Red = new Color (1, 0, 0, 0.5f); //定义不可建区域红色
Color Green = new Color (0, 1, 0, 0.5f); //定义可建区域绿色
void Start()
{
rend = GetComponent<Renderer> ();
}
// Update is called once per frame
void Update () {
var tempTarget = RtsManager.Current.ScreenPointToMapPosition (Input.mousePosition);
if (tempTarget.HasValue == false)
return;
transform.position = tempTarget.Value;
if (RtsManager.Current.IsGameObjectSafeToPlace (gameObject)) //判断此区域是否可建造建筑
{
rend.material.color = Green;
} else {
rend.material.color = Red;
}
}
}
现在返回到RTSManager重新写一下IsGameObjectSafeToPlace这个函数,为了检测是否可建,我要判断每一个顶点看它是不是在可通过的地形上,首先要得到顶点,取得MeshFilter,从中获得mesh,接下来还要取得哪些潜在可能阻碍建造的障碍物列表,例如建筑。代码如下:
public bool IsGameObjectSafeToPlace(GameObject go)
{
var verts = go.GetComponent<MeshFilter> ().mesh.vertices; //获取全部顶点
var obstacles = GameObject.FindObjectsOfType<NavMeshObstacle> (); //得到障碍物集合
var cols = new List<Collider> ();
foreach (var o in obstacles) {
if (o.gameObject != go) {
cols.Add (o.gameObject.GetComponent<Collider> ());
}
}
//检测每一个顶点,对于每个顶点都要检测其是否在可通过的地形上,
foreach (var v in verts) {
NavMeshHit hit;
var vReal = go.transform.TransformPoint (v); //取得顶点的世界位置坐标,
NavMesh.SamplePosition (vReal, out hit, 20, NavMesh.AllAreas);
//接下来需要检测顶点是不是在核实的XZ平面或碰撞体内,因为不关心离地多高,所以可以忽略Y轴,只关心点在不在障碍物内,
bool onXAxis = Mathf.Abs (hit.position.x - vReal.x) < 0.5f; //如果这两个点的距离小于0.5 我们认为在 X 轴上是可行的
bool onZAxis = Mathf.Abs(hit.position.z - vReal.z) < 0.5f; //如果这两个点的距离小于0.5 我们认为在 Z 轴上是可行的
bool hitCollider = cols.Any (c => c.bounds.Contains (vReal)); //如果任何一个碰撞体的范围内有这个顶点,则HitCollider为true
if (!onXAxis || !onZAxis || hitCollider) {
return false;
}
}
return true;
}
保存代码,运行Unity,则会发现我们把建筑拖拽到山上就变红,拖到平地就会变绿。
现在我们来实现鼠标再次点击时建造建筑,我们找到FindBuildingSite脚本,并修改Start方法,为确保建筑物被认为或意外的销毁后要恢复操作,在Update内判断是否可建
using UnityEngine;
using System.Collections;
public class FindbuildingSite : MonoBehaviour {
public float Cost = 200; //建造费用
public float MaxBuildDistance = 30; //建造距离
public GameObject BuildingPrefab; //建筑预设
public PlayerSetupDefinition Info; //玩家信息
public Transform Source; //资源的位置坐标,用来判断是否可建造
Renderer rend;
Color Red = new Color (1, 0, 0, 0.5f);
Color Green = new Color (0, 1, 0, 0.5f);
void Start()
{
MouseManager.Current.enabled = false;
rend = GetComponent<Renderer> ();
}
// Update is called once per frame
void Update () {
var tempTarget = RtsManager.Current.ScreenPointToMapPosition (Input.mousePosition);
if (tempTarget.HasValue == false)
return;
transform.position = tempTarget.Value;
if (Vector3.Distance (transform.position, Source.position) > MaxBuildDistance) //判断和无人机的位置,如果太远不可建
{
rend.material.color = Red;
return;
}
if (RtsManager.Current.IsGameObjectSafeToPlace (gameObject)) {
rend.material.color = Green;
if (Input.GetMouseButtonDown (0)) //鼠标再次点击时建造建筑
{
var go = GameObject.Instantiate (BuildingPrefab);
go.transform.position = transform.position;
Info.Credits -= Cost; //扣除费用
go.AddComponent<Player> ().Info = Info;
Destroy (this.gameObject);
}
} else {
rend.material.color = Red;
}
}
void OnDestroy()
{
MouseManager.Current.enabled = true;
}
}
返回Unity修改CreateBuildingAction脚本,如下:
using UnityEngine;
using System.Collections;
public class CreateBuildingAction : ActionBehavior {
public float Cost = 0; //建筑花费
public GameObject BuildingPrefab;//建筑预设
public float MaxBuildDistance = 30; //最远可建造距离
public GameObject GhostBuildingPrefab;
private GameObject active = null;
public override System.Action GetClickAction ()
{
return delegate() {
var player = GetComponent<Player>().Info;
if (player.Credits < Cost)
{
Debug.Log("Not enough, this costs " + Cost);
return;
}
//建造建筑逻辑处理
var go = GameObject.Instantiate(GhostBuildingPrefab);
var finder = go.AddComponent<FindbuildingSite>();
finder.BuildingPrefab = BuildingPrefab;
finder.MaxBuildDistance = MaxBuildDistance;
finder.Info = player;
finder.Source = transform;
active = go;
};
}
void Update()
{
if (active == null)
return;
if (Input.GetKeyDown (KeyCode.Escape)) //取消建造建筑
GameObject.Destroy (active);
}
void OnDestroy()
{
if (active == null)
return;
Destroy (active);
}
}
接下来我们来为建筑添加一个可以生产金币的功能,新建Earning脚本:
using UnityEngine;
using System.Collections;
public class Earnings : MonoBehaviour {
public float CreditsPerSecond = 1; //每秒生产金币数量
private PlayerSetupDefinition player; //所归属玩家信息
// Use this for initialization
void Start () {
player = GetComponent<Player> ().Info; //得到玩家信息
}
// Update is called once per frame
void Update () {
player.Credits += CreditsPerSecond * Time.deltaTime; //生产金币
}
}
好了,这一章就写到这,这是源码地址:链接:http://pan.baidu.com/s/1pLVkU8N 密码:xbe2
欢迎大家加入QQ群:280993838 或者关注我的公众号: