在Unity中创建推墙

时间:2017-08-30 17:07:25

标签: c# unity3d

我想在3D游戏中创建一个推墙。这是一个在超级马里奥64推墙的例子

Pushing Walls in Super Mario 64 (Video on Youtube)

Pushing Wall

所以这就是检查员的墙壁外观

Inspector

这是附在推墙上的代码

public class PushingObstacle : MonoBehaviour {

    private Vector3 startPoint; // the current position when loading the scene

    [SerializeField]
    private Vector3 endPoint; // the target point

    [SerializeField]
    private float forwardSpeed; // speed when moving to the end

    [SerializeField]
    private float backwardSpeed; // speed when moving back to start

    float currentSpeed; // the current speed (forward/backward)

    private Vector3 direction; // the direction the wall is moving
    private Vector3 destination; // the target point

    private Rigidbody obstacleRigid; // rigidbody of the wall

    private void Start()
    {
        startPoint = transform.position;
        obstacleRigid = GetComponent<Rigidbody>();
        SetDestination(endPoint); // set the target point
    }

    private void FixedUpdate()
    {
        obstacleRigid.MovePosition(transform.position + direction * currentSpeed * Time.fixedDeltaTime); // start moving

        if (Vector3.Distance(obstacleRigid.position, destination) < currentSpeed * Time.fixedDeltaTime) // set a new target point
            SetDestination(destination == startPoint ? endPoint : startPoint);
    }

    private void SetDestination(Vector3 destinationPoint)
    {
        destination = destinationPoint;
        direction = (destination - transform.position).normalized; // set the movement direction
        currentSpeed = destination == endPoint ? forwardSpeed : backwardSpeed; // set the speed
    }
}

因此,当玩家移动到墙上并稍微接触它时,墙就会飞走。

我可以在运动模式下设置墙体刚体。但我希望墙壁在推动他时给玩家增加一点力量。我怎样才能实现这两种行为(不会飞离玩家并对玩家施加小小的力量)?

修改

我无法将其设置为运动学,因为当跳到墙顶(立方体)时,播放器不会相对于墙移动。

2 个答案:

答案 0 :(得分:2)

这很难。但这是我的解决方案:

  • 为了让推动墙能够推动玩家需要更大的推动力 质量比它。在我的情况下,我设置了墙Mass = 10 以及角色Mass = 1
  • 推动墙是运动学的,不会受到碰撞的影响 与GameObject。
  • 推墙是一个空游戏对象的孩子,它会移动它 无限循环中的前后退。我们需要一个空GameObject所以 孩子跳过平台(并成为它的孩子) 规模不受影响。
  • 空GameObject有一个触发器对撞机,用于检测何时 玩家跳过平台。当发生这种情况时,两个动 地点:

    1. 播放器成为Empty GameObject的子节点并移动
      与平台一起,但同时仍然可以 用键盘输入控制。
    2. 玩家将成为与Plataform一起移动的运动学
  • 当玩家离开平台的顶部时,它就会停止 Emtpy GameObject的孩子并停止运动

    这是选择了Empty GameObject的场景图像,以显示平台顶部的对撞机:

enter image description here

这里是Empty GameObject的检查器

enter image description here

这里是平台的检查员:

enter image description here

这是玩家的检查员:

enter image description here

最后是脚本。

空游戏对象的脚本(用于检测玩家是否在平台上并在场景中放置的两个空游戏对象之间移动平台以确定平台的路径)

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


public class Push : MonoBehaviour {

    public Transform target;
    public Transform end;

    bool movingForward = true;

    float speed = 9f;

    bool moving = false;

    // Update is called once per frame
    void Update () {

        if(movingForward)
         {
            //transform.position = new Vector3(transform.position.x + 0.001f, transform.position.y, transform.position.z);
            float step = speed * Time.deltaTime;
            transform.position = Vector3.MoveTowards(transform.position, target.position, step);

            if(transform.position.Equals(target.position))
                movingForward = false;
         }else{
            float step = speed * Time.deltaTime;
            transform.position = Vector3.MoveTowards(transform.position, end.position, step);

            if(transform.position.Equals(end.position))
                movingForward = true;
         }

    }

    void OnTriggerEnter(Collider other)
    {
        print("Something Inside");
        if(other.tag == "Player")
        {
            print("It is the player");
            other.gameObject.GetComponent<Rigidbody>().isKinematic=true;
            other.gameObject.transform.parent = this.transform;
        }
    }

    void OnTriggerExit(Collider other)
    {
        if(other.tag == "Player")
        {
            other.gameObject.GetComponent<Rigidbody>().isKinematic=false;
            other.gameObject.transform.parent = null;
        }
    }

}

现在移动播放器的脚本

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    public float speed = 6f;
    Vector3 movement;
    Rigidbody playerRigidbody;
    int floorMask;
    float camRaylength = 100f;
    float JumpSpeed = 15f;

    void Awake()
    {
        floorMask = LayerMask.GetMask("Floor");
        playerRigidbody = GetComponent <Rigidbody> ();
    }
    void FixedUpdate()
    {
        float h = Input.GetAxisRaw ("Horizontal");
        float v = Input.GetAxisRaw ("Vertical");

        Move (h, v);
        Turning ();
        if(Input.GetKeyDown(KeyCode.Space))
            Jump();

    }

    void Jump()
    {
        playerRigidbody.isKinematic=false;
        playerRigidbody.AddForce(Vector3.up *JumpSpeed);

    }

    void Move(float h, float v)
    {
        movement.Set(h, 0f, v);

        movement = movement.normalized * speed * Time.deltaTime;

        playerRigidbody.MovePosition (transform.position + movement);
    }

    void Turning()
    {
        Ray camRay = Camera.main.ScreenPointToRay (Input.mousePosition);

        RaycastHit floorHit;

        if (Physics.Raycast (camRay, out floorHit, camRaylength, floorMask)) {

            Vector3 playerToMouse = floorHit.point - transform.position;
            playerToMouse.y = 0f;

            Quaternion newRotation = Quaternion.LookRotation (playerToMouse);
            playerRigidbody.MoveRotation (newRotation);

        }
    }

    void Animating(float h, float v)
    {
        bool walking = h != 0f || v != 0f;

    }

}

测试它并让我知道是否有任何不清楚

答案 1 :(得分:1)

我相信你的问题是由于玩家的质量与墙壁的质量造成的。确保这些值是相互关联的半实际值。如果你的墙的质量为1,那么尝试将你的玩家的质量设置为0.1,因为显然混凝土墙比平均有机生命形式重得多。

此外,Unity论坛对这些类型的问题往往有更好的结果。我不相信这是您的代码的问题,只是提供给正在使用的对象的值的问题。