【Unity】2D坦克大战游戏分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39574690/article/details/89074582

2D坦克大战不是在Canvas下开发的,而是直接用SpriteRenderer来。

2D坦克大战核心功能是2D地图的生成,有:草、河流、土墙、钢铁墙、空气墙元素以及一个特殊的物体(出生效果),在生成地图的时候需要将地图视为一个二维空间,每个坐标都是一个资源,使用了的坐标将它放入一个列表保存,以便于随机出可用的坐标,不然同一个地方会生成多个地图元素。

地图是随机生成的,使用一个脚本去生成地图,地图大小可自己定义,其中基地和基地周围的墙生成是固定的,空气墙如果地图大小固定的话,生成方法也是固定的,代码如下,一般的话可以看得懂。

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

public class MapCreation : MonoBehaviour {

    //各种场景物体
    //0.老家 1.墙 2.障碍 3.出生效果 4.河流 5.草 6.空气墙
    public GameObject[] item;
    //已有物体位置的列表标志
    private List<Vector3> itemPositionList = new List<Vector3>();

    private void Awake()
    {
        //实例化地图和玩家
        InitMap();
    }
    //实例化地图和玩家
    private void InitMap()
    {
        //实例化老家
        CreateItem(item[0], new Vector3(0, -8, 0), Quaternion.identity);
        //用墙把老家围起来
        CreateItem(item[1], new Vector3(-1, -8, 0), Quaternion.identity);
        CreateItem(item[1], new Vector3(1, -8, 0), Quaternion.identity);
        for (int i = -1; i < 2; i++)
        {
            CreateItem(item[1], new Vector3(i, -7, 0), Quaternion.identity);
        }
        //实例化外围墙
        for (int x = -11; x <= 11; x++)
        {
            CreateItem(item[6], new Vector3(x, 9, 0), Quaternion.identity);
            CreateItem(item[6], new Vector3(x, -9, 0), Quaternion.identity);
        }
        for (int y = -9; y <= 9; y++)
        {
            CreateItem(item[6], new Vector3(-11, y, 0), Quaternion.identity);
            CreateItem(item[6], new Vector3(11, y, 0), Quaternion.identity);
        }
        //初始化玩家
        GameObject go = Instantiate(item[3], new Vector3(-2, -8, 0), Quaternion.identity);
        go.GetComponent<Born>().createPlayer = true;

        //产生敌人
        CreateItem(item[3], new Vector3(-10, 8, 0), Quaternion.identity);
        CreateItem(item[3], new Vector3(0, 8, 0), Quaternion.identity);
        CreateItem(item[3], new Vector3(10, 8, 0), Quaternion.identity);
        InvokeRepeating("CreateEnemy", 4, 5);
        //实例化地图
        for (int i = 0; i < 60; i++)
        {
            CreateItem(item[1], CreateRandomPosition(), Quaternion.identity);
        }
        for (int i = 0; i < 20; i++)
        {
            CreateItem(item[2], CreateRandomPosition(), Quaternion.identity);
        }
        for (int i = 0; i < 20; i++)
        {
            CreateItem(item[4], CreateRandomPosition(), Quaternion.identity);
        }
        for (int i = 0; i < 20; i++)
        {
            CreateItem(item[5], CreateRandomPosition(), Quaternion.identity);
        }
    }
    private void CreateItem(GameObject createGameObject,Vector3 createPosition,Quaternion rotation)
    {
        GameObject itemGo = Instantiate(createGameObject, createPosition, rotation);
        itemGo.transform.SetParent(gameObject.transform);
        itemPositionList.Add(createPosition);
    }

    //产生随机位置的方法
    private Vector3 CreateRandomPosition()
    {
        //不生成x=-10 ,10两列,y=8,-8这一行的位置
        while(true)
        {
            Vector3 createPosition = new Vector3(Random.Range(-9, 10), Random.Range(-7, 8), 0);
            if (!HasThePosition(createPosition))//如果没有该位置在位置列表中,那么可以产生出这个随机位置
            {
                return createPosition;
            }
        }
    }
    //判断位置列表中是否有该位置
    private bool HasThePosition(Vector3 createPos)
    {
        for(int i=0;i<itemPositionList.Count;i++)
        {
            if(createPos==itemPositionList[i])
            {
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// 生成一个敌人在随机三个固定的位置.
    /// </summary>
    private void CreateEnemy()
    {
        int num = Random.Range(0, 3);
        Vector3 enemyPos = new Vector3();
        if(num==0)
        {
            enemyPos = new Vector3(-10, 8, 0);
        }
        else if (num ==1)
        {
            enemyPos = new Vector3(0, 8, 0);
        }
        else if (num == 2)
        {
            enemyPos = new Vector3(10, 8, 0);
        }
        CreateItem(item[3], enemyPos, Quaternion.identity);
    }
}

其中,出生效果是一个挂有Born脚本的物体,可理解成是一个孵化器,可生成玩家坦克或敌人坦克,而玩家坦克身上有玩家脚本,控制玩家移动和死亡等逻辑,敌人坦克有敌人脚本,敌人用简单的逻辑去跑动和攻击之类的以及死亡之类的。直接放代码看吧。

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

public class Player : MonoBehaviour {

    public AudioSource moveAudio;
    public AudioClip[] tankAudio;
    public float speed = 10f;
    public Sprite[] tankSprites;//上 右 下 左
    public GameObject bullet;
    public GameObject explosionPrefab;
    private SpriteRenderer sr;
    private Vector3 bulletEulerAngles;
    private float timeVal;
    private float defendTimeVal=3;
    private bool isDefended = true;
    public GameObject defendEffectPrefab;
    private void Awake()
    {
        sr = GetComponent<SpriteRenderer>();
    }
    void Start () {
		
	}
	
    //不固定
	void Update () {
        //是否处于无敌状态
        if (isDefended)
        {
            defendEffectPrefab.SetActive(true);
            defendTimeVal -= Time.deltaTime;
            if(defendTimeVal<=0)
            {
                defendEffectPrefab.SetActive(false);
                isDefended = false;
            }
        }
    }
    //Update后执行,固定时间执行0.02s执行一次
    private void FixedUpdate()
    {
        //如果游戏失败了,那么禁止玩家的一切行为,即移动,发射子弹
        if(PlayerManager.Instance.isDefeat)
        {
            return;
        }
        Move();
        //至少等0.4秒发射间隔时间
        if (timeVal >= 0.4f)
        {
            Attack();
        }
        else
        {
            timeVal += Time.fixedDeltaTime;
        }

    }
    //坦克攻击
    private void Attack()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            //子弹产生的角度:当前坦克角度+子弹应该旋转的角度
            Instantiate(bullet, transform.position, Quaternion.Euler(transform.eulerAngles+bulletEulerAngles));
            timeVal = 0;
        }
    }
    //坦克移动
    private void Move()
    {
        float v = Input.GetAxisRaw("Vertical");
        transform.Translate(Vector3.up * v * speed * Time.fixedDeltaTime, Space.World);
        if (v < 0)
        {
            sr.sprite = tankSprites[2];
            bulletEulerAngles = new Vector3(0, 0, -180);
        }
        else if (v > 0)
        {
            sr.sprite = tankSprites[0];
            bulletEulerAngles = new Vector3(0, 0, 0);
        }
        if(Mathf.Abs(v)>0.05f)
        {
            moveAudio.clip = tankAudio[1];
            if(!moveAudio.isPlaying)
            {
                moveAudio.Play();
            }
        }

        if (v != 0)
        {
            return;//意味着 玩家按着上或者下,只能上下移动,而无法再会执行左右操作
        }
        float h = Input.GetAxisRaw("Horizontal");//h就是D按下或者→按下时是1,←或者A按下是-1,让物体左右移动
        transform.Translate(Vector3.right * h * speed * Time.fixedDeltaTime, Space.World);
        //×上Time.deltaTime是以秒为单位移动
        if (h < 0)
        {
            sr.sprite = tankSprites[3];
            bulletEulerAngles = new Vector3(0, 0, 90);
        }
        else if (h > 0)
        {
            sr.sprite = tankSprites[1];
            bulletEulerAngles = new Vector3(0, 0, -90);
        }

        if (Mathf.Abs(h) > 0.05f)
        {
            moveAudio.clip = tankAudio[1];
            if (!moveAudio.isPlaying)
            {
                moveAudio.Play();
            }
        }
        else
        {
            moveAudio.clip = tankAudio[0];
            if (!moveAudio.isPlaying)
            {
                moveAudio.Play();
            }
        }
    }

    //坦克的死亡方法
    public void Die()
    {
        if (!isDefended)
        {
            //玩家死亡标志位设置为true
            PlayerManager.Instance.isDead = true;
            //产生爆炸
            Instantiate(explosionPrefab, transform.position, transform.rotation);
            //死亡
            Destroy(gameObject);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour {

    //引用
    public float speed = 10f;
    public Sprite[] tankSprites;//上 右 下 左
    public GameObject bullet;
    public GameObject explosionPrefab;
    //属性
    private SpriteRenderer sr;
    private Vector3 bulletEulerAngles;
    private float h;
    private float v=-1;
    //计时器
    private float timeVal;
    private float timeValChangeDirection;

    private void Awake()
    {
        sr = GetComponent<SpriteRenderer>();
    }
    void Start()
    {

    }

    //不固定
    void Update()
    {
       //攻击的时间间隔2秒一次
        if (timeVal >= 2f)
        {
            Attack();
        }
        else
        {
            timeVal += Time.deltaTime;
        }
    }
    //Update后执行,固定时间执行0.02s执行一次
    private void FixedUpdate()
    {
        Move();
    }
    //坦克攻击
    private void Attack()
    {
            //子弹产生的角度:当前坦克角度+子弹应该旋转的角度
            Instantiate(bullet, transform.position, Quaternion.Euler(transform.eulerAngles + bulletEulerAngles));
            timeVal = 0;
    }
    //坦克移动
    private void Move()
    {
        if(timeValChangeDirection>=4)
        {
            int num = Random.Range(0, 8);
            if(num>=5)// 5 6 7会向下走
            {
                v = -1;
                h = 0;
            }
            else if(num==0)//0向上走
            {
                v = 1;
                h = 0;
            }
            else if(num>0&&num<=2)//1,2向右走
            {
                h = -1;
                v = 0;
            }
            else if(num>2&&num<=4)//3,4向左走
            {
                h = 1;
                v = 0;
            }
            timeValChangeDirection = 0;
        }
        else
        {
            timeValChangeDirection += Time.deltaTime;
        }
    
        transform.Translate(Vector3.up * v * speed * Time.fixedDeltaTime, Space.World);
        if (v < 0)
        {
            sr.sprite = tankSprites[2];
            bulletEulerAngles = new Vector3(0, 0, -180);
        }
        else if (v > 0)
        {
            sr.sprite = tankSprites[0];
            bulletEulerAngles = new Vector3(0, 0, 0);
        }
        if (v != 0)
        {
            return;//意味着 玩家按着上或者下,只能上下移动,而无法再会执行左右操作
        }
        transform.Translate(Vector3.right * h * speed * Time.fixedDeltaTime, Space.World);
        //×上Time.deltaTime是以秒为单位移动
        if (h < 0)
        {
            sr.sprite = tankSprites[3];
            bulletEulerAngles = new Vector3(0, 0, 90);
        }
        else if (h > 0)
        {
            sr.sprite = tankSprites[1];
            bulletEulerAngles = new Vector3(0, 0, -90);
        }
    }

    //坦克的死亡方法
    public void Die()
    { 
            //产生爆炸
            Instantiate(explosionPrefab, transform.position, transform.rotation);
            //死亡
            Destroy(gameObject);
    }

    //如果两个敌人碰到了就会相反移动
    private void OnCollisionEnter2D(Collision2D collision)
    {
        if(collision.gameObject.tag=="Enemy")
        {
            timeValChangeDirection = 4;
        }
    }
}


在生成地图后,需考虑层级问题,因为草是会遮挡坦克的,所以坦克的层级在1,草的层级在2,其他层级在0,层级指的是

坦克的子弹能够把土墙打烂之类的逻辑都是很简单的,一般都懂怎么做了,基本就以上说明

猜你喜欢

转载自blog.csdn.net/qq_39574690/article/details/89074582