Hey stackoverflow Community,
First of all:
I'm still very new about programming with C# and Unity.
My question:
I'm working on an idea for a Movement of a Cube.
It is planned that the cube will move forward by pressing a key (W-Key). But it shouldn't just move forward. It should jump forward to the next point. So always plus 1 of its axis into which it should go. Accordingly, it is only intended to go forward, right, down, left. He won't be able to jump over behind. You should also see that the cube jumps in the respective direction, so it should not teleport itself. :D
Does anyone have an idea how I can realize this movement?
I am very much looking forward to your ideas.
(Sorry if my English is not so good, my English not the best. ^^)
best regards
xKarToSx
So, in order to understand movement, it's best to first understand Vectors in Unity. Since you want to be moving the cube in the forward direction, I'm going to assume this is a 3D game, in which case you want to use a Vector3.
A Vector3 has three components: X, Y, and Z. Each component is tied to an axis. In simple terms, X is tied to left and right, Y is tied to up and down, and Z is tied to forward and back. So, Vector3 position = new Vector3(0, 1, 2); will be a vector that is 1 unit above and 2 units in front of the starting position.
Assuming you've attached this script to the cube you want to move, you can track its position with transform.position. So, if you want to move the cube one unit forward, your code would look something like this:
if(Input.GetKeyDown(KeyCode.W)) // This code will activate once the user presses W.
{
transform.position += new Vector3(0, 0, 1);
}
That will move the cube one unit forward in the Z direction. However, you don't want it to teleport, you want to see it move, correct? In that case, you want to check out Unity's Vector3.Lerp function. Basically, you would use it to smoothly transition an object between two defined positions. You'll need to implement a timer and a for loop in order to make this work correctly.
So, to summarize, for moving one unit forward in the Z direction, your code would look something like this:
if(Input.GetKeyDown(KeyCode.Z))
{
float startTime = Time.time; //Time.time is the current in-game time when this line is called. You'll want to save this to a variable
float speed = 1.0f; //The speed if something you'll want to define. The higher the speed, the faster the cube will move.
Vector3 startPosition = transform.position; //Save the starting position to a different variable so you can reference it later
Vector3 endPosition = startPosition + Vector3.forward; //Vector3.Forward is equivalent to saying (0, 0, 1);
float length = Vector3.Distance(startPosition, endPosition); //You'll need to know the total distance that the cube will move.
while(transform.position != endPosition) //This loop while keep running until the cube reaches its endpoint
{
float distCovered = (Time.time - startTime) * speed; //subtracting the current time from your start time and multiplying by speed will tell us how far the cube's moved
float fraction = distCovered / length; //This will tell us how far along the cube is in relation to the start and end points.
transform.position = Vector3.Lerp(startPosition, endPosition, fraction); //This line will smoothly transition between the start and end points
}
}
I hope this helps you. This is my first time answering a question so sorry if I got some things wrong/it's not the most optimized. Good Luck!
Related
I want a sprite to always face the camera, except in the Z-Axis. My sprites keep tipping left or right when I move the camera, and I can't have that.
I have been googling this for hours. I've tried transform.LookAt or Quaternion.LookRotation and manually setting the z to 0, but for whatever reason the z keeps adjusting. I've seen and tried so many solutions that feel like they should work but just don't. If it matters, my sprite is a child of another object, but trying localRotation doesn't work either. Freezing rigidbody constraints also has no effect.
The most accurate I can get it is this:
public class Billboard : MonoBehaviour
{
GameObject cam;
float minDist;
// Start is called before the first frame update
void Start()
{
cam = GameObject.Find("Main Camera");
}
// Update is called once per frame
void LateUpdate()
{
//Scale
minDist = cam.GetComponent<CameraOrbit>().distanceMin;
transform.localScale = new Vector3(1f, 1f, 1f) * (cam.GetComponent<CameraOrbit>().distance - minDist) * 1.01f / 3;
//Direction
transform.LookAt(cam.transform.position);
Vector3 rot = transform.rotation.eulerAngles;
transform.rotation = Quaternion.Euler(rot.x, rot.y, 0);
}
}
With this I can get the sprite to face the camera, but the z axis refuses to stay at zero.
Special thanks to StarManta for answering this question on the Unity Forums.
"OK, I think I see what's happening. Them looking like they're rotated is, I think, an illusion; I think they really are accurately pointing at the camera and right-side-up. But, you're treating the camera as if it has a round/fisheye projection, when it really has a rectilinear projection. Usually this doesn't matter but in this case it does. It's hard to explain exactly how this affects this, but the upshot is that, when things that are on either side of the center of the screen are set to "look towards" the camera, they actually appear to be rotated around their Y axes.
The solution to this is actually annoyingly simple: don't set the rotation to look at the camera, set it to be the same as the camera."
transform.rotation = cam.transform.rotation;
Have you tried rotation constraints?
https://docs.unity3d.com/Manual/class-RotationConstraint.html
I had a similar problem, where I wanted some 3d text to always look up, but rotated to the camera.
What worked for me was setting the undesired euler components to zero after applying the lookat rotation.
In your case, it would be something like this.
transform.LookAt(cam.transform.position);
var rot = transform.rotation.eulerAngles;
transform.rotation = Quaternion.Euler(rot.x, rot.y, 0);
In case you need another z value, just replace the 0.
I'm trying to find a way to handle reflections for a breakout clone.
I would upload an image to the post instead of the following paragraph, however i have not yet gained the privilege of that yet.
If the ball intersects the left hand side i want it to bounce off to the left.
if the ball intersects the right hand side i want it to bounce off to the right. if the ball intersects the middle section i want it to bounce up the way. i want to learn how to make it bounce in a varying direction dependant on what side of the left, right, or middle section was intersected
I would like to not use three separate rectangles for this, i want to learn how to do it with one.
I use a Vector2 for ball velocity, projVel.
It's position is projPos.
A rectangle for the paddle lightRect.
The reason I use proj.collRect for the beginning of the if is because I cannot use the intersect method with Vector2.
This is my makeshift collision handler at present, which does work but the speed changes to an extent which renders the game unplayable. The speed clamp i have only slightly slows it down i think. i have a variable for projSpeed i cannot clamp that or it will never be able to stop.
if (proj.collRect.Intersects(lightSaber.lightRect))
{
proj.projPos.Y = lightSaber.lightRect.Y - proj.projTxr.Height;
proj.projVel.Y *= -1;
proj.projVel.X = 10 * (proj.projPos.X - lightSaber.lightRect.Center.X) / (lightSaber.lightRect.Center.X);
}
proj.projVel.X = Math.Max(-4, Math.Min(proj.projVel.X, 4));
proj.projVel.Y = Math.Max(-4, Math.Min(proj.projVel.Y, 4));
Help me by showing me how I could do this, maybe in the Math. method, or even an alternative to .Intersects so I can use projPos instead of collRect.
I really am not sure where to start, if there is another way I could do it an example would be great.
Instead of manipulating X and Y velocities independently, I recommend that you calculate a reflection angle based on the position and then derive the velocity from the angle and the speed prior to impact.
Example:
// NOTE: this code assumes that positive Y is down
if (proj.collRect.Intersects(lightSaber.lightRect) && projPos.projVel.Y > 0.0f) // only bounce if projectile is moving downward
{
// remember current speed for when we calculate new velocity
var projSpeed = projVel.Length();
// make sure the projectile no longer intersects the bar
proj.projPos = lightRect.Y - proj.projTxr.Height;
// interpolate reflection angle
var t = (proj.projPos.X - lightSaber.lightRect.X) / lightSaber.lightRect.Width;
var reflectDegrees = 150.0f - t * 120f; // straight up +/- 60 degrees
var reflectRadians = reflectDegrees * (float)Math.PI / 180.0f;
// final velocity determined by angle and original projectile speed
proj.projVel = new Vector2((float)Math.Cos(reflectRadians) * projSpeed, -(float)Math.Sin(reflectRadians) * projSpeed);
}
I'm using unity to develop my game. I've made a custom swipe gesture by calculating the startPosition and the end Position of the touch. I got the vector direction by subtracting the two positions and debugged it successfully.
But when it comes to applying force to my game object I'm not getting any success after trying a lot.
here's what I'm doing:
swipeDirection = new Vector3(endPos.x - startPos.x,0f, endPos.z - startPos.z);
swipeDirection.Normalize();
Debug.Log("The direction is "+ swipeDirection);
ball.rigidbody.AddForce(swipeDirection * 5);
where ball is just a GameObject. Whenever I run it on my iPhone, the game just gets stuck giving a EXC_BAD_ACCESS code after the first swipe.
So I just tested your code. And it works. This issue you may be having is that those number are pretty small most likely, and you need a LOT of force to move it noticeably. Try changing your 5 to a 1000 or something big so you can definitely see the change. Here is my code, just added to a ball with rigidbody.
void Start ()
{
Vector3 dir = new Vector3 (100f, 0f, 0f);
dir.Normalize ();
this.gameObject.rigidbody.AddForce (dir * 100);
}
almost identical. you just need to make the multiplier big enough to see.
good luck.
I've got an empty game object filled with all my player components, within it is a model which animates itself when the controls are pressed which are instantiated by GetButtonDown. Currently everything in the player game object moves instantly to the next point (basically teleports there with no transition). Is there a way I can get it all to move over say 1 second rather than going there instantly? Here's what happens on GetButtonDown
if (Input.GetButtonDown ("VerticalFwd"))
{
amountToMove.y = 1f;
transform.Translate (amountToMove);
}
I've tried transform.Translate (amountToMove * Time.deltaTime * randomint);
and all sorts of ways to use Time
however that doesn't seem to work even though it seems the most logical way. I'm guessing because the GetButtonDown only "runs" when it is pressed and has no update function to "time" the move every frame? Any ideas?
amountToMove is saved as a Vector3 aswell.
The first formula is wrong. The correct formula would be:
this.transform.position += (Distance/MoveTime) * time.deltatime
Try .Lerp, it runs as a coroutine interpolating a value over some amount of time Vector3.Lerp(Vector3 start, Vector3 end, float time)
See documentation here
This should give you a rough idea of whats going on
Vector3 Distance = End - Start;
// this will return the difference
this.transform.position += Distance/time.deltatime * Movetime
// this divides the Distance equal to the time.deltatime.. (Use Movetime to make the movement take more or less then 1 second
IE: If the Distance is 1x.1y.1z, and time.deltatime is .1 and Movetime is 1.... you get a movement of .1xyz per tick, taking 1 second to reach the end point
FYI: transform.Translate works as a fancy .position +=, for this purpose you can use them interchangeably
EDIT
Here are a few solutions
Easy ::
Vector3 amountToMove = new Vector3(0,1,0); // Vector3.up is short hand for (0,1,0) if you want to use that instead
if (Input.GetButtonDown ("VerticalFwd"))
{
transform.position = Vector3.Lerp(transform.position ,transform.position + amountToMove, 1);
}
Hard and probably unnecessary ::
Write a Coroutine that does a kind of Linear interpolation for your specific application See documentation here
I'm pretty new to C# and XNA and well programing (like I can follow a tutorial but most of the creating it on my own is still really really hard). Right now I'm going round and round trying to figure out how to do this one "simple" thing.
Here's the idea, its going to be a tower defense game; right now I'm working on bare bone basics. I've got my little sprite guy who will move around with Keyboard input, now I want to click somewhere on the screen and have him "walk" to that point. Only I'm lost on the logic. I can click and he'll jump there with
if (aMouse.LeftButton == ButtonState.Pressed)
{
Position.X = aMouse.X;
Position.Y = aMouse.Y;
}
From what I've read for other mousing input, I'm thinking I'll need some kind of loop (bool maybe?) that will move the sprite in a direction and will have to run a check to see if he's got to that point yet. But getting that point after the mouse click and creating that loop, running the check...I'm clueless.
You need to add some instance variables:
Point2D targetPos;
And some constants:
const Point2D speed;
When you run through your Update() loop, update the current position by adding the speed vector to it (in the correct direction of course) until you are within a predefined threshold from the target position (usually the thresholds are calculated from the speed vector - if the distance from the current position to the target position is less than the length of the speed vector, then you're at your position). Using a bool in this case would work well. When you click your mouse set another instance variable (moving) to true, and once you've reached your target position, set moving to false.
People are answering your question at a very low level. Sometimes it help to think of the problem at a higher level.
What you need is a type of state management. The fancy Computer Science term for that is a Finite State Machine. But don't bother looking that up right now. It's fairly dry and confusing at first :)
Your character currently has one state - "standing around". You need to add and process the "walking to destination" state.
From what I've read for other mousing input, I'm thinking I'll need some kind of loop
You need one loop, called the game loop. If you're using XNA, you've already got one. But you're on the right track.
Every time through the game loop, you should process the current state, and check for what are called State Transitions. That's when you change something in your world from one state to another state. For example, when you click the mouse, you want the guy to start moving.
In your game loop you check to see if a mouse click just happened. If it did, then set up some data (where to move to), and tell him to start walking by setting his state to "walking to destination". Next update, you'll process that state instead.
When your character is in the "walking to desintation" state, you need to update their position, based on the amount of time that passed since the last game update. In XNA, this is calculated for you. If you're not using XNA, then you'll have to check yourself. You might be able to use something like the Stopwatch class, and check the Elapsed field.
If the character is at the destination, you need to switch them back to the "standing around" state.
If you receive another mouse click, it is up to you if you want the "walking to destination" state to pay attention to it or not. If you do pay attention to it, you set up the same sort of data as when you transitioned from the "standing around" state.
So, you'll need these variables:
A timer, to find out the elapsed time since the last game loop (XNA gives it to you)
The current player state (maybe an enum)
The current player position (a vector)
The walking speed of the player (a float, probably), measured in units per second (or millisecond)
Data for the "walking to destination" state - target position (another vector)
Data related to user input (mouse events that occurred since the last update, the position of those clicks, etc)
The character specific data will be different for each character in your game, so you want a new copy of it for each. You'll probably want to put it in a class. The rest of it is more global, so you can keep it separate, or make it part of your game, game loop, input classes, etc (however you choose to organize it).
I won't cover the vector math for how to actually calculate the partial movement stuff, since other people have covered that. No sense in duplicating those answers. It basically boils down to making a vector between your current position and the target position, and multiplying/dividing it by your walking speed (to chop it up to the distance moved in a single update).
I'm assuming you have three things:
Current position
Desired position
Speed to move each 'game tick' // don't know what a game tick is? find out!
You're looking at doing this
// dx, dy are delta x and delta y. It's how far in each direction
// the player must travel
// note, I fixed a typo where they were desired - desired... should be
// desired - current, as they are now
float dx = desiredX - currentX;
float dy = desiredY - currentY;
// d uses the pythagorean theorum to find the distance between current and desired
float d = sqrt(dx*dx + dy*dy);
// fac is how far along that line between desired and current will you move
float fac = d / speed;
// mx is the component of the dx line proportional to the size of fac : d
// which means it's how far in the x direction you'll move
float mx = dx * fac;
float my = dy * fac;
// the new postition is the old position plus the move value
float newPositionX = dx + mx;
float newPositionY = dy + my;
I have found this code to be most useful... additionally I have added an extra couple lines to prevent certain situations from occuring. For instance there will be times where direction is 0.83 and speed may have been modified by game factors like terrain/wheather/etc.... if speed is below 1, the sprite may not move at all or even move in the wrong direction!
if (Vector2.Distance(Position, TargetPosition) > 2.0f)
{
velocity = Vector2.Subtract(TargetPosition, Position);
velocity.Normalize();
/// Now no matter which direction we are going we are always moving # sprite.Speed
/// at velocity or speed below 1 - problems occur where the unit may not move at all!!
if(current_Speed < 1)
{
Vector2 temp = (velocity * 10) * (current_Speed * 10);
Position += temp / 10;
}
else
{
Vector2 temp = velocity * current_Speed;
Position += temp;
}
//convert to int to render sprite to pixel perfect..
Position = new Vector2((int)Position.X, (int)Position.Y);
}