Mooc Hero - FPS(一)

截图与代码均来自        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秒后删除敌人对象
		}
	}
}


7.敌人自动生成
8.人称变换

9.游戏开始、进行、结束画面(uGUI)


10.移动平台UI设置(uGUI)

11.粒子系统


12.线渲染器
13.物品收集
14.游戏胜利与失败画面

猜你喜欢

转载自blog.csdn.net/qq_27012963/article/details/80186527