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
Related
I'm recreating the movement system from the DS game Dragon Quest Heroes Rocket Slime in Unity. Currently I've got pretty desirable results but it's not 100%.
One of the things that are different is that my player bounces back from walls further on long distance slings than he does in the original game. (left is my recreation, right is original game). Obviously, I can't find out how the game was made and the exact maths/values they use for slinging but one of the things I got from the game is that:
The player moves at constant velocity while slinging in a direction (no slow down, they just stop at a certain point)
Which led me to believe the game doesn't use traditional velocity mechanics so I made it so:
While stretching, the players 'pVelocity' (potentialVelocity) goes up. When they let go a point create at curPlayerPosition + pVelocity is created. I then move the player at a constant velocity to that point. My idea to fix my issue of bouncing too far is by getting the distance from the position where I slung from to the end point and making the player bounce less the larger the distance and further the smaller the distance.
Problem is, I'm not really sure how to do that last part.
Here's my code:
Vector2 reflectedVelocity = Vector2.Reflect(pVelNormalized, foundHit.normal);
playerAnimator.SetFloat("VelocityX", reflectedVelocity.x);
playerAnimator.SetFloat("VelocityY", reflectedVelocity.y);
float DistanceFromOrigin = Vector3.Distance(slingOrigin, transform.position);
print(DistanceFromOrigin);
//ToDo: reflectedVelocity is lower the higher DistanceFromOrigin is.
The other solution I thought of is that maybe my idea of how the 'velocity' works in the original game is completely wrong and if so, please tell me how it actually is/looks to be actually done
reflectedVelocity is lower the higher DistanceFromOrigin is.
So reflectedVelocity should have an inverse relationship with DistanceFromOrigin
Vector2 reflectedVelocity = Vector2.Reflect(pVelNormalized, foundHit.normal);
float DistanceFromOrigin = Vector3.Distance(slingOrigin, transform.position);
if(DistanceFromOrigin == 0) DistanceFromOrigin = 0.00001f;//to avoid division by zero
reflectedVelocity *= (SomeConstant / DistanceFromOrigin);
playerAnimator.SetFloat("VelocityX", reflectedVelocity.x);
playerAnimator.SetFloat("VelocityY", reflectedVelocity.y);
You may use a linear relationship instead of non-linear:
reflectedVelocity *= (SomeConstant - DistanceFromOrigin);
I'm going to create an endless runner in Unity and I was wondering if I should move the player or the scenario during the runs.
The most obvious answer sounds like "the player" because you are moving fewer objects but... does the performance get affected if the size of the scenes is too large? I don't think so but my real worry is about the coordinate:
What happens if the player runs so far away that the coordinates can't fit in a float variable? I think that the transform component uses a Vector3 to store the coordinates and this Vector3 uses float variables (with a limit of +3.4E+38) for each of the coordinates.
Thank you for your answers in advance,
Guillem Poy
Even if I don't know what happens if the value of the coordenates exceeds the capacity of a float variable (I think that then the number simply will be wrong) doing some calculus...
Even if the player is moving 1000 units per second, to create that problem, the player should be playing during 9.4+E32 hours (2.5+E29 years). I think that nobody is going to play this much.
So, the best option I think that is to move the player.
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!
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!
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.