切换到PlaceMonster.cs脚本,更新canPlaceMonster和canUpdateMonster方法如下,就是加上检查剩余金币是否足够的条件。
private bool canPlaceMonster() { int cost = monsterPrefab.GetComponent<MonsterData>().levels[0].cost; return monster == null && gameManager.Gold >= cost; //确保金币足够 } private bool canUpdateMonster() { if (monster != null) { MonsterData monsterData = monster.GetComponent<MonsterData>(); MonsterLevel nextLevel = monsterData.getNextLevel(); if (nextLevel != null) { return gameManager.Gold >= nextLevel.cost; //确保金币足够 } } return false; }保存,并运行游戏,试试还能不能无限添加怪物。
是时候给敌人“铺路”了。敌人首先在第一个路标的地方出现,然后向下一个路标移动并重复这个动作,知道他们抵达你的饼干。
我们将通过下面的手段使敌人行军起来:
在Hierarcy中右键,选择Create Empty创建一个新的空的游戏对象,命名为Road,并确保其位置坐标为(0, 0, 0)
接下来,右键点击Road并创建另一个空的游戏对象,命名为Waypoint0 并将其坐标设置为(-12, 2, 0),这将是敌人开始进攻的起始点。
创建另外5个路标:
下面的截图标示出了路标的位置以及最终的路线:
现在是时候去创建一些敌人来沿着上面的路线移动了。在Prefabs的文件夹中包含了一个Enemy的prefab。 它的位置坐标是(-20,0,0) ,所以新创建的敌人对象一开始在平面外面。
跟Monster的prefab一样,Enemy的prefab同样包含了一个AudioSource,一个精灵图片(一会儿可以旋转其方向)。
向Prefabs\Enemy新建一个名为MoveEnemy的C#脚本,使用代码编辑器打开,并添加下面的变量定义:
[HideInInspector] public GameObject[] waypoints; private int currentWaypoint = 0; private float lastWaypointSwitchTime; public float speed = 1.0f;waypoints以数组的形式存储了所有的路标,它上面的HideInInspector特性确保了我们不会在inspector面板中不小心修改了它的值,但是我们仍然可以在其他脚本中访问。
currentWaypoint记录了敌人当前所在的路标,lastWaypointSwitchTime记录了当敌人经过路标时用的时间,最后使用speed存储敌人的移动速度。
增加下面这行代码到Start方法中:
lastWaypointSwitchTime = Time.time;这里将lastWaypointSwitchTime初始化为当前时间。
为了使敌人能沿路线移动,在Update方法中添加下面的代码:
// 1 Vector3 startPosition = waypoints[currentWaypoint].transform.position; Vector3 endPosition = waypoints[currentWaypoint + 1].transform.position; // 2 float pathLength = Vector3.Distance(startPosition, endPosition); float totalTimeForPath = pathLength / speed; float currentTimeOnPath = Time.time - lastWaypointSwitchTime; gameObject.transform.position = Vector3.Lerp(startPosition, endPosition, currentTimeOnPath / totalTimeForPath); // 3 if (gameObject.transform.position.Equals(endPosition)) { if (currentWaypoint < waypoints.Length - 2) { // 3.a currentWaypoint++; lastWaypointSwitchTime = Time.time; // TODO: Rotate into move direction } else { // 3.b Destroy(gameObject); AudioSource audioSource = gameObject.GetComponent<AudioSource>(); AudioSource.PlayClipAtPoint(audioSource.clip, transform.position); // TODO: deduct health } }让我们一步一步来看:
A. 敌人尚未抵达最终的路标,所以增加currentWayPoint并更新lastWaypointSwitchTime,稍后我们要增加旋转敌人的代码使他们朝向前进的方向。
B. 敌人抵达了最终的路标,就销毁敌人对象,并触发声音特效,稍后我们要增加减少玩家生命值的代码。
保存文件,并返回到Unity。
给敌人指明方向现在,敌人还不知道路标的次序。
在Hierarchy中选中Road,然后添加一个新的C#脚本命名为SpawnEnemy,并在代码编辑器中打开,增加下面的变量:
public GameObject[] waypoints;我们将使用waypoints来存放路标的引用。
保存文件返回Unity, 在Hierarchy中选中Road,将WayPoints数组的大小改为6,拖拽Road的孩子节点到想用的Element位置,Waypoint0对应Element0以此类推。
现在我们已经有了路线的路标数组,注意到敌人不会退缩。。。
打开SpawnEnemy脚本,增加下面的变量:
public GameObject testEnemyPrefab;这里使用了testEnemyPrefab保存对Enemyprefab的引用。
使用下面的代码,当脚本开始时添加一个敌人:
上面的代码使用testEnemyPrefab实例化一个敌人对象,并将路标赋值给它。