Unity3D上路_02-第一视角射击游戏

官网:http://unity3d.com 
4.3.4http://netstorage.unity3d.com/unity/UnitySetup-4.3.4.exe 
本文资源:http://pan.baidu.com/s/1i3rAhBR 

书接前文

一。新建关卡

FileSave Scene
FileNew Scene
FileSave Scene as... Level02.unity

1.建立场景

Assets中拖放场景模型到Hierarchy中,
Unity3D上路_02-第一视角射击游戏_第1张图片

2.为游戏体添加多边形碰撞体

Hierarchy中选择3个构造游戏空间的游戏体,
ComponentPhysicsMesh Collider
操作后,游戏空间游戏体可以用于物理碰撞检测。
Unity3D上路_02-第一视角射击游戏_第2张图片

3.创建灯光

现在游戏空间内光线不好,调整一下,

1)创建电光源

根据需求,创建若干。可使用Ctrl + D 快速复制,
Unity3D上路_02-第一视角射击游戏_第3张图片

2)调整亮度

Unity3D上路_02-第一视角射击游戏_第4张图片

二。创建玩家

1.创建空对象

GameObjectCreate Empty
Hierarchy中将之命名为FPSPlayer

2.设置标签

选择FPSPlayerInspectorTag,修改为“Player”,
Unity3D上路_02-第一视角射击游戏_第5张图片

3.添加角色控制器

FPSPlayer仍旧被选中,
ComponentPhysicsCharacter Controller
执行这一步后,玩家在场景中移动时,会和其它游戏体发生物理交互。
Unity3D上路_02-第一视角射击游戏_第6张图片

4.添加刚体属性

仍旧选中玩家,
ComponentPhysicsRigidbody
Unity3D上路_02-第一视角射击游戏_第7张图片

5.控制脚本

首先,创建FPSPlayer.cs脚本,

using UnityEngine;
using System.Collections;

[AddComponentMenu("MyGame/FPSPlayer")]
public class FPSPlayer : MonoBehaviour {

    private CharacterController m_ch;   // 玩家角色控制器
    public Transform m_transform;       // 玩家实例
    private float m_movSpeed = 3.0f;    // 玩家移动基速
    public int m_life = 5;              // 生命值

    private float m_gravity = 2.0f;     // 重力

    private Transform m_camTransform;   // 摄像机
    private Vector3 m_camRot;           // 摄像机姿势-旋转角度
    private float m_camHeight = 4.5f;   // 摄像机高度-玩家的眼睛

    void Start() {

        m_transform = this.transform;                       // 本角色实例
        m_ch = this.GetComponent<CharacterController>();    // 本角色的控制器

        m_camTransform = Camera.main.transform;// 获取摄像机

        /** 设置摄像机初始位置 **/
        Vector3 pos = m_transform.position; // 玩家位置
        pos.y += m_camHeight;               // 镜头高度
        m_camTransform.position = pos;                  // 初始化初始摄像机位置
        m_camTransform.rotation = m_transform.rotation; // 初始化摄像机姿势

        /**
         * eulerAngles的三个变量 z,x,y 表示三个绕坐标轴旋转的角度(世界坐标轴)
         * 顺序是z,x,y。如果角度超过360的话,要用Rotate来代替,用四元数来旋转
         * 这三个x,y,z的值对应Inspector上的transform/Rotation的三个值
         * 所绕角度是顺着坐标轴看,按逆时针旋转的角度
         **/
        m_camRot = m_camTransform.eulerAngles;      // 存储摄像机姿势

        Screen.lockCursor = true;       // 锁定鼠标

    }

    void Update() {

        if (m_life <= 0) return;                // 如果生命为0,什么也不做

        /**
         * Input.GetAxis(string name);
         * 根据坐标轴名称返回虚拟坐标系中的值。返回值类型:float
         * 参数:Horizontal, Vertial, Mouse X, Mouse Y
         * 其中Horizontal, Vertical 默认对应小键盘上的左右、上下键,返回值为-1或1
         * Mouse X, Mouse Y 对应鼠标位置,返回值不定
         * 以上都是在Unity3d中预定义好的映射,可以通过 Edit->Project Settings->Input 来重新定义映射
         **/
        float rv = Input.GetAxis("Mouse Y");    // 鼠标 Y 轴移动距离,抬头角度
        float rh = Input.GetAxis("Mouse X");    // 鼠标 X 轴移动距离,转身角度

        m_camRot.x -= rv;                       // X轴 摄像机仰角-抬头
        m_camRot.y += rh;                       // Y轴 摄像机旋转
        m_camTransform.eulerAngles = m_camRot;  // 摄像机姿势修正

        // 使主角的面向方向与摄像机一致
        Vector3 camrot = m_camTransform.eulerAngles;    // 提取摄像机姿势
        camrot.x = 0; camrot.z = 0;                     // 防止后退
        m_transform.eulerAngles = camrot;               // 玩家姿势修正
         
        float xm = 0, ym = 0, zm = 0;

        // 重力运动
        ym -= m_gravity * Time.deltaTime * 10;

        // 前进/后退
        if (Input.GetKey(KeyCode.W))
            zm += m_movSpeed * Time.deltaTime * 3;
        else if (Input.GetKey(KeyCode.S))
            zm -= m_movSpeed * Time.deltaTime * 3;
        // 左移/右移
        if (Input.GetKey(KeyCode.A))
            xm -= m_movSpeed * Time.deltaTime * 3;
        else if (Input.GetKey(KeyCode.D))
            xm += m_movSpeed * Time.deltaTime * 3;
        
        // 移动
        m_ch.Move(m_transform.TransformDirection(new Vector3(xm, ym, zm)));

        // 使摄像机的位置与主角一致
        Vector3 pos = m_transform.position;
        pos.y += m_camHeight;
        m_camTransform.position = pos;

    }
    void OnDrawGizmos() {
        Gizmos.DrawIcon(transform.position, "pfsPlayer.png", true);
    }
}
然后,关联到玩家游戏体,
Unity3D上路_02-第一视角射击游戏_第8张图片


6.创建武器

1)设置主相机

可选操作,
Unity3D上路_02-第一视角射击游戏_第9张图片

2)创建武器游戏体

将已经做好的武器prefab文件加入场景,
Unity3D上路_02-第一视角射击游戏_第10张图片

3)建立父子关系

首先,拖动M16游戏体到MainCamera游戏体上松开鼠标即可,
Unity3D上路_02-第一视角射击游戏_第11张图片

然后,修改一下M16的参数,使之和主相机在一个位置,
Unity3D上路_02-第一视角射击游戏_第12张图片
 

三。创建僵尸

1.地形寻路设置

1)开启地形游戏体的寻路支持

首先,选中地形游戏体(可每次选一个,依次配置),
然后,在InspectorStatic,选中“Navigation Static”,
Unity3D上路_02-第一视角射击游戏_第13张图片

2)寻路计算

首先WindowNavigation
Unity3D上路_02-第一视角射击游戏_第14张图片

然后,在“Bake”标签页,配置参数
Unity3D上路_02-第一视角射击游戏_第15张图片

最后,点击“Bake”按钮,开始寻路计算,

计算结束后,可寻路的地形变色,
Unity3D上路_02-第一视角射击游戏_第16张图片

2.创建寻路者-僵尸

1)创建游戏体

Assets中拖放僵尸模型资源到Hierarchy中,
Unity3D上路_02-第一视角射击游戏_第17张图片

2)添加寻路功能

Unity3D上路_02-第一视角射击游戏_第18张图片

3)寻路设置

Unity3D上路_02-第一视角射击游戏_第19张图片

3.僵尸控制脚本

1)脚本代码

using UnityEngine;
using System.Collections;

public class Zombie : MonoBehaviour {

    Transform m_transform;          // 僵尸实例
    FPSPlayer m_player;             // 玩家实例
    NavMeshAgent m_agent;           // 寻路器

    private float m_moveSpeed = 0.5f;   // 僵尸移动基速度

	void Start () {
        m_transform = this.transform;   // 初始化僵尸
        
        m_player = GameObject.FindGameObjectWithTag("Player").GetComponent<FPSPlayer>();    // 玩家实例

        m_agent = this.GetComponent<NavMeshAgent>();                // 本僵尸的寻路器
        m_agent.SetDestination(m_player.transform.position);      // 寻路目标-玩家位置

        /**
         * UnassignedReferenceException: The variable m_transform of 'FPSPlayer' has not been assigned.
         * You probably need to assign the m_transform variable of the FPSPlayer script in the inspector.
         **/
        //m_agent.SetDestination(m_player.m_transform.position);      // 出现上面的报错
	}
	
	void Update () {
        float speed = m_moveSpeed * Time.deltaTime;
        //m_transform.TransformDirection:从自身坐标到世界坐标变换方向。把一个具体的点坐标的三位向量转变成一个方向向量
        m_agent.Move(m_transform.TransformDirection(new Vector3(0, 0, speed))); // 寻路位置更新
	}
}


2)关联

点击Hierarchy中的僵尸游戏体,拖动Assets中的脚本到上面,
Unity3D上路_02-第一视角射击游戏_第20张图片

4.僵尸的动作

1)打开僵尸的动画管理器

Hierarchy中选择僵尸游戏体,切换到Inspector面板,
打开Animator项目,(这个属性是游戏资源已经创建好的)
查看Controller条目,
WindowAnimator
Unity3D上路_02-第一视角射击游戏_第21张图片

2)添加角色属性

在“Parameters”子面板,点击“+”加号,选择“Bool”类型,
新建“idlerunattackdeath4个属性,(对应4种动作)
Unity3D上路_02-第一视角射击游戏_第22张图片

3)设置动画切换

Unity3D上路_02-第一视角射击游戏_第23张图片

4)修改僵尸控制脚本

using UnityEngine;
using System.Collections;

public class Zombie : MonoBehaviour {

    public Transform m_transform;   // 僵尸实例
    FPSPlayer m_player;             // 玩家实例
    NavMeshAgent m_agent;           // 寻路器
    private float m_moveSpeed = 0.5f;   // 僵尸移动基速度

    Animator m_ani;     // 动画控制器
    float m_rotSpeed;   // 转身
    float m_timer = 0;  // 计时器。更新寻路的时间
    int m_life = 15;    // 生命值

	void Start () {
        m_player = GameObject.FindGameObjectWithTag("Player").GetComponent<FPSPlayer>();    // 玩家实例
        m_transform = this.transform;                                                       // 初始化僵尸
        m_agent = this.GetComponent<NavMeshAgent>();                                        // 本僵尸的寻路器
        m_agent.SetDestination(m_player.m_transform.position);                              // 寻路目标(玩家的实例的位置)

        m_ani = this.GetComponent<Animator>();      // 动画控制器
	}

	void Update () {
        // 如果主角生命为0,什么也不做
        if (m_player.m_life <= 0) return;

        // 获取当前动画状态。AnimatorStateInfo:保存全部动作-动画类型(走、攻、立、死)
        AnimatorStateInfo stateInfo = m_ani.GetCurrentAnimatorStateInfo(0);

        // 如果处于静止状态。当前动画==动画控制器内定义的动作,且 不是过渡状态
        if (stateInfo.nameHash == Animator.StringToHash("Base Layer.idle") && !m_ani.IsInTransition(0)) {
            m_ani.SetBool("idle", false);

            // 静止一定时间
            m_timer -= Time.deltaTime;

            if (m_timer > 0) return;

            // 如果距离主角小于3米,进入攻击动画状态
            if (Vector3.Distance(m_transform.position, m_player. m_transform.position) < 3.0f) {
                m_ani.SetBool("attack", true);
            }
            else {
                // 重置定时器
                m_timer=0;

                // 设置寻路目标点
                m_agent.SetDestination(m_player. m_transform.position);

                // 进入跑步动画状态
                m_ani.SetBool("run", true);
            }
        }

        // 如果处于跑步状态
        if (stateInfo.nameHash == Animator.StringToHash("Base Layer.run") && !m_ani.IsInTransition(0)) {

            m_ani.SetBool("run", false);

            // 每隔1秒重新定位主角的位置
            m_timer -= Time.deltaTime;
            if (m_timer < 0) {
                m_agent.SetDestination(m_player. m_transform.position);

                m_timer = 1;
            }

            float speed = m_moveSpeed * Time.deltaTime;
            //m_transform.TransformDirection:从自身坐标到世界坐标变换方向。把一个具体的点坐标的三位向量转变成一个方向向量
            m_agent.Move(m_transform.TransformDirection(new Vector3(0, 0, speed))); // 寻路位置更新

            // 如果距离主角小于3米,向主角攻击
            if (Vector3.Distance(m_transform.position, m_player.m_transform.position) <= 3.0f) {
                //停止寻路	
                m_agent.ResetPath();
                // 进入攻击状态
                m_ani.SetBool("attack", true);
            }
        }

        // 如果处于攻击状态
        if (stateInfo.nameHash == Animator.StringToHash("Base Layer.attack") && !m_ani.IsInTransition(0)) {

            /** 面向主角 **/
            Vector3 oldangle = m_transform.eulerAngles; // 当前角度

            m_transform.LookAt(m_player.m_transform);   // 转身看着玩家
            float target = m_transform.eulerAngles.y;   // 保存当前朝向

            float speed = m_rotSpeed * Time.deltaTime;                          // 定义一个速度
            // MoveTowardsAngle:基于旋转速度,计算当前角度转向目标角度的旋转角度
            float angle = Mathf.MoveTowardsAngle(oldangle.y, target, speed);    // 要完成的动作角度
            m_transform.eulerAngles = new Vector3(0, angle, 0);                 // 转向目标角度

            /** 开启攻击模式 **/

            m_ani.SetBool("attack", false);

            // 如果攻击动画播完,重新进入待机状态
            if (stateInfo.normalizedTime >= 1.0f) {
                m_ani.SetBool("idle", true);

                // 重置计时器
                m_timer = 1;

            }
        }
	}
}


四。UI信息

1.图标

1)选择图片文件

Unity3D上路_02-第一视角射击游戏_第24张图片

2)创建纹理

CameObjectCreate OtherGUI Texture
Unity3D上路_02-第一视角射击游戏_第25张图片

3)设置纹理贴图

GUI对象的世界坐标原点在屏幕左下方;向右为x轴正方向,向上为y轴正方向;起点为0,最右边和最上边为1
Unity3D上路_02-第一视角射击游戏_第26张图片

4)选择字体文件

Unity3D上路_02-第一视角射击游戏_第27张图片

5)创建文本控件

GameObjectCreate OtherGUI Text
Unity3D上路_02-第一视角射击游戏_第28张图片

6)设置文本控件

Unity3D上路_02-第一视角射击游戏_第29张图片

7)创建其它显示控件

Unity3D上路_02-第一视角射击游戏_第30张图片

2.控制脚本

1)创建UI管理器

首先,创建空游戏体。GameObjectCreate Empty,更名为:Level3UI_Manager
其次,将UI控件设为其子游戏体。注意修改合适的名称,
    Unity3D上路_02-第一视角射击游戏_第31张图片

2)管理器代码

using UnityEngine;
using System.Collections;

public class Level3UI_Manager : MonoBehaviour {
    //单例
    public static Level3UI_Manager Instance = null;

    public int        m_score = 0;      // 游戏得分
    public static int m_maxscore = 0;    // 游戏最高得分
    public int        m_ball = 100;     // 弹药数量
    FPSPlayer         m_player;         // 游戏主角

    // UI文字。对应Hierarchy中Level3UI_Manager空游戏体的子元素的名字
    GUIText text_Ball;      // 弹药
    GUIText text_Life;      // 生命值
    GUIText text_Score;     // 得分
    GUIText text_MaxScore;  // 最高分

    void Start() {

        Instance = this;

        // 获得玩家
        m_player = GameObject.FindGameObjectWithTag("Player").GetComponent<FPSPlayer>();

        // 获得UI控件
        text_Ball = this.transform.FindChild("text_Ball").GetComponent<GUIText>();
        text_Life = this.transform.FindChild("text_Life").GetComponent<GUIText>();
        text_Score = this.transform.FindChild("text_Score").GetComponent<GUIText>();
        text_MaxScore = this.transform.FindChild("text_MaxScore").GetComponent<GUIText>();

        text_Life.text = " 生命:" + m_player.m_life.ToString();
        text_Ball.text = "子弹:" + m_ball.ToString() + "/100";
        text_Score.text = " 得  分:" + m_score;
        text_MaxScore.text = " 最高分:" + m_maxscore;
    }

    // 更新分数
    public void SetScore(int score) {
        m_score += score;

        if (m_score > m_maxscore)
            m_maxscore = m_score;

        text_Score.text = "得分:" + m_score;
        text_MaxScore.text = "最高分:" + m_maxscore;
    }

    /**  更新弹药   **/
    public void SetBall(int ball) {
        m_ball -= ball;

        // 如果弹药为负数,重新填弹
        if (m_ball <= 0)
            m_ball = 100 - m_ball;

        text_Ball.text = "子弹:" + m_ball.ToString() + "/100";
    }
    // 更新生命
    public void SetLife(int life) {
        text_Life.text = "生命:" + life.ToString();
    }

    void OnGUI() {
        if (m_player.m_life <= 0) { // 居中显示文字
            GUI.skin.label.alignment = TextAnchor.MiddleCenter;
            GUI.skin.label.fontSize = 40;
            GUI.Label(new Rect(0, 0, Screen.width, Screen.height), "玩家已挂");

            // 重新游戏按钮
            GUI.skin.label.fontSize = 30;
            if (GUI.Button(new Rect(Screen.width * 0.5f - 150, Screen.height * 0.75f, 300, 40), "再来一次")) {
                Application.LoadLevel(Application.loadedLevelName);
            }
        }
    }
}


3)关联脚本

Assets中拖放脚本文件到Hierarchy中的控制器游戏体上。
 

五。射击

1.修改玩家控制脚本

using UnityEngine;
using System.Collections;

[AddComponentMenu("Game/FPSPlayer")]
public class FPSPlayer : MonoBehaviour {

    private CharacterController m_ch;   // 玩家角色控制器
    public Transform m_transform;       // 玩家实例
    private float m_movSpeed = 3.0f;    // 玩家移动基速
    public int m_life = 5;              // 生命值
    private float m_gravity = 2.0f;     // 重力
    private Transform m_camTransform;   // 摄像机
    private Vector3 m_camRot;           // 摄像机姿势-旋转角度
    private float m_camHeight = 4.5f;   // 摄像机高度-玩家的眼睛

    private Transform m_muzzlepoint;    // 枪口
    public LayerMask m_layer;           // 碰撞层
    public Transform m_fx;              // 射中目标时的特效
    public AudioClip m_audio;           // 打枪声音
    private float m_shootTimer = 0;     // 射击间隔

    void Start() {
        m_transform = this.transform;                       // 本角色实例
        m_ch = this.GetComponent<CharacterController>();    // 本角色的控制器
        m_camTransform = Camera.main.transform;// 获取摄像机
        Vector3 pos = m_transform.position; // 玩家位置
        pos.y += m_camHeight;               // 镜头高度
        m_camTransform.position = pos;                  // 初始化初始摄像机位置
        m_camTransform.rotation = m_transform.rotation; // 初始化摄像机姿势
        m_camRot = m_camTransform.eulerAngles;      // 存储摄像机姿势

        // 枪口。这个是在3D软件中制作模型时创建的

Unity3D上路_02-第一视角射击游戏_第32张图片

        m_muzzlepoint = m_camTransform.FindChild("M16/weapon/muzzlepoint").transform; 

        Screen.lockCursor = true;       // 锁定鼠标
    }

    void Update() {
        if (m_life <= 0) return;                // 如果生命为0,什么也不做
        float rv = Input.GetAxis("Mouse Y");    // 鼠标 Y 轴移动距离,抬头角度
        float rh = Input.GetAxis("Mouse X");    // 鼠标 X 轴移动距离,转身角度
        m_camRot.x -= rv;                       // X轴 摄像机仰角-抬头
        m_camRot.y += rh;                       // Y轴 摄像机旋转
        m_camTransform.eulerAngles = m_camRot;  // 摄像机姿势修正
        Vector3 camrot = m_camTransform.eulerAngles;    // 提取摄像机姿势
        camrot.x = 0; camrot.z = 0;                     // 防止后退
        m_transform.eulerAngles = camrot;               // 玩家姿势修正
        float xm = 0, ym = 0, zm = 0;
        ym -= m_gravity * Time.deltaTime * 10;
        if (Input.GetKey(KeyCode.W))
            zm += m_movSpeed * Time.deltaTime * 3;
        else if (Input.GetKey(KeyCode.S))
            zm -= m_movSpeed * Time.deltaTime * 3;
        if (Input.GetKey(KeyCode.A))
            xm -= m_movSpeed * Time.deltaTime * 3;
        else if (Input.GetKey(KeyCode.D))
            xm += m_movSpeed * Time.deltaTime * 3;
        m_ch.Move(m_transform.TransformDirection(new Vector3(xm, ym, zm)));
        Vector3 pos = m_transform.position;
        pos.y += m_camHeight;
        m_camTransform.position = pos;

        m_shootTimer -= Time.deltaTime; // 射击时间间隔

        // 左键射击
        if (Input.GetMouseButton(0) && m_shootTimer <= 0) {

            m_shootTimer = 0.1f;
            this.audio.PlayOneShot(m_audio);    // 播放射击音效

            Level3UI_Manager.Instance.SetBall(1);   // 更新弹药

            RaycastHit info;    // 保存射线探测结果

            // 从m_muzzlepoint的位置,向摄像机面对的正方向射击一条射线
            // 射线只能与m_layer指定的层发生碰撞
            bool hit = Physics.Raycast(
                m_muzzlepoint.position,                                       // 发射点
                m_camTransform.TransformDirection(Vector3.forward),     // 方向
                out info,                                                        // 发生碰撞时保存光线投射信息
                100,                                                              // 射线长度
                m_layer);                                                        // 碰撞目标层

            if (hit) {
                // 如果碰撞-射击-到了标签为“Zombie”的游戏体
                if (info.transform.tag.CompareTo("Zombie") == 0) {
                    // 获取游戏体实例
                    Zombie zombie = info.transform.GetComponent<Zombie>();
                    // 更新被射中游戏角色的生命
                    zombie.OnDamage(1); // 此方法尚未添加
                }

                // 播放一个射击效果
                Instantiate(m_fx, info.point, info.transform.rotation);
            }
        }

    }

    void OnDrawGizmos() {
        Gizmos.DrawIcon(transform.position, "pfsPlayer.png", true);
    }

    // 修改玩家生命值
    public void OnDamage(int damage) {
        m_life -= damage;
        // 调用管理器实例的方法
        Level3UI_Manager.Instance.SetLife(m_life);
        // 如果没命了,释放鼠标
        if (m_life <= 0) Screen.lockCursor = false;
    }
}


2.添加碰撞层-身份

1)添加层(身份)

EditProject SettingsTags and Layers
Unity3D上路_02-第一视角射击游戏_第33张图片 

同时添加一个标签,
Unity3D上路_02-第一视角射击游戏_第34张图片

2)设置身份

空间游戏体:
Unity3D上路_02-第一视角射击游戏_第35张图片 

僵尸:
Unity3D上路_02-第一视角射击游戏_第36张图片

玩家(两个身份):
Unity3D上路_02-第一视角射击游戏_第37张图片

3.为玩家添加音源

首先,选择玩家游戏体,
然后,ComponentAudioAudio Source

4.设置玩家的射击特效和声音

Unity3D上路_02-第一视角射击游戏_第38张图片

5.射击特效控制

1)添加脚本

选择Assets中的FX.prefab特效文件,打开Inspector属性面板,点击下方的“Add Component”,
Unity3D上路_02-第一视角射击游戏_第39张图片

2)控制代码

创建脚本后,关联,

using UnityEngine;
using System.Collections;

[AddComponentMenu("MyGame/AutoDestroy")]
public class AutoDestroy : MonoBehaviour {

    public float m_timer = 1.0f;

	void Update () {

        m_timer -= Time.deltaTime;
        if (m_timer <= 0)
            Destroy(this.gameObject);
	
	}
}


6.升级僵尸

1)添加碰撞体

首先,在Hierarchy中选择僵尸游戏体,
然后,ComponentPhysicsCapsule Collider-胶囊碰撞体,
Unity3D上路_02-第一视角射击游戏_第40张图片

2)升级僵尸控制脚本

添加OnDamage功能,在 五.1 升级的玩家代码中我们已经引用到了。

using UnityEngine;
using System.Collections;
public class Zombie : MonoBehaviour {
    public Transform m_transform;   // 僵尸实例
    FPSPlayer m_player;               // 玩家实例
    NavMeshAgent m_agent;             // 寻路器
    private float m_moveSpeed = 0.5f;   // 僵尸移动基速度
    Animator m_ani;     // 动画控制器
    float m_rotSpeed;   // 转身
    float m_timer = 0;  // 计时器。更新寻路的时间
    int m_life = 15;     // 生命值
	void Start () { 略 }
	void Update () {
        if (m_player.m_life <= 0) return;
        AnimatorStateInfo stateInfo = m_ani.GetCurrentAnimatorStateInfo(0);
        if (stateInfo.nameHash==Animator.StringToHash("Base Layer.idle") && !m_ani.IsInTransition(0)){
  略
         }
        if (stateInfo.nameHash == Animator.StringToHash("Base Layer.run") && !m_ani.IsInTransition(0)) {
			略
  }

        // 如果处于攻击状态
        if(stateInfo.nameHash==Animator.StringToHash("Base Layer.attack") && !m_ani.IsInTransition(0)){
            Vector3 oldangle = m_transform.eulerAngles; // 当前角度
            m_transform.LookAt(m_player.m_transform);   // 转身看着玩家
            float target = m_transform.eulerAngles.y;   // 保存当前朝向
            float speed = m_rotSpeed * Time.deltaTime;                          // 定义一个速度
            float angle = Mathf.MoveTowardsAngle(oldangle.y, target, speed);    // 要完成的动作角度
            m_transform.eulerAngles = new Vector3(0, angle, 0);                 // 转向目标角度
            m_ani.SetBool("attack", false);
            if (stateInfo.normalizedTime >= 1.0f) {
                m_ani.SetBool("idle", true);
                m_timer = 1;

                // 更新玩家的生命值
                m_player.OnDamage(1); 
            }
        }

        // 如果死亡动画播放
        if(stateInfo.nameHash==Animator.StringToHash("Base Layer.death") && !m_ani.IsInTransition(0)){
            if (stateInfo.normalizedTime >= 1.0f) {
                Level3UI_Manager.Instance.SetScore(10); // 给玩家加分
                Destroy(this.gameObject);
            }  
  } 
	}

    /** 修改生命值。已经在 五.1 中引用到 **/
    public void OnDamage(int damage) {
        m_life -= damage;

        if (m_life <= 0)
            m_ani.SetBool("death", true);   // 更新动画
    } 
}


六。僵尸生产设备

1.存储全功能僵尸

Unity3D上路_02-第一视角射击游戏_第41张图片

2.创建生产设备

GameObjectCreate Empty,命名为“ZombieSpawn”,

3.控制代码

using UnityEngine;
using System.Collections;

[AddComponentMenu("MyGame/ZombieSpawn")]
public class ZombieSpawn : MonoBehaviour {
     
    public Transform m_enemy;     // 敌人的Prefab
    public int m_enemyCount = 0; // 生成的敌人数量
    public int m_maxEnemy = 3;    // 敌人的最大生成数量
    public float m_timer = 0;     // 生成敌人的时间间隔

    protected Transform m_transform;

	void Start () {
        m_transform = this.transform;
	}
	
	void Update () {
        // 如果生成敌人的数量达到最大值,停止生成敌人
        if (m_enemyCount >= m_maxEnemy)
            return;

        // 每间隔一定时间
        m_timer -= Time.deltaTime;
        if (m_timer <= 0) {
            m_timer = Random.value * 15.0f;
            if (m_timer < 5)
                m_timer = 5;

            // 生成敌人
            Transform obj=(Transform)Instantiate(m_enemy, m_transform.position, Quaternion.identity);

            // 获取敌人的角本
            Zombie enemy = obj.GetComponent<Zombie>();

            // 初始化敌人
            enemy.Init(this);   // 此功能尚未添加
        }
	}

  // Scene中可见图标
    void  OnDrawGizmos () {
        Gizmos.DrawIcon (transform.position, "spawn.png", true);
    }
}


4.关联并设置属性

Unity3D上路_02-第一视角射击游戏_第42张图片

5.僵尸升级

using UnityEngine;
using System.Collections;
public class Zombie : MonoBehaviour {
    public Transform m_transform;
    FPSPlayer m_player;
    NavMeshAgent m_agent;
    private float m_moveSpeed = 0.5f;
    Animator m_ani;
    float m_rotSpeed;
    float m_timer = 0;
    int m_life = 15;

    protected ZombieSpawn m_spawn;  // 生产设备

    /** 初始化僵尸的生产设备。实现 六.2 中引用的功能 **/
    public void Init(ZombieSpawn spawn) {
        m_spawn = spawn;
        m_spawn.m_enemyCount++; // 生产计数
  } 
  
	void Start () { 略 }
	void Update () {
        if (m_player.m_life <= 0) return;
        AnimatorStateInfo stateInfo = m_ani.GetCurrentAnimatorStateInfo(0);
        if(stateInfo.nameHash==Animator.StringToHash("Base Layer.idle")&& !m_ani.IsInTransition(0)){ 
  略 }
        if(stateInfo.nameHash==Animator.StringToHash("Base Layer.run")&& !m_ani.IsInTransition(0)){
  略 }
        if(stateInfo.nameHash==Animator.StringToHash("Base Layer.attack")&& !m_ani.IsInTransition(0)){
  略 }

        // 如果死亡动画播放
        if(stateInfo.nameHash==Animator.StringToHash("Base Layer.death")&& !m_ani.IsInTransition(0)){ 
            // 播放完成
            if (stateInfo.normalizedTime >= 1.0f) {
                m_spawn.m_enemyCount--; 

                Level3UI_Manager.Instance.SetScore(10); // 加分
                Destroy(this.gameObject);               // 销毁僵尸实例
            }
        }
	}
    public void OnDamage(int damage) { 略 }
}


七。地图

1.创建监控摄像机

1)创建摄像机

GameObjectCreate OtherCamera,命名为“Scout Camera”,
Unity3D上路_02-第一视角射击游戏_第43张图片

2)调整视角和显示位置

Unity3D上路_02-第一视角射击游戏_第44张图片

2.创建游戏体替身

1)创建不同替身的材质

创建两种替身使用的材质,(ProjectCreateMaterial
Unity3D上路_02-第一视角射击游戏_第45张图片

2)创建2个球体-替身

GameObjectCreate OtherSphere

3)为两种球体分别指定材质,

Unity3D上路_02-第一视角射击游戏_第46张图片 

4)创建Layer-替身身份

首先,创建“Avatar”替身身份,
Unity3D上路_02-第一视角射击游戏_第47张图片

然后,为替身指定身份,

5)将替身转为Prefab资源

Unity3D上路_02-第一视角射击游戏_第48张图片

3.设置替身为子元素

1)将全功能僵尸及替身放入Hierarchy

Unity3D上路_02-第一视角射击游戏_第49张图片

2)将两个替身设为正身的子元素

Unity3D上路_02-第一视角射击游戏_第50张图片

3)将设置好的资源用以替换

Unity3D上路_02-第一视角射击游戏_第51张图片

4)检查

Unity3D上路_02-第一视角射击游戏_第52张图片

4.调整摄像机

1)主相机

Camera项目下,打开Culling Mask条目,去除“Avatar”身份,
Unity3D上路_02-第一视角射击游戏_第53张图片

2)监控相机

Camera项目下,打开Culling Mask条目,只保留“Avatar”玩家身份,
Unity3D上路_02-第一视角射击游戏_第54张图片


- end

关卡关联

1.添加关卡到项目

FileBuild Settings...
Unity3D上路_02-第一视角射击游戏_第55张图片

2.修改关卡Level01的管理器

修改打开GameManager.cs文件

using UnityEngine;
using System.Collections;
[AddComponentMenu("MyGame/GameManager")]
public class GameManager : MonoBehaviour {
    public static GameManager Instance;
    public int m_score = 0;
    public static int m_hiscore = 0;
    protected Player m_player;
    public AudioClip m_musicClip;
    protected AudioSource m_Audio;
    void Awake() { 略 }
	void Start () { 略 }
	void Update () { 略 }

    /** 专用绘制UI界面 **/
    void OnGUI() {
        if (Time.timeScale == 0) { 略 }
        int life = 0;
        if (m_player != null) { 略 }
        else {  略 }
        GUI.skin.label.fontSize = 15;
        GUI.skin.label.alignment = TextAnchor.LowerLeft;
        GUI.Label(new Rect(5, 5, 100, 30), "生命值" + life);
        GUI.Label(new Rect(0, 5, Screen.width, 90), "历史最高得分 " + m_hiscore);
        GUI.Label(new Rect(0, 125, Screen.width, 30), "得分" + m_score);

        /**       进入下一关      **/
        if (m_score >= 200) { // 居中显示文字
            GUI.skin.label.alignment = TextAnchor.MiddleCenter;
            GUI.skin.label.fontSize = 40;
            GUI.Label(new Rect(0, 0, Screen.width, Screen.height), "下一关,打僵尸");
            // 重新游戏按钮
            GUI.skin.label.fontSize = 30;
            if(GUI.Button(new Rect(Screen.width*0.5f-150, Screen.height*0.75f, 300, 40), "开始")) {
                // Application.LoadLevel(Application.loadedLevelName);  // 当前关卡
                Application.LoadLevel("Level02");   // 指定关卡
            }
        }
    }
    public void AddScore( int point ) { 略 }
}


效果图:

Unity3D上路_02-第一视角射击游戏_第56张图片

Unity3D上路_02-第一视角射击游戏_第57张图片

资源:
     本篇博文《Unity3D上路》: http://pan.baidu.com/s/1tQrmA 

你可能感兴趣的:(游戏,cocos2d,C#,unity,unity3d,3D,box2D)