Object following waypoint constantly rotates - c#

I'm trying to make an object move from one point to another in a set path, however once the object reaches the first waypoint it constantly spins around instead of moving to the next point.
Here is my code:
public class Waypoint : MonoBehaviour {
public Transform[] wayPoint = new Transform[9];
int currentWayPoint = 0;
float rotationSpeed = 6.0f;
public float accelerate = 1.8f;
// Use this for initialization
void Start ()
{
wayPoint[0] = GameObject.Find("Waypoint1").transform;
wayPoint[1] = GameObject.Find("Waypoint2").transform;
wayPoint[2] = GameObject.Find("Waypoint3").transform;
wayPoint[3] = GameObject.Find("Waypoint4").transform;
wayPoint[4] = GameObject.Find("Waypoint5").transform;
wayPoint[5] = GameObject.Find("Waypoint6").transform;
wayPoint[6] = GameObject.Find("Waypoint7").transform;
wayPoint[7] = GameObject.Find("Waypoint8").transform;
wayPoint[8] = GameObject.Find("Waypoint9").transform;
}
// Update is called once per frame
void Update ()
{
if(currentWayPoint == 9)
{
Destroy(this.gameObject);
}
else
{
walk();
}
}
void walk()
{
Quaternion rotation = Quaternion.LookRotation(wayPoint[currentWayPoint].position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime*rotationSpeed);
Vector3 wayPointDirection = wayPoint[currentWayPoint].position - transform.position;
float speedElement = Vector3.Dot(wayPointDirection.normalized, transform.forward);
float speed = accelerate + speedElement;
transform.Translate(0,0,Time.deltaTime*speed);
}
void OnTriggerEnter(Collider collider)
{
if(collider.tag == "WayPoint")
currentWayPoint++;
}
}

You need to increment currentWayPoint when you reach one. Check if the distance between the current waypoint and the script's transform are within a set distance (I usually use the speed).
if (Vector3.Distance(wayPoint[currentWayPoint].position, transform.position) < Time.deltaTime * speed)
currentWayPoint++;
P.S. I also like seeing people flex their 3D math skills, but Unity has built in functions for a lot of what you're doing. (transform.LookAt(), then transform.Translate(Vector3.forward) * speed * Time.deltaTime)
http://docs.unity3d.com/Documentation/ScriptReference/Vector3.html
http://docs.unity3d.com/Documentation/ScriptReference/Transform.html

Related

Unity limit rigidbody velocity in specific direction with addforce?

I am creating a third person player movement script. The movement adds force to the rigidbody relative to the direction of the camera. I want to have a max speed limit in the forward direction (cForward), and a separate max speed limit for the horizontal/right direction (cRight). Normally I would be fine with setting the velocity directly, however this screws up gravity for the player. Is there any way to achieve this by using addforce OR is there a way to get gravity working properly when setting velocity directly? Here is what I have so far(some of my other attempts at a solution are commented out):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public Camera mainCamera;
public float horizontalWalkSpeed = 500.0f;
public float verticalWalkSpeed = 500.0f;
public float horizontalSprintSpeed = 1000.0f;
public float verticalSprintSpeed = 1000.0f;
public bool isSprinting = false;
public bool cannotMove = false;
public float accelerationSpeed = 0.2f;
private Rigidbody pRigidBody;
private Vector2 currentInputVector;
private Vector2 smoothInputVelocity;
// Start is called before the first frame update
void Start()
{
pRigidBody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
HandleInput();
}
private void FixedUpdate()
{
Vector3 cForward = mainCamera.transform.forward;
Vector3 cRight = mainCamera.transform.right;
cForward.y = 0.0f;
cRight.y = 0.0f;
cForward.Normalize();
cRight.Normalize();
if (!cannotMove && !isSprinting)
{
Vector3 vForce = cForward * currentInputVector.y * verticalWalkSpeed;
Vector3 hForce = cRight * currentInputVector.x * horizontalWalkSpeed;
//Vector3 gravity = Vector3.up * -9.8f;
Vector3 force = vForce + hForce;
//float verSpeed = Vector3.Dot(pRigidBody.velocity, cForward);
//float horSpeed = Vector3.Dot(pRigidBody.velocity, cRight);
//if (verSpeed >= 0 && verSpeed <= verticalWalkSpeed)
//{
// pRigidBody.AddForce(vForce, ForceMode.VelocityChange);
//}
//if(horSpeed < horizontalWalkSpeed)
//{
// pRigidBody.AddForce(hForce, ForceMode.VelocityChange);
//}
//float velocityInDirection = Vector3.Dot(pRigidBody.velocity, cForward);
//if(velocityInDirection > verticalWalkSpeed)
//{
// pRigidBody.AddForce(-vForce, ForceMode.VelocityChange);
//}
//pRigidBody.velocity = force;
pRigidBody.AddForce(force, ForceMode.VelocityChange);
}
else if (!cannotMove && isSprinting)
{
pRigidBody.velocity = cForward * currentInputVector.y * verticalSprintSpeed * Time.fixedDeltaTime + cRight * currentInputVector.x * horizontalSprintSpeed * Time.fixedDeltaTime;
}
}
private void HandleInput()
{
isSprinting = Input.GetButton("Sprint");
Vector2 input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
currentInputVector = Vector2.SmoothDamp(currentInputVector, input, ref smoothInputVelocity, accelerationSpeed);
}
}
I think this thread may help --https://answers.unity.com/questions/9985/limiting-rigidbody-velocity.html.
Basically, there are two methods.
Add force in the opposite direction and increase with the extent to which the object exceeds the limit. This requires additional calculations and tests.
simply normalize the velocity value when it exceeds the limit.

How to program a bunch of 1st person animations at different speeds

I have made 4 different types of animation clips in an animator for an an empty gameobject called "Animator". The main camera is a child of this.
The animations feature a running cycle, a walking cycle, a crouch cycle, and an idle cycle. They all have a trigger that let's them play.
How am I able to measure the speed of the player and execute these animations when the player reaches a certain speed. I have found someone else trying to do this and it works but only for idle and walk. But unfortunately I can't get the sprint and crouch to work. I'm not sure what to do, either have the sprint and crouch animations or just change the speed of the walk animation depending on whether the player is sprinting or crouching. I'll leave a comment where the code I found is.
Here's what I have in my player controller (thge trigger stop is for the idle animation):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController controller;
Animator _ar;
public float speed;
[Range(-5, -20)]
public float gravity = -9.81f;
public float sprintSpeed = 6f;
public float walkSpeed = 4f;
public float crouchSpeed = 2f;
public float standHeight = 1.6f;
public float crouchHeight = 1f;
Vector3 velocity;
bool isGrounded;
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
public Light _l;
//Set this to the transform you want to check
public Transform objectTransfom;
private float noMovementThreshold = 0.0001f;
private const int noMovementFrames = 1;
Vector3[] previousLocations = new Vector3[noMovementFrames];
public bool isMoving;
//Let other scripts see if the object is moving
public bool IsMoving
{
get { return isMoving; }
}
void Awake()
{
//For good measure, set the previous locations
for (int i = 0; i < previousLocations.Length; i++)
{
previousLocations[i] = Vector3.zero;
}
}
void Start()
{
_ar = GameObject.Find("Animator").GetComponentInChildren<Animator>();
}
// Update is called once per frame
void Update()
{
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x + transform.forward * z;
controller.Move(move * speed * Time.deltaTime);
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
//Below here is the code I found. The if statements for isMoving, is what I put in to see if
//this worked.
//Store the newest vector at the end of the list of vectors
for (int i = 0; i < previousLocations.Length - 1; i++)
{
previousLocations[i] = previousLocations[i + 1];
}
previousLocations[previousLocations.Length - 1] = objectTransfom.position;
//Check the distances between the points in your previous locations
//If for the past several updates, there are no movements smaller than the threshold,
//you can most likely assume that the object is not moving
for (int i = 0; i < previousLocations.Length - 1; i++)
{
if (Vector3.Distance(previousLocations[i], previousLocations[i + 1]) >= noMovementThreshold)
{
//The minimum movement has been detected between frames
isMoving = true;
break;
}
else
{
isMoving = false;
}
}
if(isMoving == true)
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
speed = sprintSpeed;
_ar.SetTrigger("WalkSprint");
}
else if (Input.GetKeyUp(KeyCode.LeftControl))
{
speed = crouchSpeed;
_ar.SetTrigger("WalkCrouch");
//transform.localScale = new Vector3(0.8f, 0.5f, 0.8f);
}
else
{
speed = walkSpeed;
_ar.SetTrigger("Walk");
//transform.localScale = new Vector3(0.8f, 0.85f, 0.8f);
}
}
else
{
_ar.SetTrigger("Stop");
}
}
}
Unfortunately, as with many issue in Game Dev, this could be a number of different issues (or all of them!). Here is where you can start to debug:
Check your error log to see if there is anything obvious that jumps out at you, like a bad reference to a Game Object/Componenet.
Watch the animator. You should be able to have the Animator open, side-by-side with your game window while the game is running. You should be able to see the animations running and transitioning. See if something is not linked properly, or if an animation time is configured incorrectly, etc.
Add some debug statements, like outputting the current trigger being set. I would even verify that your inputs are configured correctly. Maybe add some additional conditionals at the beginning that debug what inputs are being pressed.
As #OnionFan said, your Input check is for KeyUp for the Crouch key. That should probably be KeyDown.

Cannot convert type `UnityEngine.Rigidbody' to `ProjectileController' via a built-in conversion

This has been asked about 1 million times, yet I can't find a solution to my issue, rather to my annoyance.
Help is very much appreciated as I'm not sure whats going wrong and how to solve it any more.
Script 1:
public class Something : MonoBehaviour {
[SerializeField]
private Rigidbody cannonballInstance;
public ProjectileController projectile;
public Transform firePoint;
[SerializeField]
[Range(10f, 80f)]
private float angle = 45f;
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo))
{
FireCannonAtPoint(hitInfo.point);
}
}
}
private void FireCannonAtPoint(Vector3 point)
{
var velocity = BallisticVelocity(point, angle);
Debug.Log("Firing at " + point + " velocity " + velocity);
ProjectileController newProjectile = Instantiate(cannonballInstance, transform.position, transform.rotation) as ProjectileController;
//cannonballInstance.transform.position = transform.position;
//cannonballInstance.velocity = velocity;
}
private Vector3 BallisticVelocity(Vector3 destination, float angle)
{
Vector3 dir = destination - transform.position; // get Target Direction
float height = dir.y; // get height difference
dir.y = 0; // retain only the horizontal difference
float dist = dir.magnitude; // get horizontal direction
float a = angle * Mathf.Deg2Rad; // Convert angle to radians
dir.y = dist * Mathf.Tan(a); // set dir to the elevation angle.
dist += height / Mathf.Tan(a); // Correction for small height differences
// Calculate the velocity magnitude
float velocity = Mathf.Sqrt(dist * Physics.gravity.magnitude / Mathf.Sin(2 * a));
return velocity * dir.normalized; // Return a normalized vector.
}
The following is called from the previos when instansiated, causes error is this due to the type i'm trying to create or what?
Script 2:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProjectileController : MonoBehaviour {
public float speed;
private Vector3 oldVelocity;
private Rigidbody rigidbodyTemp;
private int bounceLimit = 3;
// Use this for initialization
void Start () {
rigidbodyTemp = GetComponent<Rigidbody>();
rigidbodyTemp.isKinematic = false;
rigidbodyTemp.freezeRotation = true;
rigidbodyTemp.detectCollisions = true;
}
// Update is called once per frame
void FixedUpdate () {
rigidbodyTemp.AddForce(transform.forward * speed);
oldVelocity = rigidbodyTemp.velocity;
}
private void OnCollisionEnter(Collision collision)
{
bounceLimit -= 1;
if (collision.gameObject.tag == "Bulllet") // Check if hit another bullet
{
Destroy(this.gameObject);
}
else if (collision.gameObject.tag == "Crate") // Check if a Crate has been hit, will hold power ups
{
Destroy(this.gameObject);
Destroy(collision.gameObject);
PickUUpBounce.isActive = true;
}
else if (collision.gameObject.tag == "Player") // Check if hit a player
{
Destroy(this.gameObject);
}
else if (collision.gameObject.tag == "Enemy") // Check if enemy is hit
{
Destroy(this.gameObject);
Destroy(collision.gameObject);
}
else if (bounceLimit == 0) // check if bounce limit is reached
{
Destroy(this.gameObject);
}
else // bounce
{
Vector3 reflectedVelocity;
Quaternion rotation;
ContactPoint contact = collision.contacts[0]; // stores contact point for reflected velocity
reflectedVelocity = Vector3.Reflect(oldVelocity, contact.normal); // reflected velocity equals a reflection of the old velocity around the contact point
rigidbodyTemp.velocity = reflectedVelocity; // Change rigidbody velocity
rotation = Quaternion.FromToRotation(oldVelocity, reflectedVelocity); // old directyion -> new direction
transform.rotation = rotation * transform.rotation; // front face always facing the front
}
}
}
The prefab (cannonballInstance) you are instantiating is declared as Rigidbody. When you call the Instantiate function and pass cannonballInstance to it, it will return a Rigidbody not ProjectileController.
ProjectileController is a script. You can't cast the returned Rigidbody to ProjectileController. You have to use GetComponent to retrieve the ProjectileController instance that is attached to your prefab(cannonballInstance) .
ProjectileController newProjectile = Instantiate(cannonballInstance, transform.position, transform.rotation).GetComponent<ProjectileController>();
It's better to break that line of code into pieces to make it easier to debug just in case anything is null.
Rigidbody rg = Instantiate(cannonballInstance, transform.position, transform.rotation);
ProjectileController newProjectile = rg.GetComponent<ProjectileController>();

Unity3D smooth camera movement and lookAt

Got stuck with camera movement in my Unity3D C# project.
What I have:
some objects on the scene
a camera, which would fly from any object's poition or from it's own current position
What I need:
smooth rotare camera to one of the object's origin
fly to the spot near the object (there is an empty, so I fly to empty's coords)
Algorithm: rotate to the object's origin, when rotation finishes, start to fly to the empty's position. while flying, look at object's origin.
The problem is that it's not smooth, the camera "jumps" at the end of the movement.
My C# code (attached to the camera):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class testMove : MonoBehaviour {
public GameObject startObj;
public GameObject endObj;
public float speed = 1.0F;
private float startTime;
private float journeyLength;
private string endObjName;
private GameObject endObjLookAt;
void Start () {
startTime = Time.time;
if (startObj) {
} else {
startObj = this.gameObject;
}
journeyLength = Vector3.Distance(startObj.transform.position, endObj.transform.position);
endObjName = endObj.name;
endObjLookAt = GameObject.Find(endObjName + "LookAt");
}
void Update () {
if (endObj) {
float distCovered = (Time.time - startTime) * speed;
float fracJourney = distCovered / journeyLength;
tweenLook(endObjLookAt, fracJourney);
float angle = Quaternion.Angle(transform.rotation, Quaternion.LookRotation(endObjLookAt.transform.position - transform.position));
if (angle <= 0.0001) {
Debug.Log("rotation finished");
tweenPos(startObj, endObj, fracJourney);
transform.LookAt(endObjLookAt.transform.position);
}
}
}
private void tweenPos(GameObject startObj, GameObject endObj, float fracJourney) {
Vector3 newposition = Vector3.Lerp(startObj.transform.position, endObj.transform.position, fracJourney);
transform.position = newposition;
}
private void tweenLook(GameObject endObjLookAt, float fracJourney) {
Quaternion newrotation = Quaternion.LookRotation(endObjLookAt.transform.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, newrotation, fracJourney);
}
}
Since what you're trying to achieve implies doing actions one after another, I'd recommend using a Coroutine:
public class testMove : MonoBehaviour
{
public Transform startObj;
public Transform endObj;
private Transform endObjLookAt;
public float rotationDuration;
public AnimationCurve rotationCurve;
public float movementDuration;
public AnimationCurve movementCurve;
private IEnumerator moveAndRotateCameraIEnumerator;
void Start()
{
// If you want to do it on start just call MoveAndRotateCamera() here, else call if from anywhere you want (a script, a game button, ...)
}
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
MoveAndRotateCamera();
}
}
public void MoveAndRotateCamera(Transform startTransform = null, Transform endTransform = null)
{
if(startTransform)
{
startObj = startTransform;
}
else
{
startObj = this.transform;
}
if(endTransform)
{
endObj = endTransform;
}
endObjLookAt = GameObject.Find(endObj.name + "LookAt").transform;
if(moveAndRotateCameraIEnumerator != null)
{
StopCoroutine(moveAndRotateCameraIEnumerator);
}
moveAndRotateCameraIEnumerator = MoveAndRotateCameraCoroutine();
StartCoroutine(moveAndRotateCameraIEnumerator);
}
private IEnumerator MoveAndRotateCameraCoroutine()
{
//ROTATION
Vector3 startEulerAngles = transform.eulerAngles;
transform.LookAt(endObjLookAt);
Vector3 deltaEulerAngles = new Vector3(Mathf.DeltaAngle(startEulerAngles.x, transform.eulerAngles.x), Mathf.DeltaAngle(startEulerAngles.y, transform.eulerAngles.y), Mathf.DeltaAngle(startEulerAngles.z, transform.eulerAngles.z));
Debug.Log("Starting rotation...");
float timer = 0.0f;
while(timer < rotationDuration)
{
timer += Time.deltaTime;
transform.eulerAngles = startEulerAngles + deltaEulerAngles * rotationCurve.Evaluate(timer / rotationDuration);
yield return new WaitForEndOfFrame();
}
transform.eulerAngles = startEulerAngles + deltaEulerAngles;
Debug.Log("Rotation done!");
//----
//MOVEMENT
Vector3 startPosition = transform.position;
Debug.Log("Starting movement...");
timer = 0.0f;
while(timer < movementDuration)
{
timer += Time.deltaTime;
transform.position = Vector3.Lerp(startPosition, endObj.position, movementCurve.Evaluate(timer / movementDuration));
transform.LookAt(endObjLookAt);
yield return new WaitForEndOfFrame();
}
transform.position = endObj.position;
transform.LookAt(endObjLookAt);
Debug.Log("Movement done!");
//----
}
}
Please note a few things here:
Changed your GameObject variables to Transform ones because you always used them to get to the Transform component so you can use it directly instead
Added a time notion instead of a speed notion for rotation and movement (you can also use speed instead: simply multiply the Time.deltaTime by your speed factor)
Using AnimationCurve allows you to adjust the way the rotation/movement will occur: simply set the curve in Inspector (curve must start at (0, 0) and end at (1, 1))
Hope this helps,

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

Categories