Jump to content

General data structure for Phaser snake game


BdR
 Share

Recommended Posts

I'm using Phaser and TypeScript to create a Snake game with multiple snakes and my question is about the general structure of the program.

My question is: What is the best way to structure the data for such a game using Phaser.js?

So I mean which variable types to use for the snakes, walls, apples etc. when the key features of the game would be:

  • Everything is placed on a grid
  • There are multiple snakes that can grow and shrink during a game
  • Snakes move on a timer from tile to tile (so no smooth animation in-between tiles)
  • There are walls, the layout differs per level but doesn't change during a game
  • Food item appear randomly and can be eaten by the snakes

The snakes are build up out of several sprites, and they will display the shape of the snake including the bends and turns with shadow effect etc. These snake-parts need to be updated as the snake moves/shrinks/grows. For each move the game will need to check if the snakeheads bumps into something, either a wall or a food item or another snake (or its own tail).

I was first thinking of using just one big two-dimensional array, fill it with integers to represent all in-game items. And then another two-dimensional arry filled with sprites, make all those sprites invisible, and then for each move set the sprites (frame number/visibility) in the corresponding array positions.

Array[x][y] (entire play area) with integers representing all items, 1=snakehead 2=snake-part-up .. 8=apple, 9=wall etc.

Array[x][y] (entire play area)
|
+- Phaser.Sprite

But a better approach would be to use Phaser.Group to group each snake, and then a separate Phaser.Group to hold all the food items and maybe also the walls.
And for the hit detection/eat food etc. there need to iterate all groups children against all other groups children.
Another thing is that each snake also needs to hold some extra information (head position, direction) and I can't easily extend default classes (using Type Script)

array[snakes]
|
+- Phaser.Groups (a group for each snake)
   |
   +- Phaser.Sprites (snake parts)

Phaser.Group (FOOD + WALLS)
|
+- Phaser.Sprite (sprite for each apple or mushroom)

For the hit detection/eat food etc. it makes more sense to just put it in a two-dimensional array because everything is on a grid, and then you can simply lookup the grid positions to see if something is in it. So, I'll be glad to hear any ideas on this..

Btw I've already seen this Phaser Snake tutorial but that example does not address the issues with multiple snakes and the snake parts sprites.

snake_question2.png

Link to comment
Share on other sites

Hi @BdR

If you do not use Phaser Physics I think that it is the best way, even though maybe it's easier and faster with physics. I mean, you will have the whole grid control separating and using the mvc pattern. Well into my mind is how I'd do it.
So, for main classes:
- Snake, Gorup ( each one as you said )
- Collectable item ( food, mushroom..whatever ), Sprite
- Wall, Group
- Grid x 3, View, Controller and Model

The advantage of this composition is that you can change the game and it will work as well, for instance, in a game like candy crush, tetris, battleship, and so on..

 

Link to comment
Share on other sites

I'd just use an array for the 'world', which is the tilemap (I prefer 1d arrays, but use a [][] if thats more comfortable).

Each snake would just be a list of <x,y> coords for each section. Each tick you add a new item to the front of the list (the new head, its position dictated by the position of the old head of the list and the direction of travel) and pop one off the back. During rendering you iterate over the list using each nodes sibling to dictate which sprite to render i.e. if a node has a segment to the right and below then you know to render the right bend piece etc etc.

For collision detection, when you're calculating the new head you'd have to iterate through the main tilemap array and each snake, buts thats unlikely to be prohibitive so I doubt you'd need to make it nastier with stuff for performance reasons.

Also, if you want to extend classes and your only problem with that is Typescript then your problem is with TS, if you're going to code in a classical style then one of the biggest benefits is subclassing, if your tooling prohibits that then your tooling is wrong. Beyond the fallacy of JS type safety (its all a big lie) interoperability is the biggest problem with TS.

Link to comment
Share on other sites

@carlosnufe thanks for answering :) As for the physics, there is no momentum in the movement (just single moves per timer tick) and collision detection is really simple, so using arcade or P2 physics seems like overkill to me.

21 hours ago, carlosnufe said:

- Grid x 3, View, Controller and Model

I know what model-view-controller is but what do you mean with "grid x 3" so how would that practically apply to the phaser framework?

For the MVC pattern to work, as I understand it, you'd have to separately keep track of the snakeparts positions (the model) and the visible sprites (view). But you'd have to be able to determine which sprite belongs to which (x,y) list position. Is there a way to store a grid x,y position with a sprite (other than extending the Phaser.Sprite class) ? I know you can determine (calculate) the grid positions based on the screen positions. But that doesn't work when you add screen shake effects, or "snake shake" effect (for example when they grow or die) or when the apple have a little bouncing animation.

Link to comment
Share on other sites

15 hours ago, mattstyles said:

Each snake would just be a list of <x,y> coords for each section. Each tick you add a new item to the front of the list (the new head, its position dictated by the position of the old head of the list and the direction of travel) and pop one off the back. During rendering you iterate over the list using each nodes sibling to dictate which sprite to render i.e. if a node has a segment to the right and below then you know to render the right bend piece etc etc.

I understand you could use a list (array?) of x,y positions but same as previous post; how do you link the positions to the sprites on screen? Or do you just render/add all new sprites for ever frame?

And I know how to extend classes with TypScript but I would like to use existing classes as much possible.

 

Link to comment
Share on other sites

I'd work it out on the fly yes, for each snake segment, based on the relative positions of the previous/next segment (if the exist).

The background probably won't change much, possibly not at all if other stuff like your mushrooms/apples are on their own layer, so that can stay as it is and I'd recreate the snake layer each frame/tick from a pool of sprites. Only if that is too slow (it's unlikely to be) would I even think about some other way. It's far simpler to recreate the scene each frame and good renderers (like Pixi, which manages the scene graph) help you to do this. Of course, its less work for the CPU to just remove the last sprite, update the previous head and add a new head but you'd have to work out the diffs between your previous snake layer and the current one, and maybe that is more expensive, without testing its hard to guess, and in any case, only optimise when necessary, avoid premature optimisation where it makes code more complex.

Link to comment
Share on other sites

@BdR Sorry about that, I was listing the main classes, Grid x 3 was for GridView.js, GridController,.js GridModel.js . This is an example, you can name as you want, ofc. 

Apply MVC pattern to a Phaser game is easy, in fact, in any project ( at least, for me ). You must have a controller file that is instantiated in main Phaser game state, could be a 'Play' state, after 'Menu', 'Tutorial' or 'LevelSelection' state ( it does not matter ). Controller, in turn, instance view and model. At this point you must develop all the game logical part in this file. 

You will control your game by model class and will move your view elements accordingly to the model data.  

Can use browserify, webpack, rollup and so on, to load your files into anothers, I do not know if you use it, but you should in high percentage, it depends of how you will develop your game.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...