游戏智能--AI坦克

Jun 18, 2018


坦克对战游戏 AI 设计

游戏内容

  • 整个游戏基于tanks-tutorial 中的_Complete-Game场景,通过对场景中一些脚本的更改,实现AI效果

玩家控制蓝色坦克(WSAD,空格),与红色坦克(AI)solo

游戏分为round,在各round中,玩家发射炮弹攻击对方,活到最后的坦克获胜

先赢够5个round的玩家获得游戏胜利

Image text

AI坦克特性

使用了“感知-思考-行为”模型

可以避过障碍物寻路

通过射线探测对方是否在炮弹路径上

不会失去目标

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 ();
	}
}

参考资料