rblopes / generator-phaser-plus

[🛑 DISCONTINUED] It has been a long journey but development of `generator-phaser-plus` is now over. I recommend you have a look and fork `yandeu/phaser-project-template` instead.
https://github.com/yandeu/phaser-project-template
MIT License
144 stars 14 forks source link

Potential Improvement - auto add JSON files when generating project #21

Closed JarLowrey closed 7 years ago

JarLowrey commented 7 years ago

I think it's a best-practice to export strings, integers, dimen, font definitions, and IDK what else to external files so it's easier to change them when the project becomes large. I know Android projects follow this design paradigm. I have all my JSON in assets/json, load it on preload, and then create aliases once preload finishes. That allows me to do things like:

//Scale to device pixelRatio - consistent dimensions across all screens
this.game.dimen = this.game.cache.getJSON('dimen');
for (var dimension in this.game.dimen) { //adjust dimensions for different screen densities
  this.game.dimen[dimension] = this.game.dimen[dimension] * window.devicePixelRatio;
}
JarLowrey commented 7 years ago

Colors would be another good one. XML may be better than JSON in this instance, as XML supports comments.

http://phaser.io/docs/2.6.2/Phaser.Loader.html#xml

JarLowrey commented 7 years ago

I take it back. I started to convert my values to XML and I think it looks way dirtier and harder to read than json.

rblopes commented 7 years ago

Well, I don't know. It seems a very specific use case for me. For example, if your data is static (that is, not fetched from a remote web server), why not use modules instead of JSON documents? This way you still could consume that data the same way while keeping your app code organized. Another way could be using helper functions. Example:

// common/adjustDimensions.js
export default function adjustDimensions(dimensions, pixelRatio) {
  return Object.entries(dimensions)
    .reduce((m, [k, v]) => (m[k] = v * pixelRatio, m), {});
}

// In a game state
import assetDimensions from '../data/assetDimensions';
import adjustDimensions from '../common/adjustDimensions';
this.game.adjustedDimensions = adjustDimensions(assetDimensions, window.devicePixelRatio);
JarLowrey commented 7 years ago

I think it improves maintainability if you you keep your data and views/code separate. Instead of searching thru myriad of classes with tweens/resizing/whatever you have one point of control.

Having all the data in a class instead of JSON could work. In the end, JS classes are basically hash objects anyways. But I think it's a little confusing to create a class out of just data when that's the point of JSON. Of course, it allows you to add functions for specific use-cases, but I think it would make more sense to place those specific functions close to where they'll be used.

Your choice. I just thought it would be a good addition, especially for beginner programmers who may not think to separate their data in this way & would end up with it cluttered throughout their code.

JarLowrey commented 7 years ago

Plus a lot of JSON files other than dimen usually wouldn't need to be modified: string, color, etc. In which case placing in a class wouldn't make much sense (as far as I can tell).

rblopes commented 7 years ago

I never meant you should revert your JSON docs into JS classes. Instead, you could just create a handful of modules exporting plain objects. The assets.js module does essentially that.

rblopes commented 7 years ago

So, to complement my idea here, let's say you have an object describing the sizes of different sprites in your game, using a module like this:

// data/assetDimensions.js
export default {
  sprite1: 30,
  sprite2: 40,
  // ... and so on. The same defs you have in your JSON file.
};

With that, you could use helper functions, like the one I've shown above, to process the values you'll actually use. The advantage I see using this method is that you don't need Phaser to cache these values, just import the modules when you need them. However, I see that keeping them in the static dir may be better to keep code more organized, separate from ordinary data.

Now, other way you could use is this: look through all JSON docs you have declared in your assets.js module, and keep a reference for each object loaded. The quickest solution, avoiding possible name clashes with properties defined by Phaser, would look something like below.

// Filter declared JSON docs and get their references from the cache.
this.game.data = assets.game
  .filter(o => o.type === 'json')
  .reduce((m, o) => (m[o.key] = this.game.cache.getJSON(o.key), m), {});

OK, but this leaves me with one last problem. The 'auto[mation]' part. Right now, I don't have a reliable way of defining how everything should work. "Should I scan the assets directory and keep an index of all JSON data I find? But the program needs to know upfront what documents to process. Should I update the assets.js module then?..."

Lastly, it's tempting to add all kinds of utilities to the sample project, and I used to do just that not too long ago. However, I learned with time that each feature I add, not only places a burden on me to maintain, it risks not to be used/useful to everyone else. That's why I think users know better what to do with their projects. It comes with the most basics to bootstrap a game, however, it's just a blank slate, so users are free to decide and adapt the project to their liking.

JarLowrey commented 7 years ago

Alright @rblopes, thanks for looking it over. I see what you're saying, I may change my data around to match a class structure, haven't decided. Thanks for taking the time to respond! I appreciate that the sample shouldn't get unwieldy.