C#如何在unity3d中平滑跳跃而不将X移向最近的对象 [英] C# How to make a smooth jump in unity3d without moving the X, towards the nearest object

查看:84
本文介绍了C#如何在unity3d中平滑跳跃而不将X移向最近的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想向最近的立方体平滑过渡。我已经有一个脚本来检测最接近的多维数据集。我希望X轴被锁定,所以跳跃时只有Y轴和Z轴会改变。我想在跳跃时使用跳跃动画。我已经尝试过使用Vector3MoveTowards,但是实际上并不能很好地使用它,也许我没有正确使用它。



检测玩家应该在哪个立方体附近跳转到(C#)



  void Update(){FindClosestCube (); GameObject最接近的立方体= FindClosestCube(); Debug.Log(closestCube);} GameObject FindClosestCube(){GameObject [] gos; gos = GameObject.FindGameObjectsWithTag( cube); GameObject最接近= null;浮动距离= Mathf.Infinity;浮动位置= transform.position.z; foreach(GameObject go in gos){float diff = go.transform.position.z-位置; float curDistance = diff;如果(curDistance< distance){最接近=转到;距离= curDistance;返回最接近的; }  



棘手的部分是,在某些立方体上,您必须跳向上(y + 1),对于某些多维数据集,您向着相同的Y(y + 0)跳转,对于某些多维数据集,您向下跳转(y-1)。
我该怎么做?



图片如下:





编辑:我现在有此代码:



  ---------------- C#------------ -----刚体rb;公开内部点击数= 0; Vector3目标;公共动画jumpAnimation; bool jump = false; float cubeDiffY; bool movePlayer;公共浮动smoothTime = 0.3f;公众持股yVelocity = 0.0f; void Start(){rb = GetComponent< Rigidbody> (); } void Update(){FindClosestCube(); GameObject最接近的立方体= FindClosestCube(); Debug.Log( Closestcube = +最近的立方体); target =最近的立方体。变换。位置+新的Vector3(0f,0.7f,0f); cubeDiffY = target.y-transform.position.y; movePlayer = true; Debug.Log( Cube Difference Y-axis = + Mathf.Round(cubeDiffY));如果(Input.GetMouseButtonDown(0)){单击+ = 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 =新的Vector3(0,newPosition,transform.position.z); }  



我计算了两个立方体之间的Y轴差玩家站在最接近的立方体上。但是Jump()无效。如何解决该问题?

解决方案

好吧,我为您的游戏设置了一个快速版本,得到了您想要的作品,它并不是一种快速的解决方案,因为您所做的事情除了使用动画之外还没有内置功能。<​​/ p>

这是包含您所有代码的字符脚本

 使用UnityEngine; 

公共类角色:MonoBehaviour
{
//玩家的对撞机
新的BoxCollider私人对撞机;

//空游戏对象上的跳转框对撞器,该空游戏对象是玩家对象的子级。
public BoxCollider JumpBox;

//立方体的偏移量,这样它就不会在其中停止
public Vector3 cubeOffset;

//跳高到
公众浮动JumpHeight;

//跳转的速度有多快
public float JumpSpeed;

//保持跳转的位置变化将产生
私有Vector3 jumpDelta;

//保存跳转试图到达
私有多维数据集destinationCube的目标多维数据集;

//如果当前正在播放跳跃动画,则为true;
私人布尔跳跃= false;

//用于将跳转方向从上到下
私人布尔jumpDirection = true;

//用于保持跳转的位置,以便知道何时停止
private float jumpPosition = 0;

//用于初始化
void Start()
{
collider = GetComponent< BoxCollider>();
}

//每帧调用一次更新
void Update()
{
if(jump)
{
//直接移至立方体
transform.position = transform.position +(JumpSpeed * jumpDelta);

//上下移动以模拟跳跃
//检查当前移动方向
if(jumpDirection)
{
//添加到跳转位置JumpHeight的两倍乘积JumpSpeed的速度,以便它将
//上升和下降到移动到目标
所需的时间相同jumpPosition + = JumpHeight * JumpSpeed * 2;
//如果它已超过跳转高度,则反向跳转方向
if(jumpPosition> = JumpHeight)
jumpDirection =!jumpDirection;
transform.position + = transform.up * JumpHeight * JumpSpeed * 2;
}
//跳转方向下降
否则
{
jumpPosition-= JumpHeight * JumpSpeed * 2;
transform.position-= transform.up * JumpHeight * JumpSpeed * 2;
}
//检查角色碰撞器是否与立方体碰撞器碰撞
//如果它随后停止跳跃并将最终位置设置为目标位置
if(碰撞器。 bounds.Intersects(destinationCube.BoxCollider.bounds))
{
跳跃=假;
transform.position = destinationCube.transform.position + cubeOffset;
}
}
//如果(Input.GetKeyDown(KeyCode.Space))
{
//检测到所有点击跳箱
Collider []命中= Physics.OverlapBox(JumpBox.center,JumpBox.size * 0.5f);
//获得带有正确标签的最近对撞机
对撞机结果= GetClosestColliderWithTag(hits, Cube);

//如果有结果,然后开始跳跃动画
if(result!= null)
{
//获取目标多维数据集多维数据集组件(多维数据集上具有的自定义类)
destinationCube = result.gameObject.GetComponent< Cube>();

//计算跳跃增量
jumpDelta =(result.transform.position + cubeOffset)-transform.position;

//删除左右组件,使跳跃不会向玩家的左边或右边移动。
Vector3 component = Vector3.Project(jumpDelta,-transform.right);
jumpDelta-=组件;
component = Vector3.Project(jumpDelta,transform.right);
jumpDelta-=组件;

//将跳转动画控制字段设置为初始值
jumpPosition = 0;
jumpDirection = true;
jump = true;
}
}
}
私人对撞机GetClosestColliderWithTag(Collider []对撞机,字符串标签)
{
//只获取最近的对撞机
浮点距离= float.MaxValue;
int结果= -1;
for(int i = 0; i {
if(colliders [i] .tag ==标签)
{
float distanceTemp = Vector3.Distance(transform.position,colliders [i] .transform.position);
if(distanceTemp< distance)
{
distance = distanceTemp;
结果= i;
}
}
}
if(结果!= -1)
return colliders [result];
else返回null;
}
}

这是我的多维数据集脚本,其中包含一些内容将需要使用UnityEngine添加

 

公共类Cube:MonoBehaviour {
//这些最近的重要字段我用来设置游戏的快速版本
public GameObject StartPoint;
public GameObject EndPoint;
公众持股速度;
private Vector3 directionVector;
私人布尔指导;

//您将需要这个!
[HideInInspector]
public BoxCollider BoxCollider;


//用于初始化
void Start(){
//不重要
directionVector = EndPoint.transform.position-StartPoint.transform 。位置;
directionVector.Normalize();

//不要忘记设置邮箱收藏家
BoxCollider = GetComponent< BoxCollider>();
}

//每帧调用一次更新
void Update()
{
float distance = 0;
if(direction)
{
distance = Vector3.Distance(EndPoint.transform.position,transform.position);
transform.position + = directionVector *速度;
if(距离< Vector3.Distance(EndPoint.transform.position,transform.position))
direction =!direction;
}
else
{
distance = Vector3.Distance(StartPoint.transform.position,transform.position);
transform.position-= directionVector *速度;
if(距离< Vector3.Distance(StartPoint.transform.position,transform.position)))
direction =!direction;
}
}
}

上一个答案



我想说的是,您需要计算对象在将来的感知位置。

  Vector3 futurePos = cubePos +(cubeMoveDirection * cubeMoveSpeed); 

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



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

  // class字段
Vector3 AnimatedSpeed;

Vector3 AnimationDelta;

//基本计算

//获取从玩家当前位置到未来
区块位置的方向矢量

Vector3 dirVector = futurePos-transform.position;
//找到从当前方向到方向矢量的旋转
四元数rotation = Quaternion.FromToRotation(transform.forward,dirVector);

//计算您到多维数据集的距离,并用AnimationDelta
的大小缩放它的距离float结果= Vector3.Distance(transform.position,futurePos);

结果=结果/ animationDelta.magnitude;

//最后通过旋转旋转正向矢量,然后乘以
//动画速度和结果,以逐步移动为
//动画播放。注意:动画应基于向前的方向

transform.position + =(AnimationSpeed *旋转)*结果* Time.deltaTime;

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



祝您好运!我上床睡觉,醒来后会再检查一下。


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. 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.

Detect nearest cube where the player should jump to (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). 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. But the Jump() doesn't work. 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.

这篇关于C#如何在unity3d中平滑跳跃而不将X移向最近的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆