Wednesday, December 13, 2017

Making Santa’s Snowball part 3 – tweens and gameplay

I was able to finish and post the second game in this years Santa’s trilogy and got the final game in the trilogy running. Tonight I will be cleaning up the game in ready for release next Friday. With my Christmas obligation finished I will be able to get back to the emulator, though next week will be a making of Evil Gnome’s Revenge post and the Wednesday after that will be a post about the making of Santa’s Search.

One of the important things I wanted to do while creating this project was work with tween.js as tweening is very important for animation and can be useful for all sorts of other things. The term tween comes from animation as a shorthand word for in-between. The lead animator would draw the key frames of an animation then other animators would draw all the frames in-between the two keyframes. Computers are now taking care of the in-between frames, which is why tools like Animate are still popular even though the Flash player is fading away.

Tween.js is not tied strictly to animation but can be used on any class to change the value of a variable over time. The associative array nature of JavaScript is what allows for this, but similar functionality can be done in C by using a pointer to the variable being changed. For Santa’s Snowball, tweening is only used for animation but it is not restricted to that. One thing that I could have done had I thought of it at the time was have the change of score be done at the moment of snowball impact instead of when the snowball was thrown by setting up a tween.

Tweening is an important part of the game as I use it for handling the turning of the billboards as well as for the snowballs. My billboard works by having a blank billboard shape (a white rectangle), a Santa image, and an evil Gnome image. This allows for three states of the billboard namely empty, Santa, or Evil Gnome. The show board function lets you indicate the type of board to show and hides Santa and/or the Evil Gnome based on the provided board type. The billboard, Santa, and the evil gnome are all then tweened into going from a shrunken width to their proper size. Hiding is simply shrinking the three of them which takes advantage of the fact that the unused images are already hidden. Here is the code for that.

/* shows the billboard appearing animation using the indicated type */
this.showBillboard = function(type) {
this.santa.visible = type == 1;
this.gnome.visible = type == 2;
cjs.Tween.get(this.shape).to({scaleX:.1}, 0).to({scaleX:1}, 500);
cjs.Tween.get(this.santa).to({scaleX:.1}, 0).to({scaleX:1}, 500);
cjs.Tween.get(this.gnome).to({scaleX:.1}, 0).to({scaleX:1}, 500);
}

/* shows the billboard disappearing animation */
this.hideBillboard = function() {
cjs.Tween.get(this.shape).to({scaleX:1}, 0).to({scaleX:.01}, 500);
cjs.Tween.get(this.santa).to({scaleX:1}, 0).to({scaleX:.01}, 500);
cjs.Tween.get(this.gnome).to({scaleX:1}, 0).to({scaleX:.01}, 500);
}

Testing this code did turn up a strange issue. When I had more than one billboard, all of them would show the same image. This was due to the fact that I am overriding the Easel.js’s Container class but forgot to call the initialize method. The poor way that classes are handled is not one of the better features of JavaScript but at least future versions do improve this. That being said, web assembly is probably the direction that I will be going in the future.

While tween.js does support motion paths, it does require a plugin be installed. By plugin, I mean within the create.js code not with the browser. This would not have been difficult to do, but since I would also have to come up with the curves to use I decided I would have a bit of fun and write a simple path generator for snowballs. I break the snowball path into three parts, with the line to the target being used as the base path. A third of the length is added to the point a third of the way through the line as well as 2/3 the way through to form a rudimentary curve. Each third of the line takes a slightly different amount of time to traverse so the snowball will move faster nearer to the player and slower further away. In addition to the path, the size of the snowball is also being tweened.  The code for handling the throwing of a snowball is below.

// create a path the hard way as didn't want to bother with motion paths
var endx = this.billboards[indx].x;
var endy = this.billboards[indx].y;
var dx = endx - 320;
var dy = endy - 440;
var linelen = Math.sqrt(dx * dx + dy * dy);
var thirdlen = linelen / 3;
var mid1x = 320 + dx / 3;
var mid1y = 440 + dy / 3 - thirdlen;
var mid2x = 320 + dx / 3 * 2;
var mid2y = 440 + dy / 3 * 2 - thirdlen;
this.snowball.visible = true;
cjs.Tween.get(this.snowball).to({x: 320, y:440, scaleX:1, scaleY:1}, 0).to
({x: mid1x, y:mid1y, scaleX:.25, scaleY:.25},200).to
({x: mid2x, y:mid2y, scaleX:.1, scaleY:.1},300).to
({x: endx, y:endy, scaleX:.02, scaleY:.02},400).call(this.playSplatSound).to({visible:false},1);
// animation ends with a splat so set up the 8 splat animations as well.
for (var cntrSplat = 0; cntrSplat < 8; ++cntrSplat) {
cjs.Tween.get(this.splats[cntrSplat]).wait(899).to
({x:endx, y:endy, scaleX:.02, scaleY:.02, visible:true},1).to
({x:endx+this.splatOffsetX[cntrSplat], y:endy+this.splatOffsetY[cntrSplat],scaleX:.005, scaleY:.005},300).to
({visible:false},1);
}
this.doneBillboardTime = Date.now() + 900;

I suppose I could have used a similar technique to generate the curve, but this approach works well. I am liking the Create.js library finding it not that much more difficult to use than Animate making it a better choice for developing games in JavaScript. As web assembly starts to take off, however, it is likely that my future will be either using Kotlin or C++ and compiling them to web assembly. Still, I have many flash games to port with most of them being easier to port using Create.js than porting to another language but there will be a few that may be worth the effort to re-write.

No comments:

Post a Comment