I am building a driving game. The view is a perspective one and the player's perspective is from behind the car which is driving forward. When the car is driving forward, all the environment around it moves downwards and scales (This is looking quite good now) which gives the impression of the car moving forward. Now, I want to have some realistic driving controls, so that the car builds up speed and then slows down gradually when the up arrow is released. Currently, I call all the move functions for several sprites when the up arrow is pressed. I am looking for a way to control this so that the functions are not called as often when the car is slow etc etc. The code I have so far is:
protected void Drive()
{
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Up))
{
MathHelper.Clamp(++TruckSpeed, 0, 100);
}
else
{
MathHelper.Clamp(--TruckSpeed, 0, 100);
}
// Instead of using the condition below, I want to use the TruckSpeed
// variable some way to control the rate at which these are called
// so I can give the impression of acceleration and de-acceleration.
if (keyState.IsKeyDown(Keys.Up))
{
// Lots of update calls in here
}
}
I thought this should be easy but for some reason, I cannot make any sense out of it. Would really appreciate some help here! Thanks
First suggestion, don't use ++ and --. Make your TruckSpeed increase at a rate multiplied by the Delta Time. This means that your acceleration and deceleration will work the same on slower and faster computers and will be independent of frame rate hickups. You can also have different increase and decrease rates for better control over your gameplay.
Something along the lines of:
protected void Drive(GameTime gameTime) // Pass your game time
{
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Up))
{
TruckSpeed += AccelerationRatePerSecond * gameTime.ElapsedGameTime.TotalSeconds;
}
else
{
TruckSpeed -= DecelerationRatePerSecond * gameTime.ElapsedGameTime.TotalSeconds;
}
MathHelper.Clamp(TruckSpeed, 0, 100);
...
Also, you can probably replace
if (keyState.IsKeyDown(Keys.Up))
by
if (TruckSpeed > 0)
It's probably simpler to attach the camera to your model and move that in the environment instead of moving your entire environment around the Truck though...
The easiest and correct approach is to separate keyboard control from physics. You want acceleration to be measured in change/per-unit-of-time not change/per-button-click. Than on each time iteration you need to modify speed according to time passed since last update...
Acceleration is not linear. As such, I would recommend not to use the ++ or -- operators. Instead call a function that calculates the change in velocity over time (delta V)/time. If you want a true feeling of acceleration you might think about something to that effect.
Related
I model a swing that has its own drive. This drive consists of a housing and a weight inside it. The weight is accelerated with an electromagnetic field, so that it hits the wall of the housing at high speed and thus sets the swing in motion.
I am farely new to unity but i thought i did everything correct. At the push of a button the weight was accelerated, hit the housing and the swing startet moving. It worked very well until i started to increase the force which is accelerating the weight (The weight is pretty small, so it needs a lot of speed to move the swing). Now the weight is flying out of the housing. I checked all collision boxes. They are correct and i even made them overlapping to ensure this is not the mistake. I have no idea how to fix this problem and would be grateful for any help.
Here is the code that accelerates the weight, in case you need it:
if (rightPressed)
{
GetComponent<Rigidbody>().AddForce(transform.right * forceSlider.value, ForceMode.Impulse);
rightPressed = false;
}
else if (leftPressed)
{
leftPressed = false;
GetComponent<Rigidbody>().AddForce(transform.right * -forceSlider.value, ForceMode.Impulse);
}
For fast moving objects make sure to set the Rigidbody.collisionDetectionMode to CollisionDetectionMode.ContinuousDynamic
I have a ball game object that I am making bounce using explicit physics equations. I tried using unity's physics engine, but It was not exact enough. I am setting the balls position like so:
float dTime = Time.time - timeSinceBounce;
ballPosition.x -= meterOffset / sensitivity;
ballPosition.y = ballInitialPosition.y + GameConstants.Instance.GetBallYVel ()
* dTime - (float)0.5 * GameConstants.Instance.GetGravity () * dTime * dTime; //Yi+Vy*t-0.5(G)(time^2)
ballPosition.z = (-dTime * GameConstants.Instance.GetBallZVel ()
+ ballInitialPosition.z) * startConstant; //Zi + t*Vz
ball.transform.position = ballPosition;
This code runs in the Update() method. When a collision is detected the time and initial position as reset, and this works. Currently the ball bounces properly but shakes when it is moving quickly. The FPS is at 80. I don't think my equations are wrong because it bounces properly there is just a shake. What is the best way to remove the shake? Thank!
Edit 1: I decided to write my own physics because Unity's physics engine had a lot of other components like friction and roll that were making the ball's bounces vary. Also the camera's x and y is fixed the only thing that is changing is the camera's z position. It works a lot better in fixed update
As of asker's request I hereby add all the details I can, even though without seeing the actual, full and complete code along with seeing this "shake" effect it's challenging to give an exact and proper answer. I'll try and do my best though.So let's do this.
1. "Shaking" reason: most probably you set up some kind of animation, along with a forced positioning/rotation/etc and these two codes work against each other. Double-check your AnimatorController and Animator as well as your Mecanim if you have set/configure these (also a good read: "Locomotion").You can also keep the Animator Window open while you are testing from Unity UI, to see who is the tricky guy doing the "shaking" effect for you, and get one step closer to why it happens.If these don't help, start from scratch: Minimize the code you wrote to move the ball, remove every effect, etc and add them back one by one. Sooner or later "shakieness" will come back (if it persist with the cleanest possible code, see above, Animator/Locomotion issue)
2. Think again not rewriting Unity Physics... You mention for example "...physics engine had a lot of other components like friction and roll that were making the ball's bounces vary...".Now, this is something you can turn off. Completely if you want. Easiest way is to set everything to zero on Physics Material (i.e. friction and bouncieness) but if you want Unity to ignore all and every "actual physics" and let you do what you want with your GameObject, tick in the isKinematic property of the Rigidbody. The fun part of it, you'll still collide if and where you want, can AddForce, etc yet neither gravity nor friction or "anything physical" affect you.If you are not comfy with Unity (and you are not it seems), I highly recommend learning about it a bit first as it is a very good and very powerful engine - so don't throw it's features away as they don't work as you initially expected they'll do. For example, Sebastian Lague just started a great beginner series a few weeks ago. The guy is a teacher, his videos are both short, fun and full of information so I can just recommend his channel.
3. As of your code I would make these changes:
public static class GameConstants { //no monobehaviour == can be a "proper, global" singleton!
public static float GetGravity {
get { return [whatever you want]; }
//why not Physics.gravity, using locally when and where it's needed?
}
//etc, add your methods, properties and such
//use this approach if and only IF you access these values application wide!
//otherwise, instead of a """singleton""" logic you just implemented,
//consider adding an empty GameObject to the Scene, name it "GM" and
//attach a "GameManager" script to it, having all the methods and
//properties you'll need Scene-wide! You can also consider
//using PlayerPrefs (see help link below) instead of a global static
//class, so you save memory (but will need to "reach out" for the data)
}
private void FixedUpdate() { //FIXED update as you'll work with physics!
//float dTime = Time.time - timeSinceBounce; //not needed
//positioning like this is not recommended, use AddForce or set direction and velocity instead
ballPosition.x -= meterOffset / sensitivity;
ballPosition.y = ballInitialPosition.y + GameConstants.Instance.GetBallYVel ()
* Time.fixedDeltaTime - 0.5f * GameConstants.Instance.GetGravity () * Time.fixedDeltaTime * Time.fixedDeltaTime; //Yi+Vy*t-0.5(G)(time^2)
ballPosition.z = (-dTime * GameConstants.Instance.GetBallZVel ()
+ ballInitialPosition.z) * startConstant; //Zi + t*Vz
ball.transform.position = ballPosition;
}BUT to be honest,
I would just throw that code away, implement the Bouncing Ball example Unity Tutorials offer, alter it (see point #2) and work my way up from there.
Items not linked but I mentioned in code:
PlayerPrefs, Physics.gravity and Rigidbody.velocity.
Note that 'velocity' is ignoring parts of physics (speeding up, being "dragged", etc) i.e. objects suddenly start moving with the speed you set (This is why Unity5 recommends AddForce instead -linked above-)
It might also come handy you can alter the FixedUpdate() frequency via Time Management, but I'm not sure this is yet needed (i.e. just for bouncing a ball)
I hope this helps and that ball is going to bounce and jump and dance and everything you want it to do ;)
Cheers!
My main problem is, I'm coding a movement simulaltor for a game,
What I want to do is, to check if the character got stuck and its position is not changing.
So What I thought is something like this:
If Me.Location3D is the same for X Amount of time -> Me.SetLocation(Location3D.X = Location3D.X +1, Location3D.Y = Location3D.Y +1)
public void Pulse(float dt)
{
Skandia.Update();
Me = Skandia.Me;
if (Me == null)
{
return;
}
//This void repeats every frame of the game
//functions should take place below
}
If anyone got an idea how to check the elapsed time, that'd be great.
Sadly I havent found such a specific thing on stackoverflow yet, just saying cause the topic sound pretty general.
greetings
If you are working a game, you should use a main loop.
The solution is pretty simple.
Each time you get Inside this method, check the time elapsed between your actions.
You should read this link: https://msdn.microsoft.com/en-us/library/bb203873.aspx
Variable-Step Game Loops
A variable-step game calls its Update and Draw methods in a continuous loop without regard to the TargetElapsedTime. Setting Game.IsFixedTimeStep to false causes a Game to use a variable-step game loop.
Animation and Timing
For operations that require precise timing, such as animation, the type of game loop your game uses (fixed-step or variable-step) is important.
Using a fixed step allows game logic to use the TargetElapsedTime as its basic unit of time and assume that Update will be called at that interval. Using a variable step requires the game logic and animation code to be based on ElapsedGameTime to ensure smooth gameplay. Because the Update method is called immediately after the previous frame is drawn, the time between calls to Update can vary. Without taking the time between calls into account, the game would seem to speed up and slow down. The time elapsed between calls to the Update method is available in the Update method's gameTime parameter. You can reset the elapsed times by calling ResetElapsedTime.
When using a variable-step game loop, you should express rates—such as the distance a sprite moves—in game units per millisecond (ms). The amount a sprite moves in any given update can then be calculated as the rate of the sprite times the elapsed time. Using this approach to calculate the distance the sprite moved ensures that the sprite will move consistently if the speed of the game or computer varies.
I would usually comment with a short answer like this but I'm short 3 reputation.
My solution is just track it with a variable and reset when needed, in your case when character moves.
Double elapsedTimeInMS = 0;
private void YourTimer(object sender, EventArgs e)
{
//Every 10 ms
elapsedTimeInMS += 10;
}
private void btnClick(object sender, EventArgs e)
{
//In your case the character moves
MessageBox.Show(elapsedTimeInMS + "");
elapsedTimeInMS = 0;
}
After edit
You would need to implement a check in your timer to see if elapsed time isn't getting too high.
I am currently working on a project in C# where i play around with planetary gravitation, which i know is a hardcore topic to graps to it's fullest but i like challenges. I've been reading up on Newtons laws and Keplers Laws, but one thing i cannot figure out is how to get the correct gravitational direction.
In my example i only have 2 bodies. A Satellite and a Planet. This is to make is simplify it, so i can grasp it - but my plan is to have multiple objects that dynamically effect each other, and hopefully end up with a somewhat realistic multi-body system.
When you have an orbit, then the satellite has a gravitational force, and that is ofcourse in the direction of the planet, but that direction isn't a constant. To explain my problem better i'll try using an example:
let's say we have a satellite moving at a speed of 50 m/s and accelerates towards the planet at a speed of 10 m/s/s, in a radius of 100 m. (all theoretical numbers) If we then say that the framerate is at 1, then after one second the object will be 50 units forward and 10 units down.
As the satellite moves multiple units in a frame and about 50% of the radius, the gravitational direcion have shifted alot, during this frame, but the applied force have only been "downwards". this creates a big margin of error, especially if the object is moving a big percentage of the radius.
In our example we'd probably needed our graviational direction to be based upon the average between our current position and the position at the end of this frame.
How would one go about calculating this?
I have a basis understanding of trigonometry, but mainly with focus on triangles. Assume i am stupid, because compared to any of you, i probably am.
(I made a previous question but ended up deleting it as it created some hostility and was basicly not that well phrased, and was ALL to general - it wasn't really a specific question. i hope this is better. if not, then please inform me, i am here to learn :) )
Just for reference, this is the function i have right now for movement:
foreach (ExtTerBody OtherObject in UniverseController.CurrentUniverse.ExterTerBodies.Where(x => x != this))
{
double massOther = OtherObject.Mass;
double R = Vector2Math.Distance(Position, OtherObject.Position);
double V = (massOther) / Math.Pow(R,2) * UniverseController.DeltaTime;
Vector2 NonNormTwo = (OtherObject.Position - Position).Normalized() * V;
Vector2 NonNormDir = Velocity + NonNormTwo;
Velocity = NonNormDir;
Position += Velocity * Time.DeltaTime;
}
If i have phrased myself badly, please ask me to rephrase parts - English isn't my native language, and specific subjects can be hard to phrase, when you don't know the correct technical terms. :)
I have a hunch that this is covered in keplers second law, but if it is, then i'm not sure how to use it, as i don't understand his laws to the fullest.
Thank you for your time - it means alot!
(also if anyone see multi mistakes in my function, then please point them out!)
I am currently working on a project in C# where i play around with planetary gravitation
This is a fun way to learn simulation techniques, programming and physics at the same time.
One thing I cannot figure out is how to get the correct gravitational direction.
I assume that you are not trying to simulate relativistic gravitation. The Earth isn't in orbit around the Sun, the Earth is in orbit around where the sun was eight minutes ago. Correcting for the fact that gravitation is not instantaneous can be difficult. (UPDATE: According to commentary this is incorrect. What do I know; I stopped taking physics after second year Newtonian dynamics and have only the vaguest understanding of tensor calculus.)
You'll do best at this early stage to assume that the gravitational force is instantaneous and that planets are points with all their mass at the center. The gravitational force vector is a straight line from one point to another.
Let's say we have a satellite moving at a speed of 50 m/s ... If we then say that the framerate is one frame per second then after one second the object will be 50 units right and 10 units down.
Let's make that more clear. Force is equal to mass times acceleration. You work out the force between the bodies. You know their masses, so you now know the acceleration of each body. Each body has a position and a velocity. The acceleration changes the velocity. The velocity changes the position. So if the particle starts off having a velocity of 50 m/s to the left and 0 m/s down, and then you apply a force that accelerates it by 10 m/s/s down, then we can work out the change to the velocity, and then the change to the position. As you note, at the end of that second the position and the velocity will have both changed by a huge amount compared to their existing magnitudes.
As the satellite moves multiple units in a frame and about 50% of the radius, the gravitational direcion have shifted alot, during this frame, but the applied force have only been "downwards". this creates a big margin of error, especially if the object is moving a big percentage of the radius.
Correct. The problem is that the frame rate is enormously too low to correctly model the interaction you're describing. You need to be running the simulation so that you're looking at tenths, hundredths or thousanths of seconds if the objects are changing direction that rapidly. The size of the time step is usually called the "delta t" of the simulation, and yours is way too large.
For planetary bodies, what you're doing now is like trying to model the earth by simulating its position every few months and assuming it moves in a straight line in the meanwhile. You need to actually simulate its position every few minutes, not every few months.
In our example we'd probably needed our graviational direction to be based upon the average between our current position and the position at the end of this frame.
You could do that but it would be easier to simply decrease the "delta t" for the computation. Then the difference between the directions at the beginning and the end of the frame is much smaller.
Once you've got that sorted out then there are more techniques you can use. For example, you could detect when the position changes too much between frames and go back and redo the computations with a smaller time step. If the positions change hardly at all then increase the time step.
Once you've got that sorted, there are lots of more advanced techniques you can use in physics simulations, but I would start by getting basic time stepping really solid first. The more advanced techniques are essentially variations on your idea of "do a smarter interpolation of the change over the time step" -- you are on the right track here, but you should walk before you run.
I'll start with a technique that is almost as simple as the Euler-Cromer integration you've been using but is markedly more accurate. This is the leapfrog technique. The idea is very simple: position and velocity are kept at half time steps from one another.
The initial state has position and velocity at time t0. To get that half step offset, you'll need a special case for the very first step, where velocity is advanced half a time step using the acceleration at the start of the interval and then position is advanced by a full step. After this first time special case, the code works just like your Euler-Cromer integrator.
In pseudo code, the algorithm looks like
void calculate_accel (orbiting_body_collection, central_body) {
foreach (orbiting_body : orbiting_body_collection) {
delta_pos = central_body.pos - orbiting_body.pos;
orbiting_body.acc =
(central_body.mu / pow(delta_pos.magnitude(),3)) * delta_pos;
}
}
void leapfrog_step (orbiting_body_collection, central_body, delta_t) {
static bool initialized = false;
calculate_accel (orbiting_body_collection, central_body);
if (! initialized) {
initialized = true;
foreach orbiting_body {
orbiting_body.vel += orbiting_body.acc*delta_t/2.0;
orbiting_body.pos += orbiting_body.vel*delta_t;
}
}
else {
foreach orbiting_body {
orbiting_body.vel += orbiting_body.acc*delta_t;
orbiting_body.pos += orbiting_body.vel*delta_t;
}
}
}
Note that I've added acceleration as a field of each orbiting body. This was a temporary step to keep the algorithm similar to yours. Note also that I moved the calculation of acceleration to it's own separate function. That is not a temporary step. It is the first essential step to advancing to even more advanced integration techniques.
The next essential step is to undo that temporary addition of the acceleration. The accelerations properly belong to the integrator, not the body. On the other hand, the calculation of accelerations belongs to the problem space, not the integrator. You might want to add relativistic corrections, or solar radiation pressure, or planet to planet gravitational interactions. The integrator should be unaware of what goes into those accelerations are calculated. The function calculate_accels is a black box called by the integrator.
Different integrators have very different concepts of when accelerations need to be calculated. Some store a history of recent accelerations, some need an additional workspace to compute an average acceleration of some sort. Some do the same with velocities (keep a history, have some velocity workspace). Some more advanced integration techniques use a number of techniques internally, switching from one to another to provide the best balance between accuracy and CPU usage. If you want to simulate the solar system, you need an extremely accurate integrator. (And you need to move far, far away from floats. Even doubles aren't good enough for a high precision solar system integration. With floats, there's not much point going past RK4, and maybe not even leapfrog.)
Properly separating what belongs to whom (the integrator versus the problem space) makes it possible to refine the problem domain (add relativity, etc.) and makes it possible to easily switch integration techniques so you can evaluate one technique versus another.
So i found a solution, it might not be the smartest, but it works, and it's pretty came to mind after reading both Eric's answer and also reading the comment made by marcus, you could say that it's a combination of the two:
This is the new code:
foreach (ExtTerBody OtherObject in UniverseController.CurrentUniverse.ExterTerBodies.Where(x => x != this))
{
double massOther = OtherObject.Mass;
double R = Vector2Math.Distance(Position, OtherObject.Position);
double V = (massOther) / Math.Pow(R,2) * Time.DeltaTime;
float VRmod = (float)Math.Round(V/(R*0.001), 0, MidpointRounding.AwayFromZero);
if(V > R*0.01f)
{
for (int x = 0; x < VRmod; x++)
{
EulerMovement(OtherObject, Time.DeltaTime / VRmod);
}
}
else
EulerMovement(OtherObject, Time.DeltaTime);
}
public void EulerMovement(ExtTerBody OtherObject, float deltaTime)
{
double massOther = OtherObject.Mass;
double R = Vector2Math.Distance(Position, OtherObject.Position);
double V = (massOther) / Math.Pow(R, 2) * deltaTime;
Vector2 NonNormTwo = (OtherObject.Position - Position).Normalized() * V;
Vector2 NonNormDir = Velocity + NonNormTwo;
Velocity = NonNormDir;
//Debug.WriteLine("Velocity=" + Velocity);
Position += Velocity * deltaTime;
}
To explain it:
I came to the conclusion that if the problem was that the satellite had too much velocity in one frame, then why not seperate it into multiple frames? So this is what "it" does now.
When the velocity of the satellite is more than 1% of the current radius, it seperates the calculation into multiple bites, making it more precise.. This will ofcourse lower the framerate when working with high velocities, but it's okay with a project like this.
Different solutions are still very welcome. I might tweak the trigger-amounts, but the most important thing is that it works, then i can worry about making it more smooth!
Thank's everybody that took a look, and everyone who helped be find the conclusion myself! :) It's awesome that people can help like this!
At the moment, I have a sprite that I have arbitrarily set to move 1 pixel per second. The code is basically this (The code isn't optimised at all, I could do it much nicer but it is the principle I am trying to solve first:):
private const long MOVEMENT_SPEED = 10000000; // Ticks in 1 second
private long movementTimeSpan = MOVEMENT_SPEED;
protected void PerformMovement(GameTime gameTime)
{
movementTimeSpan -= gameTime.ElapsedGameTime.Ticks;
if (movementTimeSpan <= 0)
{
// Do the movement of 1 pixel in here, and set movementTimeSpan back to MOVEMENT_SPEED
}
}
Perform movement is called in a loop as you'd expect, and it equates to updating around 10 times per second. So if I lower the MOVEMENT_SPEED, my sprite speeds up, but it never gets any faster than 10 pixels per second. For projectiles and other stuff I obviously want it to update much faster than this.
If I alter the movement to 2 pixels or more, it creates issues with calculating collisions and suchlike, but these might be possible to overcome.
The other alternative is to store x and y as a float rather than an int, and increase the values as a fraction of the number of elapsed ticks. I am not sure if this will create smooth movement or not as there still has to be some rounding involved.
So my question is, does anyone know the standard way?
Should I increase the amount to more than 1 pixel and update my collision detection to be recursive, should I store X,Y as floats and move as a % of elapsed time, or is there a 3rd better way of doing it?
The standard way is to not count down a timer to move, but instead the opposite:
private const float MOVEMENT_SPEED = 10.0f; //pixels per second
private float time;
protected void PerformMovement(GameTime gameTime)
{
time = (float)gameTime.ElapsedGameTime.TotalSeconds;
character.X += MOVEMENT_SPEED * time;
}
Make the movement based on the time elapsed. The reason floats are commonly used is to get the fractional value of motion. Fixed-point is another common fractional representation but uses ints instead.
As for collision, collision can be very tricky but in general you don't absolutely need to do it once per pixel of motion (as you suggested with recursion); that's overkill and will lead to terrible performance in no time. If you are currently having trouble with 2-pixel motion, I would reevaluate how you're doing your collisions. In general, it becomes problematic when you're moving very fast to the point of skipping over thin walls, or even passing over to the "wrong side" of a wall, depending on how your collision is set up. This is known as "tunnelling". There are many ways of solving this. Look here and scroll down to "Preventing Tunnelling". As the article states many people just cap their speed at a safe value. But another common method is to "step" through your algorithm in smaller time steps than is currently being passed in. For example, if the current elapsed time is 0.1, you could step by 0.01 within a loop and check each small step.
A way to do what you request, although not very recommended, is to increase your game's update frequency to a higher value than the usual 30 or 60 fps, but only draw to the screen every N frames. You can do it by just having your graphics engine ignore Draw calls until a count or timer reaches the desired value.
Of course, this solution should be avoided unless it is specifically desired, because performance can degrade quite fast as the number of updated elements increases.
For example, Proun (not an XNA game) uses this trick for exactly your reasons.
With the default of IsFixedTimeStep = true, XNA behaves in a similar fashion, skipping calls to Draw if Update takes too long.