Pulsating Images

A pulsating image is similar to a static image in that it will have a position, a width and a height. Unlike a static image, a pulsating image will continuously update its position, as shown here. The code for this example is shown below.

PulsatingImage.js

/* Author: Derek O Reilly, Dundalk Institute of Technology, Ireland. */

class PulsatingImage extends GameObject
{
    /* Each gameObject MUST have a constructor() and a render() method.        */
    /* If the object animates, then it must also have an updateState() method. */

    constructor(image, x, y, originalWidth, originalHeight, numberOfSteps, stepSize, intervalTime)
    {
        super(intervalTime); /* as this class extends from GameObject, you must always call super() */

        /* These variables depend on the object */
        this.image = image;
        this.x = x;
        this.y = y;
        this.width = originalWidth;
        this.height = originalHeight;
        this.numberOfSteps = numberOfSteps;
        
        this.stepSize = stepSize; // can be positive or negative. Negative decreases the original image size
        if (this.stepSize > 0) // image is pulsating between original size to a larger size
        {
            this.incrementing = true;
        }
        else // image is pulsating between original size to a larger size
        {
            this.incrementing = false;
        }
        
        // the image pulsates about its centre
        this.centreX = x + (this.width / 2);
        this.centreY = y + (this.height / 2);

        this.currentStep = 0;
    }

    updateState()
    {
        if (this.stepSize > 0) // image pulses into a bigger image
        {
            if (this.incrementing) // incrementing to increase size of original image
            {
                this.currentStep++;
                if (this.currentStep === this.numberOfSteps)
                {
                    this.incrementing = false;
                }
            }
            else // drecrementing to return to original image size
            {
                this.currentStep--;
                if (this.currentStep === 0)
                {
                    this.incrementing = true;
                }
            }
        }
        else // image pulses into a smaller image
        {
            if (!this.incrementing) // drecrementing to decrease size of original image
            {
                this.currentStep++;
                if (this.currentStep === this.numberOfSteps)
                {
                    this.incrementing = true;
                }
            }
            else // drecrementing to return to original image size
            {
                this.currentStep--;
                if (this.currentStep === 0)
                {
                    this.incrementing = false;
                }
            }
        }
    }

    render()
    {
        ctx.drawImage(this.image, this.x - (this.currentStep * this.stepSize) / 2, this.y - (this.currentStep * this.stepSize) / 2, this.width + (this.currentStep * this.stepSize), this.height + (this.currentStep * this.stepSize));
    }
}

The intervalTime is passed to the Visual superclass (as shown below in green). This determines the frequency that updateState() method is called. Smaller values of intervalTime will result in a faster pulsating effect.
The image pulsates about its centre. The initialisation of this is shown below in blue.
The stepSize (as shown below in red) is the number of pixels to increment/decrement the width and height of the displayed image on each call of updateState(). The image can pulsate in a positive or negative direction. A positive value for stepSize will cause the image to pulsate between the original and a larger image. A negavite value for stepSize will cause the image to pulsate between the original and a smaller image.

    constructor(image, x, y, originalWidth, originalHeight, numberOfSteps, stepSize, intervalTime, centreX = null, centreY = null)
    {
        super(intervalTime); /* as this class extends from GameObject, you must always call super() */

        /* These variables depend on the object */
        this.image = image;
        this.x = x;
        this.y = y;
        this.width = originalWidth;
        this.height = originalHeight;
        this.numberOfSteps = numberOfSteps;
                this.stepSize = stepSize; // can be positive or negative. Negative decreases the original image size
        if (this.stepSize > 0) // image is pulsating between original size to a larger size
        {
            this.incrementing = true;
        }
        else // image is pulsating between original size to a larger size
        {
            this.incrementing = false;
        }

        // the image pulsates about its centre
        this.centreX = x + (this.width / 2);
        this.centreY = y + (this.height / 2);

        this.currentStep = 0;
    }

The updateState() method deals with the cases of the image incrementing (i.e. pulsating between the original and a larger image) or decrementing (i.e. pulsating between the original and a smaller image). The two sets of code are very similar. The incrementing code is shown below in red and the decrementing code is shown below in blue.

    updateState()
    {
        if (this.stepSize > 0) // image pulses into a bigger image
        {
            if (this.incrementing) // incrementing to increase size of original image
            {
                this.currentStep++;
                if (this.currentStep === this.numberOfSteps)
                {
                    this.incrementing = false;
                }
            }
            else // drecrementing to return to original image size
            {
                this.currentStep--;
                if (this.currentStep === 0)
                {
                    this.incrementing = true;
                }
            }
        }
        else // image pulses into a smaller image
        {
            if (!this.incrementing) // drecrementing to decrease size of original image
            {
                this.currentStep++;
                if (this.currentStep === this.numberOfSteps)
                {
                    this.incrementing = true;
                }
            }
            else // drecrementing to return to original image size
            {
                this.currentStep--;
                if (this.currentStep === 0)
                {
                    this.incrementing = false;
                }
            }
        }
    }

The render() method draws the image on the canvas. It is straight forward and does not need explaining.

    render()
    {
        ctx.drawImage(this.image, this.x - (this.currentStep * this.stepSize) / 2, this.y - (this.currentStep * this.stepSize) / 2, this.width + (this.currentStep * this.stepSize), this.height + (this.currentStep * this.stepSize));
    }

pulsating_image.js

/* Author: Derek O Reilly, Dundalk Institute of Technology, Ireland.             */
/* There should always be a javaScript file with the same name as the html file. */
/* This file always holds the playGame function().                               */
/* It also holds game specific code, which will be different for each game       */





/******************** Declare game specific global data and functions *****************/
/* images must be declared as global, so that they will load before the game starts  */
let beachImage = new Image();
beachImage.src = "images/beach.png";
/******************* END OF Declare game specific data and functions *****************/







/* Always have a playGame() function                                     */
/* However, the content of this function will be different for each game */
function playGame()
{
    /* We need to initialise the game objects outside of the Game class */
    /* This function does this initialisation.                          */
    /* This function will:                                              */
    /* 1. create the various game game gameObjects                   */
    /* 2. store the game gameObjects in an array                     */
    /* 3. create a new Game to display the game gameObjects          */
    /* 4. start the Game                                                */


    /* Create the various gameObjects for this game. */
    /* This is game specific code. It will be different for each game, as each game will have it own gameObjects */

    gameObjects[0] = new PulsatingImage(beachImage, 0, 0, canvas.width, canvas.height, 10, 2, 100);

    /* END OF game specific code. */


    /* Always create a game that uses the gameObject array */
    let game = new CanvasGame();

    /* Always play the game */
    game.start();
    
   
    /* If they are needed, then include any game-specific mouse and keyboard listners */
}

We add a PulsatingImage object to the gameObjects[], as shown below.

    gameObjects[0] = new PulsatingImage(beachImage, 0, 0, canvas.width, canvas.height, 10, 2, 100);

Write a class to cause an image to rotate about a given centre point, as shown here. If no centre point is given, then the image should rotate about its own centre. The user should be able to specify a positive or negative rotation stepSize.