截图与代码均来自 cousera网络游戏设计与开发专项课程 如有侵权,联系本人立即删除
1.地形系统
2.动画片段与角色替身:Animations、Avatar(实现人形动画重定向)
3.动画状态机:状态、参数4.动画层与身体遮罩:可以用于合成身体不同部位的动画
5.玩家的移动、射击与生命值
using UnityEngine; using System.Collections; using UnityStandardAssets.CrossPlatformInput; public class FPSPlayerMove : MonoBehaviour { public float moveSpeed = 6.0f; //角色移动速度 public float rotateSpeed = 30.0f; //角色转向速度 public float jumpVelocity = 5f; //角色起跳时的速度 private float miniMouseRotateX = -75.0f; //摄像机旋转角度的最小值 private float maxiMouseRotateX = 75.0f; //摄像机旋转角度的最大值 private float mouseRotateX; //当前摄像机在X轴的旋转角度 private bool isGrounded; //玩家是否在地面上 private float groundedRaycastDistance; //在判定玩家是否在地面上时,向地面发射射线的射线长度 private Camera myCamera; //角色的摄像机子对象 private Rigidbody rigid; //角色刚体组件 private CapsuleCollider capsuleCollider; //角色的胶囊体碰撞体 //初始化,获取组件,并计算相关值 void Start () { myCamera = GetComponentInChildren<Camera> (); //获取摄像机组件 mouseRotateX = myCamera.transform.eulerAngles.x; //将当前摄像机在X轴的旋转角度赋值给mouseRotateX rigid = GetComponent<Rigidbody> (); //获取刚体组件 capsuleCollider = GetComponent<CapsuleCollider> (); //获取胶囊体碰撞体 groundedRaycastDistance = capsuleCollider.height / 2 + 0.01f; //计算向地面发射射线的射线长度 } //每个固定时间执行一次,用于物理模拟 void FixedUpdate() { //从玩家的位置垂直向下发出长度为groundedRaycastDistance的射线,返回值表示玩家是否该射线是否碰撞到物体,该句代码用于检测玩家是否在地面上 isGrounded = Physics.Raycast(transform.position, -Vector3.up, groundedRaycastDistance); } //跳跃函数,用于FixedUpdate()中调用 void Jump(bool isGround) { //当玩家按下跳跃键,并且玩家在地面上时执行跳跃相关函数 if(CrossPlatformInputManager.GetButtonDown("Jump") && isGround &&(GameManager.gm == null || GameManager.gm.gameState == GameManager.GameState.Playing) ) { //给玩家刚体组件添加向上的作用力,以改变玩家的运动速度,改变值为jumpVelocity rigid.AddForce(Vector3.up * jumpVelocity, ForceMode.VelocityChange); } } //每帧执行一次,用于获取玩家输入并控制角色的行为 void Update () { //当游戏状态为游戏进行中时 if (GameManager.gm == null || GameManager.gm.gameState == GameManager.GameState.Playing) { float h = CrossPlatformInputManager.GetAxisRaw ("Horizontal"); //获取玩家水平轴上的输入 float v = CrossPlatformInputManager.GetAxisRaw ("Vertical"); //获取玩家垂直轴上的输入 Move (h, v); //根据玩家的输入控制角色移动 float rv = CrossPlatformInputManager.GetAxisRaw ("Mouse X"); //获取玩家鼠标垂直轴上的移动 float rh = CrossPlatformInputManager.GetAxisRaw ("Mouse Y"); //获取玩家鼠标水平轴上的移动 Rotate (rh, rv); //根据玩家的鼠标输入控制角色转向 Jump (isGrounded); //玩家的跳跃函数 } } //角色移动函数 void Move(float h,float v){ //玩家以moveSpeed的速度进行平移 transform.Translate ((Vector3.forward * v + Vector3.right * h) * moveSpeed * Time.deltaTime); } //角色转向函数 void Rotate(float rh,float rv){ transform.Rotate (0, rv * rotateSpeed, 0); //鼠标水平轴上的移动控制角色左右转向 mouseRotateX -= rh * rotateSpeed; //计算当前摄像机的旋转角度 mouseRotateX = Mathf.Clamp (mouseRotateX, miniMouseRotateX, maxiMouseRotateX); //将旋转角度限制在miniMouseRotateX与MaxiMouseRotateY之间 myCamera.transform.localEulerAngles = new Vector3 (mouseRotateX, 0.0f, 0.0f); //设置摄像机的旋转角度 } }
using UnityEngine; using System.Collections; using UnityStandardAssets.CrossPlatformInput; public class PlayerAttack : MonoBehaviour { public int shootingDamage = 1; //玩家射击伤害 public float shootingRange = 50.0f; //玩家射击距离 public AudioClip shootingAudio; //射击音效 public GameObject shootingEffect; //射击时的粒子效果对象 public Transform shootingEffectTransform; //播放粒子效果的Transfrom属性 private LineRenderer gunLine; //线渲染器:射击时的激光射线效果 private bool isShooting; //玩家是否正在射击 private Camera myCamera; //摄像机组件 private Ray ray; private RaycastHit hitInfo; private GameObject instantiation; private static float LINE_RENDERER_START=0.02f; //射线初始宽度 private static float LINE_RENDERER_END=0.05f; //射线末端宽度 //初始化函数,获取组件 void Start () { gunLine = GetComponent<LineRenderer> (); //获取线渲染器组件 if (gunLine != null) gunLine.enabled = false; //在游戏开始时禁用线渲染器组件 myCamera = GetComponentInParent<Camera> (); //获取父对象的摄像机组件 } //每帧执行一次,在Update函数后调用,实现玩家射击行为 void LateUpdate () { isShooting=CrossPlatformInputManager.GetButtonDown("Fire1"); //获取玩家射击键的输入 //若在游戏进行中(Playing)获取玩家射击输入,则调用射击函数 if (isShooting && (GameManager.gm==null || GameManager.gm.gameState == GameManager.GameState.Playing)) { Shoot (); } else if (gunLine != null) //若射击条件未满足,表示未进行射击,禁用线渲染器 gunLine.enabled = false; } //射击函数 void Shoot() { AudioSource.PlayClipAtPoint (shootingAudio, transform.position); //播放射击音效 if (shootingEffect != null) { //实例化玩家射击效果的粒子系统对象 instantiation = Instantiate (shootingEffect, shootingEffectTransform.position, shootingEffectTransform.rotation) as GameObject; instantiation.transform.parent = transform; } ray.origin = myCamera.transform.position; //设置射线发射的原点:摄像机所在的位置 ray.direction = myCamera.transform.forward; //设置射线发射的方向:摄像机的正方向 if (gunLine != null) { gunLine.enabled = true; //进行射击时,启用线渲染器(激光射线效果) gunLine.SetPosition (0, transform.position); //设置线渲染器(激光射线效果)第一个端点的位置:玩家枪械的枪口位置 } //发射射线,射线有效长度为shootingRange,若射线击中任何游戏对象,则返回true,否则返回false if (Physics.Raycast (ray, out hitInfo, shootingRange)) { if (hitInfo.transform.gameObject.tag.Equals ("Enemy")) { //当被击中的游戏对象标签为Enemy,表明射线击中敌人 //获取敌人生命值组件 EnemyHealth enemyHealth = hitInfo.transform.gameObject.GetComponent<EnemyHealth> (); if (enemyHealth != null) { //调用EnemyHealth脚本的TakeDamage()函数,对敌人造成shootingDamage的伤害 enemyHealth.TakeDamage (shootingDamage); } if(enemyHealth.health > 0){ //若敌人受伤未死亡,敌人将会因受到攻击而被击退 hitInfo.collider.gameObject.transform.position += transform.forward * 2; } } if (gunLine != null) { gunLine.SetPosition (1, hitInfo.point); //当射线击中游戏对象时,设置线渲染器(激光射线效果)第二个端点的位置:击中对象的位置 gunLine.SetWidth (LINE_RENDERER_START, //射线在射程内击中对象时,需要根据击中对象的位置动态调整线渲染器(激光射线效果)的宽度 Mathf.Clamp ((hitInfo.point - ray.origin).magnitude / shootingRange, LINE_RENDERER_START, LINE_RENDERER_END)); } } else if (gunLine != null) { //当射线未击中游戏对象时,设置线渲染器(激光射线效果)第二个端点的位置:射线射出后的极限位置 gunLine.SetPosition (1, ray.origin + ray.direction * shootingRange); //射线在射程内未击中对象,直接设置射线的初始与末尾宽度 gunLine.SetWidth (LINE_RENDERER_START, LINE_RENDERER_END); } } }
using UnityEngine; using System.Collections; public class PlayerHealth : MonoBehaviour { public int startHealth = 10; //玩家的初始生命值 public int currentHealth; //玩家当前生命值 public bool isAlive = true; //玩家是否存活 //初始化函数,设置玩家当前血量 void Start () { currentHealth = startHealth; } //每帧执行一次,检测玩家是否存活 void Update () { if (currentHealth <= 0) { isAlive = false; } } //玩家扣血函数,在GameManager脚本中调用 public void TakeDamage(int damage){ currentHealth -= damage; if (currentHealth < 0) currentHealth = 0; } //玩家加血函数,在GameManager脚本中调用 public void AddHealth(int value){ currentHealth += value; if (currentHealth > startHealth) //加血后当前生命值不能超过初始生命值 currentHealth = startHealth; } }
6.敌人的追踪、攻击与生命值,玩家得分
using UnityEngine; using System.Collections; public class EnemyTrace : MonoBehaviour { public GameObject target; //敌人的追踪目标 public float moveSpeed=8.0f; //敌人的移动速度 public float minDist=1.6f; //追踪距离,当敌人与目标的距离小于等于该值时,敌人不再追踪目标 private float dist; private Animator anim; //敌人的Animator组件 private EnemyHealth enemyHealth; //敌人的生命值脚本 //初始化,获取敌人的组件 void Start () { anim = GetComponent<Animator> (); //获取敌人的Animator组件 enemyHealth = GetComponent<EnemyHealth> (); //获取敌人的生命值脚本 } //每帧执行一次,用于敌人追踪目标 void Update () { //当游戏状态为游戏进行中(Playing)时 if (GameManager.gm==null || GameManager.gm.gameState == GameManager.GameState.Playing) { if (enemyHealth.health <= 0) return; //当敌人死亡时,敌人无法追踪目标 //当追踪目标未设置时,敌人无法追踪目标 if (target == null) return; dist = Vector3.Distance (transform.position, target.transform.position); //计算敌人与追踪目标之间的距离 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的速度向追踪目标靠近 } anim.SetBool ("isStop", false); //设置动画参数,将布尔型参数isStop设为false:敌人追踪目标,播放奔跑动画 } //当游戏状态为游戏失败(GameOver)时 else if (GameManager.gm==null || GameManager.gm.gameState == GameManager.GameState.GameOver) { anim.SetTrigger ("isPlayerDead"); //设置动画参数,设置isPlayerDead的Trigger参数,播放游戏失败时敌人动画 } } }
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 anim; //敌人的Animator组件,用于控制敌人动画的播放 private EnemyHealth enemyHealth; //敌人的生命值脚本 //初始化,获取对象组件,以及变量初始化 void Start(){ timer = 0.0f; //将攻击时间间隔初始化 anim = 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; //攻击后将攻击时间间隔清零 anim.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") anim.SetBool ("isAttack", false); //设置动画参数,将isAttack布尔型参数设置为false,停止播放敌人攻击动画 } //每帧执行一次,更新攻击间隔 void Update(){ timer += Time.deltaTime; //更新攻击间隔,增加上一帧所花费的时间 } }
using UnityEngine; using System.Collections; public class EnemyHealth : MonoBehaviour { public int health=2; //敌人的生命值 public int value=1; //玩家击杀敌人后所获得的分数 public AudioClip enemyHurtAudio; //敌人的受伤音效 public GameObject hurtEffect; //敌人受伤效果的粒子系统对象 public Transform hurtEffectTransform; //粒子系统对象实例化时的Transform属性 private Animator anim; //敌人的Animator组件 private Collider colli; //敌人的Collider组件 private Rigidbody rigid; //敌人的rigidbody组件 private GameObject instantiation; //初始化,获取敌人的组件 void Start(){ anim = GetComponent<Animator> (); //获取敌人的Animator组件 colli = GetComponent<Collider> (); //获取敌人的Collider组件 rigid = GetComponent<Rigidbody> (); //获取敌人的Rigidbody组件 } //敌人受伤函数,用于PlayerAttack脚本中调用 public void TakeDamage(int damage){ if (hurtEffect != null) { //实例化敌人受伤效果的粒子系统对象 instantiation = Instantiate (hurtEffect, hurtEffectTransform.position, hurtEffectTransform.rotation) as GameObject; instantiation.transform.parent = transform; } health -= damage; //敌人受伤扣血 if (enemyHurtAudio != null) //在敌人位置处播放敌人受伤音效 AudioSource.PlayClipAtPoint (enemyHurtAudio, transform.position); if (health <= 0) { //当敌人生命值小于等于0时,表明敌人已死亡 if (GameManager.gm != null) { GameManager.gm.AddScore (value);//玩家获得击杀敌人后得分 } anim.applyRootMotion = true; //设置Animator组件的ApplyRootMotion属性,使敌人的移动与位移受动画的影响 anim.SetTrigger ("isDead"); //设置动画参数,设置isDead的Trigger参数,播放敌人死亡动画 colli.enabled = false; //禁用敌人的collider组件,使其不会与其他物体发生碰撞 rigid.useGravity = false; //因为敌人的collider组件被禁用,敌人会因重力穿过地形系统下落,取消敌人受到的重力可以避免该现象 Destroy (gameObject, 3.0f); //3秒后删除敌人对象 } } }
8.人称变换
9.游戏开始、进行、结束画面(uGUI)
11.粒子系统
13.物品收集
14.游戏胜利与失败画面