Unity3D--学习太空射击游戏制作(三)

步骤四:创建敌人

创建敌人的方式与创建主角类似,不过敌人的行为需要由计算机来控制,它将从上方迎着主角缓慢飞出来,并左右来回移动:

01:创建Enemy.cs脚本,添加代码:

 1 using UnityEngine;
 2 using System.Collections;
 3 
 4 [AddComponentMenu("MyGame/Enemy")]
 5 public class Enemy : MonoBehaviour
 6 {
 7 
 8     //移动速度
 9     public float m_Movespeed = 1;
10     //旋转速度
11     public float m_RotationSpeed = 30;
12     public Transform m_transform;
13     void Start()
14     {
15         m_transform = this.transform;
16     }
17 
18     void Update()
19     {
20         UpdateMove();
21     }
22 
23     protected void UpdateMove()
24     {
25         //左右移动
26         float rx = Mathf.Sin(Time.time) * Time.deltaTime;
27         //前进
28         m_transform.Translate(new Vector3(rx, 0, -m_Movespeed * Time.deltaTime));
29     }
30 }
View Code

UpdateMove函数用来执行敌人的移动,使用了Sin函数使游戏体在x方向的移动始终在(-1,1)区间内,敌人在飞行的同时还会左右迂回;在Project窗口找到Enemy.fbx文件,拖动到Hierarchy窗口,然后参考前面内容为其创建Prefab,指定Enemy脚本作为其组件。然后将Prefab从Project窗口拖动到游戏场景中,然后在Hierarchy窗口选中Enemy按Ctrl+D复制多个,然后再Scene窗口中自己排列下位置就OK了。

游戏运行后:

步骤五:添加物理碰撞

现在的游戏虽然有了主角、敌人,也可以发射子弹,但主角和敌人之间却没有任何的交互。我们需要分别给主角、子弹、敌人添加碰撞体,并添加触发碰撞的代码,使其在发生碰撞的时候产生交互。

01:先给敌人添加碰撞体,在Scene面板选中任意一个敌人,在菜单栏选择Component->Physics->Box Collider为敌人添加一个立方体碰撞体组件,在后在Inspector窗口找到Box Collider组件,选中Is Trigger,使其具有触发作用:

02:接着在菜单栏选择Component->Physics->Rigidbody为敌人添加一个刚体组件,所有需要参与物理计算的游戏体都需要有一个刚体组件才能正常工作。在Insperctor->Rigidbody取消选择Use Gravity去掉重力作用影响,选中Is Kinematic使游戏体运动不受物理模拟影响,现在已经为一个敌人添加了物理碰撞效果组件,然后再Insperctor最上面找到Apply按钮点击,这样所有的Enemy都更新了此物理碰撞的设置。此处如果是在编辑器的Project窗口修改原始敌人的Prefab的属性,那么场景中的所有的敌人都会自动更新与Prefab一样的属性设置,如图:

然后参考给敌人设置物理碰撞组件的做法,给主角和子弹也类似的设置。

03:接下来触发碰撞,上面已经给主角、敌人、子弹添加了碰撞体,但是运行游戏的时候看不到任何的互动效果,我们将要为他们分别指定一个Tag标识,然后添加触发碰撞事件的代码,在菜单栏选择Edit->Project Settings->Tags在size中输入2,创建两个tag,名为PlayerRocket和Enemy,如图:

然后在Project窗口选择敌人的Prefab,在Inspector窗口设置Tag为Enemy;选择子弹的Prefab,在Inspector窗口设置它的Tag为PlayerRocket;选择主角设置他的Tag为Player,这个Tag是Unity预设在工程内的。

然后打开敌人Enemy.cs脚本,添加一个生命属性:

    public float m_life = 10;

    void OnTriggerEnter(Collider other) //这是一个派生自MonoBehaviour的函数,在碰撞体互相接触时
                                      //会被触发
    {
        if (other.tag.CompareTo("PlayerRocket") == 0)//如果碰到的物体是主角子弹PlayerRocket
        {
            Rocket rocket = other.GetComponent<Rocket>();//获得对方碰撞提的Rocket脚本组件
            if (rocket != null)
            {
                m_life -= rocket.m_power;
                if (m_life <= 0)
                {
                    Destroy(this.gameObject);//如果生命小于等于0就自动销毁
                }
            }
        }
        else if (other.tag.CompareTo("Player") == 0)
        {
            m_life = 0;
            Destroy(this.gameObject);//如果碰到主角就立即自动销毁
        }
    }

  然后在子弹Rocket.cs脚本中也添加一个OnTriggerEnter函数,当子弹撞击到敌人,则自我销毁。

void OnTriggerEnter(Collider other)
    {
        if (other.tag.CompareTo("Enemy") == 0)
        {
            return;
        }
        Destroy(this.gameObject);
    }

  然后在主角Player.cs脚本中添加一个生命属性,添加一个OnTriggerEnter函数,当主角与非自己发出的子弹相碰撞的时候都会损失一些生命,当生命为0时候自行销毁。

public float m_life = 3;

    void OnTriggerEnter(Collider other)
    {
        if (other.tag.CompareTo("PlayerRocket") != 0)//如果主角与非己方子弹相撞
        {
            m_life -= 1;
            if (m_life <= 0)
            {
                Destroy(this.gameObject);
            }
        }
    }

  此时我们注意到当敌人没有与主角或者主角的子弹发生碰撞的时候就会一直存活,从而造成了资源的浪费,这时候我们需要添加一个空的游戏体,把他放到最下面,然后让他的范围可以控制到整个下方横向区域,添加物理碰撞组件,为他指定一个名为Bound的Tag,然后在Enemy.cs中添加一句代码,当敌人没有被子弹消灭和主角碰撞消灭的时候飞到屏幕下方与之碰撞就会自行销毁。

 else if (other.tag.CompareTo("Bound") == 0)
        {
            m_life = 0;
            Destroy(this.gameObject);//如果碰到边界就立即自动销毁
        }

  步骤六:添加高级敌人(可以向主角发射子弹的敌人)

01:在Project窗口找到Enemy2.fbx模型,为其创建Prefab,为其创建脚本SuperEnemy.cs,该类继承自Enemy.cs,然后打开Enemy.cs,,将UpdateMove()方法写成Vitual方法,然后再SuperEnemy.cs中重写该方法,同时将新敌人的Tag改为Enemy:

using UnityEngine;
using System.Collections;
[AddComponentMenu("MyGame/SuperEnemy")]
public class SuperEnemy : Enemy
{
    protected override void UpdateMove()
    {
        //向前移动
        m_transform.Translate(new Vector3(0, 0, -m_Movespeed * Time.deltaTime));
    }
}

  此时运行游戏发现新敌人缓慢向前移动

02:新敌人向主角发射子弹

使用rocket.fbx创建一个新的子弹Prefab,取名为EnemyRocket,为其创建新的材质,使用rocket2.png作为贴图,使敌人的子弹看上去与主角的子弹不同,为敌人添加RigidBody和Box Collider组件(这里我添加组件的时候子弹就发不出来了,不知道为啥???),为敌人子弹新建一个名为EnemyRocket的Tag,创建EnemyRocket.cs脚本,继承自Rocket类:

using UnityEngine;
using System.Collections;
[AddComponentMenu("MyGame/EnemyRocket")]
public class EnemyRocket : Rocket
{
    void OnTriggerEnter(Collider other)
    {
        if (other.tag.CompareTo("Player") == 0)
        {
            return;
        }
        Destroy(this.gameObject);
    }
}

  将EnemyRocket的脚本指定给敌人子弹的Prefab,在Inspector窗口设置EnemyRocket组件,降低敌人子弹的移动速度,增加生存时间,然后关联SuperEnemy和子弹,在SuperEnemy.cs脚本中添加代码:

using UnityEngine;
using System.Collections;
[AddComponentMenu("MyGame/SuperEnemy")]
public class SuperEnemy : Enemy
{
    public Transform m_rocket;
    protected float m_fireTimer = 2;//控制发射子弹的时间间隔
    protected Transform m_player;//用来指向主角的飞船

    void Awake()//Awake方法继承自MonoBehaviour它会在游戏体实例化时执行一次,并先于Start方法
    {
        GameObject obj = GameObject.FindGameObjectWithTag("Player");//获得主角的游戏体实例
        if (obj != null)
        {
            m_player = obj.transform;
        }
    }
    protected override void UpdateMove()
    {
        m_fireTimer -= Time.deltaTime;
        if (m_fireTimer <= 0)
        {
            m_fireTimer = 2;
            if (m_player != null)
            {
                Vector3 relativePos = m_transform.position - m_player.position;
                //Quaternion.LookRotation使子弹在初始化时朝向主角的方向
                Instantiate(m_rocket, m_transform.position, Quaternion.LookRotation(relativePos));
            }
        }
        //向前移动
        m_transform.Translate(new Vector3(0, 0, -m_Movespeed * Time.deltaTime));
    }
}

  然后选择SuperEnemy的Prefab,在Inspector窗口中选择Rocket属性,与敌人的子弹的Prefab相关联,然后运行游戏。

注意:我在添加子弹游戏体的时候如果是添加了Box Collider就会看不到子弹了,不知道是不是坐标的问题??????

下面是添加声音和特效...

 

posted @ 2015-10-24 18:13  My Way!  阅读(4304)  评论(1编辑  收藏  举报