究极坦克大战--就是不用单例就是不用工厂

附上视频地址:https://www.bilibili.com/video/av25226932/

还有我github的地址:传送门,大家有兴趣可以去下载我的项目自己在电脑上运行起来玩一玩

  1. 游戏要求

        使用NavMesh实现坦克大战,要求敌方坦克能够自动寻路,并且能够主动攻击我方坦克

     2. 效果预览

                                                            

    3. NavMesh与AI

        从预览图里面我们可以看到,绿色坦克是我们要控制的坦克,而红色的坦克是敌方坦克,也就是我们的AI坦克,他们总可以移向玩家坦克所在的位置,这里需要用到的组件叫做NavMesh,那么关于这个NavMesh组件的使用,我在这里有几个推荐,这几个博客都是我从上届师兄的博客中找到的推荐

  • unity自带寻路Navmesh入门教程
  • Unity3D学习(15)之Navmesh使用                                        

你可以在这几篇博客的指导下,自己动手玩一下NavMesh,以便对它有个初步的了解

    4. 游戏实现

        首先,你得找好素材包,这里我用到的素材是在别人的网盘里找到的,这里我也放出一个百度网盘的链接,里面包含有素材、视频教学还有我的代码。但是注意,如果你只是跟着教程一步步的做,只能实现双人对战坦克,而不能实现AI坦克,但是我想这些视屏教学对你也应该有启发

                百度网盘链接                  密码:k8ms

        1. 创建场景并烘焙地图

    导入素材包之后,会有现成的地图给你用,长这样:


然后你需要对地图进行烘焙,首先在windows下面找到navigation,点击之后你就会发现Inspector栏目旁边就会出现Navgation栏目了

                                    究极坦克大战--就是不用单例就是不用工厂_第1张图片

然后你要设置Terrain的Navigation,首先你可以看一看你的地图上都有些什么东西,一般来说绝大多数都是障碍物,但是有些东西如地形什么的就不能算作障碍物了。选中你地图上的所有障碍物,进行烘焙操作:

                                    究极坦克大战--就是不用单例就是不用工厂_第2张图片

2. AI坦克寻路与攻击

你还需要给两只坦克都加上NavMeshAgent组件,注意是两个坦克都要加;因为你一定要保证被追的坦克能被找到,追坦克的坦克能找到被追的坦克(说起来像顺口溜哈哈哈

                                    究极坦克大战--就是不用单例就是不用工厂_第3张图片

这样,只要我们指定一个target,那么寻路坦克就能根据我们所制定的目标进行寻路了

至于攻击的话,有两个方法,首先肯定是要在AI坦克上面挂在脚本的,这无疑。然后你可以利用协程操作,指定坦克的攻击频率还有攻击判定条件;还有一种就是你在updata里面,指定一个framecount,只有在固定帧的时候,如果满足了条件才发起攻击【其实和协程差不多】

5. 项目完整代码(顺带说一下,我的AI坦克其实还支持人工键盘操作的哈哈哈哈)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class GameOver : MonoBehaviour {
    public GameObject player1;
    public GameObject player2;
    public Text gameInfo;
	// Use this for initialization
	void Start () {
        gameInfo.text = "";
	}
	
	// Update is called once per frame
	void Update () {
		if(player1 == null || player2 == null)
        {
            if(player1 == null)
            {
                gameInfo.text = "You Lose!";
            }
            else
            {
                gameInfo.text = "You Win!";
            }
        }
	}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Enemy : MonoBehaviour {

    public Transform player1;
    public GameObject shellPrefab;
    private Transform firePosition;
    public float shellSpeed = 10;
    private int framenumber = 0;
    // Use this for initialization
    void Start () {
        //StartCoroutine(Fire());
        firePosition = transform.Find("FirePosition");
    }

    // Update is called once per frame
    void Update()
    {
        framenumber++;
        if (player1 != null)
        {
            NavMeshAgent agent = this.GetComponent();
            agent.SetDestination(player1.position);
            if (Vector3.Distance(transform.position, player1.transform.position) < 20 && (framenumber % 24 == 0))
            {
                GameObject go = GameObject.Instantiate(shellPrefab, firePosition.position, firePosition.rotation) as GameObject;
                go.GetComponent().velocity = go.transform.forward * shellSpeed;
            }
        }
        else
        {
            NavMeshAgent agent = this.GetComponent();
            agent.velocity = Vector3.zero;
            agent.ResetPath();
        }
    }

}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FollowTarget : MonoBehaviour {

    public Transform player1;
    public Transform player2;
    private Vector3 offset;
    private Camera camera;
	// Use this for initialization
	void Start () {
        offset = transform.position - (player1.position + player2.position) / 2;
        camera = this.GetComponent();
	}
	
	// Update is called once per frame
	void Update () {
        if (player1 == null || player2 == null) return;
        transform.position = (player1.position + player2.position) / 2 + offset;
        float distance = Vector3.Distance(player1.position, player2.position);
        float size = distance * 0.58f;
        camera.orthographicSize = size;
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TankHealth : MonoBehaviour {
    public int hp = 100;
    public GameObject tankExplosion;
    public AudioClip tankExplosionAudio;

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}

    void TakeDamage()
    {
        if (hp <= 0) return;
        if(hp > 0)
            hp -= Random.Range(10, 20);
        if(hp <= 0)//受到伤害之后,血量为0,控制死亡效果
        {
            AudioSource.PlayClipAtPoint(tankExplosionAudio, transform.position);
            GameObject.Instantiate(tankExplosion, transform.position + Vector3.up, transform.rotation);
            GameObject.Destroy(this.gameObject);
        }



    }

}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shell : MonoBehaviour {
    public GameObject shellExplosionPrefab;
    public AudioClip shellExplosionAudio;


    public void OnTriggerEnter(Collider collider)
    {
        AudioSource.PlayClipAtPoint(shellExplosionAudio,transform.position);
        GameObject.Instantiate(shellExplosionPrefab, transform.position, transform.rotation);
        GameObject.Destroy(this.gameObject);

        if(collider.tag == "Tank")
        {
            collider.SendMessage("TakeDamage");
        }

    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TankAttack : MonoBehaviour {

    public GameObject shellPrefab;
    private Transform firePosition;
    public KeyCode fireKey = KeyCode.Space;
    public float shellSpeed = 10;
    public AudioClip shotAudio;
    
    
    // Use this for initialization
	void Start () {
        firePosition = transform.Find("FirePosition");
	}
	
	// Update is called once per frame
	void Update () {
        if (Input.GetKeyDown(fireKey)) {
            AudioSource.PlayClipAtPoint(shotAudio, transform.position);
           GameObject go = GameObject.Instantiate(shellPrefab, firePosition.position, firePosition.rotation) as GameObject;
            go.GetComponent().velocity = go.transform.forward * shellSpeed;

        }
	}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class TankMovement : MonoBehaviour {
    public float speed = 5;
    public float angularSpeed = 30;
    private Rigidbody rigidbody;
    public float number = 1;  //增加一个玩家的编号,通过编号区分控制


    public AudioClip idleAduio;
    public AudioClip drivingAduio;
    private AudioSource audio;


	// Use this for initialization
	void Start () {
        rigidbody = this.GetComponent();
        audio = this.GetComponent();
	}


    private void FixedUpdate()
    {
        float v = Input.GetAxis("Verticalplayer" + number);
        rigidbody.velocity = transform.forward * v * speed;


        float h = Input.GetAxis("Horizontalplayer" + number);
        rigidbody.angularVelocity = transform.up * h * angularSpeed;


        if(Mathf.Abs(h) > 0.1 || Mathf.Abs(v) > 0.1)
        {
            audio.clip = drivingAduio;
            if(audio.isPlaying == false)
                audio.Play();
        }
        else
        {
            audio.clip = idleAduio;
            if(audio.isPlaying == false)
                audio.Play();
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DestroyForTime : MonoBehaviour {
    public float time;
	// Use this for initialization
	void Start () {
        Destroy(this.gameObject, time);
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}

你可能感兴趣的:(Unity3d)