前言
本文由作者@zx一路飛奔出品,轉載請註明出處
文章地址:http://blog.csdn.net/u014735301/article/details/43055923作者微博:http://weibo.com/u/1847349851
這幾天編碼下來,是時候寫篇博客總結和分享下了,做出來的效果大致爲:
方向鍵控制人物移動,靠近怪物時,按下攻擊鍵,可以鎖定怪物,進行攻擊。也可以釋放技能,
技能分爲:單體鎖定,無鎖定,造成的傷害效果分爲:單體傷害,羣體傷害。
怪物受到人物的攻擊,開始對人物進行攻擊,人物遠離時,進行追擊,當之間的距離達到一定長度時,怪物的攻擊目標消失
放上幾張圖看看效果吧
動畫控制
//人物狀態 枚舉
public enum ControlAnimationState {Idle,Move,WaitAttack,Attack,Cast,ActiveSkill,TakeAtk,Death};
//動畫狀態
public ControlAnimationState ctrlAnimState;
//人物狀態
void HeroAnimationState() {
//靜止
if(ctrlAnimState == ControlAnimationState.Idle)
{
animation.animationState = animation.Idle;
}
//行走
if(ctrlAnimState == ControlAnimationState.Move)
{
animation.animationState = animation.Move;
}
//攻擊
if (ctrlAnimState == ControlAnimationState.Attack)
{
animation.animationState = animation.Attack;
}
//等待攻擊
if (ctrlAnimState == ControlAnimationState.WaitAttack)
{
animation.animationState = animation.Idle;
WaitAttack();
}
}
下面把動畫控制腳本代碼全部給出
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class AnimationController : MonoBehaviour {
public delegate void AnimationHandle();
public AnimationHandle animationState;
//動畫類型1
[System.Serializable]
public class AnimationType01
{
public AnimationClip animation;
public float speedAnimation = 1.0f;
}
//動畫類型2 可以控制動畫播放速度
[System.Serializable]
public class AnimationType02
{
public AnimationClip animation;
public float speedAnimation = 1.0f;
public bool speedTuning;
}
//釋放技能動畫
[System.Serializable]
public class AnimationSkill
{
public PlayerSkillController.SkillType skillType;
public int skillIndex;
public AnimationClip animationSkill;
public float speedAnimation;
public float attackTimer;
public bool speedTuning;
}
public AnimationType01 idle,death; //靜止,施法,死亡
public AnimationType02 move; //行走
public AnimationSkill skillSetup;//技能
private PlayerController playerController;
private PlayerSkillController playerSkill;
private PlayerStatus playerStatus;
public bool checkAttack; //檢測攻擊動畫是否播放結束
public bool checkSkill;
// Use this for initialization
void Start () {
checkAttack = true;
checkSkill = true;
playerController = this.GetComponent<PlayerController>();
playerStatus = this.GetComponent<PlayerStatus>();
playerSkill = this.GetComponent<PlayerSkillController>();
}
// Update is called once per frame
void Update () {
if(animationState != null){
animationState();
}
}
//Idle Method
public void Idle(){
animation.CrossFade(idle.animation.name);
animation[idle.animation.name].speed = idle.speedAnimation;
}
//Move Method
public void Move(){
animation.Play(move.animation.name);
if(move.speedTuning) //可以變換速度
{
//與人物移動速度相關
animation[move.animation.name].speed = (playerStatus.status.movespd * 2) * move.speedAnimation;
}else
{
animation[move.animation.name].speed = move.speedAnimation;
}
}
//攻擊(釋放技能)
public void Attack()
{
//接受參數
ReceiveParam();
if (skillSetup.skillType==PlayerSkillController.SkillType.FreeTarget)
{
//playerSkill.UseSkill("Attack", skillSetup.skillIndex);
// checkSkill = false;
}
animation.Play(skillSetup.animationSkill.name);
if (skillSetup.speedTuning) //能進行速度控制
{
animation[skillSetup.animationSkill.name].speed = skillSetup.speedAnimation * (playerStatus.status.atkSpd * 2);
}else
{
animation[skillSetup.animationSkill.name].speed = skillSetup.speedAnimation;
}
//計算傷害,當動畫播放時間超出攻擊時間
if (animation[skillSetup.animationSkill.name].normalizedTime > skillSetup.attackTimer && animation[skillSetup.animationSkill.name].normalizedTime < 0.9f)
{
if (checkSkill)
{
playerSkill.UseSkill("Attack", skillSetup.skillIndex);
checkSkill = false;
}
}
//攻擊動畫播放結束
if(animation[skillSetup.animationSkill.name].normalizedTime > 0.9f)
{
playerController.ctrlAnimState = PlayerController.ControlAnimationState.WaitAttack;
playerController.onceAttack = false;
checkAttack = true;
checkSkill = true;
}
}
//死亡
public void Death()
{
animation.CrossFade(death.animation.name);
animation[death.animation.name].speed = death.speedAnimation;
}
//從playskill腳本接受參數
public void ReceiveParam() {
if (checkAttack)
{
//技能ID
skillSetup.skillIndex = playerSkill.FindSkillIndex(playerController.skillID);
//技能類型
skillSetup.skillType = playerSkill.activeSkillAttack[skillSetup.skillIndex].skillType;
//技能動畫
skillSetup.animationSkill = playerSkill.activeSkillAttack[skillSetup.skillIndex].animationAttack;
//動畫播放時間
skillSetup.speedAnimation = playerSkill.activeSkillAttack[skillSetup.skillIndex].speedAnimation;
//播放時間是否可控
skillSetup.speedTuning = playerSkill.activeSkillAttack[skillSetup.skillIndex].speedTuning;
//技能攻擊時間
skillSetup.attackTimer = playerSkill.activeSkillAttack[skillSetup.skillIndex].attackTimer;
checkAttack = false;
}
}
}
技能控制
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/*
人物技能控制腳本
*/
public class PlayerSkillController : MonoBehaviour {
//技能類型:單體鎖定,無鎖定,
public enum SkillType {LockTarget,FreeTarget,Instance};
//傷害類型:單體傷害,羣體傷害
public enum TargetSkill {SingleTarget,MultipleTarget};
//主動釋放技能
[System.Serializable]
public class ActiveSkillAttack
{
public string skillName = "Skill Attack";//技能名稱
public int skillID; //技能id
public int unlockLevel = 1;//解鎖等級
public Texture2D skillIcon;//技能圖標
public int mpUse;//mp消耗
public TargetSkill targetSkill = PlayerSkillController.TargetSkill.SingleTarget;//傷害類型
public SkillType skillType = PlayerSkillController.SkillType.LockTarget;//技能類型
public float skillRange;//技能範圍
public AnimationClip animationAttack;//技能動畫
public float speedAnimation = 1;//動畫播放速度
public float CD = 0;//冷卻時間
public float attackTimer = 0.5f;
public float percentDamage = 1;//傷害百分比
public float multipleDamage = 1;//傷害次數
[Multiline]
public string description = ""; //技能描述
public bool speedTuning;//動畫播放速度是否可控
public GameObject skillFX;
public AudioClip soundFX;
}
public List<ActiveSkillAttack> activeSkillAttack = new List<ActiveSkillAttack>();
//在技能範圍中的enemy
public List<GameObject> monsterInArea = new List<GameObject>();
//碰撞組
public Collider[] groupNearbyObject;
private int currentUseSkill;
private PlayerController controller;
private AnimationController animation;
// Use this for initialization
void Start () {
controller = this.GetComponent<PlayerController> ();
animation = this.GetComponent<AnimationController>();
}
// Update is called once per frame
void Update () {
}
public void UseSkill(string skillType,int indexSkill)
{
if (skillType=="Attack") {
//爲鎖定攻擊
if (activeSkillAttack[indexSkill].skillType == SkillType.LockTarget)
{
//技能特效
if (activeSkillAttack[indexSkill].skillFX != null)
{
//在目標處生成技能特效
Instantiate(activeSkillAttack[indexSkill].skillFX, controller.target.gameObject.transform.position, Quaternion.identity);
}
//技能音效
if (activeSkillAttack[indexSkill].soundFX != null)
{
//在目標處生成技能音效
AudioSource.PlayClipAtPoint(activeSkillAttack[indexSkill].soundFX, controller.target.gameObject.transform.position);
}
//如果爲鎖定且單體攻擊
if (activeSkillAttack[indexSkill].targetSkill == TargetSkill.SingleTarget)
{
EnemyController enemy;
enemy = controller.target.GetComponent<EnemyController>();
enemy.GetDamage(activeSkillAttack[indexSkill].percentDamage*100, activeSkillAttack[indexSkill].multipleDamage);
}
//如果爲鎖定且羣體攻擊
if (activeSkillAttack[indexSkill].targetSkill == TargetSkill.MultipleTarget)
{
MakeDamage(activeSkillAttack[indexSkill].percentDamage * 100, activeSkillAttack[indexSkill].multipleDamage, activeSkillAttack[indexSkill].skillRange, controller.target.transform);
}
}
//爲無鎖定攻擊
if (activeSkillAttack[indexSkill].skillType == SkillType.FreeTarget)
{
//技能特效
if (activeSkillAttack[indexSkill].skillFX != null)
{
//在目標處生成技能特效
Instantiate(activeSkillAttack[indexSkill].skillFX, transform.position, Quaternion.identity);
}
//技能音效
if (activeSkillAttack[indexSkill].soundFX != null)
{
//在目標處生成技能音效
AudioSource.PlayClipAtPoint(activeSkillAttack[indexSkill].soundFX, transform.position);
}
//爲無鎖定攻擊(默認是羣體傷害)
if (activeSkillAttack[indexSkill].skillType == SkillType.FreeTarget)
{
MakeDamage(activeSkillAttack[indexSkill].percentDamage * 100, activeSkillAttack[indexSkill].multipleDamage, activeSkillAttack[indexSkill].skillRange, this.transform);
}
}
}
}
//返回技能在列表中的下標
public int FindSkillIndex(int skillID)
{
for(int i=0;i<activeSkillAttack.Count;i++)
{
if(skillID == activeSkillAttack[i].skillID)
{
currentUseSkill = i;
return currentUseSkill;
}
}
return 0;
}
//對技能範圍內的enemy造成傷害
public void MakeDamage(float hit, float multipleDamage, float radius,Transform transform)
{
//清空列表
monsterInArea.Clear();
//返回球型半徑之內(包括半徑)的所有碰撞體 collider[]。
groupNearbyObject = Physics.OverlapSphere(transform.position, radius);
foreach (Collider groupObj in groupNearbyObject)
{
//其中是enemy的話 加入列表
if (groupObj.gameObject.tag == Tags.enemy)
monsterInArea.Add(groupObj.transform.gameObject);
}
if (monsterInArea.Count > 0)
{
//對列表中的enemy造成傷害
foreach (GameObject enemy in monsterInArea)
{
EnemyController enemyController;
enemyController = enemy.GetComponent<EnemyController>();
enemyController.GetDamage(hit, multipleDamage);
}
}
}
}
這裏我把普通攻擊也算作一種技能。大概的攻擊流程就是這樣
技能範圍確定
代碼可以參考 上面 MakeDamage()方法,通過在目標位置畫出半徑爲radius的相交球,返回在這個球內的怪物,對其操作就行了
怪物AI
void Update () {
EnemyAnimationState();
Move();
}
public void Move() {
if (target != null)
{
this.transform.LookAt(target.transform.position);
destinationDistance = Vector3.Distance(target.transform.position, this.transform.position);
if (destinationDistance < 1.4f)
{
moveSpeed = 0;
WaitAttack();
}
if (destinationDistance > 1.4f && destinationDistance < 5f)
{
moveSpeed = 2f;
ctrlAnimState = ControlAnimationState.Move;
}
if (destinationDistance > 5f)
{
target = null;
moveSpeed = 0;
ctrlAnimState = ControlAnimationState.Idle;
}
}
總結
//角色自身基礎屬性
[System.Serializable]
public class AttributeBase
{
public int lv, hp, mp, atk, def;//等級,血,藍,攻擊,防禦
public float criticalRate, atkSpd,movespd, exp;//暴擊率,攻速,移速,經驗
}
其次是研究NGUI HUD插件,讓 player和怪物之間攻擊造成的傷害不僅僅侷限在控制檯內,讓血條,和傷害數字顯示在屏幕上,更直觀的呈現!