I'm new to Unity and use CharacterController.Move to move my character around. In my game world, 1 unit = 1 meter.
This works great, for example for speed: if I use a speed of 5, the character has a speed of 5m/s.
I make my character jump using:
if (Input.GetButton("Jump"))
moveDirection.y = jumpHeight;
...
moveDirection.y -= gravity * Time.deltaTime;
This works fine too, but since the gravity is pulling my character down, the jumpHeight isn't actually reached. For example, a jumpHeight of 8 result in a jump of something around 2.4 meters.
How can I change my code so jumpHeight represents the height the character will jump, even with the gravity pulling him down? Basically, with a jumpHeight of 8, I want my player to perform a jump of 8 meters.
According to physics, with an initial velocity of 8, the height would be 1.6 with a gravity of 20 (height = initialvelocity^2/(2*gravity)). If this indeed would be the height I'm seeing in-game, I could simply transform the formula, but I'm seeing a height of around 2.4 meters...
You're on the right track. I'm assuming you know the SUVAT equations.
Our knowns can be jumpheight (8) and timeToJumpApex (0.5f) <- You can change this to whatever, but 0.5f is a good start.
Time to jump apex is as the name implies, the time taken to hit the apex of a jump.
We now need to solve for the remaining variables needed, gravity and jump velocity. Gravity can be defined as such:
gravity = 2 * jumpheight / timeToJumpApex^2;
Jump velocity can be defined as such:
jumpVelocity = gravity * timeToJumpApex;
Then you can do:
if (Input.GetButton("Jump"))
moveDirection.y = jumpVelocity;
...
moveDirection.y -= gravity * Time.deltaTime;
Related
So my friends and I are developing a game where you play as a snowball rolling down a hill avoiding obstacles. We're having trouble with our movement, however. We want our snowball to gains speed the larger it gets and the longer it goes without hitting something. Our forward movement is controlled by
void FixedUpdate(){
rb.velocity += Physics.gravity * 3f * rb.mass * Time.deltaTime;
//to accelerate
rb.AddForce(0, 0, 32 * rb.mass);
}
We're applying a sideways force on key input
if (Input.GetKey(ControlManager.CM.left))
{
if (rb.velocity.x >= -15 - (rb.mass * 8))
{
rb.AddForce(Vector3.left * sidewaysForce * (rb.mass * .5f), ForceMode.VelocityChange);
}
}
if (Input.GetKey(ControlManager.CM.right))
{
if (rb.velocity.x <= 15 + (rb.mass * 8))
{
rb.AddForce(Vector3.right * sidewaysForce * (rb.mass * .5f), ForceMode.VelocityChange);
}
}
The mass increases as the scale increases and vice versa.
The issue comes when the snowball gets larger than a certain scale. Once it hits that point it massively accelerates left and right while you push the keys then snaps back to its forward speed when you let go. I assume it's something to do with the mass and the way the applied forces are compounding.
Is there a better way to accelerate our snowball downhill or move it left and right? I've tried transform.Translate and transform.MovePosition, but they lead to choppy left and right movement.
For one, most movement code should multiply the velocity by Time.deltaTime. In a hypothetical game, if you increased the velocity by a certain amount each frame, then somebody with a beefy 60 fps computer will go twice as fast as a poor 30 fps laptop gamer because they will accelerate less frequently. In order to fix this, we multiply acceleration by Time.deltaTime, which is the time since the last frame.
Instead of this code, where framerate would determine speed;
Vector3 example = new Vector3(1,1,1);
void Update()
{
rb.AddForce(example);
}
We would use this code. If the framerate is half as much, Time.deltaTime will be twice as much, so the acceleration will be constant for everyone using it.
Vector3 example = new Vector3(1,1,1);
void Update()
{
rb.AddForce(example * Time.deltaTime);
}
There may be another source of this problem, although getting rid of frame-rate dependencies is a good place to start. It looks like you already have used Time.deltaTime for downward velocity, but not for sideways movement. Even if it doesn't fix the problem, using Time.deltaTime is essential for any consistent game.
First off: I am very new to Unity, as in VERY new.
I want to do the following: I want to rotate a cube around a stationary point (in my case a camera) with a radius that is adjustable in the inspector. The cube should always have its Z-axis oriented towards the camera's position. While the cube is orbiting around the camera, it should additionally follow a sine function to move up and down with a magnitude of 2.
I have some working code, the only problem is an increase in distance over time. The longer the runtime, the higher the distance between the cube and the camera.
Here is what I currently have:
void Awake()
{
cameraPosition = GameObject.FindGameObjectWithTag("MainCamera").transform;
transform.position = new Vector3(x: transform.position.x,
y: transform.position.y,
z: cameraPosition.position.z + radius);
movement = transform.position;
}
I instantiate some variables in the Awake()-method and set the cube's position to where it should be (do you instantiate in Awake()?). I'll use the Vector3 movement later in my code for the "swinging" of the cube.
void Update()
{
transform.LookAt(cameraPosition);
transform.RotateAround(cameraPosition.position, cameraPosition.transform.up, 30 * Time.deltaTime * rotationSpeed);
MoveAndRotate();
}
Here I set the orientation of the cube's z-axis and rotate it around the camera. 30 is just a constant i am using for tests.
void MoveAndRotate()
{
movement += transform.right * Time.deltaTime * movementSpeed;
transform.position = movement + Vector3.up * Mathf.Sin(Time.time * frequency) * magnitude;
}
To be quite frank, I do not understand this bit of code completely. I do however understand that this includes a rotation as it moves the cube along it's x-axis as well as along the world's y-axis. I have yet to get into Vector and matrices, so if you could share your knowledge on that topic as well I'd be grateful for that.
It seems like I have found the solution for my problem, and it is an easy one at that.
First of all we need the initial position of our cube because we need to have access to its original y-coordinate to account for offsets.
So in Awake(), instead of
movement = transform.position;
We simply change it to
initialPosition = transform.position;
To have more readable code.
Next, we change our MoveAndRotate()-method to only be a single line long.
void MoveAndRotate()
{
transform.position = new Vector3(transform.position.x,
Mathf.Sin(Time.time * frequency) * magnitude + initialPosition.y,
transform.position.z);
}
What exactly does that line then? It sets the position of our cube to a new Vector3. This Vector consists of
its current x-value
our newly calculated y-value (our height, if you want to say so) + the offset from our original position
its current z value
With this, the cube will only bop up and down with distancing itself from the camera.
I have also found the reason for the increase in distance: My method of movement does not describe a sphere (which would keep the distance the same no matter how you rotate the cube) but rather a plane. Of course, moving the cube along a plane will automatically increase the distance for some points of the movement.
For instantiating variables in Awake it should be fine, but you could also do it in the Start(){} Method that Unity provides if you wanted to.
For the main problem itself I'm guessing that calling this function every frame is the Problem, because you add on to the position.
movement += transform.right * Time.deltaTime * movementSpeed;
Would be nice if you could try to replace it with this code and see if it helped.
movement = transform.right * Time.deltaTime * movementSpeed;
I've been trying for some time now with different tutorials to get a nice firstperson (cockpit view) spaceship controll system. I tried using mouse only, keyboard only and combinations but I keep encountering the same problem with all tutorials. even this simple line of code does it:
transform.position += transform.forward * Time.deltaTime * 90f;
transform.Rotate( Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"), 0.0f);
The problem I keep getting is that if I pitch its ok. it I yaw its ok. But If I do both (so I go diagonaly) it also rotates my ship on the Z axis and messes up my orientation. I tried locking the z rotation in the rigidbody but that does'nt help either. I tried making code myself alternating with apply torque and simply rotating, followed some tutorials including this one: Tutorial but keep getting the rotation problem.
What I want to make is a game that controlls like the old game Helbender
Does anyone of you know of a way that I can get spaceship controlls to work?
----EDIT-----
Got a bit further now. It doenst turn on my z axis anymore becouse I keep setting it to 0. Only problem now is that if I try to make a looping the ship flips around instead of nicely looping.
if (Input.GetKey("up"))
{
transform.Rotate(transform.right * -ShipPanSpeed * Time.deltaTime, Space.World);
}
if (Input.GetKey("down"))
{
transform.Rotate(transform.right * ShipPanSpeed * Time.deltaTime, Space.World);
}
if (Input.GetKey("left"))
{
transform.Rotate(transform.up * -ShipPanSpeed * Time.deltaTime,Space.World);
}
if (Input.GetKey("right"))
{
transform.Rotate(transform.up * ShipPanSpeed * Time.deltaTime,Space.World);
}
float z = transform.eulerAngles.z;
transform.Rotate(0, 0, -z);
You could always try to make one parent object for the Controls and then a child object (the spaceshit) that you can rotate for the pivot but not attach any movement beside rotation.
What i mean is that you can rotate the parent on the Y axis to make it rotate and move the transform forward or backward at the same time. If you want to pivot up or down you can transform forward at the sametime you transform up/down multiplied with the axis you want to pivot with
Example:
private void Update(){
//PARENT--------------------------------------------
// MOVING FORWARD AND BACKWARD
transform.position += transform.forward * Input.GetAxis("Vertical") * speed * Time.deltaTime();
// MOVING RIGHT AND LEFT
transform.position += transform.right * Input.GetAxis("Horizontal") * speed * Time.deltaTime();
//PIVOT UP AND DOWN
transform.position += transform.up * -Input.GetAxis("Mouse Y") * speed * Time.deltaTime();
//ROTATE AROUND THE Y AXIS
tranform.Rotate(0f, Input.GetAxis("Horizontal") * rotationspeed, 0f);
}
For the spaceship (child) for the pivot i would recommend you to make a emptyobject and set the chip to lookAt that object based on the input axis you use to move up/down and forward/backward.
Hope this helped or at least gave you a idea of how to make it :)
So last week I started working on an RPG and I've started working on the enemy AI and it should rotate to it's target but it doesn't. What I did is for the enemy I created a child object and put a script that rotates it to the target, then in the enemy script I did this:
if(transform.eulerAngles.y > rotTracker.transform.eulerAngles.y) {
transform.eulerAngles.y -= 2 * Time.deltaTime;
}
if(transform.eulerAngles.y < rotTracker.transform.eulerAngles.y) {
transform.eulerAngles.y += 2 * Time.deltaTime;
}
the rotTracker is a GameObject variable. So, what is wrong with this code? The rotation tracker changes rotations but not the enemy. Maybe because it has child objects that look at a different thing? I created a sprite and put it on top of the enemy and it represents the enemies health and always turns towards the camera.
You can't change directly the angles. You need to change the vector positions. For example:
var yRotation -= 2 * Time.deltaTime;
transform.eulerAngles = new Vector3(0, yRotation, 0);
Hope this helps!
You shouldn't use transform.eulerAngles for increment, only fixed values. Also, better set it as vector, not the single axis.
If you've put the the script on the child and actually want to rotate the parent, then you have the wrong transform, but I can't clearly read that.
Further on I'd recommend doing something like this:
var dir = transform.postion - target.position;
dir.y = 0; // set the axis you want to rotate around to 0
var targetRotation = Quaternion.LookRotation(dir);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, Time.deltaTime * speed);
speed being a factor for how fast you want to rotate.
(I think the code should be correct, I'm using C# though.)
I need a method for accelerating the addforce method to the object.
Force Result feels too slow and I want it to be applied faster and for the final result time lapse shorten.
void FixedUpdate()
{....
Vector3 v_x = new Vector3(keyb_x, 0, 0);
Vector3 force_ = v_x * kspeed * Time.deltaTime;
float speed = rigidbody.velocity.magnitude;
rigidbody.AddForce(force_, ForceMode.Impulse);
....}
Raising gravity from -9 to -19 or more in the y direction gives the expected result, but all other objects are affected. I want only it to apply to a specific object only.
All gravity does is apply a downward force to all of your rigidbodies every physics update. For 2D unity physics you could use rigidbody2D.GravityScale, which scales gravity's effect on a per-rigidbody basis, but for 3D rigid bodies you should apply a constant force equal to the change in gravity you want for your object
e.g.
//adds a downforce of 10 per second
rigidbody.AddForce(Vector3.down * 10f * Time.fixedDeltaTime);
You'll want to put this in your fixed update function.
object_Rigid2D.gravityScale += gravity_Increase * Time.deltaTime;
I found an easy way to reach this. Consider you have an object which you move with addForce (I use impulse, other modes probably work too) by 1 unit (so vector is something like (1, 0, 0)) and object mass and drag are both 1, so the object moves properly but you want to make it quicker/slower. In that case you need to reduce it's mass and increase drag to make it quick and vice versa. For example you can make it quicker if you set mass to 2 and drag for 0.5 or slower if mass is 0.25 and drag is 4. Only rule is that drag * mass = 1.