[英]C# How to make a smooth jump in unity3d without moving the X, towards the nearest object
I would like to make a smooth jump towards the nearest cube. 我想顺利地跳到最近的立方体。 I already have a script to detect the closest cube.
我已经有一个脚本来检测最接近的多维数据集。 I want that the X-axis is locked, so only the Y-axis and the Z-axis change when jumping.
我希望X轴被锁定,所以跳跃时只有Y轴和Z轴会改变。 I would like to use a Jump animation when jumping.
我想在跳跃时使用跳跃动画。 I already tried to use Vector3MoveTowards, but that didn't really work well, maybe I didn't use it properly.
我已经尝试过使用Vector3MoveTowards,但这并不是很好,也许我没有正确使用它。
Detect nearest cube where the player should jump to (C#) 检测玩家应跳至(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; }
The tricky part is that at some cubes you have to jump up (y+1), with some cubes you jump towards the same Y (y+0) and with some cubes you jump down (y-1). 棘手的部分是,在某些多维数据集上,您必须向上跳(y + 1),在某些多维数据集上,您向同一Y(y + 0)跳,而在某些多维数据集上,您跳下(y-1)。 How do I do this?
我该怎么做呢?
Image of how it looks like: 外观如下图:
EDIT: I have this code right now: 编辑:我现在有此代码:
----------------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); }
I calculated the difference in Y-axis between the cube where the player is standing on and the closestCube. 我计算了玩家站立的立方体和最近的立方体之间在Y轴上的差异。 But the Jump() doesn't work.
但是Jump()不起作用。 How do I fix that?
我该如何解决?
Okay I set up a quick version of your game and got what you wanted to work, it is not exactly a quick solution, because what your doing doesn't have built in functionality for other than using animations. 好吧,我为您的游戏设置了一个快速版本,并获得了您想要的功能,但这并不是一个快速的解决方案,因为您所做的工作并没有内置功能,只能使用动画。
Here is the character script that has all the code you need and commented thoroughly so it should explain itself. 这是字符脚本,其中包含您需要的所有代码并进行了彻底注释,因此应自行解释。
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;
}
}
And here is my cube script which has some things you will need to add 这是我的多维数据集脚本,其中包含一些您需要添加的内容
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;
}
}
}
Previous Answer 上一个答案
I would say you need to calculate the perceived position of the object in the future. 我要说的是,您需要计算将来对象的感知位置。
Vector3 futurePos = cubePos + (cubeMoveDirection * cubeMoveSpeed);
Once you have the future position, even if it is not exact, you should aim your animation towards that position. 一旦有了将来的位置,即使位置不准确,也应该将动画对准该位置。 To do this I would have the animation change a speed vector instead of an actual transforms position that way we can rotate this speed vector in any direction you want while keeping the orientation of the block.
为此,我将让动画更改速度矢量而不是实际的变换位置,这样我们就可以在保持块方向的同时,沿所需的任何方向旋转该速度矢量。 Otherwise you have to rotate the entire block to point towards the direction you want.
否则,您必须旋转整个块以指向所需的方向。 If this is what you want then put your block under a empty gameobject, rotate the empty gameobject to point to where you want and do the speed calculations only.
如果这是您想要的,则将您的积木放在一个空的游戏对象下,旋转该空的游戏对象以指向您想要的位置,然后仅进行速度计算。
Next your animation should have a net move vector which should be pre-calculated and scaled down or up to meet the distance to the future position. 接下来,您的动画应具有净移动矢量,该矢量应预先计算并按比例缩小或放大,以适应到未来位置的距离。 It will look something like this(note this is not tested)
它看起来像这样(注意这未经测试)
//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;
Hopefully this does it, like I said I haven't tested it at all so you may have to do some tweaking based on your particular case as this is essentially psuedo-code. 希望可以做到这一点,就像我说过我还没有测试过那样,所以您可能必须根据您的特定情况进行一些调整,因为这本质上是伪代码。
Good luck! 祝好运! I'm off to bed I'll check back when I wake up.
我上床睡觉,醒来后会再检查一次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.