Unity 2D游戏开发教程之使用脚本实现游戏逻辑
使用脚本实现游戏逻辑
通过上一节的操作,我们不仅创建了精灵的动画,还设置了动画的过渡条件,最终使得精灵得以按照我们的意愿,进入我们所指定的动画状态。但是这其中还有一些问题。例如,我们无法使用键盘控制精灵当前要进入的动画状态,而且精灵也只是在原地播放动画而已。但我们希望精灵在进入到PlayerWalkingAnimation状态时,位置应该发生改变。
要解决这些问题,就需要编写脚本。也就是说,要使用脚本来实现动画的播放控制,以及其它一些游戏的逻辑。
精灵动画状态的控制
在Project视图里,新建一个文件夹,命名为Scripts,在此文件夹里新建一个C#脚本,命名为PlayerStateController,然后为此脚本添加下面的代码:
- 01 using UnityEngine;
- 02 using System.Collections;
- 03
- 04 public class PlayerStateController : MonoBehaviour
- 05 {
- 06 //定义游戏人物的状态
- 07 public enum playerStates
- 08 {
- 09 idle = 0, //表示空闲
- 10 left, //表示左移
- 11 right, //表示右移
- 12 }
- 13 //定义委托和事件
- 14 public delegate void playerStateHandler(PlayerStateController.playerStates newState);
- 15 public static event playerStateHandler onStateChange;
- 16 void LateUpdate ()
- 17 {
- 18 //获取玩家在键盘上对A、D,或者左、右方向键的输入
- 19 float horizontal = Input.GetAxis("Horizontal");
- 20 if(horizontal != 0.0f)
- 21 {
- 22 //如果按下的是左方向键,则广播左移状态
- 23 if(horizontal < 0.0f)
- 24 {
- 25 if(onStateChange != null)
- 26 onStateChange(PlayerStateController.playerStates.left);
- 27 }
- 28 //如果按下的是右方向键,则广播右移状态
- 29 else
- 30 {
- 31 if(onStateChange != null)
- 32 onStateChange(PlayerStateController.playerStates.right);
- 33 }
- 34 }
- 35 else
- 36 {
- 37 //广播空闲状态
- 38 if(onStateChange != null)
- 39 onStateChange(PlayerStateController.playerStates.idle);
- 40 }
- 41 }
- 42 }
将此脚本赋予Hierarchy视图里的Player对象。对于此脚本,有以下几点需要说明:
- q 脚本07行,定义了名为playerStates的枚举类型,此类型中定义了精灵的具体状态;
- q 脚本19行,会获取玩家在键盘上对指定按键的输入。不同的输入值会直接导致精灵进入不同的游戏状态;
- q 此脚本中定义的是一个可以控制精灵当前所进入动画状态的类,也可以认为是一个管理类型的类,只负责向精灵“发号施令”,具体的实现过程不是这个类要考虑的;
监听精灵当前的动画状态
上一小节里,我们使用脚本,定义了一个用于“发号施令”的类,而本小节将使用脚本定义一个“负责具体执行”的类。
在Project视图里的Scripts文件夹下,新建一个C#脚本,命名为PlayerStateListener,为此脚本添加下面的代码:
- 01 using UnityEngine;
- 02 using System.Collections;
- 03
- 04 [RequireComponent(typeof(Animator))]
- 05 public class PlayerStateListener : MonoBehaviour
- 06 {
- 07 public float playerWalkSpeed = 3f; //表示精灵移动的速度
- 08 private Animator playerAnimator = null; //表示对象上的Animator组件
- 09 //表示精灵当前的动画状态
- 10 private PlayerStateController.playerStates currentState = PlayerStateController.playerStates.idle;
- 11 //对象可用时,加入到订阅者列表中
- 12 void OnEnable()
- 13 {
- 14 PlayerStateController.onStateChange += onStateChange;
- 15 }
- 16 //不可用时,从订阅者列表中退出
- 17 void OnDisable()
- 18 {
- 19 PlayerStateController.onStateChange -= onStateChange;
- 20 }
- 21 void Start()
- 22 {
- 23 //建立与对象上Animator组件的联系
- 24 playerAnimator = GetComponent<Animator>();
- 25 }
- 26 void LateUpdate()
- 27 {
- 28 onStateCycle();
- 29 }
- 30 //用于检测当前所处的动画状态,在不同的状态下将表现出不同的行为
- 31 void onStateCycle()
- 32 {
- 33 //表示当前对象的大小
- 34 Vector3 localScale = transform.localScale;
- 35 //判断当前处于何种状态
- 36 switch(currentState)
- 37 {
- 38 case PlayerStateController.playerStates.idle:
- 39 break;
- 40 //向左移动
- 41 case PlayerStateController.playerStates.left:
- 42 transform.Translate(
- 43 new Vector3((playerWalkSpeed * -1.0f) * Time.deltaTime, 0.0f, 0.0f));
- 44 //角色将转向
- 45 if(localScale.x > 0.0f)
- 46 {
- 47 localScale.x *= -1.0f;
- 48 transform.localScale = localScale;
- 49 }
- 50 break;
- 51 //向右移动
- 52 case PlayerStateController.playerStates.right:
- 53 transform.Translate(new Vector3(playerWalkSpeed * Time.deltaTime, 0.0f, 0.0f));
- 54 //角色将转向
- 55 if(localScale.x < 0.0f)
- 56 {
- 57 localScale.x *= -1.0f;
- 58 transform.localScale = localScale;
- 59 }
- 60 break;
- 61 }
- 62 }
- 63
- 64 //当角色的状态发生改变的时候,调用此函数
- 65 public void onStateChange(PlayerStateController.playerStates newState)
- 66 {
- 67 //如果状态没有发生变化,则无需改变状态
- 68 if(newState == currentState)
- 69 return;
- 70 //判断精灵能否由当前的动画状态,直接转换为另一个动画状态
- 71 if(!checkForValidStatePair(newState))
- 72 return;
- 73 //通过修改Parameter中Walking的值,修改精灵当前的状态
- 74 switch(newState)
- 75 {
- 76 case PlayerStateController.playerStates.idle:
- 77 playerAnimator.SetBool("Walking", false);
- 78 break;
- 79 case PlayerStateController.playerStates.left:
- 80 playerAnimator.SetBool("Walking", true);
- 81 break;
- 82 case PlayerStateController.playerStates.right:
- 83 playerAnimator.SetBool("Walking", true);
- 84 break;
- 85 }
- 86 //记录角色当前的状态
- 87 currentState = newState;
- 88 }
- 89
- 90 //用于确认当前的动画状态能否直接转换为另一动画状态的函数
- 91 bool checkForValidStatePair(PlayerStateController.playerStates newState)
- 92 {
- 93 bool returnVal = false;
- 94 //比较两种动画状态
- 95 switch(currentState)
- 96 {
- 97 case PlayerStateController.playerStates.idle:
- 98 returnVal = true;
- 99 break;
- 100 case PlayerStateController.playerStates.left:
- 101 returnVal = true;
- 102 break;
- 103 case PlayerStateController.playerStates.right:
- 104 returnVal = true;
- 105 break;
- 106 }
- 107 return returnVal;
- 108 }
- 109 }
将此脚本赋予Hierarchy视图里的Player对象,选中后者,然后在Inspector视图里,找到此脚本组件,发现里面有一个属性Player Walk Speed,如图1-31所示。正如属性名的含义,它可以用于设置精灵的移动速度,并且值越大,精灵的移动速度越快。
图1-31 脚本组件,及其属性
对于此脚本,有以下几点需要说明:
- q 脚本10行,说明默认情况下,精灵在游戏开始时,所处的是Idle动画状态;
- q 脚本12、17行定义的方法OnEnable()和OnDisable(),说明只有成为订阅者的对象才会收到动画状态改变的消息;
- q 脚本31行定义的方法onStateCycle(),可以依据精灵当前所处的动画状态,修改精灵在场景中的位置属性。例如,当精灵进入左移的动画状态时,就向左修改场景里精灵的位置;
- q 脚本65行定义的方法onStateChange(),用于真正修改精灵当前所处的动画状态,也就是通过设置Parameters中Walking的值,进而完成的精灵动画状态的切换;
- q 脚本91行定义的方法checkForValidStatePair(),说明动画状态并非可以随意转换,这是为了更加符合逻辑。例如,人可以从“跑”的状态过渡到“跑跳”的状态,但是无法从“走”的状态过渡到“跑跳”的状态。
- q 脚本中44~49、54~59行的代码应该被关注,因为它使得精灵实现了“转身”。为什么这么说呢?因为没有它们的话,精灵会始终朝向一个方向,读者可以注释掉它们并运行程序查看效果。精灵默认在游戏场景里的位置属性,以及显示效果如图1-32所示。如果修改位置属性里Scale在X属性上的值为原来的负数,游戏场景里的精灵就会“转身”,如图1-33所示。
图1-33 Scene和Inspector视图,精灵面朝左
本文选自:Unity 2D游戏开发快速入门大学霸内部资料,转载请注明出处,尊重技术尊重IT人!