Planets | A Multiplayer Planet Gravity Game

avatar
(Edited)

Repository

https://github.com/ajayyy/Planets

What is this

This is multiplayer planet-based game. There are planets, circles with a gravitational pull, that pull all players towards them. When a player collides with the planet, they bounce off. You can press W and A to move left and right relative to the normal of the planet position you are currently in. You can also click on-screen to launch a projectile. Launched projectile will fly in the direction you point and also get pulled in by gravity, but they will not bounce off the planet. When you launch a projectile, you get pushed in the other direction (equal and opposite force). The is another way to move. When a projectile collides with a player, they bounce off of each other, allowing one player to launch a projectile at another player to push them around.

At the moment, there is no game, however you can move around and shoot other players. Theoretically, it can support as many players as you need (or hit the integer cap of 2.14 billion).

planets demo 1.gif

Instructions to run

Launch the server project to get started, then launch as many instances of Planet-desktop as you need. By default, the clients currently connect to “localhost”. Beware of joining two players without moving the first one from the start location, as they start in the same position, they could get stuck in eachother.

Press A and D to move around and click to shoot projectiles. Everything should sync and be visible on all clients.

Technology Stack

This is written in Java with the library Lib-GDX. Lib-GDX is an open-source library that wraps LWJGL function and allows you to export you Java game into many more platforms such as even HTML5/WebGL. LWJGL is a library that is adds Java functions for OpenGL calls.

The networking is handled with a library called Java-WebSockets (https://github.com/TooTallNate/Java-WebSocket). Websockets are used since they are the only network type supported in JavaScript, which I am planning on porting this to later (with Lib-GDX’s WebGL export).

Main features so far

  • All of the non client or server specific code is kept in a base project, that the two other projects extend. This is really nice for organization and removes duplicate code
  • Game updates are run at exactly the same speed on all clients by making sure to repeat frames if necessary. This is required to ensure that all clients and the server run identical simulations and don’t get off.
    This is done by running a for loop that will loop through the required number of updates before rendering to keep going at exactly 60 fps.
  • When a projectile is launched by one player at frame x, then next client receives the info about what frame it was launched at and will go back in time to replay that action. This makes sure that all users’ inputs are handled instantly, no matter their internet connection to the server. Normally, games don’t trigger the action until the server gets info about it. That makes it feel delayed when you do stuff. This way is much better in my opinion, but way less used.
  • Planet gravity
    • This took time to get perfect
  • Planet bouncing physics
    • The players are able to bounce off the side of a planet and keep part of their velocity.
  • Queue code to make sure that all frame repeating code is run on the frame to be able to pause all calculations to resimulate frames. This needs to be on the same thread because otherwise two threads will be modifying the same variables and it would be a disaster.
  • Old states of all players (in future, should be all physics objects) are saved to make resimulation of frames possible.
    Issues that will be fixed soon:
  • Not a perfect simulation yet, the clients sometimes get a little off from eachother
  • Non perfect mathematics (differentials)
    My main goal with this project was to attempt to estimate in code as little as possible. With planet gravity, the force of the gravity depends on the position relative to the planet. This can be estimated using a euler method by simply adding the acceleration to the velocity, then the velocity to the position every timestep. I wanted to try and make this perfect by creating a differential equation to solve this algebraically. The rearranged gravity equation is for x and for y with subscript p representing the planet and r representing the real position. I attempted to convert these to formulas that could get the exact x and y position variable for any t, time variable. Sadly, these equations have no closed form solution, so I ended up wasting a lot of time on this journey, though I did learn a lot.

This issue sadly can never be fixed, but instead a fixed inaccuracy can be used on all clients. This involves using the same timestep on all client, making the accuracy the same for all simulations.

  • No frame simulation for left and right movement yet (only projectiles)
    I was not able to get enough time to run the frame simulation for left and right movements yet, so for now this issue can be fixed by the fact that server position checks have been added temporarily.
  • Ran out of time bug fixing
  • Resimulation does not deal with projectiles yet
    When resimulating frames, it goes through the old states of all players (saved every frame) and sets their position to the state they were in that frame. There are no old states saved for projectile positions yet.
  • Resimulation does not deal with players connecting and disconnecting yet
    When a player leaves, they are removed from the player list. This makes all there old states get deleted. Ideally, there should be another list containing all the old states of the player array.
  • Really short server messages sometimes don’t send
    When a player disconnects, the server sends out a message saying “PD [id]”, this message is very short so sometimes the TCP network will not send it but instead wait for another message to be sent before sending it. This can be fixed by padding the message, sadly I ran out of time for that. Since it only affects disconnecting players and is resolved when any keys get pressed, it has little effect.

GitHub Account

https://github.com/ajayyy/



0
0
0.000
18 comments
avatar
(Edited)

What were your gravity equations(the ones for x and y) in the end?

0
0
0.000
avatar

Here is the code: https://github.com/ajayyy/Planets/blob/master/Planets-Base/src/app/ajay/planets/base/PhysicsObject.java#L54

It is the same acceleration equation, but instead of using math to integrate it and find an equation for the position, the acceleration is calculated and then added to the velocity every frame. The velocities are then added to the position every frame.

The velocity is represented as xSpeed and ySpeed.

0
0
0.000
avatar

I know how to simulate it numerically, but how did your trial at a continuous solution look like?

0
0
0.000
avatar

Sadly, these equations have no closed form solution, so I ended up wasting a lot of time on this journey, though I did learn a lot.

As far as I found, there is no continuous solution sadly.

0
0
0.000
avatar
(Edited)

Do you know about the orbit equation? It might be used together with the second kepler law to create a useful equation.

Edit:
Just noticed that you are making gravity towards more then one object at once, so it is indeed not possible :(

0
0
0.000
avatar

Ooh, I never even tried to use that equation, thanks for linking it. Sadly, I don't think this equation will work since it still doesn't find a direction of that velocity, and still requires the positioning (radius), but I will look into using this one. Thanks!

0
0
0.000
avatar

By the way: The following construct can be simplified to not use the slow trigonometric functions because:
cos(atan(Δy/Δx)) = cos(α), in the right triangle with the legs of Δx and Δy.
In the same triangle cos(α) = Δy/r
→cos(atan(Δy/Δx)) = Δy/r
So the following can be simplified to:

// slow form:
double accelX = -(Math.cos(Math.atan2(yDist, xDist)) * gravityConstant)/ (squaredDistanceFromPlanet);
// Simplified form:
double accelX = -(yDist * gravityConstant)/ (squaredDistanceFromPlanet*Math.sqrt(squaredDistanceFromPlanet));
0
0
0.000
avatar

Yea, you are right, though I think that equation is wrong, it should be:

double accelX2 = -(xDist * gravityConstant)/ (squaredDistanceFromPlanet*Math.sqrt(squaredDistanceFromPlanet));

(xDist instead of yDist in this case).

I originally planned on using this equation that I got from using a program to simplify it, but yours is so much shorter and makes sense logically.

double accelX = -1/(squaredDistanceFromPlanet * Math.sqrt(1 + Math.pow(yDist, 2)/Math.pow(xDist, 2)));

The only reason I didn't use this originally was because with 0 xDist and 0 yDist, it produces NaN instead of infinity, but this could easily be fixed in code with a simple if statement. The way you describe is also better since it actually gives zero when it should be instead of floating point errors that the trig functions give you.

With yDist = 0 and xDist = 10:

-6.123233995736766E-19
-0.0

I think I'll switch to the non-trig method, thanks!

0
0
0.000
avatar

Thanks! I changed it to not use trig and it has fixed a lot of issues I was having!

0
0
0.000
avatar

Congratulations! Your post has been selected as a daily Steemit truffle! It is listed on rank 10 of all contributions awarded today. You can find the TOP DAILY TRUFFLE PICKS HERE.

I upvoted your contribution because to my mind your post is at least 5 SBD worth and should receive 130 votes. It's now up to the lovely Steemit community to make this come true.

I am TrufflePig, an Artificial Intelligence Bot that helps minnows and content curators using Machine Learning. If you are curious how I select content, you can find an explanation here!

Have a nice day and sincerely yours,
trufflepig
TrufflePig

0
0
0.000
avatar

Seems like an interesting concept, and would be really cool to see you make it into an actual game people can play online or something. It reminds me of this game I used to play a long, long time ago, but I forgot its name Do you have any plans to do so? I've personally never done anything with physics / gravity, but I imagine it was quite complicated.


Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Chat with us on Discord.

[utopian-moderator]

0
0
0.000
avatar

It is partially based on an old flash game I used to love called "Cheese Dreams".

This is a surprisingly old idea of mine, I started working on this in 2016 and worked on it for a year, back when the "agar.io" craze was happening, sadly, the project got very bloated quickly and hard to maintain. Also, the server and client were completely different software, leading there to be inconsistencies in the physics simulations on both sides. I decided to restart from scratch with this project, focusing on having most of the code in a unified "base" project.

The hardest part is keeping real time planet physics feel right with latency on a network connection. Alone, real-time networking games can be simple to make, and planet gravity systems can be simple to create, but when together, things get pretty complex.

Right now, I am still having some inconsistencies, even when they are running on identical code, so I think there are now floating point errors causing issues.

The library I am using for Java allows you to export to WebGL, and I am using web-sockets for client-server communication, so that is the long-term plan.

0
0
0.000
avatar

Could you maybe add a non-android interface? I actually don't want to go through the stress of installing of installing android SDK to eclipse.

0
0
0.000
avatar

Yea, the android build doesn't even work right now, I think I know how to make the gradle project not load the Android project. I'm just testing it out now and will tell you how if it works.

0
0
0.000
avatar
(Edited)

Remove 'android' from the include line in settings.gradle. Remove the line referencing the project directory of the Android project in settings.gradle. Remove the project(":android") method in build.gradle.

The project should then load without needing the SDK.

I'll add it to the README.MD in a bit.

0
0
0.000