网站会对特殊的ip做跳转,制作公司网站源代码怎么弄,拼团购物网站怎么做,杭州微网站建设公司提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、通过InControl插件实现绑定玩家输入二、制作小骑士移动和空闲动画 1.制作动画2.玩家移动和翻转图像3.状态机思想实现动画切换总结 前言
好久没来CSDN看看文章写完后目录可以自动生成如何生成可参考右边的帮助文档 文章目录 前言一、通过InControl插件实现绑定玩家输入二、制作小骑士移动和空闲动画 1.制作动画2.玩家移动和翻转图像3.状态机思想实现动画切换总结 前言
好久没来CSDN看看突然看到前两年自己写的文章从零开始制作空洞骑士只做了一篇就突然烂尾了刚好最近开始学习做Unity我决定重启这个项目从零开始制作空洞骑士第一集我们导入了素材和远程git管理项目OK这期我们就从通过InControl插件实现绑定玩家输入以及制作小骑士移动和空闲动画。 一、通过InControl插件实现绑定玩家输入
其实这一部挺难的因为InControl插件你在网上绝对不超过五个视频资料但没办法空洞骑士就是用这个来控制键盘控制器输入的为了原汁原味就只能翻一下InControl提供的Examples示例里学习。
学习完成后直接来看我写的InputHandler.cs和GameManager.cs 在GameManager.cs中我们暂且先只用实现一个单例模式
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class GameManager : MonoBehaviour
{private static GameManager _instance;public static GameManager instance{get{if(_instance null){_instance FindObjectOfTypeGameManager();}if (_instance null){Debug.LogError(Couldnt find a Game Manager, make sure one exists in the scene.);}else if (Application.isPlaying){DontDestroyOnLoad(_instance.gameObject);}return _instance;}}private void Awake(){if(_instance ! this){_instance this;DontDestroyOnLoad(this);return;}if(this ! _instance){Destroy(gameObject);return;}}}在来到InputHandler.cs之前我们还需要创建映射表HeroActions
using System;
using InControl;public class HeroActions : PlayerActionSet
{public PlayerAction left;public PlayerAction right;public PlayerAction up;public PlayerAction down;public PlayerTwoAxisAction moveVector;public HeroActions(){left CreatePlayerAction(Left);left.StateThreshold 0.3f;right CreatePlayerAction(Right);right.StateThreshold 0.3f;up CreatePlayerAction(Up);up.StateThreshold 0.3f;down CreatePlayerAction(Down);down.StateThreshold 0.3f;moveVector CreateTwoAxisPlayerAction(left, right, up, down);moveVector.LowerDeadZone 0.15f;moveVector.UpperDeadZone 0.95f;}
}OK到了最关键的InputHandler.cs了
using System;
using System.Collections;
using System.Collections.Generic;
using GlobalEnums;
using InControl;
using UnityEngine;public class InputHandler : MonoBehaviour
{public InputDevice gameController;public HeroActions inputActions;public void Awake(){inputActions new HeroActions();}public void Start(){MapKeyboardLayoutFromGameSettings();if(InputManager.ActiveDevice ! null InputManager.ActiveDevice.IsAttached){}else{gameController InputDevice.Null;}Debug.LogFormat(Input Device set to {0}., new object[]{gameController.Name});}
//暂时没有GameSettings后续会创建的这里是指将键盘按键绑定到HeroActions 中private void MapKeyboardLayoutFromGameSettings(){AddKeyBinding(inputActions.up, W);AddKeyBinding(inputActions.down, S);AddKeyBinding(inputActions.left, A);AddKeyBinding(inputActions.right, D);}private static void AddKeyBinding(PlayerAction action, string savedBinding){Mouse mouse Mouse.None;Key key;if (!Enum.TryParse(savedBinding, out key) !Enum.TryParse(savedBinding, out mouse)){return;}if (mouse ! Mouse.None){action.AddBinding(new MouseBindingSource(mouse));return;}action.AddBinding(new KeyBindingSource(new Key[]{key}));}}给我们的小骑士创建一个HeroController.cs检测输入最关键的是一行代码
move_input inputHandler.inputActions.moveVector.Vector.x;
using System;
using System.Collections;
using System.Collections.Generic;
using HutongGames.PlayMaker;
using GlobalEnums;
using UnityEngine;public class HeroController : MonoBehaviour
{public ActorStates hero_state;public ActorStates prev_hero_state;public bool acceptingInput true;public float move_input;public float RUN_SPEED 5f;private Rigidbody2D rb2d;private BoxCollider2D col2d;private GameManager gm;private InputHandler inputHandler;private void Awake(){SetupGameRefs();}private void SetupGameRefs(){rb2d GetComponentRigidbody2D();col2d GetComponentBoxCollider2D();gm GameManager.instance;inputHandler gm.GetComponentInputHandler();}void Start(){}void Update(){orig_Update();}private void orig_Update(){if (hero_state ActorStates.no_input){}else if(hero_state ! ActorStates.no_input){LookForInput();}}private void FixedUpdate(){if (hero_state ! ActorStates.no_input){Move(move_input);}}private void Move(float move_direction){if(acceptingInput){rb2d.velocity new Vector2(move_direction * RUN_SPEED, rb2d.velocity.y);}}private void LookForInput(){if (acceptingInput){move_input inputHandler.inputActions.moveVector.Vector.x;}}
}[Serializable]
public class HeroControllerStates
{public bool facingRight;public bool onGround;public HeroControllerStates(){facingRight true;onGround false;}
}记得一句话FixedUpdate()处理物理移动Update()处理逻辑
二、制作小骑士移动和空闲动画
1.制作动画 素材找到Idle和Walk文件夹创建两个同名animationsprite往上面一放自己就做好了。 可能你注意到我没有给这两个动画连线其实是我想做个动画状态机通过核心代码 animator.Play来管理动画的切换。 2.玩家移动和翻转图像
我们还需要给小骑士添加更多的功能比如翻转图像
using System;
using System.Collections;
using System.Collections.Generic;
using HutongGames.PlayMaker;
using GlobalEnums;
using UnityEngine;public class HeroController : MonoBehaviour
{public ActorStates hero_state;public ActorStates prev_hero_state;public bool acceptingInput true;public float move_input;public float RUN_SPEED 5f;private Rigidbody2D rb2d;private BoxCollider2D col2d;private GameManager gm;private InputHandler inputHandler;public HeroControllerStates cState;private HeroAnimatorController animCtrl;private void Awake(){SetupGameRefs();}private void SetupGameRefs(){if (cState null)cState new HeroControllerStates();rb2d GetComponentRigidbody2D();col2d GetComponentBoxCollider2D();animCtrl GetComponentHeroAnimatorController();gm GameManager.instance;inputHandler gm.GetComponentInputHandler();}void Start(){}void Update(){orig_Update();}private void orig_Update(){if (hero_state ActorStates.no_input){}else if(hero_state ! ActorStates.no_input){LookForInput();}}private void FixedUpdate(){if (hero_state ! ActorStates.no_input){Move(move_input);if(move_input 0f !cState.facingRight ){FlipSprite();}else if(move_input 0f cState.facingRight){FlipSprite();}}}private void Move(float move_direction){if (cState.onGround){SetState(ActorStates.grounded);}if(acceptingInput){rb2d.velocity new Vector2(move_direction * RUN_SPEED, rb2d.velocity.y);}}public void FlipSprite(){cState.facingRight !cState.facingRight;Vector3 localScale transform.localScale;localScale.x * -1f;transform.localScale localScale;}private void LookForInput(){if (acceptingInput){move_input inputHandler.inputActions.moveVector.Vector.x;}}/// summary/// 设置玩家的ActorState的新类型/// /summary/// param namenewState/paramprivate void SetState(ActorStates newState){if(newState ActorStates.grounded){if(Mathf.Abs(move_input) Mathf.Epsilon){newState ActorStates.running;}else{newState ActorStates.idle;}}else if(newState ActorStates.previous){newState prev_hero_state;}if(newState ! hero_state){prev_hero_state hero_state;hero_state newState;animCtrl.UpdateState(newState);}}private void OnCollisionEnter2D(Collision2D collision){if(collision.gameObject.layer LayerMask.NameToLayer(Wall)){cState.onGround true;}}private void OnCollisionStay2D(Collision2D collision){if (collision.gameObject.layer LayerMask.NameToLayer(Wall)){cState.onGround true;}}private void OnCollisionExit2D(Collision2D collision){if (collision.gameObject.layer LayerMask.NameToLayer(Wall)){cState.onGround false;}}
}[Serializable]
public class HeroControllerStates
{public bool facingRight;public bool onGround;public HeroControllerStates(){facingRight true;onGround false;}
}创建命名空间GlobalEnums创建一个新的枚举类型
using System;namespace GlobalEnums
{public enum ActorStates{grounded,idle,running,airborne,wall_sliding,hard_landing,dash_landing,no_input,previous}
}3.状态机思想实现动画切换
有了这些我们就可以有效控制动画切换创建一个新的脚本给Player 可以看到我们创建了两个属性记录当前的actorState和上一个actorState来实现动画切换后面会用到的
using System;
using GlobalEnums;
using UnityEngine;public class HeroAnimatorController : MonoBehaviour
{private Animator animator;private AnimatorClipInfo[] info;private HeroController heroCtrl;private HeroControllerStates cState;private string clipName;private float currentClipLength;public ActorStates actorStates { get; private set; }public ActorStates prevActorState { get; private set; }private void Start(){animator GetComponentAnimator();heroCtrl GetComponentHeroController();actorStates heroCtrl.hero_state;PlayIdle();}private void Update(){UpdateAnimation();}private void UpdateAnimation(){//info animator.GetCurrentAnimatorClipInfo(0);//currentClipLength info[0].clip.length;//clipName info[0].clip.name;if(actorStates ActorStates.no_input){//TODO:}else if(actorStates ActorStates.idle){//TODO:PlayIdle();}else if(actorStates ActorStates.running){PlayRun();}}private void PlayRun(){animator.Play(Run);}public void PlayIdle(){animator.Play(Idle);}public void UpdateState(ActorStates newState){if(newState ! actorStates){prevActorState actorStates;actorStates newState;}}
}总结
最后给大伙看看效果怎么样可以看到运行游戏后cStatehero_state和prev_hero_state都没有问题,动画也正常播放 累死我了我去睡个觉顺便上传到githubOK大伙晚安醒来接着更新。