1 decade ago
by tluyben
Say I have something like:
MyGame = ig.Game.extend({
draw: function() {
this.parent();
// do some stuff
this.mainDraw();
},
mainDraw: function() {
// draw some stuff
}
changeDyn: function() {
MyGame.inject({draw: newDraw, mainDraw: newMainDraw});
}
});
When changeDyn is triggered, the draw methods are replaced and everything works fine, however, when using Impact.Debug I see the number of draws double. So when .draw() the first time does 200 draws, running changeDyn will give me 400, running again 600, then 800 etc.
So the 'old draw' is still running 'somewhere' after the inject replaces it?
What am I doing wrong? How can I prevent this?
1 decade ago
by tluyben
By 'it works' I mean, it actually draws what the new mainDraw method draws.
1 decade ago
by tluyben
As was to be expected (but I didn't see that before), it also handles all input the number of times you ran changeDyn. So If you run changeDyn 6 times and you handle a click event, it'll show 6 clicks.
1 decade ago
by tluyben
After a lot of experimenting I found out I just shouldn't inject the draw() method; moving everything from the draw() method to mainDraw etc and then injecting those will work.
Maybe someone can explain why this is the case? But at least it works now.
Post your code. You're likely calling ig.game.draw twice.
1 decade ago
by tluyben
Made some code to reproduce the issue exactly how I'm using it. Actually it doesn't up the draw count with the same number; it doubles it. I didn't notice that as my game has a much complexer setup, but here you can clearly see that it doubles every click.
Like I said above, if i don't inject draw() then it works. Must have something to do with the fact that for instance this.draw.toString() doesn't give me my code but [native code]. I would just like to know the why of it.
ig.module('game.main')
.requires('impact.game', 'impact.font', 'impact.debug.debug'
)
.defines(function () {
fps = 60;
MyGame = ig.Game.extend({
font: new ig.Font( 'media/04b03.font.png' ),
init: function () {
ig.input.bind(ig.KEY.MOUSE1, 'mclick1');
},
draw: function() {
this.parent();
this.mainDraw();
},
mainDraw: function() {
this.font.draw('Bla bla bla this does some drawing', 10, 10, ig.Font.ALIGN.CENTER );
// do something with the dynmethod
if (ig.input.pressed('mclick1')) {
this.changeDyn();
}
},
changeDyn: function() {
var newStruct = "{draw: function() {this.parent();this.mainDraw();}, mainDraw: "+this.mainDraw.toString()+"}";
var x = null;
eval("x = "+newStruct+";");
MyGame.inject(x);
},
});
ig.main('#canvas', MyGame, fps, 800, 600, 3);
});
You're calling this.mainDraw() twice. When you inject into a method, this.parent references whatever is the current function - not the class method. In this case, this.parent is:
draw: function() {
this.parent()
this.mainDraw();
},
So you call this.mainDraw() first in this.parent(); afterwards you call this.mainDraw() a second time, resulting in twice the amount of draws.
1 decade ago
by tluyben
Ah! That was subtle (at least to me). Still am not that comfortable with the javascript 'object model' I guess. Thank you very much!
1 decade ago
by tluyben
Is there any way to prevent this from happening so that this.parent() keeps working as expected after injection?
1 decade ago
by drhayes
Wait... injecting doesn't
replace the function entirely, it augments it? That doesn't sound right. Doesn't it "change the Class in place"?
Class.inject reference
So that
this.parent()
, in that case, is ig.Game's draw? That doesn't make sense.
tluyben, what happens if you replace the call to inject with this:
MyGame.prototype.draw = x.draw;
MyGame.prototype.mainDraw = x.mainDraw;
I have only seen documentation and examples of static injection so far. But you have to go for the simplest option, using javascript wisely : It would be waaay easyer to use a function 'pointer' - in fact a function.., to switch beetween two (or more?) complements to the draw function.
And also you should handle user input in the draw function: handling user input
must be done in the update method, nowhere else. And draw just takes care of ... the drawing, so simple positionning computation goes here only.
So in code it gives something like :
MyGame = ig.Game.extend({
font: new ig.Font( 'media/04b03.font.png' ),
currentDrawEnding : null,
init: function () {
ig.input.bind(ig.KEY.MOUSE1, 'mclick1');
this.currentDrawEnding=this.mainDraw;
},
update : function() {
this.paren(); // will call the standard Game.update method
// change draw method if mouse clicked
if (ig.input.pressed('mclick1')) {
this.changeDyn();
},
draw: function() {
this.parent(); // will call the standard Game.draw method
this.currentDrawEnding(); // calls the current drawing function
// ( either mainDraw or SecondDraw )
},
mainDraw: function() {
this.font.draw('Bla bla bla this does some drawing', 10, 10, ig.Font.ALIGN.CENTER );
}
},
secondDraw: function() {
this.font.draw('Another drawing to thank you for clicking', 55, 55, ig.Font.ALIGN.CENTER );
}
},
// switches beetween the two draw functions
changeDyn: function() {
this.currentDrawEnding=
( ( this.currentDrawEnding=== this.mainDraw ) ?
this.secondDraw :
this.mainDraw ) ;
},
});
1 decade ago
by tluyben
drhayes, I tried that and it yields the same result. If you log the draw() function it doesn't show my code, but rather the code from the framework:
return function() {
var tmp = this.parent;
this.parent = parent[name];
var ret = fn.apply(this, arguments);
this.parent = tmp;
return ret;
};
(impact.js)
And the parent shows the same code. So it's the code which manages the 'OO' making this happen?
What i'm looking for is quite elaborate code swapping, not just for one game; I'm looking to make life easier for me when working on an impact game in general, but without being able to swap out the main draw function, this is not going to be generic enough.
1 decade ago
by drhayes
vincentpiel has a good point: it looks like what you want to do is change what function is getting called at runtime. You can just assign to the function directly:
myGame.mainDraw = newMainDraw;
Or whatever.
Why are you swapping functions at runtime? What's the problem that this is a solution to?
1 decade ago
by tluyben
I want to swap out my code at runtime for live editing so I can code games without refreshing the browser and without losing any context. This works well (very well even, productivity rose a lot since working like that), but it's not generic, I have to manually tell it what to do because the 'internal impactjs' methods like update/draw etc do not want to get swapped for their new version.
While this is not a big problem (for me it works when doing it manually per game once), it would be much (!) nicer if it would be generic so we can live-program any impactjs application.
Currently I have two modes when working on a game: live editing via a browser based editor or automatic updating when saving files to disk.
Well if you look at ig.Class (inside impact.js, as the file name does not suggest), you will see that inject does quite little more than saving/assigning values to the prototype of the 'Class'. Maybe you had context ('this') issue, in that case look for the javascript function.apply() or function.call() or the bind() function of the framework.
If i understood well, you want to keep the main 'draw' (which clears screen and draw entities) and work on its ending, so what you can do to be generic is you can inject Game class with something like changeDrawEndingFunction (newFunction) and in your editor you do a call to this function on button click. better use try/catch to wrap the new function call, not to loose context in case of a typo...
Good idea anyway, and good luck.
1 decade ago
by tluyben
Thanks, I'll play around with that idea!
I do wrap with try/catch; fortunately Javascript supports syntax errors in try/catch which make this possible. I'll put the result on Github.
Page 1 of 1
« first
« previous
next ›
last »