【Unity】2D角色跳跃控制器

2023-11-06 09:28:14 浏览数 (1)

最近加了学校的Nova独游社,本文是社团出的二面题,后续有时间优化下可能会做成一个二维冒险小游戏。本文主要涉及相关代码,参考教程:《勇士传说》横版动作类游戏开发教程

效果演示

【Unity】2D角色跳跃模拟器

主要实现功能:

  • 角色移动翻转
  • 地图周围空气墙
  • 角色跳跃与长按连跳
  • 地面判断与连跳限制
  • 滑块控制速度与弹跳力

人物素材

人物素材选用的是童年游戏《死神VS火影》中黑崎一护卍解形态,动作分帧图如下,进行扣绿处理后,可以导入到unity中进行自动切图。

本项目目前只用到前三个动作:待机动作、奔跑动作和跳跃动作。

动画关系

动画状态图如图所示,首先进入idol待机状态,播放待机动画,根据角色的速度切换奔跑状态。

任意状态按下空格键,则切换到跳跃状态。跳跃状态使用了混合树,细分成四个状态,jump1为起跳动作,jump2为上升动作,jump3为滞空动作,jump4为落地动作。

角色移动和翻转

角色的移动主要通过读取用户的输入对刚体的位置进行调整,如果输入为反方向,则沿x轴对人物进行翻转,代码如下:

代码语言:javascript复制
void Movement()
  {
      float horizontalmove;//定义变量,当horizontalmove等于-1时向左,等于1时向右,等于0时不动;
      horizontalmove = Input.GetAxis("Horizontal");//绑定输入;
      if (horizontalmove != 0)
      {
          rb.velocity = new Vector2(horizontalmove * speed, rb.velocity.y);//更新速度变量
      }

      float faceDir = transform.localScale.x;

      if (horizontalmove > 0)
          faceDir = (float)0.5;
      if (horizontalmove < 0)
          faceDir = (float)-0.5;

      // 人物翻转
      transform.localScale = new Vector3(faceDir, (float)0.5, (float)0.5);
  }

角色跳跃与长按连跳

角色蓄力跳主要通过计时器实现,按下空格时,倒计时启动,如果秒松开,isJumping设为False,执行普通跳跃,直接调整角色y轴位置。如果按住不松手,则持续执行跳跃,倒计时结束再执行普通跳跃,从而跳的更高,代码如下:

代码语言:javascript复制
void Jump()
{   
    // 普通跳
    if (Input.GetKeyDown(KeyCode.Space) && physicscheck.isGround)
    {
        isJumping = true;
        jumpTimeCounter = jumpTime;
        rb.velocity = new Vector2(rb.velocity.x, jumpForce);
    }
    // 蓄力跳
    if (Input.GetKey(KeyCode.Space) && isJumping == true)
    {
        if(jumpTimeCounter > 0)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumpForce);
            jumpTimeCounter -= Time.deltaTime;
        }
        else
        {
            isJumping = false;
        }
    }
    if (Input.GetKeyUp(KeyCode.Space))
    {
        isJumping = false;
    }
}

地面判断相关代码:

代码语言:javascript复制
public void Check()
{
    isGround = Physics2D.OverlapCircle(transform.position, checkRaduis, groundLayer);
}

滑块控制

滑块传参只需要在游戏的Canvas中设置Slider,在参数面板中绑定相关方法:

相关代码:

代码语言:javascript复制
public void OnChangeSpeed(float newSpeed)
{
    speed = newSpeed * maxSpeed;
}

public void OnChangeJumpForce(float newJumpForce)
{
    jumpForce = newJumpForce * maxJumpForce;
}

完整代码

PlayerController.cs

代码语言:javascript复制
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public Rigidbody2D rb;  //添加Rigidbody

    [Header("基本属性")]
    public float speed = 10;  //速度
    public float jumpForce = 4; //跳跃力度

    private float jumpTimeCounter;
    public float jumpTime;
    private bool isJumping;

    // Slider相关
    private float maxSpeed = 50;
    private float maxJumpForce = 30;

    private PhysicsCheck physicscheck;

    private void Awake()
    {
        physicscheck = GetComponent<PhysicsCheck>();
    }

    // Update is called once per frame
    void Update()
    {
        Movement();//移动
        Jump();
    }

    void Movement()
    {
        float horizontalmove;//定义变量,当horizontalmove等于-1时向左,等于1时向右,等于0时不动;
        horizontalmove = Input.GetAxis("Horizontal");//绑定输入;
        if (horizontalmove != 0)
        {
            rb.velocity = new Vector2(horizontalmove * speed, rb.velocity.y);//更新速度变量
        }

        float faceDir = transform.localScale.x;

        if (horizontalmove > 0)
            faceDir = (float)0.5;
        if (horizontalmove < 0)
            faceDir = (float)-0.5;

        // 人物翻转
        transform.localScale = new Vector3(faceDir, (float)0.5, (float)0.5);

    }

    void Jump()
    {   
        // 普通跳
        if (Input.GetKeyDown(KeyCode.Space) && physicscheck.isGround)
        {
            isJumping = true;
            jumpTimeCounter = jumpTime;
            rb.velocity = new Vector2(rb.velocity.x, jumpForce);
        }
        // 蓄力跳
        if (Input.GetKey(KeyCode.Space) && isJumping == true)
        {
            if(jumpTimeCounter > 0)
            {
                rb.velocity = new Vector2(rb.velocity.x, jumpForce);
                jumpTimeCounter -= Time.deltaTime;
            }
            else
            {
                isJumping = false;
            }
        }
        if (Input.GetKeyUp(KeyCode.Space))
        {
            isJumping = false;
        }
    }
    public void OnChangeSpeed(float newSpeed)
    {
        speed = newSpeed * maxSpeed;
    }

    public void OnChangeJumpForce(float newJumpForce)
    {
        jumpForce = newJumpForce * maxJumpForce;
    }
}

拓展

对于2D平面游戏来说,有的游戏会做更多优化,比如:

  • 跳跃缓冲(Jump Buffer):当玩家即将落地前按下跳跃键时,该次跳跃命令将被缓存,玩家落地后会直接执行缓存的跳跃命令;包含可以调整大小的 缓存时间;
  • 野狼时间(Coyote Time):当玩家刚刚离开地面几帧时,玩家按下跳跃键仍然可以起跳;包含可以调整大小的野狼时间;

实测发现,只要移动速度和弹跳值合适,手感本身就还不错,因此就没去实现这些有些花哨的设计,不过可以纳入之后拓展的一个考虑范畴。

0 人点赞