你如何让一个游戏对象保持在另一个之上?

问题描述

我正在开发 puzzle platformer I made, 的完整版本,您可以在其中切换玩家,在这种情况下(或问题,idk),携带不受控制的其他玩家。

基本上我希望被控制的玩家能够将另一个玩家放在头上,并且仍然能够跳得一样高。在游戏果酱版本中,我只是将刚体质量设置为零,并使速度与其下方的立方体相同。但是现在,如果我这样做,每当我移动时,顶部的玩家就会极快地被甩到周围并传送。不完全是我想要的。

我试过让他们在移动和跳跃时都施加力,但是上面的一个跳到下面的一个,然后他们在空中相遇,上面的一个又跳了起来。我也尝试过使用固定关节,但运动速度太快而且损坏,而且它们结合得很好。我尝试施加更大的力,但顶部的立方体跳得非常高。我就是赢不了。

最重要的是,每当顶部的立方体在空中落到底部的立方体上时,顶部的立方体几乎将底部的立方体猛烈撞击地面 - 它们落得非常快

我想要的是让顶部立方体很好地坐在底部立方体上不要比底部立方体高,只是坐在上面,而不会降低跳跃度,但也很容易被一个方块推开,然后底部的玩家跳到它下面。

EDIT:尝试将多维数据集作为孩子的父母没有用,反而出现了奇怪的故障。

EDIT 2:我用稍微不同的设置尝试了 FixedJoint2D,有时它可以工作,但有时它会无缘无故地中断并且运动很奇怪。就像......你不应该跳那么高。 代码

        //amControlled is true if this is the player that is being controlled.
        if (!amControlled)
        {
            //rayHitGroundLeft and rayHitGroundRight are raycasts off the left side of the bottom side and the right side of the bottom respectively.
            if ((rayHitGroundLeft && rayHitGroundLeft.collider.CompareTag("Player")) || (rayHitGroundRight && rayHitGroundRight.collider.CompareTag("Player")))
            {
                if (!gameObject.TryGetComponent(out FixedJoint2D joint))
                {
                    joint = gameObject.AddComponent<FixedJoint2D>();
                }

                joint.connectedBody = rayHitGroundLeft.rigidbody;
                // See https://docs.unity3d.com/ScriptReference/Joint-breakForce.html
                // this allows the other collisions simply breaking this connection
                joint.breakForce = 100f;
                // Shall these two objects still be able to collide with each other while they are attached?
                // And shall other objects attached to the same body collide with each other?
                joint.enableCollision = true;

                rb.mass = 0f;
            }
            else
            {
                if (gameObject.TryGetComponent(out FixedJoint2D joint))
                {
                    Destroy(joint);
                }
                rb.mass = 1f;
            }
        }

jumping way too high

解决方法

首先禁用所有可以移动顶部对象的功能,例如刚体(使其成为运动学)。 然后你可以将顶部对象作为底部对象的父对象(或者可能是它头部的空或骨骼),就是这样!当您将一个对象作为另一个对象时,父对象将移动子对象。 对于代码中的父级使用“topObject.transform.SetParent(bottomObject.transform)” 对于非父级使用“topObject.transform.SetParent(null)”

,

我认为您想研究FixedJoint

固定关节将对象的移动限制为依赖于另一个对象。这有点类似于 Parenting,但它是通过物理而不是 Transform 层次结构实现的。使用它们的最佳场景是当您想要轻松地将对象分开,或者在没有父级的情况下连接两个对象的运动时。

您可以通过

在运行时轻松附加它
if(!yourObject.TryGetComponent<FixedJoint>(out var joint))
{
    joint = yourObject.AddComponent<FixedJoint>();
}

joint.connectedBody = theBottomObject;
// See https://docs.unity3d.com/ScriptReference/Joint-breakForce.html
// this allows the other collisions simply breaking this connection
joint.breakForce = FORCE_REQUIRED_TO_BREAK_APART;
// Shall these two objects still be able to collide with each other while they are attached?
// And shall other objects attached to the same body collide with each other?
joint.enableCollision = false;

如果你想分离自己,就像设置一样简单

joint.enabled = false;

Destroy(joint);
,

首先需要使用脚本将Top cube转为Kinematic,然后需要Bottom cube的引用来获取它的Rigidbody.position,让TopCube.Rigidbody.position = BottomCube.rigidbody.position + offset,with offset = new vector 3(0,TopCube's height/2 +0.01,0)(+0.01 表示它们不相互重叠)。当你停止进位时,只需将 Top Cube 返回到 Dynamic。

,

我想我已经修好了!花了一段时间 - 实际上是 11 天。基本上,当它在玩家身上时,我让它的速度保持静止(使用 rb.AddForce(new Vector2(rb.velocity.x * -50f,rb.velocity.y * -50f));。我还根据玩家顶部的玩家数量增加了更多的力(通过将跳跃力乘以比玩家多一个)在顶部),我让它在着陆后等待一帧后再跳。这可以防止在跳上和立即跳下更高的平台时跳得更低。基本上我现在要复制相关代码。

isGrounded = false;

        float length = 0.017f;
        float extraDistance = 0.004f;

        RaycastHit2D rayHitGroundLeft = Physics2D.Raycast(new Vector2(boxCollider.bounds.center.x - boxCollider.bounds.extents.x + extraDistance,boxCollider.bounds.center.y - boxCollider.bounds.extents.y - extraDistance),Vector2.down,length,groundMask);
        Debug.DrawRay(new Vector2(boxCollider.bounds.center.x - boxCollider.bounds.extents.x + extraDistance,Vector2.down * length,color);

        RaycastHit2D rayHitGroundRight = Physics2D.Raycast(new Vector2(boxCollider.bounds.center.x + boxCollider.bounds.extents.x - extraDistance,groundMask);
        Debug.DrawRay(new Vector2(boxCollider.bounds.center.x + boxCollider.bounds.extents.x - extraDistance,color);

        RaycastHit2D rayHitCeilingLeft = Physics2D.Raycast(new Vector2(boxCollider.bounds.center.x - boxCollider.bounds.extents.x + extraDistance,boxCollider.bounds.center.y + boxCollider.bounds.extents.y + extraDistance),Vector2.up,Vector2.up * length,color);

        RaycastHit2D rayHitCeilingRight = Physics2D.Raycast(new Vector2(boxCollider.bounds.center.x + boxCollider.bounds.extents.x - extraDistance,color);


        //amControlled is true if this is the player that is being controlled.
        if (!amControlled)
        {
            //rayHitGroundLeft and rayHitGroundRight are raycasts off the left side of the bottom side and the right side of the bottom respectively.
            if ((rayHitGroundLeft && rayHitGroundLeft.collider.CompareTag("Player")) || (rayHitGroundRight && rayHitGroundRight.collider.CompareTag("Player")))
            {
                if (rayHitGroundLeft && rayHitGroundLeft.collider.CompareTag("Player"))
                {
                    rb.AddForce(new Vector2(rb.velocity.x * -50f,rb.velocity.y * -50f));
                    //rb.velocity = new Vector2(0f,0f);
                    //rb.AddForce(rayHitGroundLeft.rigidbody.velocity * 50f);
                }
                if (rayHitGroundRight && rayHitGroundRight.collider.CompareTag("Player"))
                {
                    rb.AddForce(new Vector2(rb.velocity.x * -50f,0f);
                    //rb.AddForce(rayHitGroundRight.rigidbody.velocity * 50f);
                }

                //rb.mass = 0f;

                //rb.velocity = new Vector2(0f,0f);
            }
            else
            {
                if (!((rayHitDownLeft && rayHitDownLeft.collider.CompareTag("Player")) || (rayHitDownRight && rayHitDownRight.collider.CompareTag("Player")) || (rayHitUpLeft && rayHitUpLeft.collider.CompareTag("Player")) || (rayHitUpRight && rayHitUpRight.collider.CompareTag("Player"))))
                {
                    rb.AddForce(new Vector2(rb.velocity.x * -50f,0));
                }
                //rb.AddForce(new Vector2(rb.velocity.x * -50f,0));
            }
        }

        if ((rayHitCeilingLeft && rayHitCeilingLeft.collider.CompareTag("Player")) || (rayHitCeilingRight && rayHitCeilingRight.collider.CompareTag("Player")))
        {
            playersAboveMe = 1;
        }
        else
        {
            playersAboveMe = 0;
        }

        if (amControlled)
        {
            if (Input.GetKey(KeyCode.A))
            {
                horizontal -= 1f;
            }

            if (Input.GetKey(KeyCode.D))
            {
                horizontal += 1f;
            }

            if (Input.GetKey(KeyCode.W) && isGrounded && wasGrounded)
            {
                isJumping = true;
                jumpTimeCounter = jumpTime;
                vertical = 10.4f;
            }
            if (!Input.GetKey(KeyCode.W))
            {
                isJumping = false;
            }
            if (isGrounded)
            {
                jumpTimeCounter = jumpTime;
            }
            if (Input.GetKey(KeyCode.W) && isJumping)
            {
                if (jumpTimeCounter > 0)
                {
                    vertical += 0.7f;
                    jumpTimeCounter -= Time.deltaTime;
                }
                else
                {
                    isJumping = false;
                }
            }

            if (isGrounded && !wasGrounded)
            {

            }

            if (Input.GetKeyUp(KeyCode.W))
            {
                isJumping = false;
                isGrounded = false;
            }

            if (Input.GetKey(KeyCode.S))
            {
                vertical -= 0.3f;
            }
        }

        Vector2 movement = new Vector2(horizontal,vertical);
        if (!(rb.velocity.x > 3f && movement.x > 0) && !(rb.velocity.x < -3f && movement.x < 0))
        {
            rb.AddForce(new Vector2(movement.x * 20f,0f));
        }
        if (!(rb.velocity.y > 5f && movement.y > 0))
        {
            rb.AddForce(new Vector2(0f,movement.y * 20f * (playersAboveMe + 1)));
        }
        if (rb.velocity.y > 5.5f)
        {
            rb.AddForce(new Vector2(0f,rb.velocity.y * -10f));
        }

        if (movement.x == 0 && amControlled)
        {
            rb.AddForce(new Vector2(rb.velocity.x * -50f,0));
        }

        if (movement.x > 0)
        {
            GetComponent<SpriteRenderer>().flipX = false;
        }
        else if (movement.x < 0)
        {
            GetComponent<SpriteRenderer>().flipX = true;
        }

        if (rb.velocity.y < 0)
        {
            rb.velocity += Vector2.up * Physics2D.gravity.y * (fallMultiplier - 1) * Time.deltaTime;
        }

        wasGrounded = isGrounded;

        vertical = 0f;
        horizontal = 0f;