Unity 3D : AI Tank

要求

  • 使用“感知-思考-行为”模型,建模AI坦克
    AI坦克可以在一定范围内感知玩家,并移动过来发起攻击。AI每隔3秒钟就发射一次攻击。
  • 场景中要放置一些障碍阻碍对手视线
    使用房屋、或者路障阻碍视线
  • 坦克需要放置一个矩阵包围盒触发器,以保证 AI 坦克能使用射线探测对手方位
  • AI 坦克必须在有目标条件下使用导航,并能绕过障碍。(失去目标时策略自己思考)

游戏实现:

1:导入资源:

本次实验使用了资源商店的资源Kawaii Tank
需要导入使用:

在这里插入图片描述

这时发现出现了报错,资源不完整,还需要导入标准资源的CrossPlatformInput:

在这里插入图片描述

2:导入场景:

  • 使用资源包中的场景Test_field;该场景已经实现了很丰富的画面和功能;
  • 有一辆可以驾驶的坦克SD_tiger;可以驾驶它对敌机发起攻击;还有一辆敌机SD_firely;
  • 我们在场景中添加多点障碍物和敌机

在这里插入图片描述
在这里插入图片描述

3:设置navigation:

  • 打开Navigation设置窗口:
    window->AI->Navigation
  • 并进行如下设置:

Navigation Static : true
Walkable;
在这里插入图片描述

在这里插入图片描述

  • 给每个SD_firely的MainBody添加组件 Nav Mesh Agent:
    Component->Navigation->Nav Mesh Agent

在这里插入图片描述

在这里插入图片描述

  • 生成导航图:

在Navigation窗口选择Bake,然后点击bake;就会在场景的目录下生成导航图:

在这里插入图片描述
在这里插入图片描述

4:脚本:

4.1 PlaceTarget

  • 为SD_firely AI坦克的组件Mainbody添加脚本;用来跟踪玩家;
  • 将玩家即SD_tiger的组件Mainbody添加到脚本成员Target那里;使得AI坦克可以跟踪玩家:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class PlaceTarget : MonoBehaviour
{
    public GameObject target;  //获取目标点,注意在面板中赋值
    NavMeshAgent mr;   //声明变量
                       // Use this for initialization
    void Start()
    {
        //获取到自身的NavMeshAgent组件
        mr = GetComponent<NavMeshAgent>();
    }

    // Update is called once per frame
    void Update()
    {
        //使用属性将目标点的坐标进行传递
        //mr.destination = target.transform.position;
        //使用方法获取目标点坐标,,和前一行代码作用相同
        mr.SetDestination(target.transform.position);
    }
}

在这里插入图片描述

4.2:Fire_Control_CS

在原先玩家可以可控制主坦克发起攻击的基础上,为AI敌机添加了每三秒钟就发射一次炮弹的功能。

		/*
		void Update ()
		{
			if (idScript.isPlayer) {
				#if UNITY_ANDROID || UNITY_IPHONE
				Mobile_Input ();
				#else
				Desktop_Input ();
				#endif
			}
		}
		*/

		void Update ()
		{
			if (idScript.isPlayer) {
				#if UNITY_ANDROID || UNITY_IPHONE
				Mobile_Input ();
				#else
				Desktop_Input ();
				#endif
			} else
            {
                count = count + Time.deltaTime;
                if(count > 3.0f)
                {
                    Fire();
                    count = 0;
                }
            }
		}

4.3:Damge_Control_CS

  • 修改玩家坦克的血条一直显示
  • 当AI坦克的血量耗光时,会消失:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;

#if UNITY_ANDROID || UNITY_IPHONE
using UnityStandardAssets.CrossPlatformInput;
#endif

namespace ChobiAssets.KTP
{
	
	public class Damage_Control_CS : MonoBehaviour
	{
		[Header ("Damage settings")]
		[Tooltip ("Durability of this tank.")] public float durability = 300.0f;
		[Tooltip ("Prefab used for destroyed effects.")] public GameObject destroyedPrefab;
		[Tooltip ("Prefab of Damage Text.")] public GameObject textPrefab;
		[Tooltip ("Name of the Canvas used for Damage Text.")] public string canvasName = "Canvas_Texts";

		Transform bodyTransform;
		Damage_Display_CS displayScript;
		float initialDurability;

		ID_Control_CS idScript;

		void Start ()
		{ // Do not change to "Awake()".
			initialDurability = durability;
		}

		void Set_DamageText ()
		{
			if (textPrefab == null || string.IsNullOrEmpty (canvasName) || durability == Mathf.Infinity) {
				return;
			}
			// Instantiate Damage Text, and set it to the Canvas.
			GameObject textObject = Instantiate (textPrefab, Vector3.zero, Quaternion.identity) as GameObject;
			displayScript = textObject.GetComponent <Damage_Display_CS> ();
			displayScript.targetTransform = bodyTransform;
			GameObject canvasObject = GameObject.Find (canvasName);
			if (canvasObject) {
				displayScript.transform.SetParent (canvasObject.transform);
				displayScript.transform.localScale = Vector3.one;
			} else {
				Debug.LogWarning ("Canvas for Damage Text cannot be found.");
			}
		}
		/*
				void Update ()
		{
			// Destruct
			if (idScript.isPlayer) {
				#if UNITY_ANDROID || UNITY_IPHONE
				if (CrossPlatformInputManager.GetButtonDown ("Destruct")) {
				#else
				if (Input.GetKeyDown (KeyCode.Return)) {
				#endif
					Start_Destroying ();
				}
			}
		}
*/

		void Update ()
		{
            // 游戏玩家一直显示血条,AI坦克受到攻击后显示血条
            if(idScript.isPlayer)
            {
                displayScript.Get_Damage(durability, initialDurability);
            }
            // Destruct
            if (idScript.isPlayer) {
				#if UNITY_ANDROID || UNITY_IPHONE
				if (CrossPlatformInputManager.GetButtonDown ("Destruct")) {
				#else
				if (Input.GetKeyDown (KeyCode.Return)) {
				#endif
					Start_Destroying ();
				}
			}
		}

		public void Get_Damage (float damageValue)
		{ // Called from "Bullet_Nav_CS".
			durability -= damageValue;
			if (durability > 0.0f) { // Still alive.
				// Display Text
				if (displayScript) {
					displayScript.Get_Damage (durability, initialDurability);
				}
			} else { // Dead
				Start_Destroying ();
			}
		}
/*
		void Start_Destroying ()
		{
			// Send message to all the parts.
			BroadcastMessage ("Destroy", SendMessageOptions.DontRequireReceiver);
			// Create destroyedPrefab.
			if (destroyedPrefab) {
				GameObject tempObject = Instantiate (destroyedPrefab, bodyTransform.position, Quaternion.identity) as GameObject;
				tempObject.transform.parent = bodyTransform;
			}
			// Remove the Damage text.
			if (displayScript) {
				Destroy (displayScript.gameObject);
			}
			// Destroy this script.
			Destroy (this);
		}
		*/
		void Start_Destroying ()
		{
            if(idScript.isPlayer == false)
            {
                this.gameObject.SetActive(false);
            }
			// Send message to all the parts.
			BroadcastMessage ("Destroy", SendMessageOptions.DontRequireReceiver);
			// Create destroyedPrefab.
			if (destroyedPrefab) {
				GameObject tempObject = Instantiate (destroyedPrefab, bodyTransform.position, Quaternion.identity) as GameObject;
				tempObject.transform.parent = bodyTransform;
			}
			// Remove the Damage text.
			if (displayScript) {
				Destroy (displayScript.gameObject);
			}
			// Destroy this script.
			Destroy (this);
		}

		void Get_ID_Script (ID_Control_CS tempScript)
		{
			idScript = tempScript;
			bodyTransform = idScript.storedTankProp.bodyTransform;
			Set_DamageText ();
		}

		void Pause (bool isPaused)
		{ // Called from "Game_Controller_CS".
			this.enabled = !isPaused;
		}

	}

}

游戏运行:

  • 场景已经保存在Assets/Scene/AI Tank,点击运行即可:

在这里插入图片描述

  • 游戏运行视频:

Tank

项目地址

gitee 地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值