【问题标题】:Unity2D: Can't balance wall jump forcesUnity2D:无法平衡跳墙力量
【发布时间】:2019-12-17 03:19:18
【问题描述】:

我的目的是让我的角色墙跳/爬/滑,我让滑动部分工作正常,但如果他在滑墙时跳跃,他应该“弹”回墙上,问题是我不能' t 平衡力量。在我看到的所有教程中,这只是检测角色是否在滑动墙壁,如果他在滑动并且他跳跃,那么你在墙壁的对面添加一个力。

这对我不起作用,因为如果我增加足够的力量让他跳起来,他跑得太快了,玩家几乎看不到他跳了,他只是看到角色现在在墙上更高了。如果我增加较小的力,不足以进行相当大的跳跃,玩家必须击中空间一千次才能让他在墙上爬上几厘米。

感谢任何帮助,我已经尝试了很多事情,甚至尝试冻结控件,将重力比例设置为 0 并使用 MoveTowards 使角色 fo 到正确的点,这就是我的绝望。

我对 Unity 也很陌生,所以我可能会遗漏一些非常简单的东西。

这是一个显示角色行为的 gif: https://imgur.com/a/TgUHzP6

这是我角色剧本的相关部分:

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

public class TheBot : MonoBehaviour {

    public float speed;
    public int jumpForce;
    public Transform groundCheck;
    public Transform meleeCheck;
    public Transform bulletSpawner;
    public LayerMask layerGround;
    public float meleeCoolDown;
    public float meleeDamage;

    private Rigidbody2D body;
    private Animator anim;
    private Dash dashController;
    private Shooter shotController;
    private float unloadWaitingTime = 3;
    private float idleGunTime = 0;

    private bool facingRight = true;
    private bool onGround = true;
    private bool jumping = false;
    private bool attacking = false;
    private bool dead = false;
    private bool isGunLoaded = false;
    private bool isGunLoading = false;
    private bool isGunUnloading = false;
    private bool takingDamage = false;
    private bool dashing = false;
    private bool isWallSliding = false;

    private float wallJumpTime = 0f;
    private Vector3[] wallJumpControlPoint;

    // Use this for initialization
    void Start () {
        body = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
        dashController = GetComponent<Dash>();
        shotController = GetComponent<Shooter>();
    }

    // Update is called once per frame
    void Update () {
        PlayAnimations();
        CheckIfGrounded();
        checkIfWallSliding();
        dashing = dashController.IsDashing();

        if (Input.GetButtonDown("Jump") && (onGround || isWallSliding)  && !isGunLoading && !jumping && !takingDamage){
            jumping = true;
            wallJumpControlPoint = new Vector3[3];
            wallJumpControlPoint[0] = body.position;
            wallJumpControlPoint[1] = new Vector3(body.position.x +4, body.position.y + 2);
            wallJumpControlPoint[2] = new Vector3(body.position.x, body.position.y + 4);
        }
        if (Input.GetButtonDown("Melee") && !attacking && !isGunLoading){
            Attack();
        }
        if(Input.GetButtonDown("Ranged") && !attacking  && !isGunLoading && onGround){
            Shoot();
        }

        if(Input.GetButtonDown("Dash") && !attacking && !isGunLoading && onGround){
            dashController.DashTo(facingRight? Dash.RIGHT : Dash.LEFT);
        }


        if(isGunLoaded){
            idleGunTime += Time.deltaTime;
            if (idleGunTime >= unloadWaitingTime){
                UnloadGun();
            }
        }

    }

    void FixedUpdate(){
        if(!takingDamage){

            float move = Input.GetAxis("Horizontal");

            //while charachter is wall sliding, slowly fall
            if (isWallSliding){
                body.velocity = new Vector2(body.velocity.x, -0.7f);
            }

            if(!dashing){
                if(onGround){
                    //if not dashing on on ground, walk with normal speed
                    body.velocity = new Vector2(move * speed, body.velocity.y);
                } else {
                    //if character is not on ground, reduce the speed so he doesn't jump too far away
                    body.velocity = new Vector2(move * (speed * 0.7f), body.velocity.y);
                }
            }

            if((move < 0 && facingRight) || (move > 0 && !facingRight) ){
                //control direction character is facing
                Flip();
            }

            if (jumping){

                if(isWallSliding){
                    body.velocity = new Vector2(30, 20);
                } else {
                    body.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
                }

                if(Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.LeftArrow)){
                    //if is moving while jumping, reduce jump height
                    body.velocity = new Vector2(body.velocity.x, body.velocity.y*0.8f);
                }
                onGround = false;
                jumping = false;
            }       
        }
    }

    void CheckIfGrounded(){
        onGround = false;
        Collider2D[] collisionResults = new Collider2D[2];
        int objectsBeneath = Physics2D.OverlapBoxNonAlloc(groundCheck.position, new Vector2(0.9f, 0.3f), 0.0f, collisionResults, layerGround);
        for (int i=0; i <objectsBeneath; i++ ){
            if (!GameObject.ReferenceEquals(gameObject, collisionResults[i].gameObject)){
                onGround = true;
            }
        }
    }

    void checkIfWallSliding(){
        if (!onGround){
            RaycastHit2D[] ray = new RaycastHit2D[1];
            int totalRayHits = Physics2D.LinecastNonAlloc(bulletSpawner.position, body.position, ray, 1 << LayerMask.NameToLayer("SolidGround"));
            bool wallFound = totalRayHits > 0 && ray[0].collider.gameObject.tag == "SolidGround";

            isWallSliding = wallFound && ( (facingRight && Input.GetKey(KeyCode.RightArrow)) ||  (!facingRight && Input.GetKey(KeyCode.LeftArrow))) ;
        } else {
            isWallSliding = false;
            if (body.velocity.y > 10){
                body.velocity = new Vector2(body.velocity.x, 5);
            }
        }
    }


    public void Die(){
        dead = true;
    }

}

【问题讨论】:

  • 尝试在你的角色上施加更多的垂直力和更少的水平力。此外,您需要确保您添加的他强制具有正确的正或负 x 分量,具体取决于墙与角色的哪个方向。
  • 感谢您的帮助,但我试过了,我认为问题不是力量的大小。如果增加更多的垂直和更少的水平,他仍然跳得太快而看不见,更糟糕的是,如果玩家释放箭头并且没有回到墙上,他会跳到月球,因为。另外,我知道积极/消极的力量,但这种方式更简单。一旦墙跳向一个方向,我将使用正确的力量。
  • 当您在if(isWallSliding){ 中重置y 速度然后AddForce 时会发生什么? body.velocity = new Vector2(body.velocity.x, 0);body.AddForce(new Vector2(0.25 * jumpForce, jumpForce), ForceMode2D.Impulse);
  • 其实你这里为什么要把垂直速度重置为5:body.velocity = new Vector2(body.velocity.x, 5);
  • 当我添加力量时,他只是跳得非常快,就像在 gif 中一样。回答你的第二条评论:我将速度重置为 5,因为我试图设置一个限制速度,以便玩家可以看到角色跳跃,但这不起作用

标签: c# unity3d


【解决方案1】:

正如您之前尝试过的那样,您需要降低跳跃时的水平跳跃加速度/速度。

当你跳墙时,你会压向墙。正如您的代码当前一样,当您在空中时,您的水平速度设置为您按下的方向。这使得从墙壁跳跃的任何水平运动都很难看到,除非它大到足以在一帧中将你推得很远。

这(以及我们在 cmets 中讨论的变化)是为什么您之前尝试低墙跳幅度的尝试没有奏效。

要解决此问题,您必须更改空气控制的工作方式。一种解决方法是让它为您的水平速度添加一个固定的修改器,而不是直接将其设置为目标速度。

if(!dashing){
    if(onGround){
        //if not dashing on on ground, walk with normal speed
        body.velocity = new Vector2(move * speed, body.velocity.y);
    } else {
        //if character is not on ground, reduce the speed so he doesn't jump too far away
        float airControlAccelerationLimit = 0.5f;  // Higher = more responsive air control
        float airSpeedModifier = 0.7f; // the 0.7f in your code, affects max air speed
        float targetHorizVelocity = move 
                * speed 
                * airSpeedModifier;  // How fast we are trying to move horizontally
        float targetHorizChange = targetHorizVelocity 
                - body.velocity.x; // How much we want to change the horizontal velocity
        float horizChange = Mathf.Clamp(
                targetHorizChange ,
                -airControlAccelerationLimit , 
                airControlAccelerationLimit ); // How much we are limiting ourselves 
                                               // to changing the horizontal velocity
        body.velocity = new Vector2(body.velocity.x + horizChange, body.velocity.y);
    }
}

在这里,在您的代码中,同时确保我们只更新速度一次或使用 AddForce 每次 FixedUpdate 调用。我们还将滑墙减速代码更改为仅在玩家即将下降的速度快于滑墙速度时才激活。

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

public class TheBot : MonoBehaviour {

    public float speed;
    public int jumpForce;
    public Transform groundCheck;
    public Transform meleeCheck;
    public Transform bulletSpawner;
    public LayerMask layerGround;
    public float meleeCoolDown;
    public float meleeDamage;

    private Rigidbody2D body;
    private Animator anim;
    private Dash dashController;
    private Shooter shotController;
    private float unloadWaitingTime = 3;
    private float idleGunTime = 0;

    private bool facingRight = true;
    private bool onGround = true;
    private bool jumping = false;
    private bool attacking = false;
    private bool dead = false;
    private bool isGunLoaded = false;
    private bool isGunLoading = false;
    private bool isGunUnloading = false;
    private bool takingDamage = false;
    private bool dashing = false;
    private bool isWallSliding = false;

    private float wallJumpTime = 0f;
    private Vector3[] wallJumpControlPoint;

    // Use this for initialization
    void Start () {
        body = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
        dashController = GetComponent<Dash>();
        shotController = GetComponent<Shooter>();
    }

    // Update is called once per frame
    void Update () {
        PlayAnimations();
        CheckIfGrounded();
        checkIfWallSliding();
        dashing = dashController.IsDashing();

        if (Input.GetButtonDown("Jump") && (onGround || isWallSliding)  && !isGunLoading && !jumping && !takingDamage){
            jumping = true;
            wallJumpControlPoint = new Vector3[3];
            wallJumpControlPoint[0] = body.position;
            wallJumpControlPoint[1] = new Vector3(body.position.x +4, body.position.y + 2);
            wallJumpControlPoint[2] = new Vector3(body.position.x, body.position.y + 4);
        }
        if (Input.GetButtonDown("Melee") && !attacking && !isGunLoading){
            Attack();
        }
        if(Input.GetButtonDown("Ranged") && !attacking  && !isGunLoading && onGround){
            Shoot();
        }

        if(Input.GetButtonDown("Dash") && !attacking && !isGunLoading && onGround){
            dashController.DashTo(facingRight? Dash.RIGHT : Dash.LEFT);
        }


        if(isGunLoaded){
            idleGunTime += Time.deltaTime;
            if (idleGunTime >= unloadWaitingTime){
                UnloadGun();
            }
        }

    }

    void FixedUpdate(){
        if(!takingDamage){

            float move = Input.GetAxis("Horizontal");

            //while charachter is wall sliding, slowly fall
            if (isWallSliding && !jumping && body.velocity.y < -0.7f){ 
                body.velocity = new Vector2(body.velocity.x, -0.7f)
            }

            if(!dashing){
                if(onGround){
                    //if not dashing on on ground, walk with normal speed
                    body.velocity = new Vector2(move * speed, body.velocity.y);
                } else {
                    //if character is not on ground, reduce the speed so he doesn't jump too far away
                    float airControlAccelerationLimit = 0.5f;  // Higher = more responsive air control
                    float airSpeedModifier = 0.7f; // the 0.7f in your code, affects max air speed
                    float targetHorizVelocity = move 
                            * speed 
                            * airSpeedModifier;  // How fast we are trying to move horizontally
                    float targetHorizChange = targetHorizVelocity 
                            - body.velocity.x; // How much we want to change the horizontal velocity
                    float horizChange = Mathf.Clamp(
                            targetHorizChange ,
                            -airControlAccelerationLimit , 
                            airControlAccelerationLimit ); // How much we are limiting ourselves 
                                                           // to changing the horizontal velocity
                    body.velocity = new Vector2(body.velocity.x + horizChange, body.velocity.y);
                }
            }

            if((move < 0 && facingRight) || (move > 0 && !facingRight) ){
                //control direction character is facing
                Flip();
            }

            if (jumping){

                if(isWallSliding){
                    body.velocity = new Vector2(body.velocity.x + 0.25f * jumpForce, jumpForce);
                } else {
                    body.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
                }

                if(Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.LeftArrow)){
                    //if is moving while jumping, reduce jump height
                    body.velocity = new Vector2(body.velocity.x, body.velocity.y*0.8f);
                }
                onGround = false;
                jumping = false;
            }       
        }
    }

    void CheckIfGrounded(){
        onGround = false;
        Collider2D[] collisionResults = new Collider2D[2];
        int objectsBeneath = Physics2D.OverlapBoxNonAlloc(groundCheck.position, new Vector2(0.9f, 0.3f), 0.0f, collisionResults, layerGround);
        for (int i=0; i <objectsBeneath; i++ ){
            if (!GameObject.ReferenceEquals(gameObject, collisionResults[i].gameObject)){
                onGround = true;
            }
        }
    }

    void checkIfWallSliding(){
        if (!onGround){
            RaycastHit2D[] ray = new RaycastHit2D[1];
            int totalRayHits = Physics2D.LinecastNonAlloc(bulletSpawner.position, body.position, ray, 1 << LayerMask.NameToLayer("SolidGround"));
            bool wallFound = totalRayHits > 0 && ray[0].collider.gameObject.tag == "SolidGround";

            isWallSliding = wallFound && ( (facingRight && Input.GetKey(KeyCode.RightArrow)) ||  (!facingRight && Input.GetKey(KeyCode.LeftArrow))) ;
        } else {
            isWallSliding = false;
        }
    }


    public void Die(){
        dead = true;
    }

}

【讨论】:

  • 这不起作用,您编辑了角色刚刚跳跃的部分(抱歉,如果我的代码难以理解)。我尝试在角色从墙上跳下时应用相同的逻辑(在if (jumping){ if(isWallSliding){ 部分),但它也不起作用
  • 我的 cmets 中关于您的问题的代码进入了跳板。这个答案的代码进入你的空气控制块(我留下了最初在你的代码中的 cmets 来显示它的去向)。 “没有工作”是什么意思?它没有编译吗?请更具描述性。
  • 已编译,但角色仍在远离墙壁,要么快得让玩家看不到,要么慢得无法获得足够的动力向上
  • 为了清楚起见,您需要使用 1. 这个答案在您的空气控制代码中的更改,和 2. 在@987654321 中的更改@ 在//while charachter is wall sliding, slowly fall 下方的注释和 3. this comment 中的更改,您在其中检查 if (jumping){ if(isWallSliding){ 之后的跳转
  • @YuriWaki 我编辑了我的答案,将您的代码与我一起推荐的所有更改包括在内,以防我的建议不清楚。如果您有任何问题,请告诉我。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多