【问题标题】:C# How to make a smooth jump in unity3d without moving the X, towards the nearest objectC#如何在unity3d中平滑跳转而不移动X,朝向最近的物体
【发布时间】:2017-01-01 18:28:44
【问题描述】:

我想平稳地跳向最近的立方体。我已经有一个脚本来检测最近的立方体。我希望X轴被锁定,所以跳跃时只有Y轴和Z轴发生变化。我想在跳跃时使用跳跃动画。我已经尝试过使用 Vector3MoveTowards,但效果并不好,可能是我没有正确使用它。

检测玩家应该跳到的最近的立方体 (C#)

void Update()
{
  FindClosestCube ();
  GameObject closestCube = FindClosestCube ();
  Debug.Log (closestCube);
}

GameObject FindClosestCube() {

		GameObject[] gos;
		gos = GameObject.FindGameObjectsWithTag("cube");
		GameObject closest = null;
		float distance = Mathf.Infinity;
		float position = transform.position.z;
		foreach (GameObject go in gos) {
			float diff = go.transform.position.z - position;

			float curDistance = diff;
			if (curDistance < distance) {
				closest = go;
				distance = curDistance;
			}
		}
		return closest;
	}

棘手的部分是,在某些立方体上您必须向上跳 (y+1),在某些立方体上您必须跳向相同的 Y (y+0),而在某些立方体上您必须向下跳 (y-1)。 我该怎么做?

外观图片:

编辑:我现在有这个代码:

	----------------C#-----------------

    Rigidbody rb;
	public int clicks = 0;
	Vector3 target;
	public Animation jumpAnimation;
	bool jump = false;
	float cubeDiffY;
	bool movePlayer;
	public float smoothTime = 0.3f;
	public float yVelocity = 0.0f;

	void Start()
	{
		rb = GetComponent<Rigidbody> ();
	}

	void Update () 
	{
		FindClosestCube ();
		GameObject closestCube = FindClosestCube ();
		Debug.Log ("Closestcube = " + closestCube);					

		target = closestCube.transform.position + new Vector3 (0f, 0.7f, 0f);

		cubeDiffY = target.y - transform.position.y;
		movePlayer = true;

		Debug.Log("Cube Difference Y-axis = " + Mathf.Round(cubeDiffY));

		if (Input.GetMouseButtonDown (0)) 
		{
			clicks += 1;

			jump = true;
			jumpAnimation = gameObject.GetComponent<Animation>();
			//jumpAnimation.Play ();
		}

		if (jump == true) 
		{
			Jump ();
		}
	}

	void Jump()
	{

		float newPosition = Mathf.SmoothDamp (transform.position.y, target.y, ref yVelocity, smoothTime);
		transform.position = new Vector3 (0, newPosition, transform.position.z);
	}

我计算了玩家站立的立方体和最近的立方体在 Y 轴上的差异。但是 Jump() 不起作用。我该如何解决?

【问题讨论】:

  • 这些多维数据集都位于不同的x/y/z 位置。如果不修改x,你不可能在它们之间跳转。
  • 这不是一个编程问题,而是一个物理问题。如果您希望玩家跳到最近的立方体并且下一个立方体相对于玩家的位置没有模式,则必须取起点和目标点,并计算会导致玩家来执行该弧线。
  • 在@Abion47 之后,我建议您查看heretherethis thread
  • Pastebin 页面随机删除,新增一个:pastebin.com/gbwtLU34
  • 我修复了计算玩家站立的立方体和最近的立方体之间的 Y 轴差异的问题。

标签: c# unity3d 3d


【解决方案1】:

好的,我为你的游戏设置了一个快速版本并得到了你想要的工作,这并不是一个快速的解决方案,因为你所做的除了使用动画之外没有内置功能。

这是包含您需要的所有代码并经过彻底注释的字符脚本,因此它应该可以自行解释。

using UnityEngine;

public class Character : MonoBehaviour
{
    //the collider for the player
    private new BoxCollider collider;

    //the jump box collider on a empty game object that is a child to the player object
    public BoxCollider JumpBox;

    //the offset of the cube so it doesn't stop inside of it
    public Vector3 cubeOffset;

    //how high the jump will be
    public float JumpHeight;

    //how fast the jump will be
    public float JumpSpeed;

    //holds the change in position the jump will produce
    private Vector3 jumpDelta;

    //holds the destination cube the jump is attempting to hit
    private Cube destinationCube;

    //true if a jumping animation is currently playing
    private bool jumping = false;

    //used to swap the jump direction from up to down
    private bool jumpDirection = true;

    //used to hold the position of the jump so it knows when to stop
    private float jumpPosition = 0;

    // Use this for initialization
    void Start()
    {
        collider = GetComponent<BoxCollider>();
    }

    // Update is called once per frame
    void Update()
    {
        if(jumping)
        {
            //move straight towards the cube
            transform.position = transform.position + (JumpSpeed * jumpDelta);

            //move up and down to simulate a jump
            //check the current move direction
            if (jumpDirection)
            {
                //add to the jump position twice product of the JumpHeight the JumpSpeed so that it will 
                //rise and fall the same amount of time it takes to move to the destination
                jumpPosition += JumpHeight * JumpSpeed * 2;
                //if it has passed the jump height reverse the jump direction
                if (jumpPosition >= JumpHeight)
                    jumpDirection = !jumpDirection;
                transform.position += transform.up * JumpHeight * JumpSpeed * 2;
            }
            //the jump direction is going down
            else
            {
                jumpPosition -= JumpHeight * JumpSpeed * 2;
                transform.position -= transform.up * JumpHeight * JumpSpeed * 2;
            }
            //check if the character collider intersects witht he cubes collider
            //if it has then stop jumping and set the final position as the destination position
            if (collider.bounds.Intersects(destinationCube.BoxCollider.bounds))
            {
                jumping = false;
                transform.position = destinationCube.transform.position + cubeOffset;
            }
        }
        //detect a jump
        if (Input.GetKeyDown(KeyCode.Space))
        {
            //detect all hits on the jump box
            Collider[] hits = Physics.OverlapBox(JumpBox.center, JumpBox.size * 0.5f);
            //get the closest collider with the right tag
            Collider result = GetClosestColliderWithTag(hits, "Cube");

            //if we have a result then begin the jumping animation
            if(result != null)
            {
                //gets the destination cubes cube component(the custom class you have on your cubes)
                destinationCube = result.gameObject.GetComponent<Cube>();

                //calculate the jump delta
                jumpDelta = (result.transform.position + cubeOffset) - transform.position;

                //remove the left and right components so the jumping doesnt move to the left or right of the player
                Vector3 component = Vector3.Project(jumpDelta, -transform.right);
                jumpDelta -= component;
                component = Vector3.Project(jumpDelta, transform.right);
                jumpDelta -= component;

                //setup the jump animation control fields to the initial values
                jumpPosition = 0;
                jumpDirection = true;
                jumping = true;
            }
        }
    }
    private Collider GetClosestColliderWithTag(Collider[] colliders, string tag)
    {
        //just gets the closest collider
        float distance = float.MaxValue;
        int result = -1;
        for (int i = 0; i < colliders.Length; i++)
        {
            if (colliders[i].tag == tag)
            {
                float distanceTemp = Vector3.Distance(transform.position, colliders[i].transform.position);
                if (distanceTemp < distance)
                {
                    distance = distanceTemp;
                    result = i;
                }
            }
        }
        if (result != -1)
            return colliders[result];
        else return null;
    }
}

这是我的多维数据集脚本,您需要添加一些内容

using UnityEngine;

public class Cube : MonoBehaviour {
    //these arent important just fields I used to set up a quick version of your game
    public GameObject StartPoint;
    public GameObject EndPoint;
    public float Speed;
    private Vector3 directionVector;
    private bool direction;

    //YOU WILL NEED THIS!!
    [HideInInspector]
    public BoxCollider BoxCollider;


    // Use this for initialization
    void Start() {
        //not important
        directionVector = EndPoint.transform.position - StartPoint.transform.position;
        directionVector.Normalize();

        //DONT FORGET TO SET YOUR BOX COLLIDER
        BoxCollider = GetComponent<BoxCollider>();
    }

    // Update is called once per frame
    void Update()
    {
        float distance = 0;
        if (direction)
        {
            distance = Vector3.Distance(EndPoint.transform.position, transform.position);
            transform.position += directionVector * Speed;
            if (distance < Vector3.Distance(EndPoint.transform.position, transform.position))
                direction = !direction;
        }
        else
        {
            distance = Vector3.Distance(StartPoint.transform.position, transform.position);
            transform.position -= directionVector * Speed;
            if (distance < Vector3.Distance(StartPoint.transform.position, transform.position))
                direction = !direction;
        }
    }
}

上一个答案

我会说你需要计算未来物体的感知位置。

Vector3 futurePos = cubePos + (cubeMoveDirection * cubeMoveSpeed);

一旦你有了未来的位置,即使它不准确,你也应该将你的动画对准那个位置。为此,我将让动画更改速度矢量而不是实际的变换位置,这样我们就可以在您想要的任何方向上旋转该速度矢量,同时保持块的方向。否则,您必须旋转整个块以指向您想要的方向。如果这是您想要的,则将您的块放在一个空的游戏对象下,旋转空的游戏对象以指向您想要的位置并仅进行速度计算。

接下来,您的动画应该有一个净移动矢量,该矢量应该预先计算并按比例缩小或放大,以满足到未来位置的距离。它看起来像这样(注意这未经测试)

//class fields
Vector3 AnimatedSpeed;

Vector3 AnimationDelta;

//basic calculation

//get the direction vector from the players current position to the future 
block position

Vector3 dirVector = futurePos - transform.position;
//find the rotation from the current orientation to the direction vector
Quaternion rotation = Quaternion.FromToRotation(transform.forward, dirVector);

//calculate the distance from you to the cube and scale it with the magnitude of the AnimationDelta
float result = Vector3.Distance(transform.position, futurePos);

result = result / animationDelta.magnitude;

//finally rotate the forward vector by the rotation and multiply it by the 
//animation speed and the result to get the step by step movement as
//the animation plays. NOTE: The animation should be based on forward direction

transform.position += (AnimationSpeed * rotation) * result * Time.deltaTime;

希望这样做,就像我说的那样,我根本没有测试过它,所以您可能需要根据您的特定情况进行一些调整,因为这本质上是伪代码。

祝你好运!我去睡觉了,等我醒来再回来看看。

【讨论】:

  • 感谢您的回复。我不明白你说的一些话:“计算未来物体的感知位置。”我已经有了一个脚本来计算每帧最近的立方体。那不一样吗? ''将你的动画对准那个位置。'' 我想让它像 x 轴一样不会改变。只有站在一个移动的立方体上。所以动画应该保持相同的x轴,只有Y和Z应该改变。但是为什么我不使用smoothdamp 作为y?和 z 的 lerp?
  • 我称它为未来物体的感知位置,因为它假设立方体不会改变速度,这只是一个猜测。但是你基本上是在用我放的代码做一个 lerp,如果你愿意,你可以修改它以完成一个平滑的步骤。不会有太多额外的代码
  • 如果你只是想让玩家向前跳跃,那么只需将 z 跳跃高度缩放到最近的立方体的高度,上面的代码可以修改来做到这一点。它只是挑选和选择您更改的轴以及您如何设置动画。试着这样想。你希望 y 轴怎样移动,你希望 z 轴怎样移动?一次只专注于一个。
  • 我查看了代码,但我有点困惑,我不确定这是否是我想要的。动画不是必需的,它只是一个插件。也许我可以使用 Vector3.MoveTowards,但问题是它正在直线移动到最近的立方体,所以它会在立方体的一侧崩溃。我想让 MoveTowards 以曲线(弧)移动,使其落在最近的立方体的顶部。我试图为此找到答案,但找不到答案。也许你知道该怎么做。谢谢!
  • 嘿,对不起,还没有回复,我整个周末都要工作 12 小时,现在正在做一些差事,但是一旦我回到家打开电脑,如果你仍然需要它,我会想出一个解决方案。在向您展示之前,我会进行测试并确保它可以正常工作。如果您仍需要帮助,请告诉我。
猜你喜欢
  • 1970-01-01
  • 2019-06-14
  • 1970-01-01
  • 2014-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多