What is the ideal way to implement projectile physics, like a cannonball or arrow? I've been experimenting with BodyForce / BodyVelocity but those look like they're applying a constant, non-diminishing force / velocity to the projectile which doesn't look realistic. I've also just set the Velocity property of the projectile directly which works better, but I'm assuming there's a standard pattern used for something like this.
In physics, velocity is split into 2 components, the vertical component and the horizontal component. When a projectile is in motion through the air, we don't consider air resistence affecting its speed, as it's such a minute force.
Since velocity is split into 2 components, if velocity changes or is applied horizontally, that horizonal velocity or force does not affect the vertical force or velocity, and vice versa. This is why projectiles travel at a constant speed horizontally. The vertical velocity, however, is not constant. Due to gravity, the projectile will fall to the earth faster over time. This is acceleration.
What you could try is to add a body velocity with a high value, such as 400,400,0: a velocity for the x, y and z axis, and then immediately remove the velocity a fraction of a second later. What this does is creates an initial velocity, which eventually gets changed by gravity on the y component.
To learn more about projectile physics, you can check out online resources such as the following:
http://bowlesphysics.com/images/AP_Physics_B_-_Projectile_Motion.pdf
Related
I made a very simple program where it creates edgecolliders on the edges of the screen, and then launches an ellipse that has a circleCollider2d attached to it with impulse force.
I set all the colliders (edge and circle) to use the bouncy material with bounciness set at 1.0 (infinite bounce).
I am having a strange issue where over time, one of the axis of velocity converges to 0. For example
this.GetComponent<Rigidbody2D> ().AddForce (new Vector2 (100, 100), ForceMode2D.Impulse);
What happens is that the object will start moving in a diagonal fashion, but given enough bounces, the velocity goes to just alternating between (100,0) and (-100,0). This can happen either where the x axis goes to 0 or the Y axis goes to 0. It depends on which one was higher during the start.
I am not sure why this is happening. Basically visually, the object will start bouncing around, and after about 10 bounces or so, it will just be bouncing back and forth in a straight line instead of preserving the other axis as well. I have no idea why it does that. I don't have any of the constraints on (I also tried constraining Z axis rotation, but that did nothing).
bouncyness on all edge colliders as well as the circle collider are set to 1.0.
The rigid body has mass at 1, and all drag coefficients are set to 0 as well.
The intention is for it to just bounce endlessly.
I will answer my own question here as I just realized why this is happening once I observed the behavior of the rotation. It completely did not occur to me that friction would have a hand in this, especially since friction in this case was resulting in the same simulation each time.
Along with turning bounciness to a 1, you must also turn friction to 0.
So my friend and I are making some 2D game, we are using some custom character controller, so we are not using rigidbody2D. Now we have some sort of catapult which needs to eject the player in a projectile-motion style.
We've done it for the catapult which shoots the player straight up
In inspector you can decide how much units do you want player to jump and how much does it need to get to reach max height.
So here is the code for the catapult that shoots the player up.
float ejectInicialY = (jumpHeight - ( player.physics.gravity * Mathf.Pow(timeToReachMaxHeight, 2) / 2)) / timeToReachMaxHeight;
float ejectVelocityY = ejectInicialY + player.physics.gravity * Time.deltaTime;
player.physics.playerVelocity = new Vector2(ejectVelocityY, 0f);
I tried to apply the same formulas for the X coordinate, but it doesn't work well.
Any help would be greatly appreciated.
This is ultimately a physics problem.
You are calculating current velocities by determining the acceleration of the object. Acceleration of an object can be determined from the net force acting on the object (F) and the mass of the object (m) through the formula a = F / m. I highly recommend reading some explanations of projectile motion and understanding the meaning of the motion equations you are using.
Vertical Direction
For the vertical direction, the net vertical force during the jump (assuming no air drag, etc.) is player.physics.gravity. So you apply your motion formulas assuming a constant acceleration of player.physics.gravity, which you've seemed to have accomplished already.
Horizontal Direction
Becausegravity does not commonly act in the horizontal direction, the net horizontal force during the jump (assuming no air drag, etc.) is 0. So again you can apply your motion formulas, but this time using 0 as your acceleration. By doing this, you should realize that velocityX does not change (in the absence of net horizontal force). Therefore the X coordinate can be determined through (in pseudo-code) newPositionX = startPositionX + Time.deltaTime * velocityX
I have the jump component who use the AddForce for jumping and the movement component who move left and right using the Velocity.
If you don't move the character when your are jumping the jumping will be fine but when you move the character and jump at the same time then the movement component will break the jumping because the velocity is setting up a Vector2 point where define the Y axis too. I tried to use the current Y axis from the transform component in the movement but even that doesn't work.
What I should do for fix the problem between AddForce and then use Velocity?
It seems your move function is creating a new velocity vector and overwriting the existing one.
Vector2 velocityVector = rigidbody.velocity;
velocityVector.x += movement * force;
rigidbody.velocity = velocityVector;
This will retain the existing velocity, both X and Y, and modify it. You will of course need to add deceleration (usually I use something along the lines of if(grounded) velocityVector.x *= 0.999f;, but I'm sure more fancy maths exists for more realistic deceleration) and some kind of maximum speed (again, I keep things simple and use similar to if(velocityVector.x > maxSpeed) velocityVector.x = maxSpeed;).
Rigidbody.AddForce has the following definition:
public void AddForce(Vector3 force, ForceMode mode = ForceMode.Force);
One of the options available for ForceMode is ForceMode.VelocityChange:
Add an instant velocity change to the rigidbody, ignoring its mass.
Apply the velocity change instantly with a single function call. In contrast to ForceMode.Impulse, VelocityChange will change the velocity of every rigidbody the same way regardless of differences in mass. This mode is useful for something like a fleet of differently-sized space ships that you want to control without accounting for differences in mass. In this mode, the unit of the force parameter is applied to the rigidbody as distance/time.
How does SpriteKit's physics engine (Box2d) move bodies and apply gravity to them?
is it just the standard:
velocity = velocity + gravity
position = position + velocity * deltaTime
or is there a more complex equation.
I ask this because I am trying to calculate the trajectory of the body and plot it.
Simplified, this is correct. However there can be other forces acting on a body (collisions, joints) and thresholds (ie stop moving if velocity below threshold, etc) and floating point rounding errors can add up.
So if you're looking for a forward calculation it depends on how precise it needs to be.
The most precise option would be to actually run the simulation to advance it to see where bodies will be - however since SK doesn't give you the Box2D sources this can't be done, ie you can't copy the world state and advance it manually in a copy of the current world.
I was wondering if anyone can give me pointers on how to achieve the following using Box2D on the iphone:
1) I have a Box2D world with normal gravity of -9.8
2) The bottom half of the screen is a body of water
So when my sprite hits the body of water, I want him to react with buoyancy (similar to what's going on in this video: http://www.youtube.com/watch?v=0uX-1GXYIss)
Is the best way to achieve this to
1) simply calculate the y position of the main character sprite and then switch the gravity variable accordingly
or 2) is there a specific feature built into Box2D that will allow me to set my "water" sprite to behave as water in my world and "push" my main character sprite up (while still respecting the world gravity of 9.8)
Any info would be appreciated
The buoyant force is equal to the density of the fluid times the volume of the fluid displaced (which gives you the mass of the fluid displaced) times the acceleration due to gravity. The volume of fluid displaced can be costly to compute however. I would suggest making a simple estimate of the volume displaced based on the size of the object and how far it is submerged in the liquid.
Another very important force in fluid is the drag force. This is what makes it more difficult to move objects at high velocity through thick fluids. The drag force can easily be estimated by simply damping the velocity by some constant value: Force_drag = -b * v where b is your damping value and v is the object's velocity.