提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、制作一个完整的小骑士冲刺Dash行为
- 1.制作动画以及使用UNITY编辑器编辑
- 2.使用代码实现完整的冲刺行为控制
- 总结
前言
大家又好久不见(虽然就过了半天)这期我决定继续完善小骑士的行为,上一期我们实现了小骑士完整的跳跃降落行为,这一期我们就来做小骑士的冲刺行为,这其中涉及到素材的导入,创建tk2dSprite和tk2dSpriteAnimation,以及代码控制行为等等,难度适中,希望你能够耐心阅读。
一、制作一个完整的小骑士冲刺Dash行为
1.制作动画以及使用UNITY编辑器编辑
我们先把素材导入后,开始回到tk2dspriteEditor中,由于我们第二期就已经制作了小骑士的spritecollection和spriteanimation,所以我们直接把图片拖进去即可。
创建两个动画Dash和Dash To Idle:
2.使用代码实现完整的冲刺行为控制
如果你玩过空洞骑士一段时间,你可能会知道玩家的冲刺时要到苍绿之境中击败大黄蜂才能获得的,所以我们需要一个脚本来记录玩家数据,脚本包含玩家是否拥有某些能力,是否能使用这个能力,就比如这个dash,因此我们要创建PlayerData.cs:
using System;
using System.Collections.Generic;
using System.Reflection;
using GlobalEnums;
using UnityEngine;
[Serializable]
public class PlayerData
{
private static PlayerData _instance;
public static PlayerData instance
{
get
{
if(_instance == null)
{
_instance = new PlayerData();
}
return _instance;
}
set
{
_instance = value;
}
}
public bool hasDash;
public bool canDash;
protected PlayerData()
{
SetupNewPlayerData();
}
public void Reset()
{
SetupNewPlayerData();
}
private void SetupNewPlayerData()
{
hasDash = true; //测试阶段先设置为true方便测试
canDash = true;
}
}
还是先从最简单的音频管理开始吧,只需要创建一个AudioSource并把dash的audioclip拖上去即可
using System.Collections;
using System.Collections.Generic;
using GlobalEnums;
using UnityEngine;
public class HeroAudioController : MonoBehaviour
{
private HeroController heroCtrl;
private void Awake()
{
heroCtrl = GetComponent<HeroController>();
}
[Header("Sound Effects")]
public AudioSource softLanding;
public AudioSource jump;
public AudioSource footStepsRun;
public AudioSource footStepsWalk;
public AudioSource falling;
public AudioSource dash;
private Coroutine fallingCo;
public void PlaySound(HeroSounds soundEffect)
{
if(!heroCtrl.cState.isPaused)
{
switch (soundEffect)
{
case HeroSounds.FOOTSETP_RUN:
if(!footStepsRun.isPlaying && !softLanding.isPlaying)
{
footStepsRun.Play();
return;
}
break;
case HeroSounds.FOOTSTEP_WALK:
if (!footStepsWalk.isPlaying && !softLanding.isPlaying)
{
footStepsWalk.Play();
return;
}
break;
case HeroSounds.SOFT_LANDING:
RandomizePitch(softLanding, 0.9f, 1.1f);
softLanding.Play();
break;
case HeroSounds.JUMP:
RandomizePitch(jump, 0.9f, 1.1f);
jump.Play();
break;
case HeroSounds.DASH:
dash.Play();
break;
case HeroSounds.FALLING:
fallingCo = StartCoroutine(FadeInVolume(falling, 0.7f));
falling.Play();
break;
default:
break;
}
}
}
public void StopSound(HeroSounds soundEffect)
{
if(soundEffect == HeroSounds.FOOTSETP_RUN)
{
footStepsRun.Stop();
return;
}
if (soundEffect == HeroSounds.FOOTSTEP_WALK)
{
footStepsWalk.Stop();
return;
}
switch (soundEffect)
{
case HeroSounds.FALLING:
falling.Stop();
if(fallingCo != null)
{
StopCoroutine(fallingCo);
}
return;
default:
return;
}
}
public void StopAllSounds()
{
softLanding.Stop();
jump.Stop();
falling.Stop();
dash.Stop();
footStepsRun.Stop();
footStepsWalk.Stop();
}
public void PauseAllSounds()
{
softLanding.Pause();
jump.Pause();
falling.Pause();
dash.Pause();
footStepsRun.Pause();
footStepsWalk.Pause();
}
public void UnPauseAllSounds()
{
softLanding.UnPause();
jump.UnPause();
falling.UnPause();
dash.UnPause();
footStepsRun.UnPause();
footStepsWalk.UnPause();
}
/// <summary>
/// 音量淡入线性插值的从0到1
/// </summary>
/// <param name="src"></param>
/// <param name="duration"></param>
/// <returns></returns>
private IEnumerator FadeInVolume(AudioSource src, float duration)
{
float elapsedTime = 0f;
src.volume = 0f;
while (elapsedTime < duration)
{
elapsedTime += Time.deltaTime;
float t = elapsedTime / duration;
src.volume = Mathf.Lerp(0f, 1f, t);
yield return null;
}
}
/// <summary>
/// 随机旋转一个在和之间的pitch的值返回给audiosource
/// </summary>
/// <param name="src"></param>
/// <param name="minPitch"></param>
/// <param name="maxPitch"></param>
private void RandomizePitch(AudioSource src, float minPitch, float maxPitch)
{
float pitch = Random.Range(minPitch, maxPitch);
src.pitch = pitch;
}
/// <summary>
/// 重置audiosource的pitch
/// </summary>
/// <param name="src"></param>
private void ResetPitch(AudioSource src)
{
src.pitch = 1f;
}
}
回到脚本HeroAnimationController.cs中,我们要创建Dash相关动画的代码 管理Dash的动画行为:
using System;
using GlobalEnums;
using UnityEngine;
public class HeroAnimationController : MonoBehaviour
{
private HeroController heroCtrl;
private HeroControllerStates cState;
private tk2dSpriteAnimator animator;
private PlayerData pd;
private bool wasFacingRight;
private bool playRunToIdle;//播放"Run To Idle"动画片段
private bool playDashToIdle; //播放"Dash To Idle"动画片段
private bool changedClipFromLastFrame;
public ActorStates actorStates { get; private set; }
public ActorStates prevActorStates { get; private set; }
private void Awake()
{
heroCtrl = HeroController.instance;
cState = heroCtrl.cState;
animator = GetComponent<tk2dSpriteAnimator>();
}
private void Start()
{
pd = PlayerData.instance;
ResetAll();
actorStates = heroCtrl.hero_state;
if(heroCtrl.hero_state == ActorStates.airborne)
{
animator.PlayFromFrame("Airborne", 7);
return;
}
PlayIdle();
}
private void Update()
{
UpdateAnimation();
if (cState.facingRight)
{
wasFacingRight = true;
return;
}
wasFacingRight = false;
}
private void UpdateAnimation()
{
changedClipFromLastFrame = false;
if (playRunToIdle)
{
Play("Run To Idle");
animator.AnimationCompleted = new Action<tk2dSpriteAnimator, tk2dSpriteAnimationClip>(AnimationCompleteDelegate);
playRunToIdle = false;
}
if (playDashToIdle)
{
Play("Dash To Idle");
//处理animation播放完成后的事件
animator.AnimationCompleted = new Action<tk2dSpriteAnimator, tk2dSpriteAnimationClip>(AnimationCompleteDelegate);
playDashToIdle = false;
}
if (actorStates == ActorStates.no_input)
{
//TODO:
if (cState.dashing)
{
}
}
else if (cState.dashing)
{
Play("Dash"); //通过cState.dashing判断是否播放Dash动画片段
}
else if (actorStates == ActorStates.idle)
{
//TODO:
if (CanPlayIdle())
{
PlayIdle();
}
}
else if (actorStates == ActorStates.running)
{
if (!animator.IsPlaying("Turn"))
{
if (cState.inWalkZone)
{
if (!animator.IsPlaying("Walk"))
{
Play("Walk");
}
}
else
{
PlayRun();
}
}
}
else if (actorStates == ActorStates.airborne)
{
if (cState.jumping)
{
if (!animator.IsPlaying("Airborne"))
{
animator.PlayFromFrame("Airborne", 0);
}
}
else if (cState.falling)
{
if (!animator.IsPlaying("Airborne"))
{
animator.PlayFromFrame("Airborne", 7);
}
}
else if (!animator.IsPlaying("Airborne"))
{
animator.PlayFromFrame("Airborne", 3);
}
}
if (cState.facingRight)
{
if(!wasFacingRight && cState.onGround && CanPlayTurn())
{
Play("Turn");
}
wasFacingRight = true;
}
else
{
if (wasFacingRight && cState.onGround && CanPlayTurn())
{
Play("Turn");
}
wasFacingRight = false;
}
ResetPlays();
}
private void AnimationCompleteDelegate(tk2dSpriteAnimator anim, tk2dSpriteAnimationClip clip)
{
if(clip.name == "Run To Idle")
{
PlayIdle();
}
if(clip.name == "Dash To Idle")
{
PlayIdle();
}
}
private void Play(string clipName)
{
if(clipName != animator.CurrentClip.name)
{
changedClipFromLastFrame = true;
}
animator.Play(clipName);
}