坦克对战游戏 AI 设计
游戏内容
- 整个游戏基于tanks-tutorial 中的_Complete-Game场景,通过对场景中一些脚本的更改,实现AI效果
玩家控制蓝色坦克(WSAD,空格),与红色坦克(AI)solo
游戏分为round,在各round中,玩家发射炮弹攻击对方,活到最后的坦克获胜
先赢够5个round的玩家获得游戏胜利
AI坦克特性
使用了“感知-思考-行为”模型
可以避过障碍物寻路
通过射线探测对方是否在炮弹路径上
不会失去目标
NavMesh
Unity中的寻路系统
首先打开 菜单 Windows -> Navgation
将CompleteLevelArt下除Ground外全部设置为Not walkable
然后烘培(Bake)
为AI坦克添加NavMeshAgent组件
_Completed-Assets\Scripts\Managers\GameManager.cs
在每Round初始化时,会调用ResetAllTanks函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void ResetAllTanks()
{
for (int i = 0; i < m_Tanks.Length; i++)
{
if (i == 1) {
// 将用户控制取消
m_Tanks [i].m_Instance.GetComponent<Complete.TankMovement> ().enabled = false;
m_Tanks [i].m_Instance.GetComponent<Complete.TankShooting> ().enabled = false;
// Alli时AI控制脚本
m_Tanks [i].m_Instance.GetComponent<Alli> ().target = m_Tanks [i-1].m_Instance.transform;
} else {
// 玩家的坦克
m_Tanks [i].m_Instance.GetComponent<Alli> ().enabled = false;
m_Tanks [i].m_Instance.GetComponent<NavMeshAgent> ().enabled = false;
}
m_Tanks[i].Reset();
}
}
_Completed-Assets\Scripts\Managers\TankManager.cs
将此脚本挂载到Tank预制上
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Alli: MonoBehaviour {
private NavMeshAgent man;
public Transform target;
private int count = 0;
// Use this for initialization
void Start () {
man = gameObject.GetComponent<NavMeshAgent> ();
}
// Update is called once per frame
void Update () {
if (target == null)
return;
// 设置寻路的目的地
man.SetDestination (target.position);
// 判断当前位置与目的地距离
if (Vector3.Distance(target.position, transform.position) > 20)
return;
// 设置开炮间隔
count = count + 1;
if (count < 10)
return;
count = 0;
// 通过射线判断目标是否在自己的前方(在前方炮弹才有可能射中)
Ray ray = new Ray(transform.position, target.position);
RaycastHit hit;
if (Physics.Raycast (transform.position, transform.forward, out hit)) {
Debug.Log (hit.transform.gameObject.name);
if (!(hit.transform.gameObject.name == target.gameObject.name))
return;
}
// 发射炮弹,参考TankShooting中的写法(注意Complete命名空间)
Complete.TankShooting mono = gameObject.GetComponent<Complete.TankShooting> ();
Rigidbody shellInstance =
Instantiate (mono.m_Shell, mono.m_FireTransform.position, mono.m_FireTransform.rotation) as Rigidbody;
shellInstance.velocity = mono.m_MinLaunchForce * mono.m_FireTransform.forward;
mono.m_ShootingAudio.clip = mono.m_FireClip;
mono.m_ShootingAudio.Play ();
}
}