更加的跳跃手感在于你如何管理跳跃的速度和高度,让玩家只能跳到他们应该跳到的地方。
在unity里,一般有两种实现跳跃的方式:
第一种是使用unity物理引擎,通常是对一个物体施加一定的力来移动它,让它在重力的作用下再次下降。
第二种是自己使用代码模拟物体的垂直运动,在没有物理引擎的情况下手动让物体跳跃。(这种方法虽然工作量比较大,但是如果想要创建那种非自然的运动,编写自己的跳跃方式,那么这个方法将会很有用)
两种方法的原理仍然是对抗重力向上运动。
一、普遍方法实现
Gravity的y值修改的更大,这样物体受到的重力越大,下落的越快。
注意,这里没有地面检测导致多次按跳跃键可以一直跳跃,不过后面有补充
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//注意,这里没有地面检测导致多次按跳跃键可以一直跳跃,不过后面有补充
public class NormalJump : MonoBehaviour
{
[SerializeField]float jumpForce;
Rigidbody2D rb;
bool isJump;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
isJump = true;
}
}
private void FixedUpdate()
{
if (isJump)
{
Jump();
}
}
void Jump()
{
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
isJump = false;
}
}
补充:通用移动代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HorizontalMove : MonoBehaviour
{
[SerializeField] float moveSpeed;
Rigidbody2D rb;
float horizontalMove;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
horizontalMove = Input.GetAxis("Horizontal");
}
private void FixedUpdate()
{
rb.velocity = new Vector2 (horizontalMove * moveSpeed, rb.velocity.y);
}
}
然而增加物理对象的Gravity Scale会导致快速移动的物体穿过其他物体(比如地面),在接下来的物理更新中导致物体从地面反弹 ,解决方法就是将刚体的碰撞检测模式改为continuous(连续),而不是discrete(离散),这样就能防止它卡在其他物体中,同时更改插值模式,可以实现平滑的物理运动,固定更新位置变化,使得跳跃运动更加流畅。
(2)但是这种方法就会导致其他的游戏物体也会收到影响,而我们又只想对一个物体起作用,那么还有一个方法就是修改该物体的Gravity Scale(重力比例),值越大,受到的重力越大。
许多游戏里面使用跳跃曲线,上升和下降的时间一样长。
但是在某些游戏游戏机制中,玩家上跳的时间比下落的时间长(或者更短),手感和效果也会更佳,这就是接下来我们要实现的功能
接下来只实现上跳的时间比下落的时间长的效果
第一种,用物理引擎实现
用物理效果实现的方式又有很多。但是每个方法的核心都是在物体下落的是否增大它的GravityScale来实现更快速的下落
第一种:物体实现固定的跳跃高度
其中运用到一个物理公式:umpForce = (Mathf.Sqrt(height * gravity * -2)) * mass,由h = 1/2gt方推导
/// <summary>
/// 以固定的高度跳跃
/// </summary>
void JumpWithinHeight()
{
if (Input.GetKeyDown(KeyCode.Space) && isGround)
{
rb.gravityScale = gravityScale;
///jumpForce = (Mathf.Sqrt(height * gravity * -2)) *mass gravity为负数
//计算跳跃到height所需要的力,虽然这种计算方法会有一定的误差,但是总能保证物体固定跳到某一个高度
jumpForce = Mathf.Sqrt(jumpHeight * (Physics2D.gravity.y * rb.gravityScale) * (-2)) * rb.mass;
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
}
if (rb.velocity.y >= 0.1)
{
rb.gravityScale = gravityScale;
}
else
{
rb.gravityScale = fallGravityScale;
}
}
然而,虽然限制跳跃的高度是有用的,但是总是跳到相同的高度会让你在游戏中移动非常困难,所以让玩家根据按下按钮的时间来控制跳跃高度是一个好主意,也就是长按跳跃。
(2)接下来就是实现方法
实现可变跳跃的方法很多,当提前释放按键(或者跳跃时间小于完整跳跃时间),可以直接在物体上升时向物体施加向下的力,或者增大GravityScale,当物体下落又撤销向下的力或者回复原本的GravityScale。
/// <summary>
/// 方法一:根据按键的时间来改变物体的跳跃高度,即长按跳的更高,短按更低
/// 方法二:用一个bool jumpCancelled来记录玩家是否松开按键,松开了就跳的短,没松开就执行完整跳跃
/// </summary>
void JumpByTime()
{
if (Input.GetKeyDown(KeyCode.Space) && isGround)
{
rb.gravityScale = gravityScale;
///jumpForce = (Mathf.Sqrt(height * gravity * -2)) gravity为负数
//计算跳跃到height所需要的力,虽然这种计算方法会有一定的误差,但是总能保证物体固定跳到某一个高度
float jumpForce = Mathf.Sqrt(jumpHeight * (Physics2D.gravity.y * rb.gravityScale) * (-2)) * rb.mass;
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
jumping = true;
buttonPressTime = 0;//重置
}
if (jumping)
{
buttonPressTime += Time.deltaTime;//开始计时
//在上升过程中松开按键
if (buttonPressTime < buttonPressWindow && Input.GetKeyUp(KeyCode.Space))
{
//取消完整的跳跃,减少跳跃轨迹,需要抵消物体已经拥有的向上的动量
//方式一使用GravityScale来使物体上升的更慢,从而达到更低的峰值
rb.gravityScale = fallGravityScale;
}
//玩家开始下落(物体达到高度峰值),完成了完整跳跃
if (rb.velocity.y < 0)
{
jumping = false;//物体开始下落就设置为false
rb.gravityScale = fallGravityScale;
}
}
}
第二种,用非物理引擎实现
在没有物理引擎的作用下,我们不但需要实现物体跳跃向上移动,同时也要创造重力条件。
虽然物体能够跳跃了,但是由于碰撞检测的前提是,碰撞双方都需要有碰撞体,同时至少其中一个物体有rigidbody,但是我们这里跳跃的物体不能够有rigidbody,这就需要我们手动创建物理检测。
实现地面检测的方法很多,方法一就是在不应该跳跃的时候禁用重力作用,方法二就是射线检测,但是射线检测,或者盒检测等,会因为形状,大小不适而使物体在地形边缘处检测不到而掉落。