0
votes

I have recently been working on a web based project using canvas on HTML5. The program consists of a 16x16 grid of tiles that have been pseudo-randomly generated. I am relatively new to canvas, but have built this program in several other environments, none of which however compile successfully to a web based language. this is the main code section that is giving me bother:

var A = 8765432352450986;
var B = 8765432352450986;
var M = 2576436549074795;
var X = 1;
var rx = 0;
var ry = 0;
this.image = new Image();
var i = 0;
var ii  = 0;
while(i < 16)
{
    while(ii < 16)
    {
        this.image = new Image();
        this.image.src = "textures/grass.png";
        x = (((A*X)+B)%M)%M;
        if((x/2)%1 == 0)
        {
            this.image.src = "textures/grass.png";
        }
        if((x/8)%1 == 0)
        {
            this.image.src = "textures/hill.png";
        }
        if((x/21)%1 == 0)
        {
            this.image.src = "textures/trees.png";
        }
        if((x/24)%1 == 0)
        {
            this.image.src = "textures/sea.png";
        }
        if((x/55)%1 == 0)
        {
            this.image.src = "textures/mountain.png";
        }
        if((x/78)%1 == 0)
        {
            this.image.src = "textures/lake.png";
        }
        if((x/521)%1 == 0)
        {
            this.image.src = "textures/volcano.png";
        }
        if((x/1700)%1 == 0)
        {
            this.image.src = "textures/shrine.png";
        }
        if((x/1890)%1 == 0)
        {
            this.image.src = "textures/outpost.png";
        }
        if((x/1999)%1 == 0)
        {
            this.image.src = "textures/civ.png";
        }
        ctx = myGameArea.context;
        ctx.drawImage(this.image,rx, ry, 20, 20);
        ii ++;
        rx += 20;

    }
    i ++;
    rx = 0;
    ry += 16;
}

I would like canvas to draw along the lines of this code above, effectively generating a grid like this pre generated grid image

(please try and ignore the obvious bad tile drawings, I planned on either finding an artist or trying slightly harder on them when I get the game fully working.)

The black square is a separate movable object. I haven't got as far as implementing it in this version, but if you have any suggestions for it please tell me

in the full html file I have now, the canvas renders but none of the background (using the w3schools tutorials, I can make objects render however)

In short: how do I render a background consisting of a 16x16 grid of pseudo-random tiles on an event triggered or on page loaded, using canvas or if that does not work another web based technology

Thank you for your time.

1
Preload every images, store them as img, then pick one of those preloaded imgs randomly. Here you are trying to draw non loaded images, and do change their src even before it's been loaded.Kaiido

1 Answers

0
votes

A few problems but the main one is that you need to give an image some time to load before you can draw it to the canvas.

var image = new Image();
image.src = "image.png"; 
// at this line the image may or may not have loaded. 
// If not loaded you can not draw it

To ensure an image has loaded you can add a onload event handler to the image

var image = new Image();
image.src = "image.png"; 
image.onload = function(){ ctx.drawImage(image,0,0); }

The onload function will be called after all the current code has run.

To load many images you want to know when all have loaded. One way to do this is to count the number of images you are loading, and then use the onload to count the number of images that have loaded. When the loaded count is the same as the loading count you know all have loaded and can then call a function to draw what you want with the images.

// Array of image names
const imageNames = "grass,hill,trees,sea,mountain,lake,volcano,shrine,outpost,civ".split(",");
const images = []; // array of images
const namedImages = {}; // object with named images
// counts of loaded and waiting toload images
var loadedCount = 0;
var imageCount = 0;
// tile sizes
const tileWidth = 20;
const tileHeight = 20;


// NOT SURE WHERE YOU GOT THIS FROM so have left it as you had in your code
// Would normally be from a canvas element via canvasElement.getContext("2d")
var ctx = myGameArea.context;

// seeded random function encapsulated in a singleton
// You can set the seed by passing it as an argument rand(seed) or 
// just get the next random by not passing the argument. rand()
const rand = (function(){
    const A = 8765432352450986;
    const B = 8765432352450986;  // This value should not be the same as A?? left as is so you get the same values
    const M = 2576436549074795;
    var seed = 1;
    return (x = seed) => seed = ((A * x) + B) % M;
}());
// function loads an image with name 
function addImage(name){
    const image = new Image;
    image.src = "textures/" + name + ".png";
    image.onload = () => {
        loadedCount += 1;
        if(loadedCount === imageCount){
            if(typeof allImagesLoaded === "function"){
                allImagesLoaded();
            }
        }
    }
    imageCount += 1;
    images.push(image);
    namedImages[name] = image;
}
imageNames.forEach(addImage); // start loading all the images

// This function draws the tiles
function allImagesLoaded(){  /// function that is called when all the images have been loaded
    var i, x, y, image;
    for(i = 0; i < 256; i += 1){  // loop 16 by 16 times
        ctx.drawImage(
            images[Math.floor(rand()) % images.length]; //random function does not guarantee an integer so must floor
            (i % 16) * tileWidth,  // x position
            Math.floor(i / 16) * tileHeight, // y position
            tileWidth, tileHeight  // width and height
        );
    }
}