The code starts with a bit of fiddling about to calculate the number of costumes, and if animation_final_costume hasn't been provided, we set it.
Then further on, we increment our counter and change costumes, looping around as appropriate.
There's a fair bit to it, but now it's done, we can just use it without stressing about the details.
MySprite.prototype.Do_Frame_Things = function() {
ctx.save(); // Save the drawing context state
if (!this.costume_width)
this.costume_width = this.MyImg.width; // If no costumes, width is full image
var num_costumes = this.MyImg.width / this.costume_width; // How many costumes provided?
if (!this.animation_final_costume && num_costumes)
this.animation_final_costume = num_costumes-1; // if final not set, use them all
this.h = this.MyImg.height; // height of the image file
this.w = this.costume_width; // width of a costume
ctx.translate(this.x + this.w/2, this.y + this.h/2); // positioning
ctx.rotate(this.angle * Math.PI / 180); // rotating
if (this.flipV) ctx.scale(1,-1); // flipping
if (this.flipH) ctx.scale(-1,1);
if (this.visible) ctx.drawImage(this.MyImg, this.costume * this.w, 0, this.w,
this.h, -this.w/2, -this.h/2, this.w, this.h);
this.x = this.x + this.velocity_x;
this.y = this.y + this.velocity_y; // move the thing
if (this.animation_rate > 0) {
this.animation_counter++; // count frames
if (this.animation_counter > this.animation_rate) { // is it time for the next costume?
this.animation_counter = 0; // reset the counter
this.costume++; // select the next costume
if (this.costume > this.animation_final_costume) // check if past last costume
if (this.animation_continuous) this.costume = this.animation_first_costume // if continuous, loop back
else this.costume = this.animation_final_costume; // otherwise just stay on the last costume
} // time for next costume
} // we are animating
ctx.restore(); // unwarp the context
}