Loading...
墨滴

SimFg

2021/10/27  阅读:46  主题:全栈蓝

游戏中的电梯

公众号:SimFG,期待与你相遇

早上一起床,于是就开始思考怎么样我的游戏可以骗[huo]到[de]更[ge]多[da]钱[jiang]。想实现一个这样的效果:玩家需要从一个平台上移动到另外一个平台上,中间有一个移动平台,只有通过这个移动的平台才可以在进一步游戏。

移动平台

预期的效果:平台可以自动的左右来回移动;

实现:

  • 公共变量:移动速度、平台偏移
  • 私有变量:当前平台偏移、当前移动方向 具体实现:
void Update()
{
    var deltaX = speed * Time.deltaTime;
    if (currentOffset > offset)
    {
        direction = -1.0f;
    }

    if (currentOffset < (-1) * offset)
    {
        direction = 1.0f;
    }

    currentOffset += deltaX * direction;
    transform.position += new Vector3(deltaX * direction, 0, 0);
}

玩家左右移动

预期效果:玩家可以通过左右按键进行操作

实现:

  • 共有变量:速度
  • 私有变量:当前移动方向
void FixedUpdate()
{
    float speed = Input.GetAxisRaw("Horizontal") * Time.deltaTime;
    if (speed != 0.0f)
    {
        direction = speed > 0.0f ? 1.0f : -1.0f;
    }
    rigidBody.velocity = new Vector2(moveSpeed * speed, rigidBody.velocity.y);
}

玩家跳跃

预期效果:点击空格,人物可以向目前移动的方向前方跳跃

实现:

  • 公共变量:水平方向和垂直方向的力

初步方案:在点击Space,直接施加一个斜上方的力

void Update()
{
    if (Input.GetKeyDown(KeyCode.Space))
    {
        isJump = true;
    }
}

void FixedUpdate()
{
    // ... 这部分代码与上面一致
    if(isJump)
    {
        rigidBody.AddForce(new Vector2(backForce * direction, upForce), ForceMode2D.Impulse);
    }
}

运行后就会发现玩家只会往上跳,不会往前跳,尽管施加了一个x方向的力。这个原因分析了一段时间,发现,其实这部分代码和上面移动的代码冲突了,当按键按下时,确实会施加一个向前的力,但是下一帧,因为没有按下移动见,水平方向的速度立马就被改成0了,自然也就只会往上跳。

解决方案也很简单,只需要把移动设置速度的代码放到speed不等于0的if语句内就可以了。

移动平台与玩家交互

预期效果:玩家站在移动平台上,可以跟随平台移动,同时玩家也可以进行移动,就跟生活中我们坐电梯一样

初步方案:当玩家掉落到平台上,这时候给玩家添加移动平台的移动速度。但是与之也会存在问题,因为这个速度其实只能加一次,而且在掉落平台的时候,这个速度要变回来。这个时候可以换一种方法,那就是移动平台对外提供一个方法,返回当前需要添加的速度,在平台上则返回平台移动速度,不在平台上就返回0。玩家的话就直接一直调用这个移动平台的方法就好了。

另外一个小问题,因为上面跳跃的,当speed不等于0的时候,不设置移动速度,那这个时候平台的速度就无法添加上去了,如果直接在speed判断外面添加,这个时候跳跃的部分代码又会失效。这个时候就需要处理下上面的冲突了。

最终方案

关于跳跃这部分,既然不可以一个斜上方的力,那么我们就进行拆解,垂直方向使AddForce,水平方向的移动通过velocity控制,因为移动部分,我们也是通过velocity控制的。另外还有一点需要注意的是:水平方向的velocity,在按下要进行设置,同时也需要在未落地的时候进行设置。

public class SpaceBack : MonoBehaviour
{
    public float moveSpeed;
    public float upForce;
    public float backForce;
    public Transform groundChecker;
    public LayerMask groundLayer;
    private Rigidbody2D rigidBody;
    public bool isGround;
    public bool isJump;
    public float direction = 1.0f;
    public static event Func<float> initSpeedEvent;

    // Start is called before the first frame update
    void Start()
    {
        rigidBody = GetComponent<Rigidbody2D>();
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        isGround = Physics2D.OverlapCircle(groundChecker.position, 0.1f, groundLayer);
        if (isGround)
        {
            isJump = false;
            float speed = Input.GetAxisRaw("Horizontal") * Time.deltaTime;
            if (speed != 0.0f)
            {
                direction = speed > 0.0f ? 1.0f : -1.0f;
            }
            rigidBody.velocity = new Vector2(initSpeedEvent() + moveSpeed * speed, rigidBody.velocity.y);
            if (Input.GetKeyDown(KeyCode.Space))
            {
                isJump = true;
                rigidBody.velocity = new Vector2(backForce * direction, 1f);
                rigidBody.AddForce(new Vector2(0, upForce), ForceMode2D.Impulse);
            }
        }

        if (isJump)
        {
            rigidBody.velocity = new Vector2(backForce * direction, rigidBody.velocity.y);
        }
    }
}

注:对于跳跃的时候,给了一个初始的y方向的velocity,这个主要是为了让无力瞬间脱离地面,这样下一帧在进行isGround检测的时候就是force了,要不然isJump立马就会被置为false。 QQ20211019-214852

可以看到,上面代码中有一个initSpeedEvent属性,这个其实就是一个事件注册,类似于回调。

移动平台的完成代码

public class Transition : MonoBehaviour
{
    public float speed;
    public float offset;
    public LayerMask playerLayer;
    public Rigidbody2D playerRigidBody;
    private float currentOffset;
    private float direction;
    public bool playerCheck;
    public float initSpeed;
    void Start()
    {
        direction = 1.0f;
        SpaceBack.initSpeedEvent += GetInitSpeed;
    }

    // Update is called once per frame
    void Update()
    {
        var deltaX = speed * Time.deltaTime;
        if (currentOffset > offset)
        {
            direction = -1.0f;
        }

        if (currentOffset < (-1) * offset)
        {
            direction = 1.0f;
        }

        currentOffset += deltaX * direction;
        transform.position += new Vector3(deltaX * direction, 0, 0);

        playerCheck = Physics2D.OverlapCircle(transform.position, 1f, playerLayer);
        if (playerCheck)
        {
            initSpeed = direction*speed;
        } else {
            initSpeed = 0f;
        }
    }

    private float GetInitSpeed()
    {
        return initSpeed;
    }

    void OnDrawGizmos() {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(transform.position, 1f);
    }
}

注:上面为了方便演示,检测效果只是一个圆。 QQ20211019-220913 screenshot--222008

SimFg

2021/10/27  阅读:46  主题:全栈蓝

作者介绍

SimFg