Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

8 years ago by myvertigo

Hello everyone.

I have juste created a plugin that allow you to use ES6 features with impactJS.

https://github.com/myvertigo/impactES6

Here is an example of difference between classic impactJS file and impactES6 file

Classic

ig.module('game.entities.player')
.requires('impact.entity')
.defines(function () {

  EntityPlayer = ig.Entity.extend({
    ready: false,

    init: function (x, y, settings) {
      this.parent(x, y, settings);

      this.ready = true;
    });

});

ImpactES6
import Class from "lib/impactES6/Class";

ig.require('impact.entity');  // ig.require is used only for require an impact library

export default class EntityPlayer extends Class.inheritance(ig.Entity) {
  init (x, y, settings)
  {
    super.init(x, y, settings);
   
    this.ready = true;
  }
}

There is lots of cool features with ES6 like classes, arrow function, array map/find/reduce etc.

This plugin is actually at a beta version and it is not possible to have old impactJS scripts. So I recommand you to use this plugin with a new game project.

I hope you will like it. Feel free to contribute to the project or report bugs to improve the plugin.


Sorry for my bad English.

8 years ago by Joncom

Cool. I did something similar when adding TypeScript support to Impact. My player entity ended up looking like this:

///<reference path="../../impact/entity" />

var animSheet = new ig.AnimationSheet('media/tilesheet.png', 16, 16);

class EntityPlayer extends ig.Entity {

    animSheet = animSheet;

    constructor(x: number, y: number, settings: Object) {
        super(x, y, settings);
        this.addAnim('DEFAULT', 1, [0, 1, 2]);
    }
}

Notice that animSheet is defined before the class because otherwise the preloader would not preload the image. I never did come up with a satisfying solution to how using ES6 style classes broke preloading...

8 years ago by Joncom

Just wondering, how come you write your class like this:
class EntityPlayer extends Class.inheritance(ig.Entity) {

...instead of like this?:
class EntityPlayer extends ig.Entity {

Shouldn't ES6 class inheritance work without the need for "lib/ImpactES6/Class"?

8 years ago by Bum

This is awesome. What do you mean that it won't work with old impact scripts?

8 years ago by Joncom

Quote from Bum
This is awesome. What do you mean that it won't work with old impact scripts?
He means that the
ig.module('game.main').requires('...').defines(function() {...}

...way of defining modules has been removed in favor of ES6 style modules.

They would therefore need to be reformatted.

8 years ago by myvertigo

Exactly, with impactES6 you must not use ig.module(...).requires(...).defines(...) because it has its own import and definition module.

Class.inheritance(ig.Entity) is a static function which transform current object into an ES6 Class. The purpose to this function is to correctly interpret this.parent(); which is not the case currently. In fact, at this time you are not obligated to use this to extend your ES6 Class with ig.Class but it will surely change in future versions.

That's also why it is currently not possible to work with old impact scripts.

Notice that you need to use Class.inheritance([ig class name]) for impactJS library but with an ES6 Class, you can use the normal way to extend your children classes, like this :

export default class EntityPlayerDog extends EntityPlayer {
   ...
}

@Joncom : it's a good point you mentioned about the preloader. There must be a way to preload the image even if it's included directly in the class and not outside. I'll think about it

8 years ago by Bum

Ok I somewhat understand the delima. Impact pre-defines the ES6 functions module() requires() extends and conflicts with the new features.

It can't be too hard to re-write. I imagine it would take some time and I'm willing to work on that. What would we need to do in order to make impact 100% ES6 compatible?

8 years ago by Joncom

Quote from myvertigo
The purpose to this function is to correctly interpret this.parent(); which is not the case currently. In fact, at this time you are not obligated to use this to extend your ES6 Class with ig.Class but it will surely change in future versions.
Yeah, if the plan is to go the ES6 route, then it probably makes most sense to use the official this.super() instead of this.parent().

8 years ago by myvertigo

there is 3 points to do to make this 100% compatible with old scripts :

- Check and update the Class.inheritance function to correctly interpret all features of an ES5 Class (like: this.parent(...)) and make sure that when you call super.method(...) it will call the ES5 parent which calling his own parent too with this.parent()

- Find a way to correctly preload image. I've started to thinking about this method :
export default class EntityCharacterPlayer extends EntityCharacter {
  init (x, y, settings) {
    super.init(x, y, settings);
    this.foo = this.foo == 3 ? 4 : 3; // it will return 4
  }
}

EntityCaracterPlayer.propertites = {
  animSheet: new ig.AnimationSheet('media/toto.png', 30, 30),
  foo: 3
}

Properties will be accessible outside an instance (like a static function)

- Check and permit to an ES6 Class to be rendered into a map with weltmeister.

Once these features will be validated, I think it will be ok to pass it into the first release version.

8 years ago by Bum

what problem does preloading face at this time?

8 years ago by Joncom

Quote from Bum
what problem does preloading face at this time?
As Impact loads each module, it immediately executes the code inside of the .defines() call. That means that when it loads the player entity, for example, it runs this code immediately:

EntityPlayer = ig.Entity.extend({
    someImage: new ig.Image('path/to/image.png'),
    init: function(x, y, settings) {
        this.parent(x, y, settings);
        // ...
    }
});

Once all modules are loaded (and executed), then Impact says "OK, I'm done loading, time to start the game."

The reason pre-loading images works in this scenario is because someImage is just a property of an object that gets passed into ig.Entity.extend(). Meaning it executes immediately, and the ig.Image can tell the pre-loader to wait for it to load.

Here is an ES6 class of the same entity:

class EntityPlayer extends ig.Entity {
    constructor(x, y, settings) {
        this.someImage = new ig.Image('path/to/image.png');
        this.super(x, y, settings);
        // ...
    }
}

Notice how the class property is defined inside the constructor itself? This would be like defining the property inside an Impact class init function (which also would break pre-loading).

So the reason pre-loading images does not work in this scenario is because someImage will not be defined until after the class is actually constructed (ie. when the entity gets spawned in-game). Therefore the opportunity to pre-load has already passed.

8 years ago by myvertigo

Hello guys,

I've made a big update of ImpactES6 and it's now at version BETA 0.3.

What's new in this version ?

- It now support all ES5 scripts without do anything.
Class.inheritance(ig.Entity) has now disappeared because tests have shown that inheritance between ES6 and Impact ES5 Files are made naturally and safely.

So, if you want to inherit with an ES5 file, you just need to write your class like this :
ig.require('game.entities.entityPlayer') // Just load it once

export default class EntityPlayerCopter extend ig.EntityPlayer {
    init (x, y, settings)
    {
         super.init(x, y, settings);
         ...
    }
}

- ES6 Classes have now default properties preloaded
It is an important feature because in ES6, you can't have default properties before it was rendered. And without default properties, you have 2 issues :
--> You can't preload images
--> Inheritance is not render with properties of children
You can correct it now with ig.bindProperties. Let's see how it works :

In ES5
  ig.EntityPlayer = ig.Entity.extend({
    animSheet: new ig.AnimationSheet('media/player.png', 43, 50),
    size: {x: 43, y: 50},
    speed: 500,

    init: function (x, y, settings) {
      this.parent(x, y, settings);
      ...
    }
  });

In ES6
export default class EntityPlayer extend ig.Entity {
  init (x, y, settings) 
  {
    super.init(x, y, settings);
    ...
  }
}

ig.bindProperties(EntityPlayer, {
  animSheet: new ig.AnimationSheet('media/player.png', 43, 50),
  size: {x: 43, y: 50},
  speed: 500
});

8 years ago by Bum

Great work! This way is a little convoluted unfortunately.

what does ```export default class``` do?

8 years ago by myvertigo

It's not so complicated when you know how ES6 Classes work.
Do you know React JS, the framework developed by Facebook ? This framework can be written in ES5 and ES6 and it is almost the same way to define default properties on an ES6 Class. It looks like this :
export default class ReactTest extends React.Component {
  constructor (props) 
  {
    super(props);
    ...
  }
}

ReactTest.defaultProps = {
  toto: 4,
  speed: 500
}

Default properties can't be define into an ES6 Class. You can only define functions or static functions. Default properties must be defined outside.

However, in the next version of JavaScript, you can set default properties into the core of a class like this :
export default class EntityPlayer extends ig.Entity {
  static properties = {
    animSheet: new ig.AnimationSheet('media/player.png', 40, 40),
    size: {x: 40, y: 40}
  }

  init (x, y, settings) {
    super.init(x, y, settings);
    ...
  }
}

export default is the ES6 way to export / import script
export default means that the instruction following will be exported by default.
To import it, you juste need to proceed like this :
import EntityPlayer from "game/entities/player";

But if you want, you can export multiples instructions from one file. See the example :
export const speed = 500;

export const increase = function (number) {
 return number + 1;
}

This file as multiple export and you can import only one instruction like this :
import {speed} from "game/helpers/helper"; 

console.log(speed); // will return 500;

Or you can import all instructions :
import * as helper from "game/helpers/helper";

console.log(helper.speed); // will return 500
console.log(helper.increase(5)); // will return 6

7 years ago by PixelPicoSean

Just saw this amazing project, I've been waiting a ES6 version for years. It would be great if weltmeister is supported.

How I wish impactjs is open sourced, so we can contribute to a new level, like ES6 and WebGL.
Page 1 of 1
« first « previous next › last »