一、玩家移动脚本
using UnityEngine;
using System.Collections;
public class PlayerMove : MonoBehaviour {
public float moveSpeed = 10.0f; //玩家移动速度
public float rotateSpeed = 40.0f; //玩家旋转速度
public float jumpVelocity = 2.0f; //玩家起跳速度
//公有变量可以在U3D的脚本设定界面修改参数
private Animator animator; //玩家的Animator组件,用于控制玩家动画的播放
private Rigidbody rigidbody; //玩家的刚体组件
private float h; //获取玩家横轴输入
private float v; //获取玩家纵轴输入
private bool isGrounded; //玩家是否在地面上
private float groundedRaycastDistance = 0.1f; //表示向地面发射射线的射线长度
//初始化,获取玩家组件
void Start () {
animator= GetComponent<Animator> (); //获取玩家Animator组件
rigidbody = GetComponent<Rigidbody>(); //获取玩家刚体组件
}
//每个固定时间执行一次,用于物理模拟
void FixedUpdate()
{
//从玩家的位置垂直向下发出长度为射线,返回值表示玩家是否该射线是否碰撞到物体,该句代码用于检测玩家是否在地面上。三个参数分别是射线位置,射线方向,射线长度。
isGrounded = Physics.Raycast(transform.position, -Vector3.up, groundedRaycastDistance);
Jump(isGrounded); //调用跳跃函数
}
//跳跃函数,用于FixedUpdate()中调用
void Jump(bool isGround)
{
//当玩家按下跳跃键Space,并且玩家在地面上时执行跳跃相关函数
if (Input.GetKey(KeyCode.Space) && isGround)
{
//给玩家刚体组件添加向上的作用力,以改变玩家的运动速度,改变值为jumpVelocity
rigidbody.AddForce(Vector3.up * jumpVelocity, ForceMode.VelocityChange);
animator.SetBool("isJump", true); //设置动画参数,将isJump布尔型参数设置为true,播放玩家跳跃动画
}
else if(isGround) animator.SetBool("isJump", false); //设置动画参数,将isJump布尔型参数设置为false,停止播放玩家跳跃动画
}
//每帧执行一次,用于玩家的位移与旋转
void Update () {
float h = Input.GetAxisRaw("Horizontal"); //获取玩家水平轴上的输入,默认输入为ad与左右键
float v = Input.GetAxisRaw("Vertical"); //获取玩家垂直轴上的输入,默认为sw与上下键
MoveAndRotate(h, v); //根据玩家在水平、垂直轴上的输入,调用玩家的位移与旋转函数
}
//玩家的位移与旋转函数
void MoveAndRotate(float h, float v)
{
//v>0表示获取玩家向前的输入,玩家以moveSpeed的速度向前运动
if (v > 0) transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
//v<0表示获取玩家向后的输入,玩家以moveSpeed的速度向后运动
else if (v < 0) transform.Translate(-Vector3.forward * moveSpeed * Time.deltaTime);
//若玩家垂直轴上有输入,则表示玩家进行位移,设置动画参数,将isMove布尔型参数设置为true,播放玩家奔跑动画
if (v != 0.0f) animator.SetBool("isMove", true);
//若玩家垂直轴上无输入,则表示玩家没有位移,设置动画参数,将isMove布尔型参数设置为false,停止播放玩家奔跑动画
else animator.SetBool("isMove", false);
//根据玩家水平轴的输入进行旋转,顺时针为正方向
transform.Rotate(Vector3.up * h * rotateSpeed * Time.deltaTime);
}
}
二、玩家生命值脚本
using UnityEngine;
using System.Collections;
public class PlayerHealth : MonoBehaviour {
public int health = 10; //玩家的生命值
public bool isAlive = true; //玩家是否存活
//每帧执行一次,检测玩家是否存活
void Update () {
if (health <= 0)
isAlive = false;
}
//玩家扣血函数,用于GameManager脚本中调用,这个函数是公有的,需要被其他脚本调用。
public void TakeDamage(int damage){
health -= damage;
if (health < 0)
health = 0;
}
}
三、玩家攻击脚本
using UnityEngine;
using System.Collections;
public class PlayerAttack : MonoBehaviour {
public int shootingDamage = 1; //玩家射击伤害
public float shootingRange=50.0f; //玩家射击范围
public AudioClip shootingAudio; //玩家射击音效
public float timeBetweenShooting = 1.0f; //射击之间的最小时间间隔(玩家射击动画为1秒,为了使得动画正常播放,该值最好>=1.0f)
private Animator animator; //玩家的Animator组件,用于控制玩家动画的播放
private LineRenderer gunLine; //玩家的线渲染器组件,用于控制玩家开枪发出的激光射线效果
private float timer; //攻击时间间隔,记录玩家从上次射击到现在经过的时间
private Ray ray;
private RaycastHit hitInfo; //发射的射线反馈的相关信息
//初始化,获取对象组件,以及初始化变量
void Start () {
animator = GetComponentInParent<Animator>(); //获取玩家的Animator组件
gunLine = GetComponent<LineRenderer>(); //获取玩家的线渲染器组件
timer = 0.0f; //将攻击时间间隔清零
}
//每帧执行一次,用于玩家的射击行为
void Update () {
//当玩家按下攻击键J,并且攻击间隔大于射击之间的最小时间间隔,执行射击相关行为
if (Input.GetKeyDown(KeyCode.J) && timer>timeBetweenShooting)
{
timer = 0.0f; //射击后将攻击时间间隔清零
animator.SetBool("isShooting", true); //设置动画参数,将isShooting布尔型参数设置为true,播放玩家射击动画
Invoke("shoot", 0.5f); //玩家举枪花费0.5s,0.5秒后调用shoot() 射击函数
}
//否则,表示射击条件未满足
else
{
timer += Time.deltaTime; //更新攻击间隔,增加上一帧所花费的时间
gunLine.enabled = false; //将线渲染器设为禁用
animator.SetBool("isShooting", false); //设置动画参数,将isShooting布尔型参数设置为false,停止播放玩家射击动画
}
}
//射击函数
void shoot()
{
AudioSource.PlayClipAtPoint(shootingAudio, transform.position); //在枪口位置播放射击音效
ray.origin = Camera.main.transform.position; //设置射线发射的原点:摄像机所在的位置
ray.direction = Camera.main.transform.forward; //设置射线发射的方向:摄像机的正方向
gunLine.SetPosition(0, transform.position); //设置线渲染器(开枪后的激光射线)第一个端点的位置:玩家枪械的枪口位置(本游戏对象)
//发射射线,射线有效长度为shootingRange,若射线击中任何游戏对象,则返回true,否则返回false
if (Physics.Raycast(ray, out hitInfo, shootingRange))
{
if (hitInfo.collider.gameObject.tag == "Enemy") //当被击中的游戏对象标签为Enemy,表明射线射中敌人
{
//获取该名敌人的EnemyHealth脚本组件
EnemyHealth enemyHealth = hitInfo.collider.gameObject.GetComponent<EnemyHealth>();
if (enemyHealth != null)
{
//调用EnemyHealth脚本的TakeDamage()函数,对敌人造成shootingDamage的伤害
enemyHealth.TakeDamage(shootingDamage);
}
if(enemyHealth.health>0) //若敌人受伤且未死亡,敌人将会因受到攻击而被击退
hitInfo.collider.gameObject.transform.position += transform.forward * 2;
}
gunLine.SetPosition(1, hitInfo.point); //当射线击中游戏对象时,将线渲染器(开枪后的激光射线)第二个端点设为射线击中游戏对象的点
}
//若射线未射中游戏对象,则将线渲染器(开枪后的激光射线)第二个端点设为射线射出后的极限位置
else gunLine.SetPosition(1, ray.origin + ray.direction * shootingRange);
gunLine.enabled = true; //将线渲染器(开枪后的激光射线)启用,显示玩家开枪后的效果。
}
}
四、敌人追踪脚本
using UnityEngine;
using System.Collections;
public class EnemyTrace : MonoBehaviour {
public GameObject target; //敌人的追踪目标
public float moveSpeed=8.0f; //敌人的移动速度
public float minDist=2.2f; //追踪距离,当敌人与目标的距离小于等于该值时,敌人不再追踪目标
private float dist; //敌人的坐标与玩家坐标的位置
private Animator animator; //敌人的Animator组件
private EnemyHealth enemyHealth; //敌人的生命值脚本
//初始化,获取敌人的组件
void Start () {
animator = GetComponent<Animator> (); //获取敌人的Animator组件
enemyHealth = GetComponent<EnemyHealth> (); //获取敌人的生命值脚本
}
//每帧执行一次,用于敌人追踪目标
void Update () {
if (enemyHealth!=null && enemyHealth.health <= 0) return; //当敌人死亡时,敌人无法追踪目标
if (target == null) { //当追踪目标未设置时,敌人无法追踪目标
animator.SetBool ("isStop", true); //设置动画参数,将布尔型参数isStop设为true:敌人未追踪目标,播放停驻动画
return;
}
dist = Vector3.Distance (transform.position, target.transform.position); //计算敌人与追踪目标之间的距离
//当游戏状态为游戏进行中(Playing)时
if (GameManager.gm==null || GameManager.gm.gameState == GameManager.GameState.Playing) {
if (dist > minDist) { //当敌人与目标的距离大于追踪距离时
transform.LookAt (target.transform); //敌人面向追踪目标
transform.eulerAngles=new Vector3(0.0f,transform.eulerAngles.y,0.0f); //设置敌人的Rotation属性,确保敌人只在y轴旋转
transform.position +=
transform.forward * moveSpeed * Time.deltaTime; //敌人以moveSpeed的速度向追踪目标靠近
}
animator.SetBool ("isStop", false); //设置动画参数,将布尔型参数isStop设为false:敌人追踪目标,播放奔跑动画
}
}
}
五、敌人生命脚本
using UnityEngine;
using System.Collections;
public class EnemyHealth : MonoBehaviour {
public int health=2; //敌人的生命值
public int value=1; //玩家击杀敌人后所获得的分数
public AudioClip enemyHurtAudio; //敌人的受伤音效
private Animator animator; //敌人的Animator组件
private Collider collider; //敌人的Collider组件
private Rigidbody rigidbody; //敌人的rigidbody组件
//初始化,获取敌人的组件
void Start(){
animator = GetComponent<Animator> (); //获取敌人的Animator组件
collider = GetComponent<Collider> (); //获取敌人的Collider组件
rigidbody = GetComponent<Rigidbody> (); //获取敌人的Rigidbody组件
}
//敌人受伤函数,用于PlayerAttack脚本中调用
public void TakeDamage(int damage){
health -= damage; //敌人受伤扣血
if (enemyHurtAudio != null) //在敌人位置处播放敌人受伤音效
AudioSource.PlayClipAtPoint (enemyHurtAudio, transform.position);
if (health <= 0) { //当敌人生命值小于等于0时,表明敌人已死亡
if (GameManager.gm != null) {
GameManager.gm.AddScore (value);//玩家获得击杀敌人后得分
}
animator.applyRootMotion = true; //设置Animator组件的ApplyRootMotion属性,使敌人的移动与位移受动画的影响
animator.SetTrigger ("isDead"); //设置动画参数,设置isDead的Trigger参数,播放敌人死亡动画
collider.enabled = false; //禁用敌人的collider组件,使其不会与其他物体发生碰撞
rigidbody.useGravity = false; //因为敌人的collider组件被禁用,敌人会因重力穿过地形系统下落,取消敌人受到的重力可以避免该现象
Destroy (gameObject, 3.0f); //3秒后删除敌人对象
}
}
}
六、敌人攻击脚本
using UnityEngine;
using System.Collections;
public class EnemyAttack : MonoBehaviour {
public int damage=1; //敌人攻击造成的伤害值
public float timeBetweenAttack=0.8f; //敌人攻击之间的最小间隔(敌人攻击动画约为0.8秒,为了使得动画正常播放,该值最好设为0.8秒)
public AudioClip enemyAttackAudio; //敌人的攻击音效
private float timer; //攻击时间间隔,记录敌人从上次攻击到现在经过的时间
private Animator animator; //敌人的Animator组件,用于控制敌人动画的播放
private EnemyHealth enemyHealth; //敌人的生命值脚本
//初始化,获取对象组件,以及变量初始化
void Start(){
timer = 0.0f; //将攻击时间间隔初始化
animator = GetComponent<Animator> (); //获取敌人的Animator组件
enemyHealth = GetComponent<EnemyHealth> (); //获取敌人的生命值脚本
}
//与勾选了isTrigger属性的COllider组件共同用于检测:是否有物体进入敌人的攻击范围
void OnTriggerStay(Collider collider){
if (enemyHealth.health <= 0) //若敌人生命值小于等于0,则说明敌人已经死亡,不具备攻击能力
return;
//当攻击间隔大于敌人攻击之间的最小间隔,且进入敌人攻击范围的对象标签是玩家时
if (timer>=timeBetweenAttack && collider.gameObject.tag == "Player") {
//当游戏状态为游戏进行中(Playing)时
if(GameManager.gm==null || GameManager.gm.gameState==GameManager.GameState.Playing){
timer=0.0f; //攻击后将攻击时间间隔清零
animator.SetBool ("isAttack", true); //设置动画参数,将isAttack布尔型参数设置为true,播放敌人攻击动画
if(enemyAttackAudio!=null) //在敌人位置处播放敌人的攻击音效
AudioSource.PlayClipAtPoint(enemyAttackAudio,transform.position);
if (GameManager.gm != null)
GameManager.gm.PlayerTakeDamage (damage);//通过GameManager游戏管理类实现玩家扣血的效果
}
}
}
//与勾选了isTrigger属性的COllider组件共同用于检测:是否有物体离开敌人的攻击范围
void OnTriggerExit(Collider collider){
//若离开敌人攻击范围的物体标签是玩家时
if (collider.gameObject.tag == "Player")
animator.SetBool ("isAttack", false); //设置动画参数,将isAttack布尔型参数设置为false,停止播放敌人攻击动画
}
//每帧执行一次,更新攻击间隔
void Update(){
timer += Time.deltaTime; //更新攻击间隔,增加上一帧所花费的时间
}
}
七、游戏控制脚本
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour {
static public GameManager gm; //静态游戏管理器,场景中唯一的游戏管理器实例
public GameObject player; //玩家对象
private PlayerHealth playerHealth; //玩家的生命值脚本
public int TargetScore=10; //游戏获胜的目标分数
private int currentScore; //游戏当前得分
//游戏状态枚举,分别表示游戏进行(Playing)、游戏失败(GameOver)、游戏胜利(Winning)
public enum GameState {Playing,GameOver,Winning};
public GameState gameState; //游戏状态变量
public Text scoreText; //GUI控件,用于显示当前游戏得分的文本信息
public Text healthText; //GUI控件,用于显示玩家当前的生命值
//初始化,获取相关组件,并初始化变量
void Start () {
//初始化游戏管理器类
gm = GetComponent<GameManager> ();
//根据标签获取玩家对象
if (player == null)
player = GameObject.FindGameObjectWithTag ("Player");
//游戏开始前初始化变量
currentScore = 0;
//获取玩家对象的玩家生命值脚本
playerHealth = player.GetComponent<PlayerHealth> ();
}
//每帧执行一次,用于游戏状态的检测与切换,以及处理当前游戏状态需要执行的语句
void Update () {
switch (gameState) { //根据当前游戏状态来决定要执行的语句
//当游戏状态为游戏进行中(Playing)状态时
case GameState.Playing:
scoreText.text = "Score:" + currentScore; //将显示当前游戏得分的文本信息更改为“Score:分数”
healthText.text = "Health:" + playerHealth.health; //将显示玩家当前生命值的文本信息更改为“Health:生命值”
//若玩家死亡,游戏状态更改为游戏失败(GameOver)
if (playerHealth.isAlive == false)
gm.gameState = GameState.GameOver;
//若当前得分大于目标分数,游戏状态更改为游戏胜利(Winning)
else if (currentScore >= TargetScore)
gm.gameState = GameState.Winning;
break;
//当游戏状态为游戏胜利(Winning)状态时
case GameState.Winning:
SceneManager.LoadScene("level1"); //加载场景level1
break;
//当游戏状态为游戏失败(GameOver)状态时
case GameState.GameOver:
SceneManager.LoadScene("level1"); //加载场景level1
break;
}
}
//玩家击杀得分
public void AddScore(int value){
currentScore += value;
}
//玩家受伤扣血
public void PlayerTakeDamage(int value){
if (playerHealth != null)
playerHealth.TakeDamage(value);
}
}