Sign in to follow this  

Creating a server-side movement/positioning system for a web simulation

This topic is 1185 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

 

I'm creating a web based snail simulation using PHP (I know.) with Laravel. I am using HTML5 canvas/JS to render moving snails on jar and snail profile pages. MySQL is used for the db. Each snail has several senses that are determined by its training/treatment and genetics, dictating how well it can smell, see, feel, etc other objects within its jar. So, I need to store x and y positions for each object in the jar (snails, consumables, decoration, etc), which will then be used when each snail's "brain" processes incoming data (does the snail see this object that's a certain distance away? Does it smell the object? Does it perceive it at all with any of the senses? Once an object is perceived I will get stuff like how much attention the snail dedicates to the object, whether it has any short or long term memories of it, etc (basically decide if the snail reacts and how). (This is a very long term hobby project, so I realize that it's overly ambitious and I don't care smile.png)

 

However, I'm not sure how to approach the first step of this - I'm not quite sure what the best way to set snail position is. Currently I set a position within the jar at random whenever a snail hatches from its egg (posX and posY, based in part on jar capacity). From there, when I view the profile page of the jar that snail is in, the snail is spawned in that position. It then chooses a direction to crawl in at random and crawls in that direction based on its currentSpeed attribute. When it hits the edge of the jar it just turns back around. All of this, after getting the first spawn position of the snail, is random and purely client-side JS. Nothing is stored back in the DB just yet.

 

Here's what it looks like (each snail here is is moving toward the edge of the canvas, where it will flip around):

 

ejUcM1Y.png

 

Right now I'm trying to find the best approach to take when making movement that actually persists, and not just random back and forth on the client. Snails move and perform actions even when nobody is watching them, so I know I will need to run a recurring job on the server at regular intervals for this. Things I'm unsure about are:

  1. How to make this scalable to support movement (and then decision-making) calculations for potentially thousands of snails. I guess I should run this job at staggered intervals and not have one giant job for all the snails in the world, but is that really enough to totally mitigate potential performance problems caused by this? I already run recurring jobs for things like snail growth, ageing, and energy depletion. I am fully aware that it's highly unlikely anybody will actually use this simulation or that I'll ever have thousands of (living) snails in the world, but I still want to make it scalable for my peace of mind.
  2. How best to have the HTML5/JS rendered version of the snails on the client see and follow the actions on the server in real time. I guess I'll need to project some sort of targetPosition from server to client and then have the client draw the snail crawling toward that point? Or would it be better to have a target direction? Or maybe do it an entirely different way :S
  3. How best to send some actions from the client back to the server in real time (like dragging an item or snail while in jar-view, thereby repositioning that object in the db). 

I suppose I'll have to use something like Ratchet (or in this case maybe Latchet), but I'm in general looking for any examples or high level advice on how to approach this sort of thing best - the actual implementation I can then sort out on my own. I just want to have a solid plan for how to structure this before I dig in and could use some advice/starting point suggestions for how a system like this should work.

 

Thanks in advance for any advice/suggestions!

Edited by Drakonka

Share this post


Link to post
Share on other sites

To your points:

 

  1. To bastardize a Zen koan: if no one views a snail, did it ever move? Use the navigation activity of the user to trigger the update jobs, on only the snails the user is viewing. Call it "loading", people will accept it. And if snail-to-snail collisions aren't possible, you could avoid having to integrate the position of the snail, you could just calculate it in chunks of time between collisions with the walls of the jar.
  2. WebSockets. Just makes for a really nice interface for pushing updates from the server to the client, rather than having to poll constantly. Send the X, Y, and DX, DY for each snail. Have the client integrate between updates. More discussion below.
  3. Again, WebSockets. Make sure you double-check the intent of the user's input actions, don't just take it as gospel that they can move a certain object to a certain location. It's not even strictly about worry about hacking, network latency can cause packets to arrive out of order or grossly delayed, in which case your server state could disagree with your clients' states.

On integrating between updates from the server, what you want to do is check that the X,Y from the server matches the X,Y currently known by the client. If they don't, the client calculates a new DX,DY, but keeps its current X,Y, such that integrating between now and the next server update will result in the server and client converging to the same point. I.e. don't correct the location immediately, use the integration to correct for discrepancies.

 

given:

dt = average time between updates from the server

Xs, Ys, DXs, DYs = the current state from the server,

Xc, Yc, DXc, DYc = the current state on the client

 

then:

X = Xc

Y = Yc

DX = ((Xs + DXs * dt) - Xc) / dt

DY = ((Ys + DYs * dt) - Yc) / dt

 

Technically, this can be done for any continuous value communicated between client and server. And if you use fuzzy logic for booleans, it could be used there, as well. Because that's actually what you need to do: implement a fuzzy logic system to make guesses as to what the most likely state is, given two differing opinions.

 

The client will never 100% match the server, but this way it will be smooth and convincing and the difference won't much matter. This isn't perfect, as it doesn't account for network latency at all, but for such a simple job it should be sufficient. There is a whole rabbit hole you could dive into on this subject involving movement curves and modeling user activity and trying to fit what people would actually do more than just simple linear interpolation, but it's not like your game is a highly competitive FPS. You most likely have other things you want to work on and just need something sufficient.

Share this post


Link to post
Share on other sites

Thanks for the advice! 

 

 

 


To bastardize a Zen koan: if no one views a snail, did it ever move? Use the navigation activity of the user to trigger the update jobs, on only the snails the user is viewing. Call it "loading", people will accept it. And if snail-to-snail collisions aren't possible, you could avoid having to integrate the position of the snail, you could just calculate it in chunks of time between collisions with the walls of the jar.

 

In this case, it definitely moved. There is no navigation activity in the user - the user, if they are the owner of a snail, can only drag and drop snails and other objects within the jar. Actual snail actions, normal movement included, are decided in the snails' brain and are performed even if there is nobody to see the snail yet (ie profile page not being viewed). 

 

 

 


Again, WebSockets. Make sure you double-check the intent of the user's input actions, don't just take it as gospel that they can move a certain object to a certain location. It's not even strictly about worry about hacking, network latency can cause packets to arrive out of order or grossly delayed, in which case your server state could disagree with your clients' states.

 

Great point, I will be sure to remember this. 

 

I suspect I'll end up having to go with an authoritative server, constantly running update checks for all live snails using a cron job (I'll have to find a good balance between frequency and performance). For websockets I'll probably end up going with Latchet, but first I'm going to set up the server-side stuff and have the position/targetPosition update in the DB (ie set up the actual snail behaviour for movement). Then I'll worry about rendering it on the client as accurately as possible. At first I was going to let the client have more influence over the snail's position, but realized that because multiple people can have one jar page open at the same time any randomized actions from the client would create discrepancies and weird behaviour (plus as I mentioned, this entire system would break if the client simply isn't open :S). The drag/drop instructions by the jar owner would have to be sent to the server for validation as you mention, then recorded in the db, then results sent back to the client for rendering.

 

Thanks again!

Edited by Drakonka

Share this post


Link to post
Share on other sites

This topic is 1185 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this