最近加了学校的Nova独游社,本文是社团出的二面题,后续有时间优化下可能会做成一个二维冒险小游戏。本文主要涉及相关代码,参考教程:《勇士传说》横版动作类游戏开发教程
效果演示
【Unity】2D角色跳跃模拟器
主要实现功能:
- 角色移动翻转
- 地图周围空气墙
- 角色跳跃与长按连跳
- 地面判断与连跳限制
- 滑块控制速度与弹跳力
人物素材
人物素材选用的是童年游戏《死神VS火影》中黑崎一护卍解形态,动作分帧图如下,进行扣绿处理后,可以导入到unity中进行自动切图。
本项目目前只用到前三个动作:待机动作、奔跑动作和跳跃动作。
动画关系
动画状态图如图所示,首先进入idol待机状态,播放待机动画,根据角色的速度切换奔跑状态。
任意状态按下空格键,则切换到跳跃状态。跳跃状态使用了混合树,细分成四个状态,jump1
为起跳动作,jump2
为上升动作,jump3
为滞空动作,jump4为落地动作。
角色移动和翻转
角色的移动主要通过读取用户的输入对刚体的位置进行调整,如果输入为反方向,则沿x轴对人物进行翻转,代码如下:
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轴位置。如果按住不松手,则持续执行跳跃,倒计时结束再执行普通跳跃,从而跳的更高,代码如下:
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 Check()
{
isGround = Physics2D.OverlapCircle(transform.position, checkRaduis, groundLayer);
}
滑块控制
滑块传参只需要在游戏的Canvas中设置Slider,在参数面板中绑定相关方法:
相关代码:
public void OnChangeSpeed(float newSpeed)
{
speed = newSpeed * maxSpeed;
}
public void OnChangeJumpForce(float newJumpForce)
{
jumpForce = newJumpForce * maxJumpForce;
}
完整代码
PlayerController.cs
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):当玩家刚刚离开地面几帧时,玩家按下跳跃键仍然可以起跳;包含可以调整大小的野狼时间;
实测发现,只要移动速度和弹跳值合适,手感本身就还不错,因此就没去实现这些有些花哨的设计,不过可以纳入之后拓展的一个考虑范畴。