Unity3D制作塔防类游戏

Posted 接受平凡 努力出众

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity3D制作塔防类游戏相关的知识,希望对你有一定的参考价值。

 

演示

功能简介 

制作细节详解


演示

资源包:链接:https://pan.baidu.com/s/15MMtYeKkNk5xChvCx0EckQ?pwd=d1ub 提取码:d1ub 

对应视频教学:01-开始介绍和创建工程_哔哩哔哩_bilibili  

功能简介 

 分为蓝,紫,粉,红四批敌人,每一批的敌人都比前一批的数量要多,并且速度要快,血量要多,当一批敌人死光了,才会出来第二批敌人,一共有三种炮塔每个金额为70,80,90,初始金额为1000,选择炮塔类型,点击Cube,即可以插放,再次点击时候可以选择升级或拆除,由于地图过大,可以一共上下左右键来控制地图前后左右视角,用鼠标滑轮来控制上下视角,把四批敌人杀光才可以通关成功,否则失败。

制作细节详解

Cube创建基本的地图

创建一个空物体记作"MapCube",把与地图map相关的都放进去,创建一个cube,进行ctrl+d复制,要按住ctrl进行拖拽(一米一米的移动否则将随意移动)。



创建敌人行走的路

定位两个位置,起始点/终点,然后随机连起来选择一些个MapCube删除掉,然后在空的路上边还是用Cube(Road纯黑材质)连出这条路来,该长的长,该短的短。

 把上面的敌人走的路径放到一个新建的"RoadCube"

  然后做两个Cube,命名为Start 和 End,调整好大小,材质,放置在起始点和终点正上方,(注意把这两个的Collider取消掉,就不会和下面创建的敌人做碰撞了)

控制游戏的视野(视野移动和放大缩小)

由于地图还是蛮大的,在这里添加地图上下前后移动的功能,给玩家提供便利,具体情况如下所示:

 这里创建一个"Scripts"文档,把脚本都放进去,首先创建一个"ViewController"脚本来控制视野。

代码如下:

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

public class ViewController : MonoBehaviour 

    public float speed = 1;
    public float mouseSpeed = 60;
	
	// Update is called once per frame
	void Update () 
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        float mouse = Input.GetAxis("Mouse ScrollWheel");
        transform.Translate(new Vector3(h*speed, mouse*mouseSpeed, v*speed) *Time.deltaTime ,Space.World);
	

敌人的路径管理

让敌人按照我们设计的路线行走,这里我们直接在拐弯的地方添加一些关键点就可以按照这些点一个个向下移动,把这些路径点都放入到"Waypoints中"

 然后在这里添加一个脚本去管理这些路径点,

代码如下

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

public class Waypoints : MonoBehaviour 


    public static Transform[] positions;
    //脚本被载入时调用(最早的执行函数)
    void Awake()
    
//注意这里如果用transform.GetComponent这种方法,会把自身的组件也带上,所以要用下面的方式0
        positions = new Transform[transform.childCount];//先从孩子点位里获得数组大小
        for (int i = 0; i < positions.Length; i++)
        
            positions[i] = transform.GetChild(i);
        
    

创建敌人,控制敌人的移动

这里简单的就拿做不同颜色的小球,当作不同的敌人,然后创建一个预制体"Prefab"文件夹,把不同的敌人放进文件夹中,如下所示:

 为了让敌人之间区分,给小球涂上不同的颜色,给每种敌人创建一个材质:

 控制每个敌人的移动,这里创建一个"Enemy"脚本,代码如下:

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

public class Enemy : MonoBehaviour 

    public float speed = 10;
    public float hp = 150;
    private float totalHp;
    public GameObject explosionEffect;
    private Slider hpSlider;
    private Transform[] positions;
    private int index = 0;


	// Use this for initialization
	void Start () 
        positions = Waypoints.positions;
        totalHp = hp;
        hpSlider = GetComponentInChildren<Slider>();
	
	
	// Update is called once per frame
	void Update () 
        Move();
	


    void Move()
    
        if (index > positions.Length - 1) return;
        transform.Translate((positions[index].position - transform.position).normalized * Time.deltaTime * speed);
        if (Vector3.Distance(positions[index].position, transform.position) < 0.2f)
        
            index++;
        
        if (index > positions.Length - 1)
        
            ReachDestination();
        
    
    //达到终点
    void ReachDestination()
    
        GameManager.Instance.Failed();
        GameObject.Destroy(this.gameObject);
    


    void OnDestroy()
    
        EnemySpawner.CountEnemyAlive--;
    

    public void TakeDamage(float damage)
    
        if (hp <= 0) return;
        hp -= damage;
        hpSlider.value = (float)hp / totalHp;
        if (hp <= 0)
        
            Die();
        
    
    void Die()
    
        GameObject effect = GameObject.Instantiate(explosionEffect, transform.position, transform.rotation);
        Destroy(effect, 1.5f);
        Destroy(this.gameObject);
    


创建敌人孵化器管理敌人的生成

创建四种敌人,每种敌人用不同的颜色表示,每种颜色的敌人血量和移动速度是不一样的,这就需要我们创建单独的脚本来保存每一波敌人的属性,脚本记为"Wave"。

代码如下:

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

//保存每一波敌人生成所需要的属性
[System.Serializable]
public class Wave  
    public GameObject enemyPrefab;
    public int count;
    public float rate;

 接着我们创建一个生成器,管理敌人一波一波的生成,这里创建一个空物体,设置为“GameManager",创建一个"Enemy Spawner"脚本拖入"GameManager"中,

可以设置每种敌人的数量和速度。

代码如下

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

public class EnemySpawner : MonoBehaviour 

    public static int CountEnemyAlive = 0;
    public Wave[] waves;
    public Transform START;
    public float waveRate = 0.2f;
    private Coroutine coroutine;

    void Start()
    
        coroutine = StartCoroutine(SpawnEnemy());
    
    public void Stop()
    
        StopCoroutine(coroutine);
    
    IEnumerator SpawnEnemy()
    
        foreach (Wave wave in waves)
        
            for (int i = 0; i < wave.count; i++)
            
                GameObject.Instantiate(wave.enemyPrefab, START.position, Quaternion.identity);
                CountEnemyAlive++;
                if(i!=wave.count-1)
                    yield return new WaitForSeconds(wave.rate);
            
            while (CountEnemyAlive > 0)
            
                yield return 0;
            
            yield return new WaitForSeconds(waveRate);
        
        while (CountEnemyAlive > 0)
        
            yield return 0;
        
        GameManager.Instance.Win();
    


创建三种炮台Prffab

首先在Prefab文件中创建三种炮台和三种炮台升级后的炮台:将第一个激光炮塔放置到0点上的Cube位置进行调整,j将资源里的材质啥的往合适的地方塞,弄好看了然后命名并设置成LaserTurret预制体,将升级后的命名为LaserTurretUpgraded,同理弄完MissileTurret、MissileTurretUpgraded、StandardTurret、StandardTurretUpgraded。

创建炮塔选择的UI

要在场景中创建炮台,首先要有UI界面,然后才能对炮台进行选择,创建一个新文档"Canvas"然后鼠标右击UI选项,选择"Toggle"开关按钮,名为LaserToggle,将Is On的去掉勾选。来代表三种炮塔的选择。它下面用Label表示介绍,用Text表示价格。ackground里的Image-Source Image设置成资源里的LaserBeamerIcon,可点击Image-Set Native Size将其图片设置为原生大小后再进行调整。将Checkmark大小和Background改成一致(用那个Alt键充满的方式),将里面的Image-Source Image改成一种被遮罩的图片(这里用的一个圆的Knob),修改颜色中的α值透明度,代表着选中后的效果。复制出两个LaserToggle,更换一下背景图片做出MissileToggle和StandardToggle。在Canvas下创建一个空物体,命名为TurretSwitch,在它上创建一ToggleGroup组件来包含这个三开关,位置摆放在Canvas居右,设置好三个炮台开关的分组,都选中后,在Toggle下的Group将TurretSwitch拉过来,这样就可以单选了。

 创建炮台的数据类

 创建炮台数据类,用来保存炮台相关数据,创建脚本TurretData:

System.Serializable]
public class TurretData

    public GameObject turretPrefab;//炮塔的模型
    public int cost;//价格
    public GameObject turretUpgradedPrefab;//升级的模型
    public int costUpgraded;//升级的价格
    public TurretType type;


public enum TurretType

    LaserTurret,//激光炮台
    MissileTurret,//导弹炮台
    StandardTurret,//标准炮台

监听炮塔选择的事件

在GameManager中再创建一个BuildManager脚本:(测试的时候可以将selectedTurredData设成public,方便在Inspector面板选择UI炮台时能看出来是否有数据)

检测鼠标点击到了哪个Cube上

在MapCube预制体上添加一个Layer图层,叫MapCube,然后将其图层选择为MapCube。

控制开始按钮1和退出时按钮的点击事件处理

金钱的管理

下边代码有设定钱了,把它显示在UI界面上,Canvas下新建个Text命名为Money,设置一下字体和居右,在BuildManager代码新加入一个方法ChangeMoney和字段moneyText,在Inspector将Money拖入至该字段。

//放置原理:点击的时候在鼠标的位置发射出来一条射线,看一下射线和哪个Node发生了碰撞,发生碰撞后要去检查下这个Node上是否为空,再做处理
//在MapCube添加一个Layer(图层),叫做MapCube,然后选择为它,这样在利用射线做检测时只检测对MapCube的碰撞。
public class BuildManager : MonoBehaviour

    public TurretData laserTurretData;//在Inspector面板将预制体拉入,并填写其它相关数据
    public TurretData missileTurretData;//在Inspector面板将预制体拉入,并填写其它相关数据
    public TurretData standardTurretData;//在Inspector面板将预制体拉入,并填写其它相关数据
    //表示当前选择的炮台(要建造的炮台)
    private TurretData selectedTurredData;//UI上显示和选择的炮台,写三个炮台的选择方法,通过注册三个炮台的Toggle事件来识别哪个被选择了
    private int money = 1000;
    public Text moneyText;
    public Animator moneyAnimator;

    void ChangeMoney(int change=0)
    
        money += change;
        moneyText.text = "$ " + money;
    

    void Update()
    
        if (Input.GetMouseButtonDown(0))
        
            //如果鼠标在UI上面,则不做处理; EventSystem.current返回的是Hierarchy里EventSystem里EventSystem(Script)组件。
            //IsPointerOverGameObject表示鼠标是否按在了UI上
            if (EventSystem.current.IsPointerOverGameObject() == false)
            
                //开发炮台的建造,首先判断鼠标点击到了哪个MapCube上,就要使用射线检测了,得到一个射线ray
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//把鼠标的点转化成射线
                RaycastHit hit;
                //Physics.Raycast来进行射线检测,(射线,RaycastHit射线检测跟什么东西做了碰撞的结果,maxDistance最大距离,layerMask和哪一层做射线检测如不指定就是和所有的层)
                bool isCollider = Physics.Raycast(ray,out hit, 1000, LayerMask.GetMask("MapCube"));//得到是否碰撞到MapCube上
                if (isCollider)
                
                    MapCube mapCube = hit.collider.GetComponent<MapCube>();//得到点击的mapCube
                    if(mapCube.turretGo == null && selectedTurredData != null)//可以创建
                    
                        if (money > selectedTurredData.cost)
                        
                            money -= selectedTurretData.cost;
                            mapCube.BuildTurret(selectedTurredData);
                        
                        else//提示钱不够
                        
                            moneyAnimator.SetTrigger("Flicker");
                        
                    
                    else
                    
                        //TODO 升级处理
                    
                
            
        
    


    //在Canvas里的设备里有On Value Changed里添加GameManager,然后选择对应的下面方法,只要是点击设备值发生改变了,也就是is on发生改变了,都会触发
    public void OnLaserSelected(bool isOn)
    
        if (isOn)
        
            selectedTurredData = laserTurretData;
        
    
    public void OnMissileSelected(bool isOn)
    
        if (isOn)
        
            selectedTurredData = missileTurretData;
        
    
    public void OnStandardSelected(bool isOn)
    
        if (isOn)
        
            selectedTurredData = standardTurretData;
        
    

控制子弹跟敌人的碰撞处理,让子弹碰到敌人就爆炸

在Bullet预制体上添加一个Rigidbody刚体,取消勾选Use Gravity,在Bullet中处理触发检测OnTriggerEnter方法,定义好爆炸的特效字段explosionEffectPrefab,在Enemy中添加TakeDamage方法表示受到了伤害,Enemy脚本全部代码如下:

public class Enemy : MonoBehaviour

    public float speed = 10;//每秒移动10米
    public float hp = 150;
    private float totalHp;
    private Transform[] positions;
    private int index = 0;//默认的位置
    public GameObject explosionEffect;//爆炸特效
    private Slider hpSlider;//血条

    void Start()
    
        //获取到小球行走的路径点
        positions = Waypoints.positions;
        totalHp = hp;
        hpSlider = GetComponentInChildren<Slider>();//从子物体中寻找Slider物体装配上
    
    void Update()
    
        Move();
    

    void Move()
    
        //if (index > positions.Length - 1) return;//当到达最后一个位置
        //(目标位置 - 当前位置)得到一个向量.单位化每次移动1,取得单位向量之后再做计算
        transform.Translate((positions[index].position - transform.position).normalized * Time.deltaTime * speed);
        //判断有没有到达目标位置,取得两个点位置是否小于一定距离
        if( Vector3.Distance( positions[index].position,transform.position) < 0.2f)
        
            index++;
        
        if (index > positions.Length - 1)//当到达最后一个位置
        
            ReachDestination();
        
    
    //到达目的地,游戏就失败了
    void ReachDestination()
    
        GameManager.Instance.Faild();
        GameObject.Destroy(this.gameObject);
    
    //被打掉销毁
    private void OnDestroy()
    
        EnemySpawner.CountEnemyAlive--;
    
    //表示受到了伤害
    public void TakeDamage(float damage)
    
        if (hp <= 0) return;
        hp -= damage;
        hpSlider.value = (float)hp / totalHp;//hpSlider.value是一个0~1的值,所以它以百分比来计算得到
        if(hp <= 0)
        
            Die();
        
    
    void Die()
    
        GameObject effect = GameObject.Instantiate(explosionEffect, transform.position, transform.rotation);
        Destroy(effect, 1.5f);
        Destroy(this.gameObject);
    

添加爆炸特效

修改检测碰撞方式,创建一个Particle System命名为ExplosionEffect特效,然后将其拉入到Bullet的Bullet字段中,可以将Bullet下Rigidbody下的Collision Detection(碰撞检测)改成Continuous(连续的)或者Continuous Dynamic(动态的)这样对高速移动的物体检测更加准确,把Bullet图层设为Turret。

敌人添加血条显示

创建一个Canvas,把Canvas里的Render Mode修改为World Space,就可以调节画布的大小了,下面创建一个Slider,它不需要交互,所以把Slider(Script)下面Intractable(可交互的)取消勾选,Canvas调整成和Slider差不多大,将Slider下的Handle Slide Area(手柄滑动区)移除,Background取消勾选,Slider是依靠Slider(Script)下面Value来控制条长的,调整Fill Area长度与默认充满,可以把Fill(前置背景)的Image中Color改为绿色,然后把Canvas整体移到各个Enemy预制体下面,调整Canvas的位置和大小。

创建炮塔升级的UI按钮

创建一个Canvas命名为UpgradeCanvas,设置成World Space,下面创建两个Button,命名为ButtonUpgrade和ButtonDestroy,里面Image(Script)去掉,下面Text是升级和拆除,弄好后可拖到在炮塔下面进行编辑,方便定位位置和调整大小,完成后再挪出来。

控制升级面板显示

在BuildManager里进行控制,添加两个引用,public GameObject upgradeCanvas 和 public Button buttonUpgrade,在Inspector面板注册上,脚本里继续添加ShowUpgradeUI 和 HideUpgradeUI 显示/隐藏按钮方法,添加 OnUpgradeButtonDown 和 OnDestroyButtonDown 升级/拆按钮按下方法,然后在Inspector面板把后两个方法注册给两个按钮。

BuildManager脚本全部代码如下:

/放置原理:点击的时候在鼠标的位置发射出来一条射线,看一下射线和哪个Node发生了碰撞,发生碰撞后要去检查下这个Node上是否为空,再做处理
//在MapCube添加一个Layer(图层),叫做MapCube,然后选择为它,这样在利用射线做检测时只检测对MapCube的碰撞。

public class BuildManager : MonoBehaviour

    public TurretData laserTurretData;
    public TurretData missileTurretData;
    public TurretData standardTurretData;
    //表示当前选择的炮台(要建造的炮台)
    private TurretData selectedTurredData;//UI上显示和选择的炮台
    public Text moneyText;
    public Animator moneyAnimator;
    private int money = 1000;
    public GameObject upgradeCanvas;//升级UI画板
    public Button buttonUpgrade;
    private MapCube selectedMapCube;//3D场景中选择的炮台
    private Animator upgradeCanvasAnimator;//升级UI显示隐藏的动画转换状态机

    void ChangeMoney(int change=0)
    
        money += change;
        moneyText.text = "$ " + money;
    
    private void Start()
    
        upgradeCanvasAnimator = upgradeCanvas.GetComponent<Animator>();//得到状态机
    
    void Update()
    
        if (Input.GetMouseButtonDown(0))
        
            //如果鼠标在UI上面,则不做处理; EventSystem.current得到的是EventSystem模块里EventSystem那个组件。
            if (EventSystem.current.IsPointerOverGameObject() == false)//IsPointerOverGameObject表示鼠标是否按在了UI上
            
                //开发炮台的建造,首先判断鼠标点击到了哪个MapCube上,就要使用射线检测了,得到一个射线ray
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//把鼠标的点转化成射线
                RaycastHit hit;
                //Physics.Raycast来进行射线检测,(射线,RaycastHit射线检测跟什么东西做了碰撞的结果,maxDistance最大距离,layerMask和哪一层做射线检测如不指定就是和所有的层)
                bool isCollider = Physics.Raycast(ray,out hit, 1000, LayerMask.GetMask("MapCube"));//得到是否碰撞到MapCube上
                if (isCollider)
                
                    MapCube mapCube = hit.collider.GetComponent<MapCube>();//得到点击的mapCube
                    if(mapCube.turretGo == null && selectedTurredData != null)//可以创建
                    
                        if (money > selectedTurredData.cost)
                        
                            ChangeMoney(-selectedTurredData.cost);
                            mapCube.BuildTurret(selectedTurredData);
                        
                        else//提示钱不够
                        
                            //TODO
                            moneyAnimator.SetTrigger("Flicker");
                        
                    
                    else if(mapCube.turretGo != null)//如果上边有炮台,那么判断是否做升级处理
                    
                        if(mapCube.turretGo == selectedMapCube && upgradeCanvas.activeInHierarchy)//如果第二次点击此炮台了并且UI的激活属性是true
                        
                            StartCoroutine("HideUpgradeUI");//将UI隐藏,用协程的方式
                        
                        else
                        
                            //否则显示升级/拆除UI面板,第二个参数的bool值与是否有炮台判断相符,所以不再if判断直接传即可
                            ShowUpgradeUI(mapCube.transform.position, mapCube.isUpgraded);
                        
                        selectedMapCube = mapCube;//把点击的炮台赋给点击的炮台
                    
                
            
        
    
    //在Canvas里的设备里有On Value Changed里添加GameManager,然后选择对应的下面方法,只要是点击设备值发生改变了,就会触发
    public void OnLaserSelected(bool isOn)
    
        if (isOn)
        
            selectedTurredData = laserTurretData;
        
    
    public void OnMissileSelected(bool isOn)
    
        if (isOn)
        
            selectedTurredData = missileTurretData;
        
    
    public void OnStandardSelected(bool isOn)
    
        if (isOn)
        
            selectedTurredData = standardTurretData;
        
    
    void ShowUpgradeUI(Vector3 pos, bool isDisableUpgrade=false)
    
        StopCoroutine("HideUpgradeUI");//搜索下面的HideUpgradeUI协程方法有没有在运行,有的话先给暂停掉,没有也不会影响。
        //设置画布禁用,为的是切换到新的炮台时候,状态机会初始化一下,能有一个激活弹出UI的效果,这里调用状态机里show的时候,可能HideUpgradeUI还在播放,
        //为了防止冲突故在上面加上一个暂停的协程方法。
        upgradeCanvas.SetActive(false);
        upgradeCanvas.SetActive(true);//设置画布显示
        pos.y = pos.y + 4;
        upgradeCanvas.transform.position = pos;//设置画布位置
        buttonUpgrade.interactable = !isDisableUpgrade;//开启或者禁用升级按钮
    
    IEnumerator HideUpgradeUI()
    
        upgradeCanvasAnimator.SetTrigger("Hide");
        yield return new WaitForSeconds(0.8f);//消失的效果结束后再去调用下面
        upgradeCanvas.SetActive(false);//隐藏的时候不能直接把画布禁用,不然就无法播放禁用的动画了
    
    public void OnUpgradeButtonDown()//按下升级触发的方法
    
        if(money >= selectedMapCube.turretData.costUpgraded)//如果大于升级所需要的钱
        
            ChangeMoney(-selectedMapCube.turretData.costUpgraded);
            selectedMapCube.UpgradeTurret();
        
        else
        
            moneyAnimator.SetTrigger("Flicker");
        
        StartCoroutine("HideUpgradeUI");//把UI隐藏掉
    
    public void OnDestroyButtonDown()//按下拆除触发的方法
    
        selectedMapCube.DestroyTurret();
        StartCoroutine("HideUpgradeUI");
    


给升级面板添加的动画。 让升级和拆按钮”弹”出来,”缩”回去,创建一个Upgrade文件夹,右键UpgradeCanvas创建动画,创建面积从小到大的show动画,和从大到小的hide动画,存在Upgrade里,做完后会自动有一个UpgradeCanvas状态机,设置从Entry指向show,show—>hide,注意取消各自的Loop Time(从Project里点击动画能看到此菜单),show—>hide的连接线取消勾选Has Exit Time ,左上角添加一个Trigger命名为Hide来取触发这个连接。 在BuildManager里需要用状态机来控制,创建字段 private Animator upgradeCanvasAnimator ,从Start方法中由之前定义好的upgradeCanvas物体直接获得此控制器,然后在隐藏方法HideUpgradeUI里用upgradeCanvasAnimator.SetTrigger(“Hide”) 来设置播放隐藏动画,隐藏之后再禁用这个upgradeGcanvas,因为播放需要一下等待时间,所以需将HideUpgradeUI改成协程方法。 为了每一次点击不同炮台都会有show效果,在ShowUpgradeUI方法里先暂停一下HideUpgradeUI协程,再禁用一下upgradeCanvas再开启。 (暂停协程方法使用时是去搜索该方法名,有就暂停,没有也不会受影响)

设计游戏结束时候的UI界面

在主Canvas下创建一个空物体命名为End,让其与Canvas画布大小保持一致(用Alt填充方法),在它下面创建一个Image命名为Bg,修改颜色和透明度,创建一个Text命名为Message居中,创建两个Button命名为ButtonRetry、ButtonMenu,修改这俩下面的Text内容为重玩和菜单,选择End创建动画show,做一个背景慢慢显示,Text和俩Button从外进来的效果,

控制失败界面的显示

在GameManager下创建GameManager脚本,添加Win胜利和Failed失败方法,创建字段public GameObject endUI 和 public Text endMessage ,把End和它下面的Message拖入,创建字段public static GameManager Instance ,做成单例模式方便外界调用,在Enemy脚本就可以调用到GameManager脚本方法了,在Enemy脚本ReachDestination到达终点方法中调用GameManager的Faild方法。 因为EnemySpawner和GameManager在同一物体GameManager上的,所以在GameManager中控制敌人的生成, GameManager脚本全部代码如下:
public class GameManager : MonoBehaviour

    public GameObject endUI;//结束的UI画面
    public Text endMessage;
    public static GameManager Instance;
    private EnemySpawner enemySpawner;

    private void Awake()
    
        Instance = this;
        enemySpawner = GetComponent<EnemySpawner>();
    
    public void Win()
    
        endUI.SetActive(true);//设置为true后,它下面的Animator动画已经勾上了,会自动播放
        endMessage.text = "胜 利";
    
    public void Faild()
    
        enemySpawner.Stop();//停止生成敌人。
        endUI.SetActive(true);
        endMessage.text = "失 败";
    
    public void OnButtonRetry()
    
        endUI.SetActive(false);
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);//重新加载当前场景
    
    public void OnButtonMenu()
    
        SceneManager.LoadScene("MainMenu");
    

添加胜利界面和重玩,菜单按钮的点击

游戏胜利的条件是所有的敌人都生成了并且都死亡了,在EnemySpawner脚本中的SpawnEnemy协程方法中写一个对敌人数量的while循环,如果还有,就截止到此返回,如果没了就往下执行GameManager.Instance.Win() 方法。

GameManager脚本中,添加OnButtonRetry、OnButtonMenu 重玩和菜单方法,并注册到End对应的两个Button下。 可以给两个Button添加一下之前的放大的动画,在其组件下添加Animator,然后Controller处选择ButtonUpgrade动画,注意Button(Script)处的Transition选择Animation。

开发菜单场景

Project里新建一个场景命名为MainMenu,做一个Plane当做地面,Scale面积设置大一些能遮住视野,把StandardTurret拿过来,把里面有用的零件拿出来即可,弄一个空物体命名为Pviot,把炮塔拖到它下面,调整Pviot位置,创建一个Canvas的Button,因为要放在Pviot物体上随着运动所以要使用World Space,调整Button字体、大小等等,放在炮台下面再调整好位置,做成开始游戏,调好一个了再复制一个Canvas出来旋转一下做成退出,可以给俩Button添加之前的button动画(调成Animation和添加Animator设置Controller),可以在Button里添加一个Shadow组件,设置Effect Distance的值。 调整相机位置。

控制开始按钮和退出按钮的点击事件处理

控制开始按钮和退出按钮的点击事件处理。通过控制炮台Y轴旋转做一个旋转动画rotate。 创建一个空物体命名为GameMenu,在它身上添加脚本GameMenu,添加OnStartGame和OnExitGame方法,注册到两个Button下,在Build Setting里把两个场景添加进去。

GameMenu脚本全部代码如下:

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

public class GameMenu : MonoBehaviour 

    public void OnStartGame()
    
        SceneManager.LoadScene(1);
    
    public void OnExitGame()
    
#if UNITY_EDITOR
        UnityEditor.EditorApplication.isPlaying = false;
#else
        Application.Quit();
#endif
    

远古守卫/cocos2d-x 源代码/塔防游戏/高仿王国保卫战

下载地址:下载地址

本源代码高度模仿IOS游戏王国保卫战,由国外IOS商业开发教程站点raywenderlich内部project师制作,有很完整的关卡设计,战斗流程,长达12个关卡,各种敌兵,怪物,箭塔,炮塔一应俱全,还有魔法系统,成就系统以及后台数据库。差点儿达到了能够上线的商业游戏级别。

代码严格规范,提供了一整套塔防游戏实现的解决方式,如一波波怪怎样走出,怪的行走路线,我方小兵行动AI,塔搜索和攻击敌人的AI,代码严格依照MVC(model, view, controller)规范,让人一目了然,复用度极高。可惜原作者仅仅提供了MAC机上才干跑的cocos2d-iphone版。没有cocos2d-x版,本人独自一人花两个多月时间翻译转换成国内能用的cocos2d-x 3.x/win版。各种排错找错。环境转换和搭建,当中艰辛无人可知。

现将其奉献给广大cocos2d-x开发爱好者,一起学习进步

技术分享
应用平台:IOS / Windows / Android

开发工具:Eclipse / Visual Studio2012

编程语言:Objective-C / C++

游戏引擎: Cocos2d-x 3.x

源代码内容:  Cocos2d-iphone/Cocos2dx两套源代码 + 全套完整资源

完毕度:非常高 适用高级用户

使用方法:  先从别的project拷贝cocos2dx文件夹丢到源代码文件夹下。再双击proj.win32下的chaosWar.sln就可以打开project

注意:  拍下后请马上与掌柜联系,方便本人及时将宝贝下载链接发给您。本人随时在线,看到消息即会回复.

技术分享

技术分享
開始界面
技术分享
成就系统
技术分享
帮助系统
技术分享
loading
技术分享
关卡选择以及进入游戏之前的魔法选择
技术分享
战斗界面
技术分享
游戏胜利

源代码亮点:
1.简单易用的轻量级数据库sqlite

有关sqlite3,之前我不了解以为又是个鸡肋。心想有mysql了还有它做什么?经此源代码才发现原来它这么好用。说它好用是由于sqlite3不须要安装不论什么数据库后台。仅仅一个.db文件就能够当整个游戏数据库,极其适合游戏本地的配置文件。有sqliteStudio可视化工具
对其使用数据库经常使用的查询,增删改操作,对于策划来说很方便。能够代替plist, json等非常难理解的配置文件。

可是对我们程序猿来说可不这么简单的哟,还好本源代码提供了一整套完备的创建数据库。查找数据。增删改动操作,源代码看上去好像非常长只是实现了之后就能一劳永逸,到处使用。我们以后就复制/粘贴,调函数即可了。还有sqlite3库在移植到安卓环境时也会遇到不少麻烦,本源代码教程里也提供了完美的解决方式,您不用操心移植的问题
技术分享

2.塔防游戏的建塔。塔防御敌兵攻击的AI。小兵防御AI和敌兵行走AI

1.敌人怪物是怎么一波波出的,阵型该怎样控制?时间上又是怎么控制进场的时间和次序?
2.怪物怎么知道自己该走什么路线?哪些地方能走,哪些地方不能走?怎么控制不能走到道路外边去?
3.我方防御塔是怎么知道敌人已经进入了我方伏击圈?如箭塔。我们理想状态是第一个敌人一进入伏击圈就发动攻击。枪打出头鸟嘛。然后敌人非常多且就要逃出伏击圈时我方箭塔就要追击走在最后的落单小兵而不是无脑的还去打新进来的怪,要不放过不论什么一个怪嘛,不然让怪溜走了那但是一件非常遗憾的事,可这一切该怎么做?
4.我方小兵是怎样锁定自己的敌人并进行攻击?敌人是怎么知道自己被锁定并进行还击?还有小兵被打死了敌人怎么知道赶紧逃,我方兵营怎么知道应该补充防御兵?

   这一个个成堆问题真是好头疼,但又是必需要解决我们逃避不了的。这一切在代码里都有精彩体现。您能够下载下我转过来的.apk在手机跑跑看。战斗流程是不是实现了我说的上述效果
技术分享
    代码量许多。等你购买了就知道,长达128个.cpp,每个文件都很大,代码量已经超过了那个横版格斗游戏Beatup Em,只是您不用操心怎样学习阅读,我在根文件夹下已经放了一个"分章节源代码"文件夹,分成了十二个章节放置classes,您能够循序渐近学习,每个章节的classes都是能够执行的,只是文件夹结构您就要參考下终于project自己建立了,也不麻烦
技术分享
因为代码非常多,且是由mac cocos-iphone版转到cocos2d-x 3.x/c++版,存在bug在所难免。原谅下本掌柜,本人为了排错已经花了整整三个星期时间,已经到了看见这游戏都想吐血的程度!!

这样才做到了游戏流程没有严重宕机BUG,能够正常通关,小地方问题就无法保证了,只是遇到bug大家能够自己动手调试,也是提高自己编程能力水平的一条重要途径呀!

APK下载:
http://pan.baidu.com/s/1mgnEUGK
大家能够下载先玩玩,再决定是不是要购买



























以上是关于Unity3D制作塔防类游戏的主要内容,如果未能解决你的问题,请参考以下文章

如何制作塔防游戏 代码,操作,说明——Unity 5.3.5f1

使用Unity创建塔防游戏(Part1)

Unity塔防游戏源码Warfront Defenders Playmaker Kit v1.7

如何制作一个塔防小游戏

用Unity实现抛物线向目标点发射炮弹功能

小妖精的完美游戏教室——魔方塔防01,路径