I'm making a game which uses very simple collision detection. I'm not using box 2D because it's an overkill. Basically, it's a mix of Pong and fooseball. As the ball gains speed and has a very high velocity it ends up going through the wall it's supposed to collide with. The code works with slow and regular speeds, but not with very fast motion.
This is a snipet of my code:
pos.x is a vector which holds the x position of my ball.
if (pos.x - radius < wallLeft)
{
pos.x = wallLeft + radius;
vel.x *= -1;
}
What could i do to improve this?
thanks
Try increasing wallLeft a bit, so that the balls speed is never greater than wallLeft, it seems that after your ball goes below 0 it glitches (or you have some code for that that I don't know), not familiar with the framework or how the rest of your code works, but that's the easiest way to solve it. If you don't want to do that, there's probably a code somewhere that does something if the ball's x is less than 0, and you'll have to make that a bit more lenient, maybe make it so that if the ball's x is less than -50, or something like that (play around with the number until it works)
Arguably if (pos.x - radius) == wallLeft then the ball is already touching the wall and its velocity can be reversed; if you add this as an additional test in the loop does it help?
The only idea I am having is that the speed is so high that you get an overflow when adding it to the position, making pos.x > wallLeft + radius again.
Related
My main character is a ball that bounces forever at the same force.
But I having difficulties finding the right way of bouncing at the same height as the game is increasing speed. Basically, here's my formula.
by the way, I'm using C++ and SDL2 so the Y axis is POSITIVE going down and NEGATIVE going up:
every frame, I'm adding the Yvelocity to the ball. Then I add the gravity to the velocity for gravity effect:
ballY += Yvelocity
Yvelocity += gravity
if(Yvelocity >= maxVelocity)
{
Yvelocity = maxVelocity
}
Then whenever I hit the ground, I do this to bounce the ball
Yvelocity = bounceForce; // -10 for example
Everything works great. But I want to make the game faster and faster. So every specific time I do this:
bounceForce += bounceForce * multiplier;
gravity += gravity * multiplier;
maxVelocity += gravity * multiplier;
...
//increase other object's speed too
The game speed is indeed getting faster but the bounce of the ball is also getting higher.
It looks like I have to increase the gravity more than bounceForce. So I tried doing this:
bounceForce += bounceForce * multiplier;
gravity += gravity * (multiplier * 1.5f); /////// <-------------------------
maxVelocity += gravity * multiplier;
...
//increase other object's speed too
That works fine at the beginning. But will likely do the same problem as the time goes by(bounces higher).
I think the more the Yvelocity is increasing, the more the gravity's multiplier has to increase too. Because the ball is getting lighter every increase of speed.
But I really can't find the right formula for that, of how I can make the ball bounce faster and faster but at the same height. Because it's not ideal for my game to increase speed then the ball is in constant speed. Sorry I'm a newbie in game programming. Thanks in advance.
The easy way to make things “the same, only faster” is to increase your time step between frames. Of course, you then have to make explicit all the places where you should have such a dt but have hardcoded it to 1. (Finding invisible code is always fun.)
The obvious places are of course the +=s at the beginning of your code (sketch); your dynamics may include more if they’re complicated enough. (Also note that your equations will become significantly inaccurate with a very large time step; you may want to make dt smaller (at first) and run more than one physics cycle per frame of animation.)
I am editing the rollingball example map from Unreal (in Unreal Engine). I changed it so my ball you grow and melt (it's a snowball), gaining and losing size and mass.
My problem is the control of it. The example map moves the ball by adding torque. My problem is that my mass changes a lot, so I need a torque the changes depending on the size of my ball (not 1:1 as a bigger snowball should still moves slower).
My problem is that my ball seems to accumulate torque and spins a lot (I added a lot of friction to the ball, it did not helped, it just moved the problem a bit). As an example, if I press left for a while, it's gonna go left. Then if I press right, it goes right. But when I stop pressing right, it spins and goes left again.
This is my current code:
void ASnowballBall::MoveRight(float Val)
{
const FVector Torque = FVector(-1.f * getNewTorque(Val), 0.f, 0.f);
Ball->AddTorque(SpringArm->GetComponentRotation().RotateVector(Torque));
}
void ASnowballBall::MoveForward(float Val)
{
const FVector Torque = FVector(0.f, getNewTorque(Val), 0.f);
Ball->AddTorque(SpringArm->GetComponentRotation().RotateVector(Torque));
}
float ASnowballBall::getNewTorque(float Val)
{
return (Val * RollTorque * (log2(Ball->GetMass()))) / 10000;
}
Note: The log was a test to increase the torque slowly with the mass. It's not working well at all. Right now I am using return Val * RollTorque instead, but it's almost as bad.
The control is horrible and I would like to get an idea on how to fix it. If removing the torque would be better, I will change it. I simply want a responsive control that is fun, and where the player still have a sense of the size of the ball (slower when big compared to small).
PS: My original mass is about 500 kg and can go up to 20 000 kg (it's a puzzle game). I did not set the original mass, it's set by Unreal relative to it's size. I could change the mass scale though.
You could try using AddForce instead of AddTorque.
So the speed of the ball is modified every tick like this:
void APlayerBallBearing::Tick(float deltaSeconds)
{
Super::Tick(deltaSeconds);
BallMesh->AddForce(FVector(InputLongitude, InputLatitude, 0.0f) * ControllerForce * BallMesh->GetMass());
}
InputLongitude and InputLatitude are the values that are put in by the user in the current frame for movement in cardinal directions, they correspond to your MoveForward and MoveRight values I reckon.
The controller force is something you need to tweak in order to find the right value for your ball movement. With a value of at least 600.0f I started getting "decent" behaviour.
I cannot help you with the mass though you would need to try that out yourself, the default mass of the ball mesh I used was ~110.
I'm currently building a simplified Reaction Control System for a Satellite game, and need a way to use the system to align the satellite to a given unit direction in world-space coordinates. Because this is a game simulation, I am faking the system and just applying a torque force around the objects epicenter.
This is difficult because in my case, the Torque cannot be varied in strength, it is either on or off. It's either full force or no force. Calculating the direction that the torque needs to be applied in is relatively easy, but I'm having trouble getting it to align perfectly without spinning out of control and getting stuck in a logical loop. it needs to apply the opposing force at precisely the right 'time' to land on the target orientation with zero angular velocity.
What I've determined so far is that I need to calculate the 'time' it will take to reach zero velocity based on my current angular velocity and the angle between the two vectors. If that exceeds the time until I reach angle zero, then it needs to apply the opposing torque. In theory this will also prevent it from 'bouncing' around the axis too much. I almost have it working, but in some cases it seems to get stuck applying force in one direction, so I'm hoping somebody can check the logic. My simulation does NOT take mass into account at the moment, so you can ignore the Inertia Tensor (unless it makes the calculation easier!)
For one axis, I'm currently doing it this way, but I figure someone will have a far more elegant solution that can actually compute both Yaw and Pitch axes at once (Roll is invalid).
Omega = Angular Velocity in Local-Space (Degrees Per Second)
Force = Strength of the Thrusters
// Calculate Time Variables
float Angle = AcosD(DotProduct(ForwardVector, DirectionVector));
float Time1 = Abs(Angle / Omega.Z); // Time taken to reach angle 0 at current velocity
float Time2 = Abs(DeltaTime * (Omega.Z / Force); // Time it will take to reach Zero velocity based on force strength.
// Calculate Direction we need to apply the force to rotate toward the target direction. Note that if we are at perfect opposites, this will be zero!
float AngleSign = Sign(DotProduct(RightVector, DirectionVector));
float Torque.Z = 0;
if (Time1 < Time2)
{
Torque.Z = AngleSign * Force;
}
else
{
Torque.Z = AngleSign * Force * -1.0f
}
// Torque is applied to object as a change in acceleration (no mass) and modified by DeltaSeconds for frame-rate independent force.
This is far from elegant and there are definitely some sign issues. Do you folks know a better way to achieve this?
EDIT:
If anybody understands Unreal Engine's Blueprint system, this is how I'm currently prototyping it before I move it to C++
Beginning from the "Calculate Direction" line, you could instead directly compute the correction torque vector in 3D, then modify its sign if you know that the previous correction is about to overshoot:
// Calculate Direction we need to apply the force to rotate toward the target direction
Torque = CrossProduct(DirectionVector, ForwardVector)
Torque = Normalize(Torque) * Force
if (Time2 < Time1)
{
Torque = -Torque
}
But you should handle the problematic cases:
// Calculate Direction we need to apply the force to rotate toward the target direction
Torque = CrossProduct(DirectionVector, ForwardVector)
if (Angle < 0.1 degrees)
{
// Avoid divide by zero in Normalize
Torque = {0, 0, 0}
}
else
{
// Handle case of exactly opposite direction (where CrossProduct is zero)
if (Angle > 179.9 degrees)
{
Torque = {0, 0, 1}
}
Torque = Normalize(Torque) * Force
if (Time2 < Time1)
{
Torque = -Torque
}
}
Okay well what i take from the pseudocode above is that you want to start braking when the time needed to break exceeds the time left till angle 0 is reached. Have you tried to slowly start breaking (in short steps because of the constant torque) BEFORE the time to break exceeds the time till angle 0?
When you do so and your satellite is near angle 0 and the velocity very low, you can just set velocity and angle to 0 so it doesn't wobble around anymore.
Did you ever figure this out? I'm working on a similar problem in UE4. I also have a constant force. I'm rotating to a new forward vector. I've realized time can't be predicted. Take for example you're rotating on Z axis at 100 degrees/second and a reverse force in exactly .015 seconds will nail your desired rotation and velocity but the next frame takes .016 seconds to render and you've just overshot it since you aren't changing your force. I think the solution is something like cheating by manually setting the forward vector once velocity is zeroed out.
I'm having difficulty getting the Chipmunk physics engine to do what I want. The only solution that appears to work requires some heavy vector math. Before diving into that rabbit hole for the other components of my game, I was hoping someone could fill me in on a better way to go about this. The desired gameplay is as follows:
A character moves around a finite space in a top-down view
Movement is always a constant velocity in whatever direction the character faces
The player taps on the screen, which causes the character to 'turn' towards the touched location
The basic idea is like driving a car. You cannot immediately turn around, but instead must first perform a u-turn. That car must also maintain a constant speed. How might I do this? Bonus question: how can you override whatever method chipmunk calls to update a body's position, and is this a good idea?
There is this tutorial on how to do top down controls using specially configure joints:
http://chipmunk-physics.net/tutorials/ChipmunkTileDemo/
It's based on Chipmunk Pro, but the stuff about controlling the character is easily adapted to vanilla Chipmunk. The "Tank" demo that comes with the non-Pro Chipmunk source implements pretty much the same thing if you want to see some C code for it.
You basically want to rotate the orientation of the player more gradual. You could do this at a constant rate, so when you tap the screen it will start rotating at a constant rate until it has reached the right orientation. This would give a circular turn circle. This will however affect your position, so you would have to keep turning until you would be on a collision course with the position you tapped.
The path you would travel would be similar to that of the game Achtung die kurve.
So you would have to save the location and orientation of the player (x, y and phi coordinates). And to determine whether to stop turning you could do something like this:
dx = playerx - tapx;
dy = playery - tapy;
targetAngle = atan2(dy,dx);
if (phi > targetAngle)
{
if (phi - targetAngle > PI) omega = rotate;
else omega = -rotate;
}
else if (phi < targetAngle)
{
if (targetAngle - phi > PI) omega = -rotate;
else omega = rotate;
}
else omega = 0;
For the past days, I've been trying to make a ping pong like game. I have 2 paddles and a ball. All dynamic sprites. Everything's been working well except for one issue I'm having. The ball tends to bounce on the same angle at some point. So there would be times when the player can simply move the paddle on a specific part and the game can go on for a while or might be forever, since the ball doesn't change its angular velocity regardless of which part of the paddle it hits. I'm using a combination of linear and angular velocity to keep the ball moving like so:
if(_isPaused == FALSE)
{
_world->Step(dt, 10, 10);
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *sprite = (CCSprite *)b->GetUserData();
if(sprite.tag == 2)
{
b2Vec2 dir = b->GetLinearVelocity();
dir.Normalize();
float currentSpeed = dir.Length();
int maxSpeed = 60;
float accelerate = vel;
if(currentSpeed <= maxSpeed)
{
b->SetLinearVelocity(accelerate * dir);
}
sprite.position = ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
sprite.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
//Keep sprite from bouncing in a straight angle
b->SetAngularVelocity(_body->GetAngle());
}}}
So my question is, how can I manipulate the angular velocity to keep the ball bouncing on different angles everytime it collides with my paddle? I'm thinking something like getting the current angular velocity then multiplying it with some value but I'm not sure if that's the right way to approach the issue I'm having. Any suggestions or ideas would be greatly appreciated. Thanks in advanced.
The way I see it, you have two options:
Check the location of a collision. If it's close to the top/bottom edge of the paddle, deflect the outgoing velocity by an angular amount proportional to the surface "curvature" at that point. Of course, this is cheating, but if the artwork and code are in agreement, it looks correct. And graphics is "the art of cheating without getting caught".
You could take into account the current velocity of the paddle as well as that of the ball. Eg: if the ball is moving downwards and to the right, and the paddle is moving down, then you can compute the outgoing direction using conservation of linear momentum. Just make sure you restrict the paddle's change in momentum along the horizontal axis to be zero.
Finally, you could combine the above techniques, but now you'd have to use accurate collision detection (not the hack I described in (1) above).
Hope that helps!
A few pointers, you should use SetLinearVelocity() and SetAngularVelocity() rarely. Each alters a property of the body definition, which could make you run into problems later on when things get more complex. It would be better to use ApplyForceToCenter() or ApplyLinearImpulse() in the place of SetLinearVelocity() as these two are much more versatile functions and are a bit more coder-friendly. In my opinion, I don't think you should use b->SetAngularVelocity(_body->GetAngle()); If you wanted to change the angular velocity each time it collided, you could, in your beginContact method, write that every time the body collides with the paddle body, a random angular impulse is applied to the ball, using ApplyAngularImpulse().Hope that helps.