Gravitational attraction and collision - java

I made a simple program that simulates how a round object would behave with a roudn surface in an environment with gravity and collision.
My problem is related with the application of gravity: whenever an object get's very close to the attractor it starts reegaining height, what I think is causing the issue is that, let's say that the ball is touching the ground with very low speed, my program applies gravity and, sicne it will make contact, reverses the force and sends it into the air again.
I tried stopping the ball once it reached low enough speed, but the effect is overall unpleasing (it never is slow enough to make it seemless)
This is the code, what do you thin kis the mistake? As I listed only part of the code and it's pretty complciated I don't expect a specific response, but where do you think the issue could generally lie?
My guess is that I didn't respect the kinetic/potential energy relation, but I wouldn't know how to make it right either :/
void update(ArrayList<Attracter>a) {
pos.add(acceleration);
println(acceleration.mag());
for (Attracter ar : a)
if (PVector.dist(pos, ar.pos)<ar.size/2+size/2) {
//send the compenetrated body back
float difference=((ar.size/2+size/2)-PVector.dist(pos, ar.pos)+1);
pos.sub(acceleration.copy().normalize().mult(difference));
//calculate the new acceleration
PVector perpendicular= PVector.sub(pos,ar.pos).normalize(); //perpendicolare
float angle=perpendicular.rotate(-PI/2).heading();//angolo dellatangente
perpendicular.rotate(-angle); //normalizzo l'angolo
acceleration.rotate(-angle); //normalizzo l'accellerazione
PVector newAcceleration= PVector.fromAngle(perpendicular.heading()-acceleration.heading());
acceleration=newAcceleration.setMag(acceleration.mag());
acceleration.rotate(angle); //denormalizzo l'accellerazione
//push the body forward
pos.add(acceleration.copy().normalize().mult(difference));
acceleration.mult(0.9);
}
}

Remove the +1 in the difference calculation, i.e. try to replace
float difference=((ar.size/2+size/2)-PVector.dist(pos, ar.pos)+1);
with
float difference=((ar.size/2+size/2)-PVector.dist(pos, ar.pos));

Related

Calculating collisions, taking into account velocity

I'm making a platformer game. The jumping and movement are working, and now I want to program the collisions. I have a sort of idea as to how this will work:
I wasn't sure whether this question should be here or in the game dev site.
I have two Vector2's - velo and momentum (velo is the velocity). Both are (0, 0). The momentum is what's added to the velocity each frame.
Each frame, I first get the input. Momentum is increased and/or increased based on the keys pressed (e.g: if (Gdx.input.isKeyPressed(Keys.A)) { momentum.x -= speed; })
I then multiply the momentum by 0.15. This is so that it slows down.
After this, I multiply the velocity by 0.8.
Then, I add the momentum to the velocity, to increase the velocity, as
this is what actually moves the player.
I then add the velocity to the position of the player.
To apply the gravity, I add a gravity vector (0, -10) to the position of the player.
So I need to find a way to move the player, but not allowing it to overlap any part of the world. The world is made up of lots of Rectangle instances. The player's body is also an instance of Rectangle. Would it be easier to rewrite the collisions using Box2D? What I've tried is checking if the player overlaps any rectangles when it's moved, and if it will, not moving it. But this doesn't seem to take everything into account - sometimes it works, but other times, it stops before touching the world.
TL;DR: I want to make collisions of my player with a world which is stored as a grid of rectangles. How would I do this, as my player is also a Rectangle. Would it be easier to use Box2D?
This answer gives a good overview about the details of collision detection:
https://gamedev.stackexchange.com/a/26506
However, that might be a bit overwhelming if you just want to get a simple game going. Does your game loop happen in fixed interval or is it dependent on the framerate? Maybe you could solve a part of your issue by simply dividing the collision detection into more steps. Instead of moving the full way during one update, you could make 10 little updates that each move you only a 10th of the distance. Then you do a collision check after each step, so it's less likely that you stop too early or move through thin objects.
That would of course be more taxing on the performance, but it's a naive and easy to implement approach to a solution.
EDIT:
Just wrap the position update in a for loop. I don't know how your code for collision checking and updating, but the general structure would be something like
for (int i = 0; i < 10; i++) {
newPosX += deltaX * 0.1; // 1/10th of the usual update
newPosY += deltaY * 0.1; // 1/10th of the usual update
if (checkCollision(newPosX, newPosY))
{
posX = newPosX;
posY = newPosY;
}
else
{
break; // We hit something, no more mini-updates necessary.
}
}

Will "Rubber banding" resolve multiplayer interpolation stutter?

I wrote multiplayer Pong using UDP. I am using interpolation and extrapolation in order to create a smooth looking effect on the client.
It works. However, there is a bit of constant stuttering in the ball. It jumps a tiny bit forward every time a new packet is received. It looks a little laggy, but it is playable.
There must be a way to make the game look smoother. I've read about Rubber Banding. What would be the best way to move from here?
I hope someone who is able to answer my question well will find it.
Update
As requested by Ivan, here is a graph of the ping times. However, I do believe that the problem exists inside the client smoothing code.
Filling in with context from your previous question, I understand that you are sending paddle & ball positions from each client to the other. However, as long as the clients agree on where the paddles are at each moment in time, the ball's movement is completely determined (barring rounding errors), and you should experiment zero ball-stutter.
Each client should keep its own internal state with the positions and speeds of paddles and the ball. Pseudocode would be similar to the following:
// input thread
if input changed,
alter paddle speed and/or direction
send timestamped message to inform my opponent of paddle change
// incoming network thread
if paddle packet received
alter opponent's paddle speed and/or direction at time it was sent
fix any errors in previously extrapolated paddle position <--- Easy
if ball-packet received
fix any errors in ball position and speed <--- Tricky
// update entities thread
for each entity (my paddle, opponent paddle, the ball)
compute updated entity position, adjusted by time-since-last-update
if ball reached my end, send ball-packet to other side
draw updated entity
This assumes that two package types are being exchanged:
paddle packets are timestamped positions + speeds of paddles, and are sent whenever a client alters the speed of its own paddle.
ball packets are timestamped positions + speeds of the ball, and are sent whenever a ball reaches a client's (local) side, whether it bounces off the paddle or not.
The pseudocode is performing extrapolation ("assume things keep on moving as usual") for all unknowns in the update-entities thread. The only point where problems arise is marked with <--- arrows.
You can easily correct for paddle positions by warping them to their new position, possibly interpolating the movement over a short period to make it less jarring.
Correcting for ball positions is easy if both clients more-or-less agree (and then you can do the interpolation trick again, to smoothen it up further). However, one client may see a near miss and another a near hit. In this case, since you are using a peer-to-peer model, we are letting the local client make the call, and explain what happened to the opponent (in another design, you would have a central server making these kinds of decisions; this is good to avoid cheating). You cannot avoid an ugly jump there if both clients disagree - but hopefully, this should be relatively rare and short, unless it coincides with a ping spike.
One of the ideas which allows to get rid of this effect is Using smoothing when applying error prediction corrections on client.
How that works
At some point in your code you identify that ball position and client are different.
Instead of applying that as a correction to client code immediately (which is one reason you can see those jumps), you perform that over some time, cl_smoothtime e.g. 500ms.
At first your program should store time when the error detection event occured m_flPredictionErrorTime.
public void onErrorDetected() {
this.m_flPredictionErrorTime = System.currentTimeMillis();
}
Somewhere close to the display code you calculate how much of error you're going to display. Here's some pseudocode for that.
public void draw() {
Point preditctionError = this.clientPredictedBallCoordinates - this.serverCoordinates;
Point deltaToDisplay = calculateErrorVector(preditctionError);
Point positionToDisplay = clientPredictedBallCoordinates + deltaToDisplay;
// actually draw the ball here
}
public Point calculateErrorVector(Point coordinatesDelta) {
double errorAmount = ( System.currentTimeMillis() - this.m_flPredictionErrorTime ) / this.cl_smoothtime.
if (errorAmount > 1.0) {
// whole difference applied in full, so returning zero delta
return new Point(0,0);
}
if (errorAmount < 0) {
// no errors detected yet so return zero delta
return new Point(0,0);
}
Point delta = new Point(coordinates.x*errorAmount, coordinates.y*errorAmount);
return delta;
}
I've picked this idea from Source Multiplayer Networking wiki. Actual code example in Cpp is available in their SDK around GetPredictionErrorSmoothingVector function.

Dead Reckoning - Client/Server game - How to handle keystrokes

I've read a few articles about dead reckoning, but it's still a bit confusing to me.
I'm pretty sure I understand the concept of point-and-click movement, but how would I update keystroke movement between the client and server, when the end-point of the movement is unknown?
How would you estimate where the player is going (server-side) if there is no end-point?
Let's start with dead reckoning. Try to think about it on a straight line where there is no left or right movement.
You are at point A and want to get to point B. You know the distance to point B so you can compute how much acceleration and velocity it will take to get there. Dead Reckoning works the other way. You are at point A and will move at a set speed to get near point B.
In the video game world they use this method all the time. So don't think about it as you're moving to point B you're just moving towards point B in increments because in like a FPS your point B will constantly moving. When in fact its really only moving in increments in the direction of point B.
Once you get moving forward then you can start worrying about left/right and up/down which will follow the same principle just in different directions.
As for implementing this you have 2 options.
One way, you could make this calculation on the client side then send the new position to the server. Then update what everyone else sees on screen.
The other way which I think is better you can make all these calculations on the server side and just receive an update where you ended up. X-Box live makes one of the consoles the host so that machine is running all the software and the external users are just firing events. This is why you'll hear people complain about having an unfair host advantage.
Now let's look at some code. This script comes from the Unity Sdk standard install package.
/// This script moves the character controller forward
/// and sideways based on the arrow keys.
/// It also jumps when pressing space.
/// Make sure to attach a character controller to the same game object.
/// It is recommended that you make only one call to Move or SimpleMove per frame.
var speed : float = 6.0;
var jumpSpeed : float = 8.0;
var gravity : float = 20.0;
private var moveDirection : Vector3 = Vector3.zero;
function Update() {
var controller : CharacterController = GetComponent(CharacterController);
if (controller.isGrounded) {
// We are grounded, so recalculate
// move direction directly from axes
moveDirection = Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (Input.GetButton ("Jump")) {
moveDirection.y = jumpSpeed;
}
}
// Apply gravity
moveDirection.y -= gravity * Time.deltaTime;
// Move the controller
controller.Move(moveDirection * Time.deltaTime);
}
So in this example we have speed which is set to a constant. So when moving in a direction we will travel in that Vector at a constant rate with no care about where point B is located.
Jump speed is how fast will we move in the y axis in the positive direction and gravity in the negative direction stopping at point 0.
So, How can you use this? You could build a server script that executes a move action and have a client side controller that passes the direction information to the server.
So lets say on the client side action is key press down, you send a call to the server to move you in the direction selection and the server will keep you moving you in that direction until action key press up or a change in direction from another input.
I hope this helped.
Let's see... I understand you know how to code, but not what, am I right?
You can feed the keystrokes directly to the server and let it do all the work. The server has no need to know where you are heading, it has your coordinates and direction and that's all it will need, unless you have server-handled AI. In the later case, you can do something similar to raycasting in Unity, start checking what is straight ahead and see if it is anything of interest, if so you know the potential destination.
It is safe to constantly send back to the client all his data, so it is always up to date. If you believe this will strain your connection you can do that every 50ms or as often as you believe is safe, and for smooth function estimate everything on the client side too. Make sure the server does all the collision detection and all the mechanics not related to the UI, or else the game will be prone to client-side malfunction or malicious tampering.
If you do have to look at where the player might be going, you can use a few approaches, you could either have a number of virtual cubes in the world which keep track of what is inside them, which will simplify finding what's ahead in terms of resources, or you could check everything there is, which is rather heavy on the machine, but this adds some other complexities too. In the first case do not forget to stop looking once you hit an obstacle.
You can also calculate the angle between the player's direction and other items of importance to check what else might be on his mind.
The question about UDP has already been answered, plus I'm sure Wikipedia has a helpful book on UDP and TCP, I have nothing to add.
The explanation of dead reckoning was also quite satisfactory, I hope I added other angles to the concept.
I hope I helped, if you need any clarifications or any other help feel free to contact me, if I was less than unhelpful then feel free to downvote, I study computer engineering and am creating my second game for PC so maybe I have ran into some problem already and can share the knowledge.

Make an image move across the screen at the correct speed for all displays

I have a top down shooter using the paint method and I would like for it to work on all displays. It works by getting the resolution and dividing the x and y by 40 to separate it all up into squares.
My method of making the bullets move is by having a thread and a move method.
public void move(){
x += dx;
y += dy;
}
But if the persons computer is smaller, the bullet would move across the screen quicker. How can I get it to move at slower on smaller screens and faster on bigger screens?
Thank you for any suggestions.
What do you actually mean by slower? Do you mean as in the total time (measured in seconds) for the bullet to move across the screen is different in different devices?
Assuming that you did all calculation correctly as you described, I think you forgot one factor: different devices have different computing speed (and may be screen update speed also), so a "tick" in one device might be longer or shorted than some other. So when you call move, you should calculate how much time has passed from that last time moved() was called, and then you would calculate dx and dy based on it. Hope this make sense
I think you're forgetting not every computer runs at the same speed, if you've got this looping as fast as it can it will run very different on every computer. I suggest implementing delta scaling, this consists of timing the last frame, say you want 60fps, that means it needs to be 16 milliseconds, so take the time and divide it such as:
int lastframe = getFrameTime();
float scaler = lastFrame/(1000f/targetFrameRate)
then multiply all movements to this scale. such as:
public void move() {
x += dx * scaler;
y += dy * scaler;
}
A also see what you mean with different screen sizes being faster, this is because of the pixel density, to get this you will have to get the screen physical dimensions along with the resolution. For example if your screen is 20mm wide and its 1280x720, it's 20/1280 , this gives you the fact that each pixel is 0.015mm wide. You can then use the above scalar technique to scale them to move a physical world speed.

Java: moving ball with angle?

I have started to learn game physics and I am trying to move a ball with an angle. But it does not change its angle. Java coordinate system is a little different and I think my problem is there. Here is my code.
This is for calculating x and y speed:
scale_X= Math.sin(angle);
scale_Y=Math.cos(angle);
velosity_X=(speed*scale_X);
velosity_Y=(speed*scale_Y);
This is for moving ball in run() function:
ball.posX =ball.posX+(int)velosity_X;
ball.posY=ball.posY+(int)velosity_Y;
I used (int)velosity_X and (int)velosity_Y because in ball class I draw object
g.drawOval(posX, posX, width, height);
and here g.drawOval requires int. I dont know if it is a problem or not. Also if I use angle 30 it goes +X and +Y but if I use angle 35 it goes -X and -Y. I did not figure out how to work coordinate system in Java.
Math.sin() and Math.cos() expect the angle in radians. You should transform your angles to radians (angle*Math.PI/180).
Use Math#toRadians()
scale_X = Math.sin(Math.toRadians(angle));
scale_Y = Math.cos(Math.toRadians(angle));
Check your types. You probably want everything to be floats because your scale variables are going to be less than one, greater than zero. If they are multiplied by ints, there is a good chance you will end up converting to a 1 or 0 all the time. I'm not completely sure of this, I'd code up a few simple equations to make sure (rather than memorize all the rules) if I were you.
One way to do it is to downcast your floats (or doubles) to int at the last possible moment (when you need to pass the values to a method call). This is a little bit of an overkill but doesn't hurt anything but CPU that you aren't using anyway--and may prevent bugs.

Categories