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

1 decade ago by alexandre

I'm in the process of implementing an Entity subclass Button--I'll need a lot of those and figure it won't be wasted effort--and have a couple of questions:

1. right now, things are jamming at the ig.input.bind line, with console reporting "Uncaught TypeError: Cannot call method 'bind' of undefined".

2. I'm not clear on what the difference is between an Impact plugin and a subclass.

// sample use: play: new EntityButton('media/play.png', 200, 200, this, 'play');
ig.module(
    'plugins.button'
)
.requires(
  'impact.game',
  'impact.entity',
  'plugins.input-released'
)
.defines(function()
{
  EntityButton = ig.Entity.extend (
  {
    owner: null,
    callback: null,
    
    init: function (path, x, y, owner, callback)
    {
      // TODO: load image & other things
      ig.input.bind (ig.KEY.MOUSE1, 'mouse1');
      this.owner = owner;
      this.callback = callback;
    },
    
    update: function ()
    {
      // TODO: if mouse released over button, owner callback
    },
    
    draw: function ()
    {
      // TODO: draw ouselves
    }
  });
});

Thanks in advance
Alex

1 decade ago by gxxaxx

First let me confess that I don't actually understand the innards of this whole init process. But, I've learned two things:

1) How to take an error message at its face value.
2) How to poke my program with a stick until it behaves.

The part about understanding why it behaves can often be fuzzy.

In this case you are being told by the error checker that ig.input is undefined.

As an experiment you could try something like the following:

    callback: null,
    postinit: true,

    init: function (path, x, y, owner, callback)
    {
      // TODO: load image & other things
      this.owner = owner;
      this.callback = callback;
    },
    
    update: function () {
        if (this.postinit && typeof(ig.input) != 'undefined') {
                 ig.input.bind (ig.KEY.MOUSE1, 'mouse1');
                 this.postinit = false;
        }
       // other update stuff
     }


Every time I turn around I am finding an object "undefined" when I pretty much expected it to exist. So..... I just create this postinit or "finish init later when the object I need is defined" thing.

Any way this is just an experiment. If you find this works then at least you know it really was a problem with the input not being defined by the time your button init is being called.

p.s. above code is indicative of direction. Meaning, it is untested. Could be missing a 'this' or a ; or a comma. You get the drift.

1 decade ago by alexandre

First I have to say that your principles made me laugh. I tend to try and write code one small step at a time and work at it until that works enough for me to start the next step. Refinements can come later. But your solution (postinit et al) is one further step in that same direction (get it done; fix it later), but I get the feeling that it would cause me massive amounts of fixing later. On the other hand, because the fun factor in games is such an elusive thing, your approach may make better sense: it gets me to a potentially dead end that much sooner.

Food for thought your reply has given me. Thanks. :)

And yes, your snippet worked. !!

Which still doesn't satisfy my need to know why, thus leaving me perplexed,

and thankful nonetheless.
Alex

1 decade ago by yatayata

hi -

i also ended up using a similar construct as above, usually when i need to behave differently when instance variables are set eg from weltmeister. it would be good to have a bit more clarity on the impact entity lifecycle, as the init() really seems more like a pre-init to me...

1 decade ago by alexandre

seconded (and I sense a revelatory explanation, followed by an ahhh by me, coming from dominic).

1 decade ago by delly

I also have this same problem once in a while,
maybe we need some kind of postInit / start function that will be called
after all entity's init are done but before the very first update()

so the order of execution will be:

- init (called once when creating a new Entity)
- postInit / start (called once after all Entity's init is done)
- update (every frame)
- draw ((every frame)

with a postInit, we can even avoid the use of:
if( !ig.global.wm ) {
     // bunch of initialization stuff
}

since we can move that part to postInit section.

let's wait for dominic if he has something to say about this :D

1 decade ago by dominic

A plugin is just a normal Impact module that lives in the lib/plugins/ folder. This module may define one or more new classes or modify existing ones.

The whole idea of plugins is to have easily shareable code snippets that may be useful for a number of games. The lib/plugins/ directory is just a convention - you don't have to use it, but if everybody uses it, it makes sharing these code snippets easier :)

Now, the difference between using .inject() and .extend() is, that .inject() modifies an existing class in place, whereas .extend() creates a new one. Remember, plugins can do both: Some plugins, may offer completely new functionality, like a Camera class; some plugins may modify Impact's own classes.

Have a look at the tiny map-size plugin. This plugin modifies ig.Map using .inject(). ig.Map is the super class (or parent) of ig.BackgroundMap and ig.CollisionMap. Both of these super classes will have the properties and functions that were defined in the plugin.


Regarding your Cannot call method 'bind' of undefined error: ig.input is created when you call ig.main() - so my guess is, you tried to create one of your button entities before you called ig.main().

To fix this, just create your buttons in the init() method of your Game class (lib/game/main.js). This method is the last step in initializing Impact. When your Game's init() is called, everything else - ig.system, ig.input, ig.music and all assets - is ready.

If you really need a postInit method for your entities, that is called when ALL entities have been added to the level, just... do it :)

// Add the postInit method to your entity class
EntityPlayer = ig.Entity.extend({
	
	...
	
	postInit: function() {
		// do something!
	}
});


// In your game class, call the postInit method on all entities after 
// level loading is complete:
MyGame = ig.Game.extend({
	
	...
	
	loadLevel: function( data ) {
		this.parent( data );

		for( var i = 0; i < this.entities.length; i++ ) {			
			// Make sure this entity really has a postInit method 
			// before calling it
			if( typeof(this.entities[i].postInit) == 'function' ) {
				this.entities[i].postInit();
			}
		}
	}
});

-

Update: I just noticed the first line from your Button snippet:
// sample use: play: new EntityButton('media/play.png', 200, 200, this, 'play');

So I guess you were using it like so:
MyGame = ig.Game.extend({
	// This wont work as expected!
	buttonPlay: new EntityButton('media/play.png', 200, 200, this, 'play');
	...
});

This will create the Entity instance as soon as the Game class (not the instance of that class) is created. At this time, neither ig.system, ig.input, ig.game or anything else is ready. The browser is still busy loading the modules and Impact hasn't even begun to load the graphics and sounds, let alone started the game.

Also, just creating an Entity like this wont add it to the game world. Impact doesn't know it's there; it won't call the .update() or .draw() method of this entity. Use .spawnEntity if you want to add entities to the game world by hand (i.e. not load them with the level).

But I don't think you want your buttons to be Entities at all. When you load a new level, all buttons will be removed. After all, Entities are objects in the game world.

Instead, just subclass your Buttons from ig.Class, give them a .update() and .draw() method and call these methods for each of your buttons in your Game's .update() and .draw(). You may want to add an array to your Game that holds all these buttons.

1 decade ago by alexandre

plugins vs. classes
Understood perfectly, and clearest in the case of map-size's injection of new methods.

ig.input woes
Dominic, you were right about my main.js instantiating the button before init(), hence leading to the failure.
Title = ig.Game.extend ({
	playBtn: new EntityButton(200, 200, {path:'media/play.png', owner:this, callback:'play'});

	init: function ()
	{
		ig.input.bind(ig.KEY.MOUSE1, 'mouse1');
	}

And in retrospect, that ig.input was not recognized makes perfect sense. Before main's init(), the system hasn't been setup yet. My bad.

ig.Class vs. ig.Entity
I'll keep Button as an Entity for the next while, as I may want to animate them, move them around, hell, even perhaps respond to collisions for reasons obscure at this point. They are views, after all, just like all entities. Plus I may want to lay them out with wm and tag them as such from inside wm, for later iteration.

Thanks guys.
Alex
Page 1 of 1
« first « previous next › last »