Unity从零开始制作空洞骑士①制作人物的移动跳跃转向以及初始的动画制作

Posted dangoxiba

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity从零开始制作空洞骑士①制作人物的移动跳跃转向以及初始的动画制作相关的知识,希望对你有一定的参考价值。

事情的起因:

  首先我之前在b站的时候突然发现有个大佬说复刻了空洞骑士,点进去一看发现很多场景都福源道非常详细,当时我除了觉得大佬很强的同时也想自己试一下,而且当时对玩家血条设计等都很模糊,就想着问up主,结果因为制作的时间过了很久了,大佬也有些答不上来,于是我就先下来,然后一直跟着其它视频继续学,这几天闲着就试着通过大佬的代码能不能逐步做一个空洞骑士的mod出来,所幸前面的步骤都比较顺利,通过大佬的代码还是能慢慢做出来

(Steam截图镇个楼)

学习目标:

大佬的视频以及Github源码:

【Unity3D】空洞骑士の复刻_哔哩哔哩_bilibili

项目开源:https://github.com/dreamCirno/Hollow-Knight-Imitation


学习内容:

初始工作就先创建一个2D项目,然后本项目需要准备的插件有点多,把没必要的插件删除后就这些了,ProCamera2D,Input system,Post Poccessing,PlayerMaker(这个我没买)

打开开源项目,先别一次性把Assets的项目全部导入,不然肯定一堆报错的,我们先把角色的精灵图导入,然后再拖入几个地板,然后场景就暂时这样了。 

接着我们要为玩家创建动作了。

创建Input Actions命名为InputControl,然后这些都是老操作了。

 

然后就生成一个C#脚本名字就叫InputControl,然后创建一个名字叫InputManger的空对象以及一个同名脚本、

我们暂时只用到GamePlayer的动作表所以就先这样写了。 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InputManager : MonoBehaviour

    private static InputControl inputControl;
    public static InputControl InputControl
    
        get
        
            if(inputControl == null)
            
                inputControl = new InputControl();
            
            return inputControl;
        
    

    private void OnEnable()
    
        InputControl.GamePlayer.Movement.Enable();
        InputControl.GamePlayer.Jump.Enable();
        InputControl.GamePlayer.Attack.Enable();
    

    private void OnDisable()
    
        InputControl.GamePlayer.Movement.Disable();
        InputControl.GamePlayer.Jump.Disable();
        InputControl.GamePlayer.Attack.Disable();
    





 

玩家类脚本:

  我们为我们的Player创建一个名字叫CharacterController2D的脚本。

然后为我们的Player对象添加上组件

2D物理材质如下

首先我们先实现玩家的移动和转向

对于移动我们采用InputSystem对于行为动作的订阅事件和退订事件,用vectorInput读入键盘的输入,

对于转向则根据任务面部朝向,当向右移动的时候transform.localScale为(-1,1,1),向左则为(1,1,1);

using Com.LuisPedroFonseca.ProCamera2D;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class CharacterController2D : MonoBehaviour

    #region Propertries
    readonly Vector3 flippedScale = new Vector3(-1, 1, 1);

    private Rigidbody2D controllerRigibody;

    [Header("依赖脚本")] Animator animator;

    [Header("移动参数")]
    [SerializeField] float maxSpeed = 0.0f;
    [SerializeField] float maxGravityVelocity = 10.0f;
    [SerializeField] float jumpForce = 0.0f;
    [SerializeField] float groundedGravityScale = 0.0f;

    [SerializeField] float jumpGravityScale = 0.0f;
    [SerializeField] float fallGravityScale = 0.0f;

    private Vector2 vectorInput;
    private int jumpCount;
    private bool JumpInput;
    private float counter;

    private bool enableGravity;
    private bool canMove;

    private bool isOnGround;
    private bool isFacingLeft;
    private bool isJumping;
    private bool isFalling;

    private int animatorFirstLandingBool;
    private int animatorGroundedBool;
    private int animatorMovementSpeed;
    private int animatorVelocitySpeed;
    private int animatorJumpTrigger;
    private int animatorDoubleJumpTrigger;

    [Header("其它参数")]
    [SerializeField] private bool firstLanding;

    #endregion

    #region CallBackFunctions
    private void Awake()
    
        controllerRigibody = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
    

    private void OnEnable()
    
        InputManager.InputControl.GamePlayer.Movement.performed += ctx => vectorInput = ctx.ReadValue<Vector2>();
        InputManager.InputControl.GamePlayer.Jump.started += Jump_Started;
        InputManager.InputControl.GamePlayer.Jump.performed += Jump_Performed;
        InputManager.InputControl.GamePlayer.Jump.canceled += Jump_Canceled;
    

    private void OnDisable()
    
        InputManager.InputControl.GamePlayer.Movement.performed -= ctx => vectorInput = ctx.ReadValue<Vector2>();
        InputManager.InputControl.GamePlayer.Jump.started -= Jump_Started;
        InputManager.InputControl.GamePlayer.Jump.performed -= Jump_Performed;
        InputManager.InputControl.GamePlayer.Jump.canceled -= Jump_Canceled;
    

    private void Start()
    
        animatorFirstLandingBool = Animator.StringToHash("FirstLanding");
        animatorGroundedBool = Animator.StringToHash("Grounded");
        animatorVelocitySpeed = Animator.StringToHash("Velocity");
        animatorMovementSpeed = Animator.StringToHash("Movement");
        animatorJumpTrigger = Animator.StringToHash("Jump");
        animatorDoubleJumpTrigger = Animator.StringToHash("DoubleJump");

        animator.SetBool(animatorFirstLandingBool, firstLanding);

        enableGravity = true;
        canMove = true;
    

    private void FixedUpdate()
    
        UpdateVelocity();
        UpdateDirection();

    

    #endregion

    #region Movement

    private void UpdateVelocity()
    
        Vector2 velocity = controllerRigibody.velocity;
        if (vectorInput.x != 0)
        
            velocity.y = Mathf.Clamp(velocity.y, -maxGravityVelocity / 2, maxGravityVelocity / 2);
        
        else
        
            velocity.y = Mathf.Clamp(velocity.y, -maxGravityVelocity, maxGravityVelocity);
        
        animator.SetFloat(animatorVelocitySpeed, controllerRigibody.velocity.y);
        if (canMove)
        
            controllerRigibody.velocity = new Vector2(vectorInput.x * maxSpeed, velocity.y);
            animator.SetInteger(animatorMovementSpeed, (int)vectorInput.x);
        
    

    private void UpdateDirection()
    
        //控制玩家的旋转
        if (controllerRigibody.velocity.x > 1f && isFacingLeft)
        
            isFacingLeft = false;
            transform.localScale = flippedScale;
        
        else if (controllerRigibody.velocity.x < -1f && !isFacingLeft)
        
            isFacingLeft = true;
            transform.localScale = Vector3.one;
        
    

   
    

    private void UpdateGrounding(Collision2D collision,bool exitState)
    
        if (exitState)
        
            if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian") || collision.gameObject.layer == LayerMask.NameToLayer("Soft Terrian"))
            
                isOnGround = false;

            
        
        else
           
//判断为落地状态
            if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian")
                || collision.gameObject.layer == LayerMask.NameToLayer("Soft Terrian")
                && collision.contacts[0].normal == Vector2.up
                && !isOnGround)
            
                isOnGround = true;
                isJumping = false;
                isFalling = false;
            
            //判断为头顶碰到物体状态
            else if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian") || collision.gameObject.layer == LayerMask.NameToLayer("Soft Terrian")
                && collision.contacts[0].normal == Vector2.down && isJumping)
            

            
        
        animator.SetBool(animatorGroundedBool, isOnGround);
    

    public void StopHorizontalMovement()
    
        Vector2 velocity = controllerRigibody.velocity;
        velocity.x = 0;
        controllerRigibody.velocity = velocity;
        animator.SetInteger(animatorMovementSpeed, 0);
    

    public void SetIsOnGrounded(bool state)
    
        isOnGround = state;
        animator.SetBool(animatorGroundedBool, isOnGround);
    
    #endregion

    #region Combat
    private void Jump_Canceled(InputAction.CallbackContext context)
    
        
    

    private void Jump_Performed(InputAction.CallbackContext context)
    
       
    

    private void Jump_Started(InputAction.CallbackContext context)
    
        
    

    private void OnCollisionEnter2D(Collision2D collision)
    
        UpdateGrounding(collision, false);
    

    private void OnCollisionStay2D(Collision2D collision)
    
        UpdateGrounding(collision, false);
    

    private void OnCollisionExit2D(Collision2D collision)
    
        UpdateGrounding(collision, true);
    
    #endregion

    #region Others

    public void FirstLanding()
    

    

    #endregion


接着我们制作动画,制作好Idle,walk,Run的动画

 

 

 

 

 

 

由于我们还没为动画判断条件Grounded作代码判断条件,所以就先创建一个空对象用于地面检测

 

 再给他一个脚本

using UnityEngine;

public class GroundDetector : MonoBehaviour

    private CharacterController2D character;

    private void Awake()
    
        character = FindObjectOfType<CharacterController2D>();
    

    private void OnTriggerEnter2D(Collider2D collision)
    
        if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian"))
        
            character.SetIsOnGrounded(true);
        
    

    private void OnTriggerExit2D(Collider2D collision)
    
        if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian"))
        
            character.SetIsOnGrounded(false);
        
    

 移动的脚本做完了我们还需要做跳跃,跳跃分为一段跳和二段跳,首先打开CharacterController2D,我们将通过跳跃计数器决定播放一段跳或是二段跳的动画,并通过判断条件决定什么时候重置动画

using Com.LuisPedroFonseca.ProCamera2D;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class CharacterController2D : MonoBehaviour

    #region Propertries
    readonly Vector3 flippedScale = new Vector3(-1, 1, 1);

    private Rigidbody2D controllerRigibody;

    [Header("依赖脚本")] Animator animator;

    [Header("移动参数")]
    [SerializeField] float maxSpeed = 0.0f;
    [SerializeField] float maxGravityVelocity = 10.0f;
    [SerializeField] float jumpForce = 0.0f;
    [SerializeField] float groundedGravityScale = 0.0f;

    [SerializeField] float jumpGravityScale = 0.0f;
    [SerializeField] float fallGravityScale = 0.0f;

    private Vector2 vectorInput;
    private int jumpCount;
    private bool JumpInput;
    private float counter;

    private bool enableGravity;
    private bool canMove;

    private bool isOnGround;
    private bool isFacingLeft;
    private bool isJumping;
    private bool isFalling;

    private int animatorFirstLandingBool;
    private int animatorGroundedBool;
    private int animatorMovementSpeed;
    private int animatorVelocitySpeed;
    private int animatorJumpTrigger;
    private int animatorDoubleJumpTrigger;

    [Header("其它参数")]
    [SerializeField] private bool firstLanding;

    #endregion

    #region CallBackFunctions
    private void Awake()
    
        controllerRigibody = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
    

    private void OnEnable()
    
        InputManager.InputControl.GamePlayer.Movement.performed += ctx => vectorInput = ctx.ReadValue<Vector2>();
        InputManager.InputControl.GamePlayer.Jump.started += Jump_Started;
        InputManager.InputControl.GamePlayer.Jump.performed += Jump_Performed;
        InputManager.InputControl.GamePlayer.Jump.canceled += Jump_Canceled;
    

    private void OnDisable()
    
        InputManager.InputControl.GamePlayer.Movement.performed -= ctx => vectorInput = ctx.ReadValue<Vector2>();
        InputManager.InputControl.GamePlayer.Jump.started -= Jump_Started;
        InputManager.InputControl.GamePlayer.Jump.performed -= Jump_Performed;
        InputManager.InputControl.GamePlayer.Jump.canceled -= Jump_Canceled;
    

    private void Start()
    
        animatorFirstLandingBool = Animator.StringToHash("FirstLanding");
        animatorGroundedBool = Animator.StringToHash("Grounded");
        animatorVelocitySpeed = Animator.StringToHash("Velocity");
        animatorMovementSpeed = Animator.StringToHash("Movement");
        animatorJumpTrigger = Animator.StringToHash("Jump");
        animatorDoubleJumpTrigger = Animator.StringToHash("DoubleJump");

        animator.SetBool(animatorFirstLandingBool, firstLanding);

        enableGravity = true;
        canMove = true;
    

    private void FixedUpdate()
    
        UpdateVelocity();
        UpdateJump();
        UpdateDirection();
        UpdateGravityScale();
    

    #endregion

    #region Movement

    private void UpdateVelocity()
    
        Vector2 velocity = controllerRigibody.velocity;
        if (vectorInput.x != 0)
        
            velocity.y = Mathf.Clamp(velocity.y, -maxGravityVelocity / 2, maxGravityVelocity / 2);
        
        else
        
            velocity.y = Mathf.Clamp(velocity.y, -maxGravityVelocity, maxGravityVelocity);
        
        animator.SetFloat(animatorVelocitySpeed, controllerRigibody.velocity.y);
        if (canMove)
        
            controllerRigibody.velocity = new Vector2(vectorInput.x * maxSpeed, velocity.y);
            animator.SetInteger(animatorMovementSpeed, (int)vectorInput.x);
        
    

    private void UpdateDirection()
    
        //控制玩家的旋转
        if (controllerRigibody.velocity.x > 1f && isFacingLeft)
        
            isFacingLeft = false;
            transform.localScale = flippedScale;
        
        else if (controllerRigibody.velocity.x < -1f && !isFacingLeft)
        
            isFacingLeft = true;
            transform.localScale = Vector3.one;
        
    

    private void UpdateJump()
    
        if(isJumping && controllerRigibody.velocity.y < 0)
        
            isFalling = true;
        

        if (JumpInput)
        
            controllerRigibody.AddForce(new Vector2(0,jumpForce), ForceMode2D.Impulse);
            isJumping = true;
        
        if(isOnGround && !isJumping && jumpCount != 0) //如果已经落地了,则重置跳跃计数器
        
            jumpCount = 0;
            counter = Time.time - counter;
        
    

    private void UpdateGravityScale()
    
        var gravityScale = groundedGravityScale;

        if (!isOnGround)
        
            
            gravityScale = controllerRigibody.velocity.y > 0.0f ? jumpGravityScale : fallGravityScale;
        

        if (!enableGravity)
        
            gravityScale = 0;
        

        controllerRigibody.gravityScale = gravityScale;
    

    private void JumpCancel()
    
        JumpInput = false;
        isJumping = false;
        if(jumpCount == 1)
        
            animator.ResetTrigger(animatorJumpTrigger);
        
        else if(jumpCount == 2)
        
            animator.ResetTrigger(animatorDoubleJumpTrigger);
        
    

    private void UpdateGrounding(Collision2D collision,bool exitState)
    
        if (exitState)
        
            if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian") || collision.gameObject.layer == LayerMask.NameToLayer("Soft Terrian"))
            
                isOnGround = false;
            
        
        else
        
            //判断为落地状态
            if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian")
                || collision.gameObject.layer == LayerMask.NameToLayer("Soft Terrian")
                && collision.contacts[0].normal == Vector2.up
                && !isOnGround)
            
                isOnGround = true;
                isJumping = false;
                isFalling = false;
                //effect
            
            //判断为头顶碰到物体状态
            else if (collision.gameObject.layer == LayerMask.NameToLayer("Terrian") || collision.gameObject.layer == LayerMask.NameToLayer("Soft Terrian")
                && collision.contacts[0].normal == Vector2.down && isJumping)
            
                JumpCancel();
            
        
        animator.SetBool(animatorGroundedBool, isOnGround);
    

    public void StopHorizontalMovement()
    
        Vector2 velocity = controllerRigibody.velocity;
        velocity.x = 0;
        controllerRigibody.velocity = velocity;
        animator.SetInteger(animatorMovementSpeed, 0);
    

    public void SetIsOnGrounded(bool state)
    
        isOnGround = state;
        animator.SetBool(animatorGroundedBool, isOnGround);
    
    #endregion

    #region Combat
    private void Jump_Canceled(InputAction.CallbackContext context)
    
        JumpCancel();
    

    private void Jump_Performed(InputAction.CallbackContext context)
    
        JumpCancel();
    

    private void Jump_Started(InputAction.CallbackContext context)
    

        counter = Time.time;
        if(jumpCount <= 1)
        
            ++jumpCount;
            if(jumpCount == 1)
            
                //Anim+Audio
                animator.SetTrigger(animatorJumpTrigger);
            
            else if(jumpCount == 2)
            
                //Anim+Audio+Effect
                animator.SetTrigger(animatorDoubleJumpTrigger);
            
        
        else
        
            return;
        
        JumpInput = true;
    

    private void OnCollisionEnter2D(Collision2D collision)
    
        UpdateGrounding(collision, false);
    

    private void OnCollisionStay2D(Collision2D collision)
    
        UpdateGrounding(collision, false);
    

    private void OnCollisionExit2D(Collision2D collision)
    
        UpdateGrounding(collision, true);
    
    #endregion

    #region Others

    public void FirstLanding()
    

    

    #endregion


 对于动画我们则要创建一个新的动画状态机名字就叫Jump StateMachine

为我们的Jump,Fall,Soft Land,Double Jump添加好动画

 

 

 

接着就是动画连线了。凡是到Jump和DoubleJump都只用Triiger来作为动画转化条件

 

 

 

 

 

 

 

 

 

 

 

 

回到Base状态机中,Walk,Run,Idle的动画到Jump状态机的动画暂时只有Jump和Fall,而且动画条件也都是一模一样的

 

 

 

 

 

 

 

 

 

 

 

 除此之外我们还要为动画添加行为脚本,

由此我们先对部分创建好行为脚本。 

 这些里面大多都是添加音乐和粒子效果所以先不用管,但FallingBehavior则要进行修改

using UnityEngine;

public class FallingBehavior : StateMachineBehaviour

    float lastPositionY;
    float fallDistance;
    CharacterController2D character;

    private void Awake()
    
        //audio
        character = FindObjectOfType<CharacterController2D>();
    

    // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    
        fallDistance = 0;
        animator.SetFloat("FallDistance", fallDistance);

        //auido
    

    // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
    override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    
        if(lastPositionY > character.transform.position.y)
        
            fallDistance += lastPositionY - character.transform.position.y;
        
        lastPositionY = character.transform.position.y;
        animator.SetFloat("FallDistance", fallDistance);
    

    // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    
        //audio
    

    public void ResetAllParams()
    
        lastPositionY = character.transform.position.y;
        fallDistance = 0;
    

 


学习产出:

  参数先随便设计,设计好后效果如图。

 

 

 

 

unity虚拟摇杆

参考技术A 在手机游戏中,虚拟摇杆游戏中的虚拟遥感很常见,先根据自己已经会虚拟摇杆来制作,虚拟摇杆醉主要的核心是

C#部分

2D虚拟摇杆

先弄个自定义的触发事件,然后给每一个需要触发的事件按钮添加,EventTrigget,需要注意的是这个事件要继承unity的接口,

制作unity的摇杆的话,需要继承unity的的UI接口 IBeginDragHandler, IDragHandler, IEndDragHandler,IPointerClickHandler

首先先定义四个委托

    public Action<GameObject, PointerEventData> onBeginDrag;

    public Action<GameObject, PointerEventData> onDrag;

    public Action<GameObject, PointerEventData> onEndDrag;

    public Action<GameObject, PointerEventData> onClick;

其次是重写unity继承的四个接口,把每个委托的回调放进去这些接口函数里面,一但满足条件,委托会执行函数回调方法

public void OnBeginDrag(PointerEventData eventData)   

        if (onBeginDrag != null)

       

            onBeginDrag(gameObject, eventData);

       

   

    public void OnDrag(PointerEventData eventData)

        if (onDrag != null)

       

            onDrag(gameObject, eventData);

       

   

    public void OnEndDrag(PointerEventData eventData)

        if (onEndDrag != null)

       

            onEndDrag(gameObject, eventData);

       

   

    public void OnPointerClick(PointerEventData eventData)

        if (onClick != null)

       

            onClick(gameObject, eventData);

       

   

有了这些委托方法之后,如何使用,这个调用方法,会在初始化注册事件,

public static EventTrigger GetEventCallBack(GameObject obj)

   

        Event trigger = obj.GetComponent<EventTrigger>();

        if (trigger == null)

       

            trigger = obj.AddComponent<EventTrigger>();

       

        return trigger;



创建以一个控制虚拟摇杆StickJoyUI脚本,注册委托事件

        TriggerEvent.Get(bgObj).onBeginDrag = OnDragBegin;

        TriggerEvent.Get(bgObj).onDrag = OnDrag;

        TriggerEvent.Get(bgObj).onEndDrag = OnDragEnd;

        TriggerEvent.Get(transform.Find("changeAttack").gameObject).onClick = OnChangeAttack;

        TriggerEvent.Get(transform.Find("AttackBtn").gameObject).onClick = OnAttackBtn;

再来看看虚拟摇杆部分OnDragBegin OnDrag  OnDragEnd 这个三个方法控制虚拟摇杆,

private void OnDragBegin(GameObject obj, PointerEventData evetData)

   

   

    private void OnDrag(GameObject obj, PointerEventData evetData)

        Vector2 point;

        //ScreenPointToLocalPointInRectangle("需要转换的对象的父级的RectTrasform","鼠标的位置","当前的摄像机","转换后的ui的相对坐标")

       bg为要拖拽的对象的父级对象,里面还有一个小圆PointTf,鼠标的位置取拖拽事件的的position,鼠标的位置取拖拽事件的的摄像机,转

        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(bgTf, evetData.position, evetData.pressEventCamera, out point))   

            //拖动的方向

            Vector2 v = (point - Vector2.zero).normalized;

            x = v.x;

            y = v.y;

            if (Vector2.Distance(point, Vector2.zero) <= R)   

           

                pointTf.anchoredPosition = point;

           

            else     //超出移动的半径

           

                //位置 = 初始位置 + 方向 * 距离

                pointTf.anchoredPosition = Vector2.zero + v * R;

           

       

   

    private void OnDragEnd(GameObject obj, PointerEventData evetData)

   

        pointTf.anchoredPosition = Vector2.zero;

        x = 0;

        y = 0; 

   

Ps:2D角色还需要注意人物朝向问题

只需要把里面的的X值和Y值赋予给他实时更新,然后在写一个Flip方法判断朝向问题,本质是修改一下缩放的X改成相反的值就好了

//朝向

    void Flip()

   

        if (x > 0)

       

            transform.localScale = new Vector3(1, 1, 1);

       

        else if (x < 0)

       

            transform.localScale = new Vector3(-1, 1, 1);

       

   

3D模式:把把X值和Y赋予个移动函数的x值和z值即可

接下用JS实现虚拟摇杆(思路跟上面差不多,但是数据的处理稍有差别而已)

首先引入玩家模块

var Player = require("player");

属性定义

cc.Class(

    extends: cc.Component,

    properties: 

        stickNode:

            default:null,

            type:cc.Node

        ,

        fillNode:

            default:null,

            type:cc.Node

        ,

        skillBtn:

            default:null,

            type:cc.Node

        ,

        player:

            default:null,

            type:Player

        ,

        R:50,

        stick_x:0,

        stick_y:0

    ,

在初始化函数Onlade中注册事件

  onLoad () 

        this.stickNode = cc.find("Stick",this.node);

        this.fillNode = cc.find("Stick/fill",this.node);

        this.skillBtn = cc.find("skillBtn",this.node);

    //注册开始拖拽,拖拽事件,拖拽结束事件,和点击事件,这个更上面的四个接口类似

        this.stickNode.on(cc.Node.EventType.TOUCH_START,this.onTouchStart,this); 

        this.stickNode.on(cc.Node.EventType.TOUCH_MOVE,this.onTouchMove,this);

        this.stickNode.on(cc.Node.EventType.TOUCH_END,this.onTouchEnd,this);

        this.stickNode.on(cc.Node.EventType.TOUCH_CANCEL,this.onTouchCancel,this);

        this.skillBtn.on("click",this.onClickSkillBtn,this);

    ,

  onTouchStart(event)

    

    ,

    onTouchMove(event)

    

        var pos = event.getLocation();//v2类型 坐标系

        //当前这个鼠标的世界坐标转换成当前节点的相对坐标  

        pos = this.stickNode.convertToNodeSpaceAR(pos);

        if(pos.magSqr()<=this.R*this.R)

        

            this.fillNode.setPosition(pos);

        

        else

        

            this.fillNode.x = pos.normalizeSelf().x*this.R;

            this.fillNode.y = pos.normalizeSelf().y*this.R;

          

       this.stick_x = pos.normalizeSelf().x;

        this.stick_y = pos.normalizeSelf().y;

    ,

    onTouchEnd(event)

    

        this.fillNode.x = 0;

        this.fillNode.y = 0;

        this.stick_x = 0;

        this.stick_y = 0;

    ,

    onTouchCancel(event)

    

        this.fillNode.x = 0;

        this.fillNode.y = 0;

        this.stick_x = 0;

        this.stick_y = 0;

    ,

    onClickSkillBtn()

    

        //执行玩家脚本使用技能的方法

        this.player.playSkill();

    

PS:计算上面的pos的方向,  上面为啥半径平方而不是把开方呢??,开方消耗性能,给半径平方两者比较也能比较,相对与前者开方,后者半径平方更加节省性能,采用迂回思路,感觉这种思想有很多地方都用到,就比如前面的浮点数处理,既然有误差,那么我可以放大倍数,然后要使用时候,我再缩小倍数。

以上是关于Unity从零开始制作空洞骑士①制作人物的移动跳跃转向以及初始的动画制作的主要内容,如果未能解决你的问题,请参考以下文章

从零开始做一款Unity3D游戏<三>——编写游戏机制

unity虚拟摇杆

unity3D怎么制作人物模型,说的详细点,刚入门。 悬赏分好说。

求unity3d 用wasd与空格键控制人物移动的代码。

unity人物怎么移动

Unity 3D C#Player移动跳跃错误