Adding obstacles & collision to canvas game - javascript
I am trying to add some obstacles to the canvas game that I've got but something seems to be wrong and I can't seem to put my finger on it.
I just want some simple walls here and there to make the game harder and collision with the walls (so that if the player hits the wall it's game over).
var
// variables
COLS = 25, // Columns
ROWS = 25, // Rows
EMPTY = 0, // Empty Cell
SNAKE = 1, // Snake
FRUIT = 2, // Fruit
LEFT = 0, // left direction (key)
UP = 1, // up direction (key)
RIGHT = 2, // right direction (key)
DOWN = 3, // down direction (key)
KEY_LEFT = 37, // key codes for keyboard input (Codes can be found online)
KEY_UP = 38, // key codes for keyboard input (Codes can be found online)
KEY_RIGHT = 39, // key codes for keyboard input (Codes can be found online)
KEY_DOWN = 40, // key codes for keyboard input (Codes can be found online)
obstacle = [[0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0]],
// [0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0],
// [0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0],
// [0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0],
// [0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0,0,0,2,0,0]],
// Objects
canvas, // Canvas
ctx, // Canvas render
keystate, // Key inputs
frames, // frames per second
score; // player score
grid = {
width: null, // Amount of columns
height: null, // Amount of rows
_grid: null, // Array
init: function(d, c, r) { // initiation with direction, columns and rows.
this.width = c; // Set width to number of columns (c)
this.height = r; // set height to number of rows (r)
this._grid = []; // Initiate grid with empty array
for (var x=0; x < c; x++) {
this._grid.push([]);
for (var y=0; y < r; y++) {
this._grid[x].push(d); // set current column and push new value for each row in column
}
}
},
set: function(val, x, y) { // set values for the grid cells with x and y position
this._grid[x][y] = val;
},
get: function(x, y) { // get the value of x and y position
return this._grid[x][y];
}
}
snake = { // Creating snake
direction: null, // Direction of snake
last: null, // last element in queue pointer
_queue: null, // queue array
// Sets start position of snake, same initiation method as before
init: function(d, x, y) {
this.direction = d; // Direction set to d
this._queue = []; // Another empty queue array
this.insert(x, y); // Inserting x & y position
},
// Insert method that adds elements to queue with x and y position
insert: function(x, y) {
this._queue.unshift({x:x, y:y}); // unshift prepends an element to array
this.last = this._queue[0];
},
// Remove function to remove and return element to queue
remove: function() {
return this._queue.pop(); // pop returns the last element of array
}
};
function obstacle() {
empty.push({obstacle});
ctx.beginPath();
ctx.rect(obstacle);
ctx.fillStyle = "#7a26ce";
ctx.fill();
ctx.closePath();
}
function setFood() { // Food for hungry snake
var empty = []; // tracks all empty places in the grid
// for loop to find all empty cells in grid
for (var x=0; x < grid.width; x++) {
for (var y=0; y < grid.height; y++) {
if (grid.get(x, y) === EMPTY) {
empty.push({x:x, y:y});
}
}
}
// variable randomposition to pick random empty cell
var randpos = empty[Math.round(Math.random()*(empty.length - 1))];
grid.set(FRUIT, randpos.x, randpos.y);
}
function main() { // call all the functions that we will use in the game
// canvas
canvas = document.createElement("canvas");
canvas.width = COLS*20; // Sets canvas width to columns * 20
canvas.height = ROWS*20; // Sets canvas height to columns * 20
ctx = canvas.getContext("2d");
document.body.appendChild(canvas); // Adds canvas element to the body of the document
ctx.font = "12px sans-serif"; // font
frames = 0;
keystate = {};
document.addEventListener("keydown", function(evt) { // Track all keyboard input
keystate[evt.keyCode] = true;
});
document.addEventListener("keyup", function(evt) { // Track all keyboard input
delete keystate[evt.keyCode];
});
init(); // Initiate Game Loop
loop(); // Start Game Loop
}
function init() { // Reset and intiate game objects
score = 0; // set start score to 0
grid.init(EMPTY, COLS, ROWS);
var sp = {x:Math.floor(COLS/2), y:ROWS-1};
snake.init(UP, sp.x, sp.y); // Start direction
grid.set(SNAKE, sp.x, sp.y);
setFood();
grid._grid = grid._grid.concat(obstacle);
}
function loop() { // Game loop for rendering and objects
update();
draw();
window.requestAnimationFrame(loop, canvas); // Canvas will call loop function when it needs to redraw
}
function update() { // update function
frames++;
// Keyboard input
if (keystate[KEY_LEFT] && snake.direction !== RIGHT) {
snake.direction = LEFT;
}
if (keystate[KEY_UP] && snake.direction !== DOWN) {
snake.direction = UP;
}
if (keystate[KEY_RIGHT] && snake.direction !== LEFT) {
snake.direction = RIGHT;
}
if (keystate[KEY_DOWN] && snake.direction !== UP) {
snake.direction = DOWN;
}
// Update game every 5 frames.
if (frames%5 === 0) {
// last element from the snake queue
var nx = snake.last.x;
var ny = snake.last.y;
// Updating the position of snake depending on the direction it is heading
switch (snake.direction) {
case LEFT:
nx--;
break;
case UP:
ny--;
break;
case RIGHT:
nx++;
break;
case DOWN:
ny++;
break;
}
// if statement checking conditions whether game should keep running or reset aka game over
if (0 > nx || nx > grid.width-1 ||
0 > ny || ny > grid.height-1 ||
grid.get(nx, ny) === SNAKE
) {
return init();
}
// Checks the new position of the snake and if it's on a fruit item or not.
if (grid.get(nx, ny) === FRUIT) {
// If it is on a fruit item it will increase your score and create a new food in a random cell.
score++;
setFood();
} else {
// Takes out the tail (first item) from queue and removes identifier from the grid.
var tail = snake.remove();
grid.set(EMPTY, tail.x, tail.y);
}
// Snake identifier that is created at the new position and is added to the queue
grid.set(SNAKE, nx, ny);
snake.insert(nx, ny);
}
}
function draw() { // render grid to canvas
var tw = canvas.width/grid.width; // Calculate tile width
var th = canvas.height/grid.height; // Calculate tile height
for (var x=0; x < grid.width; x++) { // for-loop loops through entire grid to draw cells
for (var y=0; y < grid.height; y++) {
// Depending on the identifier of each cell sets certain fillstyle defined below.
switch (grid.get(x, y)) {
case EMPTY:
ctx.fillStyle = "#5a5a5a";
break;
case SNAKE:
ctx.fillStyle = "#B54548";
break;
case FRUIT:
ctx.fillStyle = "lightblue";
break;
case obstacle:
ctx.fillStyle = "yellow";
break;
}
ctx.fillRect(x*tw, y*th, tw, th);
}
}
// Change fillstyle and show score on the screen.
ctx.fillStyle = "#000";
ctx.fillText("SCORE: " + score, 10, canvas.height-10);
}
// Game Start!
main();
canvas {
display: block;
position: absolute;
border: 2px solid #000;
margin: auto;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
or Fiddle.
I have been making games with collisions for a while now, and I find that using a collision map is the easiest way, instead of making one object that stores all entities at once. Here's an example:
var collisions = [];
function addCollision(x,y){
if(typeof collisions[x] == "undefined")collisions[x] = []; //If the row is empty, create it
collisions[x][y] = true; //Set the row and column to true
};
function checkCollision(x,y){
return (typeof collisions[x] != "undefined")?//If the row is undefined, there's nothing in it, so return false
((typeof collisions[x][y] != "undefined") //If not, but the column is undefined, return false
?true:false):false; //If the row and column is true, return true.
};
Now, addCollision(x,y) will put a new piece to collide with, and checkCollision(x,y) will see there is anything at x,y.
This is good for (relatively) small maps, as a large one will eat up a lot of memory. I have been able to do 500x500, but I'm not sure what the max size is.
Related
No collision between circles and drawn lines in matter.js
I am having trouble creating a line in p5/matter.js. My sketch is available on the p5 editor. On mousePressed and mouseDragged, the code grabs the mouse position every ten moves and uses curveVertex to draw a line between the current and last point. All of these points are stored in an array. This draws on the canvas perfectly but cannot interact with other objects. function mouseDragged(){ if (pointCount == 0) { points.push({x: mouseX, y: mouseY}); pointCount += 1; } else if (pointCount == 10) { pointCount = 0; } else { pointCount += 1; } } function mousePressed(){ points.push({x: mouseX, y: mouseY}); } function mouseReleased(){ line = new Line(points); console.log(points); } function draw() { background("#efefef"); circles.push(new Circle(200, 50, random(5, 10))); Engine.update(engine); for (let i = 0; i < circles.length; i++) { circles[i].show(); if (circles[i].isOffScreen()) { circles[i].removeFromWorld(); circles.splice(i, 1); i--; } } // for (let i = 0; i < boundaries.length; i++) { // boundaries[i].show(); // // console.log(boundaries[i].body.isStatic) // } if (points.length > 0) { // Loop through creating line segments beginShape(); noFill(); // Add the first point stroke('black'); strokeWeight(5); curveVertex(points[0].x,points[0].y) curveVertex(points[0].x,points[0].y) // Draw line points.forEach(function(p){ curveVertex(p.x,p.y); }) vertex(points[points.length-1].x,points[points.length-1].y) // Duplicate ending point endShape() } // Draw points for visualization stroke('#ff9900') strokeWeight(10) // points.push({x: x, y: y}) points.forEach(function(p){ point(p.x, p.y) }) } I tried creating a class and passed the points array to it, thinking that the matter.vertices function would take the points and make the needed body for the falling balls to bounce off. The code does not throw an error, but no collision occurs with the line. The example provided in matter.js document for the vertices function is unavailable and I have been unable to find any examples online. Hoping someone can point me in the right direction to get the created line to interact with the falling balls. class Line { constructor(vertices) { let options = { friction:0, restitution: 0.95, // angle: a, isStatic: true } this.body = Matter.Body.create(options); this.v = Matter.Vertices.create(vertices, this.body) World.add(world, this.body); } }
Trying to use mousePressed on a button and it ain't working?
I’m running into some errors. I want the user to select an eye player through clicking a button (either left eye or right eye) and then draw to the canvas only the selected input. I am using an eye tracker to draw some png files onto the canvas. I want them to draw only the left eye one if the user clicks on the left button. I'm sorry for the extremely long code, I'm very new to code and don't know how to do it efficiently. The main variables I've been using for my problem is 'left' which is a button I created in setup() and in draw() I go through an array of points (clm eye tracker) and then save the left and right eye positions to objects, I then call the function mouse pressed on the left button. // NETWORKED + EYE VARIABLES let socket = io(); // new socket on client side let ctracker; // eye tracker obj let clients = {}; // client object let data = {}; // data object let w = 1200; // matrix width let h = 600; // matrix height let leftEye, rightEye; // main eye image let SleftEye, SrightEye; // shadow eye image let leftEyeX, leftEyeY, rightEyeX, rightEyeY; // current user eye data point vars let cnvPosX, cnvPosY; // postion of main canvas let playerLeft = {}; let playerRight = {}; let left,right; /// SOUND VARIABLES // let bell, bell1, bell2, bell3; // contains sound source let bPat, b1Pat, b2Pat; // an array of nums that we can use to make a sequence of beats // 1 = on, 0= off let bPhrase, b1Phrase, b2Phrase; // defines how the beat pattern is interpreted let part; // attach all the above (sound,array,phrase) into a machine (part) i.e on/off,looper let beatLength; // how big is sequence before it starts looping let cellSize; // each sqauare size contains beat let row1 = []; // array of sounds in row 1 // DOM variables let play; // play button let bg, largeText, smallText; // image variables for game instructions and background let cnv; // main canvas let matrixCnv; // canvas that draws the matrix ( music user interface ) let instructCnv; // instruction canvas at the topmost part let bpmCTRL; // beat per minute slider // let previousCo = { // left: {row: null, column: null}, // right: {row: null, column:null} // }; function preload() { // background bg = loadImage( "https://cdn.glitch.com/e024d4d5-2c9e-473c-acd3-c2e01a1ef9cd%2Fdaw-bg.png?v=1589319965142" ); //main game instruction largeText = loadImage( "https://cdn.glitch.com/e024d4d5-2c9e-473c-acd3-c2e01a1ef9cd%2FAsset%2015.png?v=1589381930278" ); // small game description smallText = loadImage( "https://cdn.glitch.com/e024d4d5-2c9e-473c-acd3-c2e01a1ef9cd%2FAsset%203.png?v=1589381926354" ); // game main player left eye leftEye = loadImage( "https://cdn.glitch.com/7e3760d0-fed0-482e-a757-d1ca0280067e%2Fleft-eye.png?v=1589284305903" ); // game main player right eye rightEye = loadImage( "https://cdn.glitch.com/7e3760d0-fed0-482e-a757-d1ca0280067e%2Fright-eye.png?v=1589284306011" ); // game shadow player left eye SleftEye = loadImage( "https://cdn.glitch.com/7e3760d0-fed0-482e-a757-d1ca0280067e%2Fother-left-eye.png?v=1589284306106" ); // game shadow player left eye SrightEye = loadImage( "https://cdn.glitch.com/7e3760d0-fed0-482e-a757-d1ca0280067e%2Fother-right-eye.png?v=1589284332165" ); //sound files bell = loadSound( "https://cdn.glitch.com/e024d4d5-2c9e-473c-acd3-c2e01a1ef9cd%2F203490__tesabob2001__g-5.mp3?v=1589326854551", () => {} ); bell1 = loadSound( "https://cdn.glitch.com/e024d4d5-2c9e-473c-acd3-c2e01a1ef9cd%2F203485__tesabob2001__c5.mp3?v=1589326924689", () => {} ); bell2 = loadSound( "https://cdn.glitch.com/e024d4d5-2c9e-473c-acd3-c2e01a1ef9cd%2F203489__tesabob2001__f5.mp3?v=1589326917439", () => {} ); bell3 = loadSound( "https://cdn.glitch.com/e024d4d5-2c9e-473c-acd3-c2e01a1ef9cd%2F203491__tesabob2001__g-4.mp3?v=1589326867294", () => {} ); } function setup() { cnvPosX = 120; cnvPosY = 50; // setup camera capture var videoInput = createCapture(VIDEO); videoInput.size(w, h); videoInput.position(cnvPosX, cnvPosY); videoInput.hide(); // setup tracker ctracker = new clm.tracker(); ctracker.init(pModel); // feed it model pca 20 ctracker.start(videoInput.elt); // feed it video data // open socket io for connections socket.on("getUpdate", function(data) { clients[data.name] = data; }); instructCnv = createGraphics(w, h); instructCnv.background(0); matrixCnv = createGraphics(w, h); // matrix canvas of daw cnv = createCanvas(w, h); // main canvas that the eys are being drawn on cnv.position(cnvPosX, cnvPosY); // main. canvas position matrixCnv.mousePressed(canvasPressed); //drawMatrix() function on matrix function cnv.mousePressed(canvasPressed); // drawMatrix() function on main function beatLength = 6; // number of beats it loops thru && columns of matrix cellSize = 200; // size of square numOfRows = 3; // rows of matrix play = createButton('Play/Pause'); play.position(1300, 10); play.size(80,30); play.mousePressed(playAudio); // basic structure of a Digital Audio Workstation // time is a sceduled delay in note play time bPat = [0, 1, 0, 0, 0, 0]; b1Pat = [0, 0, 1, 0, 1, 1]; b2Pat = [1, 0, 0, 1, 0, 0]; // random selection of sound(bell3 or bell) in row 1 function selectSong() { row1 = [bell3, bell]; selected = row1[floor(random(2))]; selected.setVolume(0.1); selected.play(); } // name, callback, array bPhrase = new p5.Phrase( "bell", time => { selectSong(); }, bPat ); b1Phrase = new p5.Phrase( "bell1", time => { // make a variable to go there insiead of bell -> use random function to give a value to the variable bell1.setVolume(0.1); bell1.play(time); }, b1Pat ); b2Phrase = new p5.Phrase( "bell2", time => { bell2.setVolume(0.1); bell2.play(time); }, b2Pat ); // creating a new part that contains all the above part = new p5.Part(); part.addPhrase(bPhrase); part.addPhrase(b1Phrase); part.addPhrase(b2Phrase); bpmCTRL = createSlider(30, 200, 60, 1); // smallest val, highest val, starting val, incremental val bpmCTRL.position(10, 10); // x, y bpmCTRL.input(() => { part.setBPM(bpmCTRL.value()); }); part.setBPM("60"); //button left left = createButton('Left'); left.position(300,15); // drawing the grid drawMatrix(); } function draw() { image(matrixCnv, 0, 0); // background(bg); let positions = ctracker.getCurrentPosition(); for (let i = 0; i < positions.length; i++) { // find in array each position point playerLeft = { x : positions[27][0], y : positions[27][1] playerRight = { x : positions[32][0], y : positions[32][1] } left.mousePressed(drawLeft(playerLeft.x, playerLeft.y)); // formatting each point into a dict entry to send over socket io data[(27).toString() + "." + "0"] = playerLeft.x; data[(27).toString() + "." + "1"] = playerLeft.y; data[(32).toString() + "." + "0"] = playerRight.x; data[(32).toString() + "." + "1"] = playerRight.y; // update client details data["name"] = socket.id; data["updated"] = new Date().getTime(); socket.emit("update", data); //recieving data by other client and drawing var x, y; for (var c in clients) { if (c == socket.id) { // if client is not the the current user continue; } var points = clients[c]; // console.log(points) var leftEyePoint = { x: points['27.0'], y: points['27.1'] }; var rightEyePoint = { x: points['32.0'], y: points['32.1'] }; image(SleftEye, leftEyePoint.x, leftEyePoint.y, 150, 100) image(SrightEye, rightEyePoint.x, rightEyePoint.y, 150, 100) // canvasEyed(leftEyePoint, rightEyePoint) } } drawMatrix(); } function drawLeft(x,y) { push(); translate(x, y); image(leftEye, 0, 0, 150, 100); pop(); } function drawRight() { push(); translate(playerRight.x, playerRight.y); image(rightEye, 0, 0, 150, 100); pop(); } /////// conditional to check if all files are loaded function playAudio() { if (bell.isLoaded() && bell1.isLoaded() && bell2.isLoaded()) { if (!part.isPlaying) { part.loop(); } else { part.stop(); } } else { console.log("relax and wait for sound to load"); } } /// user interact function canvasPressed() { // console.log("mousepressed") let rowClicked = floor(numOfRows * (mouseY / height)); let columnClicked = floor(beatLength * (mouseX / width)); if (rowClicked === 0) { console.log("first row"); bPat[columnClicked] = +!bPat[columnClicked]; } else if (rowClicked === 1) { console.log("second row"); b1Pat[columnClicked] = +!b1Pat[columnClicked]; } else if (rowClicked === 2) { console.log("third row"); b2Pat[columnClicked] = +!b2Pat[columnClicked]; } } /// drawing the grid function drawMatrix() { matrixCnv.background(bg); //line matrixCnv.stroke(25, 40, 100); matrixCnv.strokeWeight(2); for (let i = 0; i < beatLength + 1; i++) { matrixCnv.line(i * cellSize, 0, i * cellSize, height); } for (let i = 0; i < numOfRows + 1; i++) { matrixCnv.line( 0, (i * height) / numOfRows, width, (i * height) / numOfRows ); } //circle matrixCnv.noStroke(); matrixCnv.fill(25, 40, 100); for (let i = 0; i < beatLength; i++) { if (bPat[i] === 1) { matrixCnv.ellipse(i * cellSize + 0.5 * cellSize, 100, 50); } if (b1Pat[i] === 1) { matrixCnv.ellipse(i * cellSize + 0.5 * cellSize, 300, 40); } if (b2Pat[i] === 1) { matrixCnv.ellipse(i * cellSize + 0.5 * cellSize, 500, 30); } } }
Dan O is right, That is not the correct way of passing variables as arguments in callback functions. left.mousePressed(drawLeft(playerLeft.x, playerLeft.y)); It Should be: left.mousePressed( function()=>{ drawLeft( playerLeft.x, playerLeft.y ); } ); This way you create a new function, an extra step inbetween. The function calls drawLeft(). Then pass that new function as the callback function. It's the same as doing this: let afterMousePressed = function(){ drawLeft( playerLeft.x, playerLeft.y ); }; left.mousePressed( afterMousePressed );
Overlap callback never called
I am creating a small space invaders-like game. In create function I create enemies enemies = game.add.group(); enemies.enableBody = true; enemies.physicsBodyType = Phaser.Physics.ARCADE; enemies.x = 100; enemies.y = 50; for (var y = 1; y < 200; y += 50) { for (var x = 233; x <= 800; x += 50) { var enemy = enemies.create(x, y, 'enemy'); enemy.anchor.setTo(0.5, 0.5); enemy.body.moves = false; } } and bullets bullets = game.add.group(); bullets.enableBody = true; bullets.physicsBodyType = Phaser.Physics.ARCADE; bullets.createMultiple(30, 'bullet'); bullets.setAll('anchor.x', 0.5); bullets.setAll('anchor.y', 1); bullets.setAll('outOfBoundsKill', true); bullets.setAll('checkWorldBounds', true); and set the overlap callback game.physics.arcade.overlap(bullets, enemies, collisionHandler); But, unfortunately, when the bullet overlaps an enemy, nothing happens. Callback is function collisionHandler (bullet, enemy) { console.log("poft"); bullet.kill(); enemy.kill(); }
In your case you only need to check if there is a collision between both groups, so you would choose to use the 'overlap' method that will be evaluated in the function update: function update() { game.physics.arcade.overlap(bullets, enemies, collisionHandler, null, this); } The method receives five arguments, you can consult them here. And simple example of Physics Arcade: Group vs Group
Make identical objects move independently in Javascript Canvas
So I am trying to make a simple space game. You will have a ship that moves left and right, and Asteroids will be generated above the top of the canvas at random X position and size and they will move down towards the ship. How can I create Asteroid objects in seperate positions? Like having more than one existing in the canvas at once, without creating them as totally seperate objects with seperate variables? This sets the variables I would like the asteroid to be created on. var asteroids = { size: Math.floor((Math.random() * 40) + 15), startY: 100, startX: Math.floor((Math.random() * canvas.width-200) + 200), speed: 1 } This is what I used to draw the asteroid. (It makes a hexagon shape with random size at a random x coordinate) function drawasteroid() { this.x = asteroids.startX; this.y = 100; this.size = asteroids.size; ctx.fillStyle = "#FFFFFF"; ctx.beginPath(); ctx.moveTo(this.x,this.y-this.size*0.5); ctx.lineTo(this.x+this.size*0.9,this.y); ctx.lineTo(this.x+this.size*0.9,this.y+this.size*1); ctx.lineTo(this.x,this.y+this.size*1.5); ctx.lineTo(this.x-this.size*0.9,this.y+this.size*1); ctx.lineTo(this.x-this.size*0.9,this.y); ctx.fill(); } I included ALL of my code in this snippet. Upon running it, you will see that I currently have a ship that moves and the asteroid is drawn at a random size and random x coordinate. I just need to know about how to go about making the asteroid move down while creating other new asteroids that will also move down. Thank You for all your help! I am new to javascript. // JavaScript Document ////// Variables ////// var canvas = {width:300, height:500, fps:30}; var score = 0; var player = { x:canvas.width/2, y:canvas.height-100, defaultSpeed: 5, speed: 10 }; var asteroids = { size: Math.floor((Math.random() * 40) + 15), startY: 100, startX: Math.floor((Math.random() * canvas.width-200) + 200), speed: 1 } var left = false; var right = false; ////// Arrow keys ////// function onkeydown(e) { if(e.keyCode === 37) { left = true; } if(e.keyCode === 39) { right = true; } } function onkeyup(e) { if (e.keyCode === 37) { left = false; } if(e.keyCode === 39) { right = false; } } ////// other functions ////// //function to clear canvas function clearCanvas() { ctx.clearRect(0,0,canvas.width,canvas.height); } // draw the score in the upper left corner function drawscore(score) { var score = 0; ctx.fillStyle = "#FFFFFF"; ctx.fillText(score,50,50); } // Draw Player ship. function ship(x,y) { var x = player.x; var y = player.y; ctx.fillStyle = "#FFFFFF"; ctx.beginPath(); ctx.moveTo(x,y); ctx.lineTo(x+15,y+50); ctx.lineTo(x-15,y+50); ctx.fill(); } // move player ship. function moveShip() { document.onkeydown = onkeydown; document.onkeyup = onkeyup; if (left === true && player.x > 50) { player.x -= player.speed; } if (right === true && player.x < canvas.width - 50) { player.x += player.speed; } } // Draw Asteroid function drawasteroid() { this.x = asteroids.startX; this.y = 100; this.size = asteroids.size; ctx.fillStyle = "#FFFFFF"; ctx.beginPath(); ctx.moveTo(this.x,this.y-this.size*0.5); ctx.lineTo(this.x+this.size*0.9,this.y); ctx.lineTo(this.x+this.size*0.9,this.y+this.size*1); ctx.lineTo(this.x,this.y+this.size*1.5); ctx.lineTo(this.x-this.size*0.9,this.y+this.size*1); ctx.lineTo(this.x-this.size*0.9,this.y); ctx.fill(); } // move Asteroid function moveAsteroid() { //don't know how I should go about this. } // update setInterval (update, 1000/canvas.fps); function update() { // test collisions and key inputs moveShip(); // redraw the next frame of the animation clearCanvas(); drawasteroid(); drawscore(); ship(); } <!doctype html> <html> <head> <meta charset="UTF-8"> <title>My Game</title> <script src="game-functions.js"></script> <!-- <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script> --> </head> <body> <canvas id="ctx" width="300" height="500" style="border: thin solid black; background-color: black;"></canvas> <br> <script> ////// Canvas setup ////// var ctx = document.getElementById("ctx").getContext("2d"); </script> </body> </html>
You want to make the creation of asteroids dynamic...so why not set up a setInterval that gets called at random intervals as below. You don't need a separate declaration for each Asteroids object you create. You can just declare a temporary one in a setInterval function. This will instantiate multiple different objects with the same declaration. Of course you need to store each object somewhere which is precisely what the array is for. You also have to make sure that asteroids get removed from the array whenever the moveAsteroid function is called if they are off of the canvas. The setInterval function below should be called on window load and exists alongside your main rendering setInterval function. You are also going to have to change your moveAsteroid function a bit to be able to point to a specific Asteroids object from the array. You can do this by adding the Asteroids object as a parameter of the function or by making the function a property of the Asteroids class and using this. I did the latter in the example below. var astArray = []; var manageAsteroidFrequency = 2000; var Asteroids { X: //something Y://something speed:1 move: function() { this.X -= speed; } } var mainRenderingFunction = setInterval( function() { for (var i = astArray.length-1 ; i > -1; i --){ if(astArray[i].Y < 0){ astArray.splice(i, 1) }else{ astArray[i].move; } } }, 40); var manageAsteroids = setInterval( function () { if (astArray.length < 4){ var tmpAst = new Asteroids(); astArray.push(tmpAst); } manageAsteroidFrequency = Math.floor(Math.random()*10000); }, manageAsteroidFrequency);
Count Amount of Colored Squares in Canvas
Here is the fiddle: http://jsfiddle.net/sw31uokt/ Here is some of the relevant code for the incrementValue function I set up to count overall clicks within the canvas element. What I would like to do is be able to display a count of each color, so "you have placed 14 red pixels, 3 blue pixels, 4 black pixels'. function incrementValue() { var value = parseInt(document.getElementById('number').value, 10); value = isNaN(value) ? 0 : value; value++; document.getElementById('number').value = value; } $(c_canvas).click(function(evt) { var pos = getNearestSquare(getMousePos(c_canvas, evt)); if (pos != null) { context.fillStyle=(currentColor); context.fillRect(pos.x,pos.y,19,19); incrementValue(); } });
Basically, what MarkE said above ... In the outer scope, add two new vars : var palette = ["333333", "0000ff", "a0522d", "46ad42", "808080", "ffc0cb", "d73952", "ffe2a8", "ffff7d", "ffffff"];//as originally defined in the .spectrum() call. var gridModel = [];//Eventually a sparse array of sparse arrays, representing colored grid squares. Uncolored grid squares remain undefined. And two new functions, in the same scope : function updateGridModel(pos, color) { var x = (pos.x - 0.5) / 20; var y = (pos.y - 0.5) / 20; color = color.substr(1).toLowerCase(); if (!gridModel[x]) { gridModel[x] = []; } gridModel[x][y] = palette.indexOf(color); } function paletteTally() { //initialise an array, same length as palettes, with zeros var arr = palette.map(function () { return 0; }); for (var x = 0; x < gridModel.length; x++) { if (gridModel[x]) { for (var y = 0; y < gridModel[x].length; y++) { if (gridModel[x][y] !== undefined) { arr[gridModel[x][y]] += 1; } } } } return arr; } Modify the canvas's click handler to keep the gridModel up to date : $(c_canvas).click(function (evt) { var pos = getNearestSquare(getMousePos(c_canvas, evt)); if (pos != null) { context.fillStyle = currentColor; context.fillRect(pos.x, pos.y, 19, 19); incrementValue(); updateGridModel(pos, currentColor); //keep the gridModel up to date. } }); Modify printColor() as follows : function printColor(color) { currentColor = color.toHexString(); $(".label").text(currentColor); } Modify the .spectrum() options and add an initialising call to printColor() as follows : $("#showPaletteOnly").spectrum({ color: palette[0], showPaletteOnly: true, showPalette: true, hideAfterPaletteSelect: true, change: printColor, palette: [palette] //<<<< palette is now defined as an outer var }); printColor( $("#showPaletteOnly").spectrum('get') );//initialize currentcolor and $(".label").text(...) . Now paletteTally() will return an array congruent with palette containing counts of each color. EDIT 1 Original code above was untested but is now debugged and includes improved spectrum options. Demo.