I am trying to make objects follow player with offset without delay on Z-axis but delayed on X-axis. When player entered a object(coin) trigger, i am adding this object to a list and i am updating each one’s position using this code. Each coin has previous and next coin that current coin follows.
{
foreach (Coin coin in coins)
{
Vector3 desiredPos = new Vector3(
coin.previous.transform.position.x,
coin.previous.transform.position.y,
coin.previous.transform.position.z + .15f);
Vector3 smoothedPos = Vector3.Lerp(
coin.transform.position,
desiredPos,
smoothness);
coin.transform.position = smoothedPos;
}
}
I want to get this result
https://youtube.com/shorts/PHAg8Pqf0mA?feature=share
This is what i got
https://youtube.com/shorts/fzukzL_0r74?feature=share
But as you can see coins struggling some times. It is not updating their positions properly. I dont want to make it child because i need to move them on x-axis with delay.
I’ll be appreciated if you can help me.
You are using Vector3.Lerp which lerps all x y and z. If you want to lerp only on x axis, you should use Mathf.Lerp on the x instead:
var x = Mathf.Lerp(x, desiredPos.x, smoothness);
Related
I have 1 year experience of coding in C++ , but just yesterday i've started learning Unity.I saw it needs C# so this won't be too different.Right now , I am trying to move a 2d object , but i really want to understand how it works and not just copy some lines of code.So , this is how they do it :
//
float horizontal = Input.GetAxis("Horizontal");
//which i assume gets the x coordonate of my object;
myRigidBody.velocity = new vector2(horizontal , myRigidBody.velocity.y);
//
And i don't think i get the idea of this code.I read that velocity takes 2 values (x,y) but i am not quite sure what it is doing with them.And getAxis takes a value from [-1,1] which i also don't understand.If you could help me i'd be grateful.
Input.GetAxis("Horizontal"); returns the current value for the axis named Horizontal as defined in Unity's Input manager.
Also, new vector2(horizontal, myRigidBody.veloicty.y); is probably a typo, because the type of Rigidbody.velocity is Vector3. And Vector2 is an object that has an implicit conversion to Vector3.
Anyway, myRigidBody.velocity = new Vector2(horizontal , myRigidBody.velocity.y); creates an instance of a Vector2 type where the x component is horizontal, and the y component is the current y component of the rigidbody's velocity, and then it assigns that Vector2 to the rigidbody's velocity.
GetAxis("Horizontal") returns the values from left (-1,0,0) and right (1,0,0) when you press the arrows keys. Anyway, you'll get the values interpolated and not a sudden change. Try the code below and see how it looks on the inspector
public float horizontal;
private void Update()
{
horizontal = Input.GetAxis("Horizontal");
}
As for the velocity, you "force change" the velocity of the rigidbody in any direction you want x,y (horizontal,vertical axis). You can also multiply your axis values with a speed variable.
I need that the camera sees an object in the initial position after moving it on Y axis.
I use some images to explain myself better.
This is the initial position of the object. The main camera will not change position. At the coordinates (0, 0, 0) there is another camera I use for the background image. From this same point I draw Gizmo lines.
Now through my Editor I move a Plane on the Y axis from 0 to -2. The Y of my object is linked to the Y of the Plane, so it also goes down by 2 units.
Now comes the part I would like to automate. I want to move the object along the X and Z axis so that its feet appear to the camera as if they are in the same initial position. By manually moving it in Scene View on the X and Z axes, I put the feet in a place that looks like the same point as before and of course it is smaller as it is further away from the camera.
How can I calculate by code the X and Z coordinates to be assigned to my object's position at a given point on the Y axis, so that one point remains in the same position in screen space?
You can use rays and planes to calculate this.
Before the object moves, create a Ray from the camera to the point on the object you need to keep in the same position:
// Where the "feet" are relative to the object's origin
public Vector3 cameraKeepOffset = new Vector3(0f,-1f,0f);
public Ray perspectiveRay;
...
Vector3 positionToKeep = transform.position + cameraKeepOffset;
Vector3 cameraPosition = Camera.main.transform.position;
perspectiveRay = new Ray(cameraPosition, positionToKeep - cameraPosition);
The idea is that whenever the object moves, find where along that ray it can be placed. If we put a horizontal plane at the y position, wherever the ray intersects that plane is where the object should be placed.
So, when the object moves, create a Plane where the offset is, find where the perspectiveRay intersects it, then move the object so that its offset is at that point:
Plane yPlane = new Plane(Vector3.up, cameraKeepOffset + transform.position);
float distanceFromCam;
if ( !Raycast(perspectiveRay, out distanceFromCam)) {
Debug.log("Camera is not pointing at plane");
// Handle bugs here, return if necessary, etc.
} else {
Vector3 intersectionPoint = Ray.GetPoint(distanceFromCam);
transform.position = intersectionPoint - cameraKeepOffset;
}
I am making a top down game in Unity, how do I instantiate objects based on the players current position from the top of the camera view in Unity?
So far I have tried:
Instantiate(prefab, player.transform.position * 2 * Space.World)
but this didn't work. This just spawned objects from the center of the camera.
Space is simply an enum and has nothing to do with what you are trying! (Its purpose is to define the relative transform space for e.g. Transform.Rotate or Transform.Translate)
in that enum afaik
Space.World simply has the int value 0
Space.Self has the int value 1
so what you actually do is
Instantiate(prefab, player.transform.position * 2 * 0);
which equals
Instantiate(prefab, Vector3.zero);
which means the object is instantiated at World position 0,0,0.
Also using
Instantiate(prefab, player.transform.position * 2);
looks a bit strange. Are you sure you want to duplicate the actual position of the player? This would mean the spawned object is always on a line with the player and the World 0,0,0 and always double as far from the center as the player.
To me it sounds more like you rather want to spawn something in front of the player ... depending on the player's view direction (in topdown games usually player.transform.up or player.transform.right) so I guess what you are trying to do instead is something like
Instantiate(prefab, player.transform.position + player.transform.forward * 2);
which would instead spawn the object 2 Unity units in front of the player object
After your comment it sounds like instead you want to spawn the object at the player position on the X-axis but "over it" on the Y-axis so
Instantiate(prefab, player.transform.position + Vector3.Up * 2);
maybe you'll have to tweak the 2 depending how your player can move and how far it has to be to be "off screen". Alternatively you could also use a bit more complex using Camera.ScreenToWorldPoint
// get players position
var playerPos = player.transform.position;
// get camera's position
var cameraPos = Camera.main.transform.position;
// get difference on Z-axis
var cameraDistance = cameraPos.z - playerPos.z;
// Get the world 3d point for the upper camera border
// don't care about the X value
// and as distance we use the z-distance to the player
var cameraTopPoint = Camera.main.ScreenToWorldPoint(new Vector3(0, Camera.main.pixelHeight, cameraDistance);
// use the players X-axis position
cameraTopPoint.x = player.transform.x;
// to spawn it exactly on the Screen border above the player
Instantiate(prefab, cameraTopPoint);
// or to spawn it a bit higher
Instantiate(prefab, cameraTopPoint + Vector3.Up * 1);
Update
you said you want the prefab to be spawned on the "opposide" of the player position on the X axis.
If your Camera is static on world x=0 than this is actually quite simple:
cameraTopPoint.x = -player.transform.x;
If your camera is moving or not on x=0 than we have to calculate it already on the screen position level:
// get players position
var playerPos = player.transform.position;
// additionally convert the player position to screen space
var playerScreenPos = Camera.main.WorldToScreenPoint(playerPos);
var centerX = Camera.main.pixelWidth / 2.0f;
// get the difference between camera an player X (in screen space)
var differenceX = Mathf.Abs(playerScreenPos.x - centerX);
// here calculate the opposide side
var targetX = centerX + differenceX * (playerScreenPos.x < centerX ? 1 : -1);
// or alternatively if you want e.g. that the prefab always
// spawn with a bit of distance to the player even though he is very close
// to the center of the screen you could do something like
//var targetX = centerX + centerX / 2 * (playerScreenPos.x < centerX ? 1 : -1);
// Get the world 3d point for the upper camera border
// with the calculated X value
// and as distance we use the z-distance to the player
var cameraTopPoint = Camera.main.ScreenToWorldPoint(new Vector3(targetX, Camera.main.pixelHeight, playerScreenPos.z);
// to spawn it exactly on the Screen border above the player
Instantiate(prefab, cameraTopPoint);
// or to spawn it a bit higher
Instantiate(prefab, cameraTopPoint + Vector3.Up * 1);
Other Update
Ok so you want the prefab always spawn next to the player in a certain distance. The side depends on which side of the screen the player is so you could actually use the first approach again but just add the desired distance:
// Adjust this is the Inspector (in Unity units)
public float spawnDistanceToPlayer;
...
// get players position
var playerPos = player.transform.position;
// additionally convert the player position to screen space
var playerScreenPos = Camera.main.WorldToScreenPoint(playerPos);
var centerX = Camera.main.pixelWidth / 2.0f;
// Get the world 3d point for the upper camera border
// with the calculated X value
// and as distance we use the z-distance to the player
var cameraTopPoint = Camera.main.ScreenToWorldPoint(new Vector3(playerScreenPos.x, Camera.main.pixelHeight, playerScreenPos.z);
// now add or reduce spawnDistanceToPlayer
// depending on which side of the screen he is
cameraTopPoint.x += spawnDistanceToPlayer * (playerScreenPos.x < centerX ? 1 : -1);
// OR if your camera sits static on X=0 anyway you also could compare
// the player position directly without calculating in screenspace:
cameraTopPoint.x += spawnDistanceToPlayer * (playerPos.x < 0 ? 1 : -1);
// to spawn it exactly on the Screen border above the player
Instantiate(prefab, cameraTopPoint);
// or to spawn it a bit higher
Instantiate(prefab, cameraTopPoint + Vector3.Up * 1);
Typed on smartphone so might not be "copy-paste-able" ;)
I have a plane. It is rotated 180 degrees on the Y , his position is 0,0,0 he is facing the X axis. That means that I rotate it around the Z (Euler angles) to change the direction it is facing. I have clouds the clouds have a movement script. I want the clouds to move in the opposite direction of the direction the plane is facing at the Y axis and X axis.
For example when the plane's rotation.eulerAngles.Z = 0. The clouds should move at full speed toward minus X. And when rotation.eulerAngles.Z = 90 the clouds should move at full speed towards minus Y. When rotation.eulerAngles.Z = 45 the clouds should move at half speed towards minus X and at half speed towards minus Y and so on.
Here's two illustrations to make it easier for you to visualize :
illustration 1
illustration 2
Here's a photo of the scene again to make it easier for you to visualize:
the scene
The idea is to create the illusion that the plane is moving, actually moving the plane in this scene will make a lot of problems that I really don't want to deal with.
Current cloud movement script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCloud : MonoBehaviour
{
public float speed;
void Update()
{
var plane = GameObject.Find("plane");
var dir =(plane.transform.position - plane.transform.forward)*speed*Time.deltaTime ;
transform.position = new Vector3(transform.position.x + dir.x , transform.position.y + dir.y , transform.position.z);
if (transform.position.x < -140)Destroy(gameObject);
}
}
So how would you approch this problem ?
With unity.
Edit:
I think trigo may be helpful here using a linear function
here's my new code :
public float speed;
void Update()
{
var plane = GameObject.Find("plane");//Get the airplane
var slope = Mathf.Tan(360 - plane.transform.rotation.eulerAngles.z);//Degrees to a slope (how much y it does in one x)
var y = 1*slope;//kinda the very definition of the slope...
var x = 1/slope;//math
transform.position += new Vector3(x,y,0)*Time.deltaTime*speed;//the 1 , 1 point of our linear function(our direction) * delta * speed
if (transform.position.x < -140)Destroy(gameObject);
}
currently the clouds just shake all over the scene. sometimes they do finally go to the right direction but it's not idle.
Would like to get a second opnion on my math.
How I solved the problem :
I just did
transform.position += GameObject.Find("plane").transform.right * Time.deltaTime * speed;
Thanks to PrinceOfRavens for his help on finding this out
does the blue axis(z) of the airplane face forward? with the code you have implemented? what direction do the clouds move?
forward in unity is the red axis (z). you code should work if the plain is oriented correctly. find the axis thats coming from the nose, and note the color.
if its :
blue you want -transform.right,
green you want -transform.up
Why does Gravity in Physics2D engine for Unity2D act different when these two following lines of codes are implemented alternately?
For example, I have attached to my player sprite a Player Controller C# script:
private float speed = 500f;
RigidBody2D playerChar = null;
And then to make my character walk:
Vector2 vec = new Vector2 (Input.GetAxis("Horizontal"), 0);
playerChar.AddForce(vec * speed);
And the Gravity is set to 50
Result 1: My character avatar falls down normally.
Meanwhile when I do:
Vector2 vec = new Vector2 (Input.GetAxis("Horizontal"), 0);
playerChar.velocity = (vec * speed);
And the Gravity is still set to 50
Result 2: My character now takes a long time to fall (it slowly "floats" down).
Why is that?
This is because you're forcing the y component of the rigidbody's velocity to zero.
When you add force, it adds, it doesn't replace.
When you set the velocity, you're specifically setting it to a Vector2 that has a y value of 0, gravity then kicks in on the fixed update cycle and adds a small amount of gravity, causing your player to fall slowly. Then Update happens again and you force the y value back to 0 once more.