距离开始写Unity学习笔记已经过去4个月了,回过头来看看写下的笔记,竟然也有个二十多章的积累。可惜国庆回家忘了把练习用的工程文件拷贝到笔记本电脑里,倒是一头栽在Photon Server里研究了好几天。不知道各位同学国庆期间玩的可好,有没有被堵在马路上打网球呢:)
今天准备把之前做的敌人AI部分丰富一下(待命、攻击、死亡、归位、重生),顺便把怪物的模型也一并导进来,加上动画和音效,作为第二版。
▇ 知识点
(GameObjectinstance).SendMessage(),调用当前对象上所有组件上的某个方法;
本章几乎没有新的知识点,只是把以前学过的东西整合起来。看起来代码量有点多,其实还有很多可以精简优化的地方。
▇ 思路
最后一步中的模型可以任意选择,总之完成后记得保存到一个Prefab中,这样就可以快速创建新的怪物了。
▇ EnermyAI.cs
复制代码
▇ Creature.cs
复制代码
▇ CreatureAnimation.cs
复制代码
▇ CreatureSound.cs
复制代码
▇ 实现效果
狼来啦!!!:P
今天准备把之前做的敌人AI部分丰富一下(待命、攻击、死亡、归位、重生),顺便把怪物的模型也一并导进来,加上动画和音效,作为第二版。
▇ 知识点
(GameObjectinstance).SendMessage(),调用当前对象上所有组件上的某个方法;
本章几乎没有新的知识点,只是把以前学过的东西整合起来。看起来代码量有点多,其实还有很多可以精简优化的地方。
▇ 思路
- 新建一个CreatureSound的脚本,由它负责游戏里生物声音的播放;
- 新建一个CreatureAnimation的脚本,由它负责游戏里生物动画的播放;
- 更新已有的Creature脚本,添加Attack和UnderAttack方法,用来控制攻击和被攻击效果;
- 新建一个EnemyAI的脚本,在其中维护一个EnermyState枚举,并在Update中根据这个成员变量来实现不同状态下的行为;
- 新建一个空游戏对象,并重命名为Wolf,为它添加以上四个脚本。导入一个WOW中狼的模型,添加到Wolf中作为子对象;
最后一步中的模型可以任意选择,总之完成后记得保存到一个Prefab中,这样就可以快速创建新的怪物了。
▇ EnermyAI.cs
- using UnityEngine;
- using System.Collections;
-
- [RequireComponent(typeof(CharacterController))]
- [RequireComponent(typeof(Creature))]
- [RequireComponent(typeof(CreatureAnimation))]
- public class EnemyAI : MonoBehaviour
- {
- /// <summary>
- /// 敌人状态
- /// </summary>
- public enum EnermyState
- {
- /// <summary>
- /// 重生
- /// </summary>
- Respawn,
- /// <summary>
- /// 待命
- /// </summary>
- Idle,
- /// <summary>
- /// 攻击
- /// </summary>
- Attack,
- /// <summary>
- /// 逃跑
- /// </summary>
- RunAway,
- /// <summary>
- /// 死亡
- /// </summary>
- Dead,
- /// <summary>
- /// 归位
- /// </summary>
- Homing,
- }
-
- /// <summary>
- /// 移动速度
- /// </summary>
- public float MoveSpeed = 4;
-
- /// <summary>
- /// 旋转速度
- /// </summary>
- public float RotateSpeed = 10;
-
- /// <summary>
- /// 攻击速度
- /// </summary>
- public float AttackSpeed = 1.0f;
-
- /// <summary>
- /// 攻击范围
- /// </summary>
- public float AttackRange = 2.0f;
-
- /// <summary>
- /// 视野距离
- /// </summary>
- public float SightRange = 10.0f;
-
- /// <summary>
- /// 重生时间
- /// </summary>
- public float RespawnTime = 10.0f;
-
- /// <summary>
- /// 状态
- /// </summary>
- public EnermyState State = EnermyState.Idle;
-
- private float mAttackCooldown;
- private float mRespawnTimer;
- private Vector3 mHomePosition;
-
- private Transform mTargetTransform;
- private CharacterController mController;
- private Creature mCreature;
- private CreatureAnimation mCreatureAnimation;
-
- void Awake()
- {
- //初始化
- mTargetTransform = GameManager.Instance.Player.transform;
- mController = GetComponent<CharacterController>();
- mHomePosition = transform.position;
- mCreature = GetComponent<Creature>();
- mCreatureAnimation = GetComponent<CreatureAnimation>();
- }
-
- void Update()
- {
- //攻击冷却计时
- mAttackCooldown -= Time.deltaTime;
- if (mAttackCooldown <= 0)
- mAttackCooldown = 0;
-
- //状态机
- switch (State)
- {
- case EnermyState.Respawn:
- respawn();
- break;
- case EnermyState.Idle:
- idle();
- break;
- case EnermyState.Attack:
- attack();
- break;
- case EnermyState.RunAway:
- break;
- case EnermyState.Dead:
- dead();
- break;
- case EnermyState.Homing:
- homing();
- break;
- default:
- break;
- }
-
- }
-
- private void respawn()
- {
- //重生
- transform.position = mHomePosition;
- mCreature.Health = mCreature.MaxHealth;
- State = EnermyState.Idle;
- }
- private void idle()
- {
- //获取和玩家之间的距离
- var distance = Vector3.Distance(transform.position, mTargetTransform.position);
- if (distance <= SightRange)
- {
- //若在警觉范围内就主动攻击
- State = EnermyState.Attack;
- }
- mCreatureAnimation.PlayIdle();
- }
- private void attack()
- {
- //获取和玩家之间的距离
- var distance = Vector3.Distance(transform.position, mTargetTransform.position);
- if (distance <= AttackRange)
- {
- //在攻击范围内:面朝玩家
- var lookRotation = Quaternion.LookRotation(mTargetTransform.position - transform.position);
- transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, RotateSpeed * Time.deltaTime);
-
- //攻击已冷却:攻击
- if (mAttackCooldown == 0)
- {
- mCreature.Attack(mTargetTransform.GetComponent<Creature>());
- mAttackCooldown = AttackSpeed;
- }
- else
- {
- mCreatureAnimation.PlayAttackReady();
- }
- }
- else if (distance < SightRange)
- {
- //在视野范围内:冲向玩家
- runTo(mTargetTransform.position);
- }
- else
- {
- //超出距离:归位
- State = EnermyState.Homing;
- }
- }
- private void dead()
- {
- //死亡
- if (mRespawnTimer == 0)
- {
- SendMessage("OnDead");
- mCreatureAnimation.PlayDead();
- }
- mRespawnTimer += Time.deltaTime;
- if (mRespawnTimer > RespawnTime)
- {
- //死亡一定时间后重生
- State = EnermyState.Respawn;
- }
- }
- private void homing()
- {
- //归位
- var distance = Vector3.Distance(mHomePosition, transform.position);
- if (distance > 1)
- {
- runTo(mHomePosition);
- }
- else
- {
- State = EnermyState.Idle;
- }
- }
- private void runTo(Vector3 iPosition)
- {
- //移动至指定位置
- mCreatureAnimation.PlayRun();
- var lookRotation = Quaternion.LookRotation(iPosition - transform.position);
- transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, RotateSpeed * Time.deltaTime);
- mController.SimpleMove(lookRotation * Vector3.forward * MoveSpeed);
- }
- }
▇ Creature.cs
- using UnityEngine;
- using System.Collections;
-
- /// <summary>
- /// 生物组件
- /// </summary>
- public class Creature : MonoBehaviour
- {
- /// <summary>
- /// 名称
- /// </summary>
- public string Name;
-
- /// <summary>
- /// 等级
- /// </summary>
- public int Level;
-
- /// <summary>
- /// 攻击力
- /// </summary>
- public int AttackPower;
-
- /// <summary>
- /// 护甲
- /// </summary>
- public int Armor;
-
- /// <summary>
- /// 生命
- /// </summary>
- public float Health;
-
- /// <summary>
- /// 最大生命值
- /// </summary>
- public float MaxHealth;
-
- /// <summary>
- /// 能量
- /// </summary>
- public float Power;
-
- /// <summary>
- /// 最大能量值
- /// </summary>
- public float MaxPower;
-
- /// <summary>
- /// 经验值
- /// </summary>
- public float Exp;
-
- /// <summary>
- /// 最大经验值
- /// </summary>
- public float MaxExp;
-
- /// <summary>
- /// 目标生物
- /// </summary>
- public Creature Target
- {
- get
- {
- return mTarget;
- }
- set
- {
- mTarget = value;
- }
- }
-
- private Creature mTarget;
-
- void Start()
- {
-
- }
-
- void Update()
- {
-
- }
-
- /// <summary>
- /// 攻击目标
- /// </summary>
- /// <param name="iTarget">目标</param>
- public void Attack(Creature iTarget)
- {
- SendMessage("OnAttack");
- iTarget.UnderAttack(this);
- }
-
- /// <summary>
- /// 受到攻击
- /// </summary>
- /// <param name="iSource">攻击来源</param>
- protected void UnderAttack(Creature iSource)
- {
- var damage = iSource.AttackPower - iSource.Armor;
- if (damage <= 0)
- damage = 1;
- Health -= damage;
- Debug.Log(string.Format("{0}->{1} damage={2}", iSource, this, damage));
- SendMessage("OnWounded");
- if (Health <= 0)
- {
- Health = 0;
- SendMessage("OnDead");
- }
- }
- }
▇ CreatureAnimation.cs
- using UnityEngine;
- using System.Collections;
-
- public class CreatureAnimation : MonoBehaviour
- {
- #region AnimationNameSetting
-
- /// <summary>
- /// 待命动画名称
- /// </summary>
- public string IdleAnimationName = "Stand";
-
- /// <summary>
- /// 行走动画名称
- /// </summary>
- public string WalkAnimationName = "Walk";
-
- /// <summary>
- /// 左转动画名称
- /// </summary>
- public string ShuffleLeftAnimationName = "ShuffleLeft";
-
- /// <summary>
- /// 右转动画名称
- /// </summary>
- public string ShuffleRightAnimationName = "ShuffleRight";
-
- /// <summary>
- /// 后退动画名称
- /// </summary>
- public string WalkBackwardAnimationName = "Walkbackwards";
-
- /// <summary>
- /// 跑步动画名称
- /// </summary>
- public string RunAnimationName = "Run";
-
- /// <summary>
- /// 跳跃动画名称
- /// </summary>
- public string JumpStartAnimationName = "JumpStart";
-
- /// <summary>
- /// 跳跃结束继续跑动动画名称
- /// </summary>
- public string JumpLandRunAnimationName = "JumpLandRun";
-
- /// <summary>
- /// 跳跃结束动画名称
- /// </summary>
- public string JumpEndAnimationName = "JumpEnd";
-
- /// <summary>
- /// 游泳待命动画名称
- /// </summary>
- public string SwimIdleAnimationName = "SwimIdle";
-
- /// <summary>
- /// 向左游泳动画名称
- /// </summary>
- public string SwimLeftAnimationName = "SwimLeft";
-
- /// <summary>
- /// 向右游泳动画名称
- /// </summary>
- public string SwimRightAnimationName = "SwimRight";
-
- /// <summary>
- /// 向前游泳动画名称
- /// </summary>
- public string SwimForwardAnimationName = "Swim";
-
- /// <summary>
- /// 后退游泳动画名称
- /// </summary>
- public string SwimBackwardAnimationName = "SwimBackward";
-
- /// <summary>
- /// 下落动画名称
- /// </summary>
- public string FallAnimationName = "Fall";
-
- /// <summary>
- /// 攻击动画名称
- /// </summary>
- public string AttackUnarmedAnimationName = "AttackUnarmed";
-
- /// <summary>
- /// 准备攻击动画名称
- /// </summary>
- public string ReadyUnarmedAnimationName = "ReadyUnarmed";
-
- /// <summary>
- /// 死亡动画名称
- /// </summary>
- public string DeadAnimationName = "Death";
-
- #endregion
-
- /// <summary>
- /// 获取或者设置动画的对象
- /// </summary>
- public Animation AnimationTarget;
-
- /// <summary>
- /// 播放待命状态动画
- /// </summary>
- public void PlayIdle()
- {
- playAnimation(IdleAnimationName);
- }
-
- /// <summary>
- /// 播放左转动画
- /// </summary>
- public void PlayShuffleLeft()
- {
- playAnimation(ShuffleLeftAnimationName);
- }
-
- /// <summary>
- /// 播放右转动画
- /// </summary>
- public void PlayShuffleRight()
- {
- playAnimation(ShuffleRightAnimationName);
- }
-
- /// <summary>
- /// 播放行走动画
- /// </summary>
- public void PlayWalk()
- {
- playAnimation(WalkAnimationName);
- }
-
- /// <summary>
- /// 播放后退动画
- /// </summary>
- public void PlayWalkBackward()
- {
- playAnimation(WalkAnimationName, 0.5f);
- }
-
- /// <summary>
- /// 播放向前游泳的动画
- /// </summary>
- public void PlaySwimForward()
- {
- playAnimation(SwimForwardAnimationName);
- }
-
- /// <summary>
- /// 播放向后游泳的动画
- /// </summary>
- public void PlaySwimBackward()
- {
- playAnimation(SwimBackwardAnimationName);
- }
-
- /// <summary>
- /// 播放游泳待机的动画
- /// </summary>
- public void PlaySwimIdle()
- {
- playAnimation(SwimIdleAnimationName);
- }
-
- /// <summary>
- /// 播放跑步动画
- /// </summary>
- public void PlayRun()
- {
- playAnimation(RunAnimationName);
- }
-
- /// <summary>
- /// 播放跳跃动画
- /// </summary>
- public void PlayJumpStart()
- {
- playAnimation(JumpStartAnimationName, 1.0f, WrapMode.ClampForever);
- }
-
- /// <summary>
- /// 播放跳跃动画
- /// </summary>
- public void PlayJump()
- {
- playAnimation(FallAnimationName);
- }
-
- /// <summary>
- /// 播放跳跃结束后继续奔跑的动画
- /// </summary>
- public void PlayJumpLandRun()
- {
- playAnimation(JumpLandRunAnimationName);
- }
-
- /// <summary>
- /// 播放跳跃结束动画
- /// </summary>
- public void PlayJumpEnd()
- {
- playAnimation(JumpEndAnimationName, 1.0f, WrapMode.ClampForever);
- }
-
- /// <summary>
- /// 播放下落动画
- /// </summary>
- public void PlayFall()
- {
- playAnimation(FallAnimationName);
- }
-
- /// <summary>
- /// 播放攻击等待中的动画
- /// </summary>
- public void PlayAttackReady()
- {
- if (!isPlaying(AttackUnarmedAnimationName))
- playAnimation(IdleAnimationName);
- }
-
- /// <summary>
- /// 播放死亡动画
- /// </summary>
- public void PlayDead()
- {
- playAnimation(DeadAnimationName, 1.0f, WrapMode.ClampForever);
- }
-
- /// <summary>
- /// 获取一个值,表示是否正在播放指定动画
- /// </summary>
- /// <param name="iAnimationName">动画名称</param>
- /// <returns></returns>
- public bool IsPlaying(string iAnimationName)
- {
- return isPlaying(iAnimationName);
- }
-
- /// <summary>
- /// 当生物攻击时调用此方法
- /// </summary>
- public void OnAttack()
- {
- playAnimation(AttackUnarmedAnimationName);
- }
-
- private void playAnimation(string iAnimationName, float iSpeed = 1.0f, WrapMode iWarpMode = WrapMode.Loop)
- {
- //播放指定动画(必须存在且未在播放状态)
- if (AnimationTarget == null)
- throw new MissingReferenceException("AnimationTarget");
- if (string.IsNullOrEmpty(iAnimationName) || AnimationTarget[iAnimationName] == null)
- throw new UnityException(string.Format("The animation state '{0}' could not be played because it couldn't be found!", iAnimationName));
-
- var isPlaying = AnimationTarget.IsPlaying(iAnimationName);
- if (!isPlaying)
- {
- AnimationTarget.wrapMode = iWarpMode;
- AnimationTarget[iAnimationName].speed = iSpeed;
- AnimationTarget.CrossFade(iAnimationName);
- }
- }
- private bool isPlaying(string iAnimationName)
- {
- //获取一个值,表示某个动画是否正在播放
- if (string.IsNullOrEmpty(iAnimationName))
- return false;
- var isPlaying = AnimationTarget.IsPlaying(iAnimationName);
- return isPlaying;
- }
- }
▇ CreatureSound.cs
- using UnityEngine;
- using System.Collections;
-
- [RequireComponent(typeof(AudioSource))]
- public class CreatureSound : MonoBehaviour
- {
- /// <summary>
- /// 攻击音效
- /// </summary>
- public AudioClip AttackClip;
-
- /// <summary>
- /// 受伤音效
- /// </summary>
- public AudioClip WoundedClip;
-
- /// <summary>
- /// 发现敌人音效
- /// </summary>
- public AudioClip ArrgoClip;
-
- /// <summary>
- /// 死亡音效
- /// </summary>
- public AudioClip DeadClip;
-
- private AudioSource mAudioSource;
-
- void Start()
- {
- mAudioSource = GetComponent<AudioSource>();
- mAudioSource.rolloffMode = AudioRolloffMode.Linear;
- }
-
- void Update()
- {
-
- }
-
- /// <summary>
- /// 当生物受到攻击时调用此方法
- /// </summary>
- public void OnAttack()
- {
- playSound(AttackClip);
- }
-
- /// <summary>
- /// 当生物发现目标并进入攻击状态时调用此方法
- /// </summary>
- public void OnArrgo()
- {
- playSound(ArrgoClip);
- }
-
- /// <summary>
- /// 当生物受伤时调用此方法
- /// </summary>
- public void OnWounded()
- {
- playSound(WoundedClip);
- }
-
- /// <summary>
- /// 当生物死亡时调用此方法
- /// </summary>
- public void OnDead()
- {
- playSound(DeadClip);
- }
-
- private void playSound(AudioClip iAudioClip)
- {
- //播放指定声音
- if (iAudioClip == null)
- return;
- mAudioSource.clip = iAudioClip;
- mAudioSource.Play();
- }
- }
▇ 实现效果
2013-4-25 11:02:10 上传
下载附件 (419.99 KB)
狼来啦!!!:P