Unity3D-第一视角射击游戏
一。新建关卡
File,Save Scene,
File,New Scene,
File,Save Scene as... ,Level02.unity
1.建立场景
从Assets中拖放场景模型到Hierarchy中,
2.为游戏体添加多边形碰撞体
在Hierarchy中选择3个构造游戏空间的游戏体,
Component,Physics,Mesh Collider,
操作后,游戏空间游戏体可以用于物理碰撞检测。
3.创建灯光
现在游戏空间内光线不好,调整一下,
1)创建电光源
根据需求,创建若干。可使用Ctrl + D 快速复制,
2)调整亮度
二。创建玩家
1.创建空对象
GameObject,Create Empty,
在Hierarchy中将之命名为FPSPlayer,
2.设置标签
选择FPSPlayer,Inspector,Tag,修改为“Player”,
3.添加角色控制器
FPSPlayer仍旧被选中,
Component,Physics,Character Controller,
执行这一步后,玩家在场景中移动时,会和其它游戏体发生物理交互。
4.添加刚体属性
仍旧选中玩家,
Component,Physics,Rigidbody,
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);
}
}
然后,关联到玩家游戏体,
6.创建武器
1)设置主相机
可选操作,
2)创建武器游戏体
将已经做好的武器prefab文件加入场景,
3)建立父子关系
首先,拖动M16游戏体到MainCamera游戏体上松开鼠标即可,
然后,修改一下M16的参数,使之和主相机在一个位置,
三。创建僵尸
1.地形寻路设置
1)开启地形游戏体的寻路支持
首先,选中地形游戏体(可每次选一个,依次配置),
然后,在Inspector,Static,选中“Navigation Static”,
2)寻路计算
首先,Window,Navigation,
然后,在“Bake”标签页,配置参数
最后,点击“Bake”按钮,开始寻路计算,
计算结束后,可寻路的地形变色,
2.创建寻路者-僵尸
1)创建游戏体
从Assets中拖放僵尸模型资源到Hierarchy中,
2)添加寻路功能
3)寻路设置
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中的脚本到上面,
4.僵尸的动作
1)打开僵尸的动画管理器
在Hierarchy中选择僵尸游戏体,切换到Inspector面板,
打开Animator项目,(这个属性是游戏资源已经创建好的)
查看Controller条目,
Window,Animator,
2)添加角色属性
在“Parameters”子面板,点击“+”加号,选择“Bool”类型,
新建“idle、run、attack、death”4个属性,(对应4种动作)
3)设置动画切换
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)选择图片文件
2)创建纹理
CameObject,Create Other,GUI Texture,
3)设置纹理贴图
GUI对象的世界坐标原点在屏幕左下方;向右为x轴正方向,向上为y轴正方向;起点为0,最右边和最上边为1,
4)选择字体文件
5)创建文本控件
GameObject,Create Other,GUI Text,
6)设置文本控件
7)创建其它显示控件
2.控制脚本
1)创建UI管理器
首先,创建空游戏体。GameObject,Create Empty,更名为:Level3UI_Manager,
其次,将UI控件设为其子游戏体。注意修改合适的名称,
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软件中制作模型时创建的
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)添加层(身份)
Edit,Project Settings,Tags and Layers,
同时添加一个标签,
2)设置身份
空间游戏体:
僵尸:
玩家(两个身份):
3.为玩家添加音源
首先,选择玩家游戏体,
然后,Component,Audio,Audio Source,
4.设置玩家的射击特效和声音
5.射击特效控制
1)添加脚本
选择Assets中的FX.prefab特效文件,打开Inspector属性面板,点击下方的“Add Component”,
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中选择僵尸游戏体,
然后,Component,Physics,Capsule Collider-胶囊碰撞体,
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.存储全功能僵尸
2.创建生产设备
GameObject,Create 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.关联并设置属性
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)创建摄像机
GameObject,Create Other,Camera,命名为“Scout Camera”,
2)调整视角和显示位置
2.创建游戏体替身
1)创建不同替身的材质
创建两种替身使用的材质,(Project,Create,Material)
2)创建2个球体-替身
GameObject,Create Other,Sphere,
3)为两种球体分别指定材质,
4)创建Layer-替身身份
首先,创建“Avatar”替身身份,
然后,为替身指定身份,
5)将替身转为Prefab资源
3.设置替身为子元素
1)将全功能僵尸及替身放入Hierarchy
2)将两个替身设为正身的子元素
3)将设置好的资源用以替换
4)检查
4.调整摄像机
1)主相机
在Camera项目下,打开Culling Mask条目,去除“Avatar”身份,
2)监控相机
在Camera项目下,打开Culling Mask条目,只保留“Avatar”玩家身份,
- end
关卡关联
1.添加关卡到项目
File,Build Settings...,
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上路》: http://pan.baidu.com/s/1tQrmA
Unity3D-第一视角射击游戏的更多相关文章
- D3D游戏编程系列(六):自己动手编写第一人称射击游戏之第一人称视角的构建
说起第一人称射击游戏,不得不提第一人称视角啊,没有这个,那么这个第一就无从谈起啊,我作为一个观察者究竟如何在这个地图上顺利的移动和观察呢,那么,我们一起来研究下. 我们首先来看下CDXCamera类: ...
- 关于Unity中FPS第一人称射击类游戏制作(专题十)
当前Unity最新版本5.6.3f1,我使用的是5.5.1f1 场景搭建 1: 导入人物模型, 手持一把枪;2: 导入碎片模型;3: 创建一个平面;4: 创建一个障碍物;5: 导入人物模型;6: 配置 ...
- Unity3D--学习太空射击游戏制作(一)
近期买了本书在学习一些Unity3D的东西,在了解了Unity3D工具的基本面板后开始学习一个太空射击游戏的开发过程. 首先下载一个关于本游戏的资源文件,(百度云下载地址:http://pan.bai ...
- 简单的射击游戏HTML+JS实现
一直想自己写一个游戏玩,时间和精力都不太允许,最近几天刚好有空闲时间,就琢磨了这个小游戏. 刚开始想着计算图片重叠事件,然后让炮弹和飞机消失,傻乎乎写了一天,越整越乱.今天一大早晕过来了,改用数组以后 ...
- Unity3D实现3D立体游戏原理及过程
Unity3D实现3D立体游戏原理及过程 183 0 0 下面的教程是我今天整理的资料,教大家一步步完成自己的3D立体游戏,并向大家介绍一些3D成像的原理. 理论上,每个普通的非立体3 ...
- 使用Cocos2dx-JS开发一个飞行射击游戏
一.前言 笔者闲来无事,某天github闲逛,看到了游戏引擎的专题,引起了自己的兴趣,于是就自己捣腾了一下Cocos2dx-JS.由于是学习,所谓纸上得来终觉浅,只是看文档看sample看demo,并 ...
- 少儿编程Scratch第四讲:射击游戏的制作,克隆的奥秘
上周的宇宙大战射击游戏中,我们只完成了宇宙飞船发射子弹的部分.还未制作敌对方.这周制作了敌方-飞龙,飞龙随机在屏幕上方出现,如果被子弹打中,则得分,飞龙和子弹都消失. 敌方:飞龙:计分. 目的 目的: ...
- Unity射击游戏实例—物理碰撞的实现
前言: 这一篇章实现物理碰撞,就是游戏体碰撞减装甲,这几天想要试着做出兼具装甲与血量的模式,可自动回复的装甲与永久损伤的血量,在一些平台上找到了不少有意思的模型,有兴趣的可以自己找找模型替换一下. 射 ...
- Skytte:一款令人印象深刻的 HTML5 射击游戏
Skytte 是一款浏览器里的 2D 射击游戏.使用 Canvas 元素和大量的 JavaScript 代码实现.Skytte 是用我们的开源和现代的前端技术创造的.经典,快节奏的横向滚动射击游戏,探 ...
随机推荐
- Delphi下URL汉字编码解码的两个函数
//汉字URL编码函数function URLEncode(const S: string; const InQueryString: Boolean): string;var Idx: Integ ...
- 第一章 andriod studio 安装与环境搭建
原文 http://blog.csdn.net/zhanghefu/article/details/9286123 第一章 andriod studio 安装与环境搭建 一.Android Stu ...
- Java调用Lua脚本(LuaJava使用、安装及Linux安装编译)
依赖包(附件有下载): 包名 类型 操作系统 luajava-1.1.jar jar ALL libluajava-1.1.so .so linux luajava-1.1.dll .dll wind ...
- iOS中通知传值
NSNotification 通知中心传值,可以跨越多个页面传值, 一般也是从后面的页面传给前面的页面. 思路: 第三个界面的值传给第一个界面. 1. 在第一个界面建立一个通知中心, 通过通知中心 ...
- Web前端性能优化——高频触发事件的防抖
JS 提供了行为层的支持,为用户提供了交互的操作性. 然而,部分事件却常常有意无意的被频繁触发.比方浏览器窗体的 resize 事件.某个元素的 mouseover 事件,假设处理触发事件的回调函数过 ...
- Sass介绍及入门教程
Sass是什么? Sass是"Syntactically Awesome StyleSheets"的简称.那么他是什么?其实没有必要太过于纠结,只要知道他是“CSS预处理器”中的一 ...
- java日期处理 calendar 和date
抄的人家的,仅作学习使用. java Date获取 年月日时分秒 package com.util; import java.text.DateFormat; import java.ut ...
- CodeSmith exclude global 文件和文件夹问题 与 输入中文显示乱码问题
1.打开C:/Documents and Settings/你的用户名/Application Data/CodeSmith/v4.1/CodeSmithGui.config文件. 2.在<te ...
- RandomAccessFile浅析
RandomAccessFile类中的write方法有以下的注意事项: 首先write方法每次都写入一个字节 api中write方法如下 public void write(int b) throws ...
- leetcode Maximum Depth of Binary Tree python
# Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x): # self.val = ...