Strange behavioral difference between rectangles and images

I am beginning to learn P5JS by creating a simple shooting game in which targets are loaded as random images and when clicked they disappear. The targets are objects that are loaded into an array and drawn each frame, and when one is clicked it is simply removed from the array and no longer drawn the next frame. I have run into a problem in which I can't get the images to be redrawn every frame, however if I replace the image with a rectangle it IS redrawn every frame.

Here is my code:

var target;

// Array the stores all targets
var targets = [];

// x and y spawn coordinates for targets
var x;
var y;
var targetX;
var targetY;

// Image that shows when a target is hit, an explosion etc
var deathImage;

function setup() {
    createCanvas(windowWidth, windowHeight);
    frameRate(2);
    imageMode(CENTER);
    cursor(CROSS);
}

function draw() {

    x = int(random(windowWidth));
    y = int(random(windowHeight));
    targetImage = createImg('assets/test.png').hide();

    targets.push(new Target(x, y, targetImage));
    fill(0, 255, 255);
    rectMode(CORNER);
    rect(0, 0, width, height);
    for (var i = 0; i < targets.length; i++) {
            targets[i].display();
    }

}

// Target Class
function Target(x, y, targetImage) {
    this.display = function() {
            this.targetX = x;
            this.targetY = y;
            this.TargetPicture = targetImage;

            /* When I use an image here it only shows in a single frame and then dissapears, the targets[i].display(); for loop fails to redraw all the targets */
            image(this.TargetPicture, this.targetX, this.targetY, 200, 200);

            /*However if I draw rectangles it works as expected            
            fill(255,0,0);
            rectMode(CENTER);
            rect(x,y,200,200); */
    }
}

function mouseClicked() {
    for (var i = 0; i < targets.length; i++) {
        var distanceChecker = dist(mouseX, mouseY, targets[i].targetX, targets[i].targetY);
        // If target is hit
        if (distanceChecker < 150) {
            fill(255, 0, 255);
            // Show explosion when target hit
            deathImage = createImg('assets/deathImage.png').hide();
            image(deathImage, mouseX, mouseY, 300, 300);
            // Remove target from array
            targets.splice(i, 1);
        }
    }

}

What am I missing? Thanks in advance!

Answers

  • You are adding your targets in line 26 which is in the draw function. Why not to load them in setup? Is it a requirement?

    Kf

  • @GoToLoop what is that reference to .hide() when calling createImg?? And createImg is from JS?

    Kf

  • edited April 2017

    createImg() creates a p5.Element object. So we should look up its API in its own reference page: :-B

    1. https://p5js.org/reference/#/p5/createImg
    2. https://p5js.org/reference/#/p5.Element
    3. https://p5js.org/reference/#/p5.Element/hide
  • saisai
    edited April 2017

    Thanks guys! The use of createImage() instead of loadImage() explains the strange behaviour. @kfrajer the reason I am loading the images during draw is that this is part of a larger project in which the script takes input from the user (just once) and quiries googles custom search API, so that the user can select what they want to use as targets. This leads to another problem @GoToLoop, I can't load the images using preload() because loading them involves a single string of user input. See the below revised code. I've added a "/***" where I'm having issues, any ideas? I've been googling around for awhile, I think that's initially why I started using createImage()

        // Google API variables
        var imageDataLoaded;
        var api = "https://www.googleapis.com/customsearch/v1?key=MYKEY&searchType=image&imgSize=large&q=";
        var end = "&amp;";
        var input;
        var image_index;
        var imageLink;
    
        // Target variables
        var target;
        var targetImage;
    
        // Array the stores all targets
        var targets = [];
    
        // x and y spawn coordinates for targets
        var x;
        var y;
        var targetX;
        var targetY;
    
        // Image that shows when a target is hit
        var deathImage;
    
    
        function setup() {
            createCanvas(windowWidth, windowHeight);
            frameRate(2);
            imageMode(CENTER);
            cursor(CROSS);
    
            var button = select('#submit');
            button.mousePressed(generateImage);
            input = select('#queryString');
    
            function generateImage() {
                loadJSON(api + input.value() + end, gotImages, 'jsonp');
            }
    
        }
    
        function gotImages(imageData) {
            imageDataLoaded = imageData;
        }
    
        gotImages();
    
        function draw() {
    
            x = int(random(windowWidth));
            y = int(random(windowHeight));
    
            /*** How can I use a callback function after user input and outside of draw?
            I am aiming to load around 10 images after the user inputs what to search 
            google with eg "planes". However I do only need to load the images once. 
            ***/
    
            if (imageDataLoaded) {
                image_index = int(random(imageDataLoaded.items.length));
                imageLink = imageDataLoaded.items[image_index];
                targetImage = loadImage(imageLink.link)();
    
            }
    
            targets.push(new Target(x, y, targetImage));
            fill(0, 255, 255);
            rectMode(CORNER);
            rect(0, 0, width, height);
    
            for (var i = 0; i < targets.length; i++) {
                if (imageDataLoaded) {
                    targets[i].display(targetImage);
                }
    
            }
    
        }
    
        // Target Class
        function Target(x, y, targetImage) {
    
            this.display = function() {
                if (imageDataLoaded) {
                    this.targetX = x;
                    this.targetY = y;
                    this.TargetPicture = targetImage;
                    image(this.TargetPicture, this.targetX, this.targetY, 200, 200);
                }
    
            }
        }
    
        function mouseClicked() {
            console.log(targets);
    
            for (var i = 0; i < targets.length; i++) {
                var distanceChecker = dist(mouseX, mouseY, targets[i].targetX, targets[i].targetY);
                // If target is hit
                if (distanceChecker < 150) {
                    fill(255, 0, 255);
                    // Show explosion when target hit
                    deathImage = createImg('assets/deathImage.png').hide();
                    image(deathImage, mouseX, mouseY, 300, 300);
                    // Remove target from array
                    targets.splice(i, 1);
                }
            }
    
        }
    
Sign In or Register to comment.