I must apologies as this seems such a simple question but I have been trying to get it work for ages.
I have a sprite and two Vector2 variables and I want a sprite to move from one vector2 to another.
Any help would be great. Thanks.
this code works for me but it does a small move every click
//CurPos is the sprite current Position and DestPos is the Destination Position
Vector2 StepAnm = (CurPos - DestPos) / 60;
and in the update function
if (currentMouseState.LeftButton ==Microsoft.Xna.Framework.Input.ButtonState.Pressed&&lastMouseState.LeftButton ==Microsoft.Xna.Framework.Input.ButtonState.Released)
{
if ((int)CurPos.X != (int)DestPos.X)
{
CurPos.X -= StepAnm.X;
}
}
Here is an example using the Update method.
The following will need to be set outside this code
Vector2 destPos;
Vector2 stepAnm; //Needs to be set when destPos is updated
float duration; //Could be dependent on distance or not
protected override void Update(GameTime gameTime)
{
float elapsedSeconds = (float)gameTime.ElapsedGameTime.TotalSeconds;
float moveAmount = elapsedSeconds / duration;
Vector2 movement = stepAnm * moveAmount;
//This should fix going too far
if (movement.LengthSquared() > destPos.DistanceSquared(curPos))
{
curPos = destPos;
}
else
{
curPos += stepAnm * moveAmount; //+= or -= depending on how you calculate stepAnm
}
}
You will probably want to change it a little if you are using a constant speed system. I included the more general duration based system.
Related
I'm trying to move a 2d object from point a to b without changing its rotation in unity
I've tried to use Vector2.Lerp() but its not working
Vector2 pointB = new Vector2(20, 10);
Vector2.Lerp(transform.position, pointB, 3F);
The code should move the object from point a to b in 3F seconds
First, Vector2.Lerp doesn't change the value of the first parameter. You'll want to assign the new value to transform.position if you want to change the transform's position that way.
Secondly, you need to update the transform's position once every frame to keep the transform moving smoothly.
Thirdly, Vector2.Lerp will only produce positions between start and end with a t between 0 and 1. This t should relate to the ratio of how much time has passed since this movement started over how much time will complete the movement.
This is a good use for a coroutine:
private IEnumerator GoToInSeconds(Vector2 pointB, float movementDuration)
{
Vector2 pointA = transform.position;
float timeElapsed = 0f;
while (timeElapsed < movementDuration)
{
yield return null;
timeElapsed += Time.deltaTime;
transform.position = Vector2.Lerp(pointA, pointB, timeElapsed/movementDuration);
}
}
Here's an example of how to use it in Start:
void Start()
{
Vector2 pointB = new Vector2(20, 10);
StartCoroutine(GoToInSeconds(pointB, 3f));
}
I've made an Isometric character controller so it can move and head on an isometric based perspective. The problem is that when I try to move using 2 keys (W + D, A + S...) and release those keys, the player tends to face the very last key that was released, so it is difficult to head a diagonal direction. This makes the character flip its rotation in the very last moment the keys are released.
I've been thinking of using a kind of sleep or coroutine checking if two keys were pressed and released in a short period of time just not rotate it.
There exist any not too rustic solution for this?
Here is my code (I just copied it from here: https://www.studica.com/blog/isometric-camera-unity)
private void SetIsometricDirections() {
vertical = Camera.main.transform.forward;
vertical.y = 0;
vertical = Vector3.Normalize(vertical);
horizontal = Quaternion.Euler(new Vector3(0, 90, 0)) * vertical;
}
private void Move() {
Vector3 horizontalMovement = horizontal * moveSpeed * Time.deltaTime * Input.GetAxis("HorizontalKey");
Vector3 verticalMovement = vertical * moveSpeed * Time.deltaTime * Input.GetAxis("VerticalKey");
Vector3 heading = Vector3.Normalize(horizontalMovement + verticalMovement);
Heading(heading);
transform.position += (horizontalMovement + verticalMovement);
}
private void Heading(Vector3 heading) {
transform.forward = heading;
}
The heading trick it's in the "Heading" method, obviously.
I finally found a solution.
I'll post it just in case any one else needs it in the future.
I calculate the current rotation based on the movement.
private void SetRotation() {
currentRotation = Quaternion.LookRotation(movement);
}
Then, I created a second Quaternion to store the last rotation if is not the same than the current. I also use a counter to store the time a rotation has been faced before stopping the movement or changing the direction.
private void CheckSameRotation() {
if (lastRotation != currentRotation || movement == Vector3.zero) {
sameRotationTime = 0;
lastRotation = currentRotation;
}
else {
sameRotationTime += Time.deltaTime;
}
}
Then, I used a bool to check if the time is high enough to make the rotation happen.
private void TimeAtSameRotation() {
canRotate = (sameRotationTime < 0.015f) ? false : true;
}
And then, I finally rotate the object if the movement is not zero and the condition "canRotate" is true.
private void Rotate() {
if (movement != Vector3.zero && canRotate) {
transform.rotation = currentRotation;
}
}
I am trying to animate a platform prefab that is spawned (the platform object itself is within an empty because its position changes) DOWN when a Runner object collides with it (onCollisonEnter) and UP on collision exit.
I have followed answers given to my old question here verbatim- Unity, C# - cannot make object move down from current y position ONCE on collision enter? but can't get animations using the Animator to work despite having this in my animator as directed:
One person who answered suggested I use Lerp to animate the platform prefab entirely using code. I have researched Lerp but as I need 2 separate states for Down/Idle Down (to make platform stay down) and the same for up/idle up I do not know how to do this.
How can I achieve this effect using Lerp programmatically? Is it possible to achieve the effect I am going for?
ERROR:
EDIT:
how i spawn (dequeue then enqueue) my platforms:
nextPosition += new Vector3 (
Random.Range (minGap.x, maxGap.x) + scale.x,
Random.Range (minGap.y, maxGap.y),
Random.Range (minGap.z, maxGap.z));
Transform o = objectQueue.Dequeue();
o.localScale = scale;
o.localPosition = position;
//o.localEulerAngles = rotation;
o.gameObject.SetActive (true);
int materialIndex = Random.Range(0, materials.Length);
o.GetComponent<Renderer>().material = materials[materialIndex];
o.GetComponent<Collider> ().material = noFrictionMaterial;
platform newScript = new o.GetComponent<platform>(); //getting an error here when I tried to implement your code
objectQueue.Enqueue (o);
if(nextPosition.y < minY){
nextPosition.y = minY + maxGap.y;
}
else if(nextPosition.y > maxY){
nextPosition.y = maxY - maxGap.y;
}
This is what the vectors should ALWAYS be and what I set them at originally in start():
up = new Vector3 (transform.position.x, transform.position.y, transform.position.z);
down = new Vector3 (transform.position.x, transform.position.y-2f, transform.position.z);
Since the platforms aren't actually spawning, are you sure that's the error? Can you help me?
This should work for you:
using UnityEngine;
using System.Collections;
public class Collision : MonoBehaviour {
public Vector3 up, down;
public bool isUp = false;
public float speed = 5f;
float startTime,
length;
bool isMoving = false;
void Start () {
//initialise the platform to a position
if (isUp) transform.position = up;
else transform.position = down;
length = Vector3.Distance(up, down);
}
void Update()
{
if (isUp)
{
//move Down
transform.position = Vector3.Lerp(up, down, ((Time.time - startTime) * speed) / length);
}
else
{
//move Up
transform.position = Vector3.Lerp(down, up, ((Time.time - startTime) * speed) / length);
}
}
//move down
void OnCollisionEnter(Collision col)
{
if (!isMoving)
{
startTime = Time.time;
isMoving = true;
}
}
//move up
void OnCollisionExit(Collision col)
{
if (!isMoving)
{
startTime = Time.time;
isMoving = true;
}
}
}
The thing you have to watch out for is making sure that the "runner" stays on the platform until it's on the bottom so that it can move up again. You could add a check so that it moves back up regardless with another bool it it doesn't work for you. Hope it helps :)
EDIT
What lerp (short for linear interpolation) does is pick points between two vectors based on the progression of the time component (0 to 1). So in order for the platform to go up and down it needs a starting point and an end point, in this case it's up or down (up to the upper position down for the other).
If you want to create a new platform without causing an error you need to set these values after creating it so that everything works correctly (if you leap from any position it will jump aggressively in the first step of the lerp). For example:
//after instantiating the new platform object
scriptName newObject = newGameobject.GetComponent<scriptName>();
newObject.up = (up Vector);
newObject.down = (down Vector);
I'm doing a 2D platform game where the player only climbs (y-axis).
What I'm trying to do is when I reach near to the top edge, my camera goes up a little bit so I can see more of the level.
I have this, but it's not working:
Public Transform player;
Void Start() { }
Void Update()
{
if (player.transform.position > Screen.height - 50)
{
transform.position.y += speed * Time.deltaTime;
}
}
Other Way is like this But not working more than once, i might need to set move = false; but dont know how without interupting Lerp:
float moveTime = 1f; // In seconds
float moveTimer = 0.0f; // Used for keeping track of time
bool moving = false; // Flag letting us know if we're moving
public float heightChange = 7.0f; // This is the delta
// These will be assigned when a collision occurs
Vector3 target; // our target position
Vector3 startPos; // our starting position
void Start()
{
}
void Update()
{
// If we're currently moving and the movement hasn't finished
if (moving && moveTimer < moveTime)
{
// Accumulate the frame time, making the timer tick up
moveTimer += Time.deltaTime;
// calculate our ratio ("t")
float t = moveTimer / moveTime;
transform.position = Vector3.Lerp(startPos, target, t);
}
else
{
// We either haven't started moving, or have finished moving
}
}
void OnTriggerEnter2D(Collider2D other)
{
if (!moving)
{
// We set the target to be ten units above our current position
target = transform.position + Vector3.up * heightChange;
// And save our start position (because our actual position will be changing)
startPos = transform.position;
// Set the flag so that the movement starts
moving = true;
}
}
}
you are comparing two different things here. Screen.height is in pixels while player position is in world units. so lets assume your screen is 1024x768 you are checking if your player is above 718 which is a huge amount in world units.
What you have to do is convert one to the others unit and compare then for example with http://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html
Another thing i noticed is that this script is named player so i assume this is controlling your player object in which case
transform.position.y += speed * Time.deltaTime;
would only change your players position. To change the position of the main camera you could use:
Camera.main.transform.position += new Vector3(0f, speed * Time.deltaTime, 0f);
And lastly, always post the errors you get when asking questions, explain what you expect to happen and what actually happens.
You could try lerping the between positions eg.
transform.position = new trasform.lerp(transform.position, player.transform.position, speed*Time.DeltaTime);
just use the if statement to trigger a bool that then does the lerp, so the camera will move to what you need it to and not just when the player hits a certain point. Then when the camera is finished mooving, reset the bool ready for next time
I am able to jump or move left/right any point in time. But unable to jump and at the same time move left/right simultaneously. Am I missing anything? My codes as follows. Thanks for advice.
public int rotationSpeed = 100;
public float jumpHeight = 8;
private bool isFalling = false;
void Update () {
// handle ball rotation
float rotation = Input.GetAxis("Horizontal") * rotationSpeed;
rotation *= Time.deltaTime;
rigidbody.AddRelativeTorque(Vector3.back * rotation);
//check input
if (Input.GetKeyDown(KeyCode.W))
{
rigidbody.velocity = new Vector3(0, jumpHeight, 0);
}
}
As stated in docs : here
In most cases you should not modify the velocity directly
you should use AddForce instead or AddForceAtPosition
EDIT :
Just to clarify why :
Velocity is a calculated result of the different forces applied to your object, you CAN assign this value to force the calculus to not be used BUT you SHOULD NOT because adding forces together with the builtin AddForce is way more stable and clean,
in short if you assign to velocity you bypass every calculus you've done before if you use AddForce, as name states you add a new force to your forces sum
EDIT 2 :
void Update () {
// handle ball rotation
float rotation = Input.GetAxis("Horizontal") * rotationSpeed;
rotation *= Time.deltaTime;
rigidbody.AddRelativeTorque(Vector3.back * rotation);
//check input
if (Input.GetKeyDown(KeyCode.W))
{
rigidbody.AddForce(new Vector3(0, jumpHeight, 0) * Time.deltaTime);
}
}