Jump to content

Generic platformer + ES6 / Webpack 4 boilerplate


nkholski
 Share

Recommended Posts

This project started off as a Phaser 3 / ES6 / Webpack boilerplate for testing Phaser 3 in its early stages, but ended up with a quite ambitious demo attached to it. I kept updating it and now it has two purposes:

1. A Phaser 3 / ES6 / Webpack 4 boilerplate. Replace the src folder with your own game and you have a good foundation watching your scripts and a built-in server with live reload plus the possibility to deploy your code for production use.

2. A,  let's call it "generic platformer". Hack around in the source to see what's making the demo tick or alter it to build something of your own. The code isn't as tidy as it should be, and some parts are still left since the beta when I had to do hacks around the API to get things running but I'm making an effort now and then to improve it. Also, when I feel for it I add an extra feature. I prioritize features that force me to explore new parts of the API. I plan to continue to improve it (but not create a complete game because of obvious copyright reasons).

GitHub: https://github.com/nkholski/phaser3-es6-webpack

Questions, suggestions and contributions are all more than welcome.

smb-phaser3-short.gif.beb9ea7b7d6781bd72d6e55c76029139.gif

 

 

Link to comment
Share on other sites

  • rich pinned this topic

I've added touch controls tonight to be able to check performance on mobiles. There is no lag at all on my Honor 8 from 2016 and I've done nothing to optimize the code. Phaser 3 is going to be great!

You can try it by the link provided above. Note that the touch controls are just a quick test to be able to move Mario at all, and not what touch controls could be in a real game.

Link to comment
Share on other sites

I'm happy to hear that. Please let me know if you think I should add something in particular. I'm thinking about title screen to demonstrate going between scenes and fireballs in a pool.

I would be a bit cautious learning webpack from the project though. Most of the time I have no clue what I'm doing and when I guessed something that works I stay with it. :-)

I updated the repository to Phaser 3.0.0 earlier today btw.

Link to comment
Share on other sites

I added a title screen running the game itself in a parallel scene in attract mode. The attract mode was made by recording my gameplay in a json and then repeat it. It's buggy and does weird things from time to time due to non-deterministic physics, but I think it looks kind of cool anyway.

I also updated the repository. What I really should have done was to clean up the code (and remove some pre-release solutions) but now I added more spaghetti code than ever when hacking in the attract mode.

5a89ecd18969c_Peek2018-02-1822-14.gif.45a56b3126ea6c070b175da3cb513deb.gif

 

 

Link to comment
Share on other sites

  • 4 weeks later...

First of all, @nikbrg, thank you very much for the boilerplate, I've been using it as a starting point when I started to play with Phaser 3 this weekend.
I have a question tho: I've noticed in the main game scene you are calling this.mario.update() to call update logic of Mario sprite, and same for the enemy sprites. I'm not an expert in Phaser, was playing around with v2 a bit, but I remember in prev version it was possible to just write an update logic in Sprite and it was working (no need to call it explicitly in the main scene/state). I've tried myself to not call it explicitly, I've rechecked that my sprite was added to the scene in it's own constructor like that: 

config.scene.add.existing(this);

but indeed, it's not working.

I wonder, is there any way in Phaser 3 to not call update() of Sprite explicitly in the main scene and make update() logic constantly work anyway after object creation?

Link to comment
Share on other sites

20 hours ago, Vlas said:

First of all, @nikbrg, thank you very much for the boilerplate, I've been using it as a starting point when I started to play with Phaser 3 this weekend.
I have a question tho: I've noticed in the main game scene you are calling this.mario.update() to call update logic of Mario sprite, and same for the enemy sprites. I'm not an expert in Phaser, was playing around with v2 a bit, but I remember in prev version it was possible to just write an update logic in Sprite and it was working (no need to call it explicitly in the main scene/state). I've tried myself to not call it explicitly, I've rechecked that my sprite was added to the scene in it's own constructor like that: 


config.scene.add.existing(this);

but indeed, it's not working.

I wonder, is there any way in Phaser 3 to not call update() of Sprite explicitly in the main scene and make update() logic constantly work anyway after object creation?

Currently this isn't a supported feature in v3; however, there's an open PR with some discussion around this topic so we may see it shortly in an upcoming version.

Link to comment
Share on other sites

@Vlas @jorbascrumps I think it's a good decision not to call an update-method for all game objects (even if I was used to this from Phaser 2 and was quite confused why my code didn't work initially with Phaser 3). I hope we get a standard method to do this, like gameObject.runUpdate(true) to push it to an array of objects that get updated for each loop (and gameObject.runUpdate(false) to remove it again). However, doing it yourself as I do isn't that complicated either. It's probably a quite common bump on the road for those going from Phaser 2 to 3 though.

@msickle The code is in the source code. I planned to clean up the code but couldn't stop myself from doing this instead, thus with a messier source code. 

The attract mode is the actual game stage running in parallel of the title screen with muted music. If you study it you see that you can activate a function to record keystrokes and positions of the player. Arcade Physics isn't deterministic and this was a big challenge, that's why I need to copy the position and velocity and not only keystrokes. I played the game while recording the keystrokes to a global variable. When happy with the result I did JSON.stringify with the object and I copied the output to a JSON-file. When running in attract mode I keep track on time and simulate keystrokes from the imported JSON and I adjust the position and velocity of Mario too to adjust it to what it was when I played. You can try to comment out the adjustment of position and velocity if you want and you'll see how soon it'll freak out. The enemies aren't controlled by anything else than game logic which means that Mario could be killed or miss a jump (he almost always fail to jump on the second goomba in the pair just before the first hole, my JSON seems to adjust Mario just in time to miss the enemy each time but sometimes Mario manages to squash it). It's far from a perfect solution but it was fun to make and good enough to keep in the demo I think :-).

@Everybody: I'm super happy to see so many of you have used the repository. I mean 200+ stars is crazy! I didn't expect that. I've been busy with other things but hope to be able to return soon to update the code to Phaser 3, go through everything for readability and move misplaced code where it belongs. And of course, most probably get obsessed to add something new that makes everything into a mess again.

Link to comment
Share on other sites

  • 3 weeks later...
  • 4 weeks later...
  • 2 weeks later...

Thanks, that's a great source of examples !

I'm curious about some of your choices on your Webpack config.

1. Is there any benefit from using BrowserSync instead of Webpack dev server ? Or this choice come from the others repos you refer to ?

2. In my project, I use both file-loader and a static folder for my assets. I don't know which way is the good way neither if one option is better than the other.

I see you serve your assets in a static folder. Is there a reason ?

3. I copied the following part from another repo and I see you have it too. But I don't know the purposes of theses lines. Can you explain ?

var definePlugin = new webpack.DefinePlugin({
    __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true')),
    WEBGL_RENDERER: true, // I did this to make webpack work, but I'm not really sure it should always be true
    CANVAS_RENDERER: true // I did this to make webpack work, but I'm not really sure it should always be true
})

 

Link to comment
Share on other sites

This entry in the changelog explains what the WEBGL_RENDERER and CANVAS_RENDERER flags are used for: https://github.com/photonstorm/phaser/blob/master/CHANGELOG.md#updates-2 (and that they've in fact changed with Phaser 3.7.1).

TL;DR When building Phaser yourself you can include/exclude the two renderers with those flags. So if your game only ever runs in Canvas mode, you can exclude the WebGL renderer to reduce your file size.

Link to comment
Share on other sites

@B.Guyl The webpack-stuff of repository a clone of a Phaser 2 boilerplate which I've managed to get to work with Phaser 3 through trial and error. I'm not a great source for webpack best practises. ? (1) No idea. It's just kept as it was in the original repository. (2) I don't really understand the question. I prefer a source folder with content that should be transpiled, a static folder and a build folder that everything get copied to. I load the assets with the Phaser 3 file loader. (3) @snowbillr got you covered ?

Link to comment
Share on other sites

  • 3 weeks later...

I've done some work on reorganizing and otherwise improve the code, but when the code got really messy (by the end of the  Game create method) I lost focus a bit and couldn't resist implementing fire Mario. If you're using this, what would you prefer: Improved code base or additional features?

The online demo was also updated:

 343520767_firemario.gif.e9441abcee78deac8262f33efa7c5735.gif

Link to comment
Share on other sites

  • 2 weeks later...
  • 2 months later...

Thank you for your post! I was looking for good ES6 examples of Phaser 3 like yours =D
Your Mario-game is the best source I found so far!

In the BootScene.js I found this code:

// Spritesheets with fixed sizes. Should be replaced with atlas:
this.load.spritesheet('mario', 'assets/images/mario-sprites.png', {
  frameWidth: 16,
  frameHeight: 32
});

You mention that "this.load.spritesheet(...)" should be replaced with atlas.
In PlayScene.js you create an instance of Mario:

// CREATE MARIO!!!
this.mario = new Mario({
  scene: this,
  key: 'mario',
  x: 16 * 6,
  y: this.sys.game.config.height - 48 - 48
});

The key:'mario' seems to refer to the spritesheet-function above.
Your atlas-function (BootScene.js) looks like this:

// Beginning of an atlas to replace the spritesheets above. Always use spriteatlases. I use TexturePacker to prepare them.
// Check rawAssets folder for the TexturePacker project I use to prepare these files.
this.load.atlas('mario-sprites', 'assets/mario-sprites.png', 'assets/mario-sprites.json');

My question is: How would you create Mario without the spritesheet-function / only with the atlas-function ?
What would you put in "key:" ? Seems easy but I could not figure it out yet ^^''' 

Link to comment
Share on other sites

I just pushed a long overdue update to the GitHub repository. The source code itself is untouched but it now runs on Phaser 3.12 and Babel 7.

I noticed that this introduced some issues related to Arcade Physics. I wouldn't say that the controls were tight before, but they are definitely less tight now. There is an issue when trying to walk into a wall (like a pipe) and when you enter a pipe the horizontal velocity might make Mario fly away. The attract mode is a bit broken, but since deterministic physics where introduced in Phaser 3.10 or something, it could also be improved beyond what it has been.

I won't have time to update the repository any time soon, but I gladly accept pull request fixing anything of the issues above if you feel up to it.

 

Link to comment
Share on other sites

@mistertabasco I use an Spriteatlas for most sprites but Mario is still in that spritesheet because I've prioritized other stuff with the little time I got. I suggest that you study the folder structure in raw assets and try texture packer. The key is generated from the path and filename. Why not practise by splitting up the Mario sprites in a folder, generate an updated Spriteatlas from that and share it ;-).

Link to comment
Share on other sites

  • samme unpinned this topic
 Share

  • Recently Browsing   0 members

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