Unity 2D launch gameObject at a specific angle without affecting speed - c#

I am working on a game where i need to shoot the ball at an angle and power defined by 2 sliders (1 angle slider, 1 power slider). I currently have this code to control the launching of the ball:
public void shoot()
{
float angle = angleSlider.GetComponent<Slider>().value;
float power = powerSlider.GetComponent<Slider>().value;
gameObject.SetActive(false);
ball.GetComponent<Rigidbody2D>().simulated = true;
Vector2 releaseVector = Quaternion.AngleAxis(angle, transform.up) * transform.forward;
ball.GetComponent<Rigidbody2D>().velocity = releaseVector * (power/3);
}
with this current code it works almost perfect apart from one thing. When the angle is like between 30 and 60, the ball is launched well but if i set it to 0 degrees the ball would barely move and on the contrary if i set it to 90 degrees, the ball launches with much more power. How can i set a constant speed for all degrees so that the speed is only affected by the power slider only please? Thanks.

Typically, you shouldn't set the velocity of a rigidbody directly. Per the Unity docs...
In most cases you should not modify the velocity directly, as this can result in unrealistic behaviour.
Instead, you usually want to impart a physical impulse to the ball using an API like AddForce or AddRelativeForce

That is easy.. You have to normalize the releaseVector.
ball.GetComponent<Rigidbody2D>().velocity = releaseVector.normalized * (power/3);
Then adjust the power to what you want. That way you will have the direction u wanted and speed depends on the power value.
If you want to know what normalize do, you can find more information here;
https://docs.unity3d.com/ScriptReference/Vector3.Normalize.html

Related

C#/Unity Camera Follow Jitter due to Time.deltaTime

Game: In a simple 2D Portrait Game made in Unity, I have a GameObject (Player) that has a fixed location and which is moving upwards. The Camera follows the Player and animated Obstacles are spawning from time to time moving left to right. The attached Screenshot shows the Scene.
The Problem:
The Movement is not smooth, as it seems like the Player is jittering. I think I already identified one of the causes: Big variation of Time.deltaTime. Average value is 0.0167, but I had variations. Minimum was 0.00177, maximum value was 0.2249519.
Settings:
Target Framerate is 60. I use Unity 2019.4.2f1 and as build target an iPhone X with iOS 14.2.
Scripts
public class Player: MonoBehaviour
{
float speed = 5f;
void Update()
{
transform.Translate(0,speed*Time.deltaTime,0);
}
}
public class CamFollow : MonoBehaviour
{
public Transform Player;
private Vector3 FollowVector;
void LateUpdate()
{
FollowVector = Player.position - new Vector3(0, -4.0f, 10);
transform.position = Vector3.Lerp(transform.position, FollowVector, Time.deltaTime * 4f);
}
}
Note: I need to use Lerp, because the Player may lower or increase the speed for one second, then the camera gently moves to the new position, before changing back. For the Obstacles I don't have a Script. They are moving, by using the Animation Component. For the Obstacles I only loop a change of the x value of the position.
My alternative solutions:
1. Changing the value for Time.deltaTime to a constant value of 0.01666667f:
void Update()
{
transform.Translate(0,speed*0.01666667f,0);
}
This makes the Player Object jitter a lot in the Unity Editor but only a little on the device
2. Using Fixed Update both for the Camera Follow and the Player Movement
This makes the movement and camera follow perfectly smooth, but the animated objects jitter a lot. I know Unity wants to adress the deltaTime issue in one of the next updates. But there should be a solution for my problem, so did anybody have a similiar problem, which could be solved? I prefer the 2nd alternative, because the movement looked really smooth and nice, so can I somehow make the animation part of "fixedUpdate"?
The variation in the 'deltaTime' is to be expected.
The variation is large on the PC because you are running on a complex computer with a complex operating system and lots of other applications running simultaneously, each with a multitude of threads, which every once in a while want to do some work. Thus, the scheduler of the operating system cannot guarantee that you are going to get a time slice at the precise moment that you want it in order to render your next frame.
The variation is smaller on the mobile device because it is a much simpler machine with a lot less going on, so the scheduler is able to give you time slices close to the precise intervals that you are asking.
You are already taking this variation into account when you do
transform.Translate( 0, speed * Time.deltaTime, 0 );
This is a fundamental technique in game development: the frame rate is never constant, so the distance by which you must move an object on each frame depends on the precise amount of time elapsed between this frame and the previous frame.
So, that part is fine.
Your problem lies in
transform.position = Vector3.Lerp( transform.position, FollowVector, Time.deltaTime * 4f );
Here you are passing Time.deltaTime * 4f for parameter t of Vector3.Lerp(). I have no idea what you are trying to accomplish, but the number you need to pass there needs to be a gradual transition between 0 and 1, and instead you are passing a randomly varying number of seconds multiplied by some magic constant 4. This does not look correct.
A couple of options that I can think of:
Always use 0.5 for t so that the camera always rushes to the right position and then slows down as it gets closer to it.
Calculate a separate speed vector for the camera, then move the camera using a translation just as you do for the player.

Unity 2D scripted friction equation

I am working on the friction for a square object for after it is done being pushed by the player. The block's movements are controlled purely through script using transform.Translate(velocity) each frame and only a boxcollider2D. I am speculating that because i am controlling the block's movements each frame manually is the reason i can't seem to get the boxcolliders2D's physics material 2D friction to work.
Basically, I am trying to recreate the built in physics similar to rigidbodies by using transform.translate, or use the built in physics if possible. So far, i've landed on something like this
newVelocity.x -= ( 1 / (newVelocity.x * newVelocity.x));
In an attempt to reduce the velocity.x each frame until it hits 0 and shorts out. Obviously, this falls apart when the velocity.x becomes a decimal number. I'm stumped on what i should be doing to achieve a friction similar to rigid bodies where it slows down a little at first and then much faster towards the end as it stops. Any and all help appreciated, thanks in advance!
You could compare the signs of the velocity before and after calculating the change in velocity, and set the velocity to zero when the sign changes, like so:
newVelocity.x -= ( 1 / (newVelocity.x * newVelocity.x));
if(Mathf.Sign(previousVelocity.x) != Mathf.Sign(newVelocity.x)) {
newVelocity.x = 0f;
}
One thing, though, is that normal friction is not calculated using the above equation, it's calculated as follows:
newVelocity.x -= frictionCoefficient*Time.fixedDeltaTime;
And with this, you wouldn't need to compare the velocity to the previous velocity as you can just say if the velocity is low, it's zero. You could still compare the previous velocity sign stuff if you wanted to though, but this is probably more efficient
if(newVelocity.x < 0.01f) {
newVelocty.x = 0f;
}

ball reflection angles Xna c#

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);
}

How to make Fluid Drag equation not framerate dependent

I am trying to plan for a game I started coding. (Very much in the beginnings)
My problem is that I want the acceleration / movement portion of all game objects to be based on acceleration force vs drag (thus resulting in terminal velocity as the upper limit of speed available)
While I could go another route, I'd rather not if possible. Additionally, it has been suggested (by a friend) that I could use a physics library, but that seems overkill and besides, I'd like to learn and understand these concepts myself - I always feel like I better understand my own programs when I do.
I am making a 2D game and using Vector2 variables for position, heading and thrust force (the acceleration force applied). It's top-down so gravity is not a part of the equation.
Before I code it, I'm working out test cases in Excel - which is how I check my math before committing math to code. And I'm discovering that my use of the drag equation is making the object in question framerate dependent!! Specifically, the better the framerate, the lower the resultant terminal velocity.
I've been trying to modify the equations as necessary to account for framerate, but it eludes me.
If you want to work with the same spreadsheet I am, you can download the spreadsheet here.
But you don't have to - here are the specifics.
The drag equation as I understand it is:
Drag = 0.5 * FluidDensity * Velocity * Velocity * DragCoefficient * IncidenceArea
Using some numbers picked from thin air for calculations, if Fluid Density is 0.233 and the Drag Coefficient is 0.4 and the Incidental Area is 0.1 and the Acceleration force is 50 pixels per second, then here is what happens:
If I calculate that acceleration is applied every 0.25 seconds (once every quarter second) at 1/4 the Acceleration force (to match the timing) then we reach terminal velocity at about 39.3 pixels per second.
If I calculate acceleration instead at every second, we reach terminal velocity at about 53.6 pixels per second.
Specifically, every time I calculate for a given DeltaTime, the resultant speed is calculated as (code is from my head - not from an IDE - apologies if there's a bug in it):
//In globals / initialization:
Vector2 Position;
Vector2 Speed;
Vector2 ThrustForce;
float Density = 0.233f;
float DragCoefficient = 0.4f;
float IncidentalArea = 0.1f;
//In the update loop
//DeltaTime is a float based upon how much of a second passed
Vector2 AccelerationToApply = ThrustForce * DeltaTime;
Vector2 NewSpeed = Speed + AccelerationToApply;
Vector2 Drag = Speed * Speed * 0.5f * Density * DragCoefficient * IncidentalArea;
NewSpeed -= Drag;
Speed = NewSpeed;
That's the problem math. Here is the question:
How should this be expressed so that it's framerate independent?
The classic approach is to step the simulated physical time independent from the game loop frame rate, calculating multiple sub-iterations per frame if necessary to advance the physics. This allows you to control your time step (generally making it smaller than the main frame rate), which also helps to keep other potentially unstable calculations under control (such as oscillators.) This of course means that your physics has to compute faster than real time for the fixed time step chosen, as otherwise your world goes into slow motion.
Speaking of instability, I imagine that you'll see some oscillation effects in your current implementation, depending on whether you're overshooting the terminal velocity in a given time step. One way to resolve this is to compute the speed via analytical integration instead of approximating using a incremental step. To do that, express your formula as a differential equation and see if it is of a form that can be readily solved analytically.
There were two parts missing from the code above. While I had played with turning one part "on" and "off" to experimentally determine if it was needed, without the other I was having problems finding the right answer.
The two parts are this: The resultant drag does need to be multiplied by the time step in order to reduce its effect upon the acceleration, but also and perhaps more importantly - the acceleration force to be applied on this frame needs the drag subtracted from it before it is applied to the speed - not after like I had above.
The modified (and now framerate independent) code looks like this:
Also, I reduced having 4 "constant" coefficients to just one coefficient for the sake of simplicity.
//In globals / initialization:
Vector2 Position;
Vector2 Speed;
Vector2 ThrustForce;
float Coefficient = 0.009f;
float PreviousDrag = 0.000f;
//In the update loop
//DeltaTime is a float based upon how much of a second passed
Vector2 AccelerationToApply = ThrustForce * DeltaTime + PreviousDrag * DeltaTime;
Vector2 NewSpeed = Speed + AccelerationToApply;
PreviousDrag = Coefficient * NewSpeed * NewSpeed;
Speed = NewSpeed;
Running this logic through excel, I find that at approximately the same times I reach the same approximate terminal velocity no matter how often (or not) I calculate a change in velocity.

Simple 2D rocket dynamics

I am currently experimenting with some physics toys in XNA using the Farseer Physics library, however my question isn't specific to XNA or Farseer - but to any 2D physics library.
I would like to add "rocket"-like movement (I say rocket-like in the sense that it doesn't have to be a rocket - it could be a plane or a boat on the water or any number of similar situations) for certain objects in my 2D scene. I know how to implement this using a kinematic simulation, but I want to implement it using a dynamic simulation (i.e. applying forces over time). I'm sort of lost on how to implement this.
To simplify things, I don't need the dynamics to rotate the geometry, just to affect the velocity of the body. I'm using a circle geometry that is set to not rotate in Farseer, so I am only concerned with the velocity of the object.
I'm not even sure what the best abstraction should be. Conceptually, I have the direction the body is currently moving (unit vector), a direction I want it to go, and a value representing how fast I want it to change direction, while keeping speed relatively constant (small variations are acceptable).
I could use this abstraction directly, or use something like a "rudder" value which controls how fast the object changes directions (either clockwise or counter clockwise).
What kind of forces should I apply to the body to simulate the movement I'm looking for? Keep in mind that I would also like to be able to adjust the "thrust" of the rocket on the fly.
Edit:
The way I see it, and correct me if I'm wrong, you have two forces (ignoring the main thrust force for now):
1) You have a static "fin" that is always pointed in the same direction as the body. If the body rotates such that the fin is not aligned with the direction of movement, air resistance will apply forces to along the length of the fin, proportional to the angle between the direction of movement and the fin.
2) You have a "rudder", which can rotate freely within a specified range, which is attached some distance from the body's center of mass (in this case we have a circle). Again, when this plane is not parallel to the direction of movement, air resistance causes proportional forces along the length of the rudder.
My question is, differently stated, how do I calculate these proportional forces from air resistance against the fin and rudder?
Edit:
For reference, here is some code I wrote to test the accepted answer:
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
float dc = 0.001f;
float lc = 0.025f;
float angle = MathHelper.ToRadians(45);
Vector2 vel = new Vector2(1, 0);
Vector2 pos = new Vector2(0, 0);
for (int i = 0; i < 200; i++)
{
Vector2 drag = vel * angle * dc;
Vector2 sideForce = angle * lc * vel;
//sideForce = new Vector2(sideForce.Y, -sideForce.X); // rotate 90 degrees CW
sideForce = new Vector2(-sideForce.Y, sideForce.X); // rotate 90 degrees CCW
vel = vel + (-drag) + sideForce;
pos = pos + vel;
if(i % 10 == 0)
System.Console.WriteLine("{0}\t{1}\t{2}", pos.X, pos.Y, vel.Length());
}
}
When you graph the output of this program, you'll see a nice smooth circular curve, which is exactly what I was looking for!
If you already have code to integrate force and mass to acceleration and velocity, then you just need to calculate the individual part of each of the two elements you're talking about.
Keeping it simple, I'd forget about the fin for a moment and just say that anytime the body of your rocket is at an angle to it's velocity, it will generate a linearly increasing side-force and drag. Just play around with the coefficients until it looks and feels how you want.
Drag = angle*drag_coefficient*velocity + base_drag
SideForce = angle*lift_coefficent*velocity
For the rudder, the effect generated is a moment, but unless your game absolutely needs to go into angular dynamics, the simpler thing to do is let the rudder control put in a fixed amount of change to your rocket body angle per time tick in your game.
I suddenly "get" it.
You want to simulate a rocket powered missile flying in air, OK. That's a different problem than the one I have detailed below, and imposes different limits. You need an aerospace geek. Or you could just punt.
To do it "right" (for space):
The simulated body should be provided with a moment of inertia around its center of mass, and must also have a pointing direction and an angular velocity. Then you compute the angular acceleration from the applied impulse and distance from the CoM, and add that to the angular velocity. This allows you to compute the current "pointing" of the craft (if you don't use gyros or paired attitude jets, you also get a (typically very small) linear acceleration).
To generate a turn, you point the craft off the current direction of movement and apply the main drive.
And if you are serious about this you also need to subtract the mass of burned fuel from the total mass and make the appropriate corrections to the moment of inertia at each time increment.
BTW--This may be more trouble than it is worth: maneuvering a rocket in free-fall is tricky (You may recall that the Russians bungled a docking maneuver at the ISS a few years ago; well, that's not because they are stupid.). Unless you tell us your use case we can't really advise you on that.
A little pseudocode to hint at what you're getting into here:
rocket {
float structuralMass;
float fuelMass;
point position;
point velocity;
float heading;
float omega; // Angular velocity
float structuralI; // moment of inertia from craft
float fuelI; // moemnt of inertia from the fuel load
float Mass(){return struturalMass + fuelMass};
float I(){return struturalI + fuelI};
float Thrust(float t);
float AdjustAttitude(float a);
}
The upshot is: maybe you want a "game physics" version.
For reason I won't both to go into here, the most efficient way to run a "real" rocket is generally not to make gradual turns and slow acceleration, but to push hard when ever you want to change direction. In this case you get the angle to thrust by subtracting the desired vector (full vector, not the unit) from the current one. Then you pointing in that direction, and trusting all out until the desired course is reached.
Imagine your in floating in empty space... And you have a big rock in your hand... If you throw the rock, a small impulse will be applied to you in the exact opposite direction you throw the rock. You can model your rocket as something that rapidly converts quantum's of fuel into some amount of force (a vector quantity) that you can add to your direction vector.

Categories