Okay, so I am trying to simulate the collision of balls on a 2-Dimensional plane. I can detect the collisions pretty easily using a simple comparison of positions and the sum of radii, however, sometimes the simulation gets ahead of itself and the circles overlap, which plays havoc with the rest of the simulation.
So I have figured that finding the normal vector between the two circles at the point of contact and adding onto the position vectors in that direction is what I need to do basically, and luckily I had a similar algorithm handling the velocity changes due to collisions so I adapted it thusly:
Vector2 normal = orgA.getCenterPosition() - orgB.getCenterPosition();
Vector2 tangent = new Vector2((normal.Y * -1), normal.X);
float diff = (orgA.getRadius() + orgB.getRadius()) - normal.Length();
normal.Normalize();
float PAn = Vector2.Dot(normal, orgA.position);
float PAt = Vector2.Dot(tangent, orgA.position);
PAn += diff;
float PBn = Vector2.Dot(normal, orgB.position);
float PBt = Vector2.Dot(tangent, orgB.position);
PBn -= diff;
Vector2 PA = (PAn * normal) + (PAt * tangent);
Vector2 PB = (PBn * normal) + (PBt * tangent);
orgA.position = PA;
orgB.position = PB;
The trouble is that when I run the simulation, and two balls meet, the whole thing goes crazy and they're suddenly going all over the shop.
Can anyone see the flaw in my algorithm? I've looked at it loads and I still can't find what's causing this.
Hey buddy i think what you need is a loop. Its going crazy because once the balls touch they are constantly being upgraded with a new logic....
im not amazing at this but try putting the collision in a loop... should look something like this:
if ( diff < (orb radius))
{
Vector2 PA = (PAn * normal) + (PAt * tangent);
Vector2 PB = (PBn * normal) + (PBt * tangent);
orgA.position = PA;
orgB.position = PB;
}
something like that... I really hope this helps a little :/
from my understanding is this is in your update method, so keep in mind update runs constantly every millisecond... so its fine when your getting the difference between the spheres and sizes but after they collide and you you want them to move in a certain way you are calculating the same equation over and over...
Better yet make a bool such as isCollided and make sure you switch that true/false according to that statement
hope it helps i have an example project of collision if you want i can send it to you, samerhachem#hotmail.com
Related
Taking Captain Forever as an example as well as this tutorial, how would I achieve similar movement? I've found a couple of answers to this question, but I can't quite seem to get them to work for me. I have a parent ridgidbody and two child thruster rigidbodies with the following applied to each.
X = transform.position.x;
Y = transform.position.y;
pos = new Vector2(X, Y);
// Should I be using these anywhere?
float angle = Mathf.Deg2Rad * Vector2.Angle(direction, forward);
Vector2 direction = COM - pos;
Vector2 forward = transform.up * force;
Vector2 distToCOM = pos - COM;
float torque = distToCOM.magnitude * forward;
if (Input.GetAxis("Vertical") > 0)
{
parentRB.AddForceAtPosition(torque,pos);
}
if (Input.GetAxis("Vertical") < 0)
{
// Not done yet
}
Quite a bit of guesswork has gone into this (and I realise some of the code is a bit crude), maths was never my strong point! I have a feeling the torque and force should be vectors, but I'm not sure how to calculate them properly.
Would appreciate any help you can give, thanks!
EDIT: I've made a few changes and I think I've managed to get it a bit closer with the above, but still getting some wonky movement.
I'm trying to create a simple mouse emulator controlled by a joystick's right thumbstick. I was trying to have the mouse move in the direction the stick pointed with a smooth gradient of pressure values dictating speed, but I've hit a number of snags when trying to do so.
The first is how to accurately translate the angle into accurate X and Y values. I can't find a way to implement the angle correctly. The way I have it, the diagonals are likely to move considerably faster than the cardinals.
I was thinking I need something like Math.Cos(angle) for the X values, and Math.Sin(angle) for the Y values to increment the mouse, but I can't think of a way to set it up.
The second, is smooth movement of the mouse, and this is probably the more important of the two. Since the SetPosition() function only works with integers, the rate at which pixels move over time seems very limited. The code I have is very basic, and only registers whole number values of 1-10. That not only creates small 'jumps' in acceleration, but limits diagonal movement as well.
The goal would to have something like 10 pixels-per-second, with the program running at 100hz, and each cycle outputting 0.1 pixel movement.
I'd imagine I might be able to keep track of the pixel 'decimals' for the X and Y values and add them to the axes when they build to whole numbers, but I'd imagine there's a more efficient way to do so and still not anger the SetPosition() function.
I feel like Vector2 objects should get this done, but I don't know how the angle would fit in.
Sample code:
//Poll Gamepad and Mouse. Update all variables.
public void updateData(){
padOne = GamePad.GetState(PlayerIndex.One, GamePadDeadZone.None);
mouse = Mouse.GetState();
currentStickRX = padOne.ThumbSticks.Right.X;
currentStickRY = padOne.ThumbSticks.Right.Y;
currentMouseX = mouse.X;
currentMouseY = mouse.Y;
angle = Math.Atan2(currentStickRY, currentStickRX);
vectorX = (int)( currentStickRX*10 );
vectorY = (int)( -currentStickRY*10 );
mouseMoveVector.X = vectorX;
mouseMoveVector.Y = vectorY;
magnitude = Math.Sqrt( Math.Pow( (currentStickRX - 0), 2 ) + Math.Pow( (currentStickRY - 0), 2 ) );
if (magnitude > 1){
magnitude = 1;
}
//Get values not in deadzone range and re-scale them from 0-1
if(magnitude >= deadZone){
activeRange = (magnitude - deadZone)/(1 - deadZone);
}
Console.WriteLine(); //Test Code
}
//Move mouse in in direction at specific rate.
public void moveMouse(){
if (magnitude > deadZone){
Mouse.SetPosition( (currentMouseX + vectorX), (currentMouseY + vectorY));
}
previousStickRX = currentStickRX;
previousStickRY = currentStickRY;
previousActiveRange = activeRange;
}
Note: I'm using all the xna frameworks.
Anyway, apologies if I'm explaining these things incorrectly. I haven't been able to find a good resource for this, and the vector examples I searched only move in integer increments and from point A to B.
Any help with any part of this is greatly appreciated.
I haven't tried it myself but from my point of view, you should normalize the pad axis after reading them, that way diagonals would move the same speed as cardinals. And for the second part, I would keep track of the mouse in floating variables, such as a Vector2 and do the cast (maybe rounding better) when setting the mouse position.
public void Start()
{
mousePosV2 = Mouse.GetState().Position.ToVector2();
}
public void Update(float dt)
{
Vector2 stickMovement = padOne.ThumbSticks.Right;
stickMovement.Normalize();
mousePosV2 += stickMovement*dt*desiredMouseSpeed;
/// clamp here values of mousePosV2 according to Screen Size
/// ...
Point roundedPos = new Point(Math.Round(mousePosV2.X), Math.Round(mousePosV2.Y));
Mouse.SetPosition(roundedPos.X, roundedPos.Y);
}
I'm programming a 3D XNA game and I'm struggling to understand how to implement a momentum-like collision between my two players. Basically the concept is for either player to hit the other and attempt to knock the opponent off the level (Like the Smash Bros games) to score a point.
//Declared Variables
PrimitiveObject player1body;
PrimitiveObject player2body;
Vector3 player1vel = Vector3.Zero;
Vector3 player2vel = Vector3.Zero;
//Created in LoadContent()
PrimitiveSphere player1 = new PrimitiveSphere(tgd, 70, 32);
this.player1vel = new Vector3(0, 135, -120);
this.player1body = new PrimitiveObject(player1);
this.player1body.Translation = player1vel;
this.player1body.Colour = Color.Blue;
PrimitiveSphere player2 = new PrimitiveSphere(tgd, 70, 32);
this.player2vel = new Vector3(0, 135, 120);
this.player2body = new PrimitiveObject(player2);
this.player2body.Translation = player2vel;
this.player2body.Colour = Color.Red;
//Update method code for collision
this.player1vel.X = 0;
this.player1vel.Y = 0;
this.player1vel.Z = 0;
this.player2vel.X = 0;
this.player2vel.Y = 0;
this.player2vel.Z = 0;
if (player1body.BoundingSphere.Intersects(player2body.BoundingSphere))
{
this.player2vel.Z += 10;
}
As you can see all I'm doing is checking for Player1's bounding sphere and when it intersects with Player 2's then player 2 will be pushed back on the Z axis, now obviously this just wouldn't work and isn't very intuitive and is where my problem lies as I'm buggered trying to work out how to come up with a solution, what I want happening is when either player collides with the other they basically swap vectors giving it that bounce effect I'm looking for and not just affecting one axis but both the X & Z.
Thanks for taking the time to read and I'll be grateful for any solutions that anyone can think of.
Notes:
PrimitiveSphere if you're wondering is using (graphics device, diameter of the sphere, tesselation).
Basically, in a collision like the one you are trying to do, you want an elastic collision, in which both the kinetic energy and momentum are conserved. All momentum (P) is is mass * velocity, and Kinetic Energy (K) is 1/2*mass*velocity^2. In your situtation, I'm assuming everything has the same mass. If so, K = 1/2 * v^2. So, Kf = Ki and Pf = Pi. Using the kinetic energy, the velocity's magnitudes of the players are swapped. And as long as the collisions are head on (which based on your code I assume you're fine with), the players will swap directions.
So you could do something as simple as this:
if (player1body.BoundingSphere.Intersects(player2body.BoundingSphere))
{
Vector3 p1v = this.player1vel;
this.player1vel = this.player2vel;
this.player2vel = p1v;
}
This should create a fairly realistic collision. Now the reason I included that info about P and K is so that if you want non-head on collisions or different masses, you should be able to incorporate that. If the masses aren't the same, the velocity's won't simply change magnitudes and directions. There will be a lot more math involved. I hope this helps.
I'm making a galaxian-like shooter, and my enemy objects have a destination Vector which they travel towards, using this bit of code:
position.X -= (Motion.X / Magnitude) * Speed;
position.Y -= (Motion.Y / Magnitude) * Speed;
Motion is worked out by:
this.Motion = InitialPosition - Destination;
This makes them travel in a straight line towards the destination.
However, I want to make them a bit more interesting, and travel on a sin or cos wave, a bit like Galaxian did.
How can I do this?
You might be better off defining a bezier curve for the movement function than simple functions like a sine wave. Galaxian certainly had more complex movements than that.
Here is a link to a primer on the maths of Bezier curves. It's quite a long document, but does a good job of covering the maths involved, with plenty of examples.
Hope that helps inspire you.
One way to do this would be to create an acceleration factor for the horizontal motion and add that factor to the horizontal speed every tick. So if your horizontal speed for a given enemy was 2 to begin, and your acceleration was -.01, then after 200 ticks the enemy would be going straight down, and after another 200 ticks it would be moving at a horizontal speed of -2. This will give a nice curve.
By determining the speed and acceleration randomly for each enemy (within certain limits determined by experimentation) you can create a nice looking variety of attack profiles without too much effort. This would give a very Galaxian-like motion.
You can do the same thing with the vertical as well, though, of course, the acceleration limits would be very different...for the horizontal acceleration you would probably want to determine a range that was equal in magnitude on either side of 0 (say -.02 to +.02), while for the vertical acceleration, you probably always want the ship to end up going down off the bottom of the screen, so you probably want that acceleration to always end up positive (or negative depending on how you're doing screen coordinates.)
You would do this by utilizing waypoint navigation, in line with your current motion code. You would calculate the waypoints by graphing the sine wave. You would do this by using something to the effect of Destination.Y = Math.Sin(Destination.X) - it's a little difficult to say for sure without seeing your code at large.
Creating an oscillator and moving the enemy (even without momentum) perpendicularly to its direction by an offset equals to the sine or cosine of the oscillator would be enough.
The following example, while working, is clearly just a guideline. I hope it can help you.
var dest = new PointF(200, 100);
var pos = new PointF(30, 140);
var oscAngle = 0d;
var dirAngle = Math.Atan2(dest.Y - pos.Y, dest.X - pos.X);
//Constants for your simulation
const int movSpeed = 2;
const int amp = 2;
const double frequency = Math.PI / 5;
//Inappropriate loop condition, change it to proper
while (true)
{
oscAngle += frequency;
//Scalar offset, you can use Cos as well
var oscDelta = Math.Sin(oscAngle);
//Linear movement
var stepVector = new SizeF((float)(Math.Cos(dirAngle) * movSpeed), (float)(Math.Sin(dirAngle) * movSpeed));
//Oscillating movement, making it transversal by adding 90° to the direction angle
var oscNormalAngle = dirAngle + Math.PI / 2;
//Vector for the oscillation
var oscVector = new SizeF((float)(Math.Cos(oscNormalAngle) * oscDelta) * amp, (float)(Math.Sin(oscNormalAngle) * oscDelta) * amp);
pos += stepVector + oscVector;
//Operate below
}
I am building a teaching platform for teaching basic Physics.
From my experience in Flash development, I have met similar problems before.
The game time is not the same as real world time. In which case, for example, the distance covered by a projectile can be larger or smaller if the computer lags or for whatever reasons.
Here is a screenshot of the said platform. As shown in the screenshot, I am only developing a lesson for teaching the basic s = v * t relation.
Necessary background
The red line marks the position 69.06284 m, our target distance. The time 11.56087 s is a given value.
The user is supposed to input a speed, moving a projectile from 0 m to the right in order to reach the red line within the time given.
The green line marks the position of the projectile when time is up.
I can assure you that I input an accurate speed up to 5 decimal points so there is no human error in this case.
Ignore the yellow rectangle. It is just a UI element.
The screen is 800 pixels wide, and therefore 10 pixels represent 1 meter.
Way to solve the problem
I'm not sure what to do, quite frankly. But I heard from someone that variable time step represents real world time better. However, Farseer, being a physics simulation engine, should be used with fixed time step, isn't it?
Any advice will be greatly appreciated.
EDIT: here in the screenshot, the actual distance covered by the projectile is ~66.3 m, whereas the theoretical distance is 69.1 m. I also notice that if the target distance (currently 69.1 m) is smaller (red line moves a lot more to the left), the error is smaller.
How do I fire a projectile?
public override void ShootProjectile(Vector2 start, float angle, float speed) {
GameTemplate g = Game as GameTemplate;
Arrow a = new Arrow(Game, start, this);
a.Initialize();
a.Restitution = 0f;
a.Friction = 0f;
a.LinearVelocity = new Vector2(speed, 0);
Console.WriteLine("Speed: "+a.LinearVelocity.X);
_fireTime = g.SinceGameStarts;
//Console.WriteLine("Fire time: "+_fireTime);
_projectiles.Add(a);
}
In the Arrow class, I basically set up Farseer through a CreateBody method:
protected override void CreateBody() {
GameTemplate g = Game as GameTemplate;
Vector2 positionInMeters = _initPos / g.MeterInPixels;
float width = 30f / g.MeterInPixels;
float height = 40f / g.MeterInPixels;
_body = BodyFactory.CreateRectangle(g.GameWorld.World, width, height, 1f, positionInMeters);
_body.BodyType = BodyType.Dynamic;
_origin = new Vector2(15f, 40f);
}
How do I calculate the flight time of projectile?
May be you are curious about the _fireTime = g.SinceGameStart line. SinceGameStart is a getter of the variable _currTime in a GameTemplate. The value of _currTime is updated once every Update(gameTime) call. So if I want to know how long the projectile has been flying, I do this:
time = _currTime - projectile.FireTime