Moving group of objects at the same time in canvas - javascript

My problem is that I have no idea how to implement group of objects, in my situation, group of rectangles moving all at the same time. Well, I implemented easily moving one rectangle with specific direction which you can see below from my code. Also I tried to add an array with group of rectangles. So again my question is how to implement group of rectangles (3 rows 3 columns, 9 of them, for instance) to move the same way how my one rectangle is moving in the code below????? So basically very right side of group and very left side of the group will hit the border while column in the middle of 3X3 will stay moving between two columns of 3X3.....Any help will appreciated. Thank you...
<html>
<head>
<title>Spaceman Invaders</title>
<script>
window.onload = function() {
var canvas = document.getElementById("screen");
context = canvas.getContext("2d");
context.fillStyle="black";
context.fillRect(0,0,canvas.width, canvas.height);
context.fillStyle = "red";
context.fillRect(30, 100, 20 , 20);
var posx = 27;
var posy = 100;
var go_right = true;
var go_down = false;
if (canvas.getContext) {
/* var array = [];
array.push(new Shape(20, 0, 50, 50, "red"));
array.push(new Shape(20, 60, 50, 50, "red"));
array.push(new Shape(20, 120, 50, 50, "red"));
array.push(new Shape(80, 0, 50, 50, "red"));
array.push(new Shape(80, 60, 50, 50, "red"));
array.push(new Shape(80, 120, 50, 50, "red"));
array.push(new Shape(140, 0, 50, 50, "red"));
array.push(new Shape(140, 60, 50, 50, "red"));
array.push(new Shape(140, 120, 50, 50, "red"));*/
setInterval( function() {
if (!go_down) {
if(posx < 250 && go_right) {
posx += 3;
} else if(posx < 30) {
go_right = true;
go_down = true;
} else if(!go_right) {
posx -= 3;
}else {
go_right = false;
go_down = true;
}
} else {
//if(posy <= 30)
posy += 5;
go_down = false;
}
context.fillStyle="black";
context.fillRect(0,0,canvas.width, canvas.height);
context.fillStyle = "red";
context.beginPath();
context.fillRect(posx, posy, 20 , 20);
context.fill();
}
, 20);
}
</script>
</head>
<body>
<canvas id="screen" width="300" height="500"/>
</body>
</html>

You will have to store the x,y position of each rectangle. You may create an new class for this. I've made you an example:
var Alien = function(x, y) {
this.x = x;
this.y = y;
this.posx = 30 + x*30;
this.posy = 90 + y*30;
this.go_right = true;
this.go_down = false;
this.perrow = 3;
}
Alien.prototype.move = function() {
if (!this.go_down) {
if(this.posx + (this.perrow-1-this.x) * 30 < 250 && this.go_right) {
this.posx += 3;
} else if(this.posx < 30 + this.x*30) {
this.go_right = true;
this.go_down = true;
} else if(!this.go_right) {
this.posx -= 3;
} else {
this.go_right = false;
this.go_down = true;
}
} else {
//if(posy <= 30)
this.posy += 30;
this.go_down = false;
}
}
Alien.prototype.draw = function(context) {
if(this.x == 0) {
context.fillStyle = "red";
} else if(this.x == 1) {
context.fillStyle = "yellow";
} else {
context.fillStyle = "blue";
}
context.beginPath();
context.fillRect(this.posx, this.posy, 20 , 20);
context.fill();
}
Then you can update the position and draw each object separately in a loop inside of your intervall callback.
EDIT:
Now the objects move downwards all at once.
You can test it here:
http://jsfiddle.net/Z6F4d/3/

Related

How to reset CreateCanvas() in JS after being called

When I was writing the code I saw that the code would not reset the canvas to (400, 400) after being changed to (600, 600). It would disorientate the canvas and stretch all the shapes with it in evaporation(). When going through all the screens and trying to go back to reset back.
//Variables
let screen = 0;
let bugs = [];
let amt = 1000;
let xpos=0;
function setup() {
colorMode(HSB);
//Changes Colormode to HSB(Hue-Saturation-Brightness)
//Creates the particles for the evaporation screen
//For loop with increasement that states more of the smoke is created
for (let i = 0; i < amt; i++) {
let x = 200;
let y = 300;
let rad = random(10, 50);
let b = new Bug(x, y, rad);
bugs[i] = b;
}
}
//Says if the value of screen changes so does the screen
function draw() {
if(screen == 0) {
evaporationscreen();
} else if(screen == 1) {
condensation();
} else if(screen == 2) {
presipitation();
}
}
//Evaporation
function evaporationscreen() {
background('#d2b48c');
createCanvas(400, 400);
//NOT RGB, HSB COLOR PALLETE(DO NOT MIX UP);
//HTML Color pallete('e928320');
noStroke();
fill('#3895d3') //Lake
circle(400, 400, 600)
fill('#18bdf0') //Sky
rect(0, 0, 400, 200);
fill('#ffff00'); //Sun
circle(300, 60, 70);
fill('#e9bd15'); //Darkspots on Sun
circle(315, 75, 10);//Forms the Sun and Darkspots
circle(280, 52, 8);//Forms the Sun and Darkspots
circle(299, 60, 13);//Forms the Sun and Darkspots
circle(320, 48, 9);//Forms the Sun and Darkspots
circle(295, 30, 6);//Forms the Sun and Darkspots
circle(284, 79, 9);//Forms the Sun and Darkspots
fill(240, 100, 50);//Forms the Sun and Darkspots
rect(0, 200, 400, 400); //Beach
console.log("EVAPORATION");
//Lots of variables
let stoprip = 45;
let lake = int(dist(400, 400, mouseX, mouseY));
var starx = random(0, 400);
var stary = random (10, 190);
var sun = int(dist(300, 60, mouseX, mouseY));
//If Statement that creates ripples
if (mouseIsPressed && lake < 300) {
if (mouseY >= 200) {
noFill();
stroke('#3895d3');
strokeWeight(4);
circle(mouseX, mouseY, ripple);
ripple = ripple + 5;
console.log('lake rippling');
if (ripple >= stoprip) {
ripple = 10
}
} else {
ripple = 10
}
} else if (mouseIsPressed && sun <=35) {
fill('#fee12b');
circle(starx, stary, 10);
console.log('stars');
}
background(50, 0.25);
//For loop that creates the smoke effect with an increasement
for (let i = 0; i < bugs.length; i++) {
bugs[i].show();
bugs[i].move();
if( bugs[i].radius > 100 ) {
bugs.splice(i, 1);
}
}
let x = 200;
let y = 300;
let rad = random(10, 50);
let b = new Bug(x, y, rad);
bugs.push(b);
}
//Particles for evaporation
class Bug {
constructor(tempX, tempY, tempRadius) {
this.x = tempX;
this.y = tempY;
this.radius = tempRadius;
this.color = color(random(80,100), 0.05);
}
//Creates the sketch for it
show() {
noStroke();
fill(this.color);
ellipse(this.x, this.y, this.radius);
}
//Moves it up at a random pace
move() {
this.x = this.x + random(-5, 5);
this.y = this.y - random(2);
this.radius = this.radius + 0.4;
}
}
function condensation() {
//Changes the canvas from 400,400 to 600,600
createCanvas(600, 600);
//Changes background to grey to imitate storm,
background(50);
console.log("CONDENSATION");
//Colors the cloud and fills it with white
noStroke();
fill(255);
//States where cloud spawns
cloud(xpos,50,1);
cloud(xpos,50,2);
cloud(xpos,80,0.75);
xpos++;
//Has cloud with an increasement
if (xpos>600) {
xpos=0;
}
}
function presipitation() {
createCanvas(600, 600);
ellipseMode(RADIUS);
noFill();
background(211, 69, 93);
console.log("PRESIPITATION")
//If statement that create a for loop that spawns new particles(rain)
if (particles.length < 200) particles.push(new Particle());
for (var i = 0; i < particles.length; i++) {
particles[i].update();
particles[i].display();
}
}
var particles = [];
//Variable
//Rain drop / Particle
class Particle {
constructor() {
this.reset();
}
//Resets Particle after update
reset() {
this.x = random(width);
this.y = random(-150, 0);
this.vy = random(0.1, 2);
this.maxy = this.y + height;
this.r = 0;
this.tr = 50;
this.w = random(0.1, 2);
}
//If statement that creates the gravity for the particle
update() {
if (this.y < this.maxy) {
this.y += this.vy;
} else {
this.r++;
}
if (this.r > this.tr) this.reset();
}
//If statement(says it will remain the raindrop form or change into the puddle
display() {
strokeWeight(this.w);
if (this.y < this.maxy) {
stroke(255);
push();
translate(this.x,this.y);
beginShape();
strokeWeight(1);
vertex(0,-5);
quadraticVertex(3, 0, 0, 1);
quadraticVertex(-3,0, 0, -5);
endShape(CLOSE);
pop();
} else {
stroke(255, map(this.r, 0, this.tr, 255, 0));
ellipse(this.x, this.y, this.r, this.r*.5);
}
}
}
//Changes Screen from evaporation, condensation, precipitation
function mousePressed(){
if(screen==0){
screen=1;
}else if(screen==1){
screen = 2;
} else if(screen == 2) {
screen = 0;
}
}
//Makes cloud
function cloud(x,y,sc){
push()
scale(sc);
ellipse(x,y,50,30);
ellipse(x,y+20,80,30);
ellipse(x+20,y,40,30);
ellipse(x+30,y+10,70,40);
pop()
}
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sketch</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="libraries/p5.min.js"></script>
<script src="libraries/p5.sound.min.js"></script>
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
From the documentation for createCanvas:
Creates a canvas element in the document, and sets the dimensions of it in pixels. This method should be called only once at the start of setup. Calling createCanvas more than once in a sketch will result in very unpredictable behavior.
Instead of calling createCanvas repeatedly in your drawing functions, you should use resizeCanvas once when transitioning from one screen to another.
I couldn't actually reproduce whatever issue you were describing (partly because I could not make sense of your description). However I did also notice an issue with the variable ripple not being declared anywhere, so I fixed that, and now the sketch appears to be working correctly.
//Variables
let previousScreen = 0;
let screen = 0;
let bugs = [];
let amt = 1000;
let xpos = 0;
let ripple = 0;
function setup() {
createCanvas(400, 400);
colorMode(HSB);
//Changes Colormode to HSB(Hue-Saturation-Brightness)
//Creates the particles for the evaporation screen
//For loop with increasement that states more of the smoke is created
for (let i = 0; i < amt; i++) {
let x = 200;
let y = 300;
let rad = random(10, 50);
let b = new Bug(x, y, rad);
bugs[i] = b;
}
}
//Says if the value of screen changes so does the screen
function draw() {
if (screen == 0) {
if (previousScreen !== screen) {
resizeCanvas(400, 400);
previousScreen = screen;
}
evaporationscreen();
} else if (screen == 1) {
if (previousScreen !== screen) {
resizeCanvas(600, 600);
previousScreen = screen;
}
condensation();
} else if (screen == 2) {
if (previousScreen !== screen) {
resizeCanvas(600, 600);
previousScreen = screen;
}
presipitation();
}
}
//Evaporation
function evaporationscreen() {
background('#d2b48c');
//NOT RGB, HSB COLOR PALLETE(DO NOT MIX UP);
//HTML Color pallete('e928320');
noStroke();
fill('#3895d3') //Lake
circle(400, 400, 600)
fill('#18bdf0') //Sky
rect(0, 0, 400, 200);
fill('#ffff00'); //Sun
circle(300, 60, 70);
fill('#e9bd15'); //Darkspots on Sun
circle(315, 75, 10); //Forms the Sun and Darkspots
circle(280, 52, 8); //Forms the Sun and Darkspots
circle(299, 60, 13); //Forms the Sun and Darkspots
circle(320, 48, 9); //Forms the Sun and Darkspots
circle(295, 30, 6); //Forms the Sun and Darkspots
circle(284, 79, 9); //Forms the Sun and Darkspots
fill(240, 100, 50); //Forms the Sun and Darkspots
rect(0, 200, 400, 400); //Beach
console.log("EVAPORATION");
//Lots of variables
let stoprip = 45;
let lake = int(dist(400, 400, mouseX, mouseY));
var starx = random(0, 400);
var stary = random(10, 190);
var sun = int(dist(300, 60, mouseX, mouseY));
//If Statement that creates ripples
if (mouseIsPressed && lake < 300) {
if (mouseY >= 200) {
noFill();
stroke('#3895d3');
strokeWeight(4);
circle(mouseX, mouseY, ripple);
ripple = ripple + 5;
console.log('lake rippling');
if (ripple >= stoprip) {
ripple = 10
}
} else {
ripple = 10
}
} else if (mouseIsPressed && sun <= 35) {
fill('#fee12b');
circle(starx, stary, 10);
console.log('stars');
}
background(50, 0.25);
//For loop that creates the smoke effect with an increasement
for (let i = 0; i < bugs.length; i++) {
bugs[i].show();
bugs[i].move();
if (bugs[i].radius > 100) {
bugs.splice(i, 1);
}
}
let x = 200;
let y = 300;
let rad = random(10, 50);
let b = new Bug(x, y, rad);
bugs.push(b);
}
//Particles for evaporation
class Bug {
constructor(tempX, tempY, tempRadius) {
this.x = tempX;
this.y = tempY;
this.radius = tempRadius;
this.color = color(random(80, 100), 0.05);
}
//Creates the sketch for it
show() {
noStroke();
fill(this.color);
ellipse(this.x, this.y, this.radius);
}
//Moves it up at a random pace
move() {
this.x = this.x + random(-5, 5);
this.y = this.y - random(2);
this.radius = this.radius + 0.4;
}
}
function condensation() {
//Changes background to grey to imitate storm,
background(50);
console.log("CONDENSATION");
//Colors the cloud and fills it with white
noStroke();
fill(255);
//States where cloud spawns
cloud(xpos, 50, 1);
cloud(xpos, 50, 2);
cloud(xpos, 80, 0.75);
xpos++;
//Has cloud with an increasement
if (xpos > 600) {
xpos = 0;
}
}
function presipitation() {
ellipseMode(RADIUS);
noFill();
background(211, 69, 93);
console.log("PRESIPITATION")
//If statement that create a for loop that spawns new particles(rain)
if (particles.length < 200) particles.push(new Particle());
for (var i = 0; i < particles.length; i++) {
particles[i].update();
particles[i].display();
}
}
var particles = [];
//Variable
//Rain drop / Particle
class Particle {
constructor() {
this.reset();
}
//Resets Particle after update
reset() {
this.x = random(width);
this.y = random(-150, 0);
this.vy = random(0.1, 2);
this.maxy = this.y + height;
this.r = 0;
this.tr = 50;
this.w = random(0.1, 2);
}
//If statement that creates the gravity for the particle
update() {
if (this.y < this.maxy) {
this.y += this.vy;
} else {
this.r++;
}
if (this.r > this.tr) this.reset();
}
//If statement(says it will remain the raindrop form or change into the puddle
display() {
strokeWeight(this.w);
if (this.y < this.maxy) {
stroke(255);
push();
translate(this.x, this.y);
beginShape();
strokeWeight(1);
vertex(0, -5);
quadraticVertex(3, 0, 0, 1);
quadraticVertex(-3, 0, 0, -5);
endShape(CLOSE);
pop();
} else {
stroke(255, map(this.r, 0, this.tr, 255, 0));
ellipse(this.x, this.y, this.r, this.r * .5);
}
}
}
//Changes Screen from evaporation, condensation, precipitation
function mousePressed() {
if (screen == 0) {
screen = 1;
} else if (screen == 1) {
screen = 2;
} else if (screen == 2) {
screen = 0;
}
}
//Makes cloud
function cloud(x, y, sc) {
push();
scale(sc);
ellipse(x, y, 50, 30);
ellipse(x, y + 20, 80, 30);
ellipse(x + 20, y, 40, 30);
ellipse(x + 30, y + 10, 70, 40);
pop();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>

Matter.js for collision detection

I'm relatively new to asking questions here, so please bear with me. I am trying to create a top down driving game with Matter.js as the primary physics engine. I would like the red car to collide with the green square. However, I am still stuck on knowing how to implement Matter.js onto my game. Any form of response will be greatly appreciated!
<html>
<canvas width=1000 height=500 style='border:1px solid black'>
</canvas>
<body onload='start()'>
<script src='matter.js'>
</script>
<script>
function start() {
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var x = 100;
var y = 100;
var s = 0;
var rot = 0;
var rightPressed = false;
var leftPressed = false;
var upPressed = false;
var downPressed = false;
document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) {
if (e.keyCode == 39) {
rightPressed = true;
} else if (e.keyCode == 37) {
leftPressed = true;
} else if (e.keyCode == 38) {
upPressed = true;
} else if (e.keyCode == 40) {
downPressed = true;
}
}
function keyUpHandler(e) {
if (e.keyCode == 39) {
rightPressed = false;
} else if (e.keyCode == 37) {
leftPressed = false;
} else if (e.keyCode == 38) {
upPressed = false;
} else if (e.keyCode == 40) {
downPressed = false;
}
}
function car() {
ctx.fillStyle = 'red';
ctx.fillRect(-20, -20, 40, 40);
ctx.beginPath();
ctx.moveTo(-20, -19);
ctx.lineTo(-20, -20);
ctx.lineTo(0, -30);
ctx.lineTo(20, -20);
ctx.lineTo(20, -19);
ctx.fill();
ctx.closePath();
ctx.fillStyle = 'black';
ctx.fillRect(-25, -20, 5, 10);
ctx.fillRect(-25, 10, 5, 10);
ctx.fillRect(20, -20, 5, 10);
ctx.fillRect(20, 10, 5, 10);
ctx.fillRect(-15, -5, 30, 20);
}
function block() {
ctx.fillStyle = 'green';
ctx.fillRect(200, 100, 50, 50);
}
function draw() {
requestAnimationFrame(draw);
ctx.clearRect(0, 0, 1000, 500);
if (s > 15) {
s = 15;
}
if (s < -15) {
s = -15;
}
if (upPressed) {
s++;
}
if (downPressed) {
s *= .9;
}
if (!upPressed) {
s *= .99;
}
if (leftPressed) {
rot -= s / 3;
}
if (rightPressed) {
rot += s / 3;
}
ctx.fillText(upPressed, 10, 10);
x += s * Math.cos(rot * Math.PI / 180);
y += s * Math.sin(rot * Math.PI / 180);
ctx.save();
ctx.translate(x, y);
ctx.rotate((rot + 90) * Math.PI / 180);
car();
ctx.restore();
block();
}
draw();
}
</script>
</body>
</html>
You would have to redo most of your code, but the movement code CAN be moved over fairly easily.
First you need to make a new engine and run it:
//Create engine - All the game stuff
var Engine = Matter.Engine,
Render = Matter.Render,
Runner = Matter.Runner,
Composites = Matter.Composites,
Common = Matter.Common,
World = Matter.World,
Bodies = Matter.Bodies,
Body = Matter.Body;
// create an engine
var engine = Engine.create(),
world = engine.world;
// create a renderer
var render = Render.create({
canvas: document.getElementById("canv"),
engine: engine,
options: {
width: 500,
height: 500,
wireframes: false,
background: '#6DDA4A'
}
});
engine.world.gravity.y = 0;
Render.run(render);
// create runner
var runner = Runner.create();
Runner.run(runner, engine);
Next, you should make and add a new car object and the block into the world. You can edit these values to whatever you need them to be.
Note: rot is not an actual parameter you need, I'm just using it to set the rotation of the car later.
var car = Bodies.rectangle(100, 100, 50, 80, {
friction: 1,
frictionAir: 0.1,
rot: 0,
restitution: 0,//Makes it so the car won't bounce off of objects
render: {
fillStyle: "#FF0000",
/*sprite: {
//You can use this to apply a background image to the car
texture: "Path/To/Image.png",
xScale: number,
yScale: number
}/**/
}
});
var block = Bodies.rectangle(350, 100, 100, 400, {
isStatic: true,//Makes block unmovable
friction: 1,
frictionAir: 0.1,
rot: 0,
restitution: 0,
render: {
fillStyle: "#0000FF",
/*sprite: {
texture: "Path/To/Image.png",
xScale: number,
yScale: number
}/**/
}
});
World.add(world, [car, block]);
For updating the car, you can either use body.setPosition or body.applyForce. Since it's a car, I would use body.applyForce so that the car keeps rolling after you've stopped pressing a button. Rotation can also be done with body.setAngle or body.rotate. This time, I'm going to use body.setAngle so the turning feels better.
function updateCar() {
//Declare variables for velocity
var speed = 5;
var carRot = car.rot*180/Math.PI;
var velY = speed * Math.cos(carRot * Math.PI / 180);
var velX = speed * Math.sin(carRot * Math.PI / 180)*-1;
var pushRot = 0;
//Update variables
if (upPressed==false&&downPressed==false) {
velY = 0;
velX = 0;
}
else {
//alert(carX+", "+carY);
}
if (downPressed == true) {
velY *= -1;
velX *= -1;
}
if (leftPressed) {
pushRot = -0.1;
}
if (rightPressed) {
pushRot = 0.1;
}
car.rot += pushRot;
//Set position of car
carX += velX;
carY += velY;
Body.applyForce(car, {x:carX,y:carY}, {x:velX/200,y:velY/200});
Body.setAngle(car, car.rot);
requestAnimationFrame(updateCar);
}
window.requestAnimationFrame(updateCar);
Check out a demo here

Remove an item that is drawn on to a canvas from an array. Where each item has a different purpose

I'm currently making a game and I am at the point where I'm trying to implement powerups. For the power ups I use a for loop that creates an object which allows me to give them different characteristics.
var type;
Powerups = [];
for(var j = 0; j < 325; j++) {
if (type="undefined"){
type = "scoreUp";
} else if(type="scoreUp"){
type = "horizonUp"
} else if (type="horizonUp"){
type = "newBall"
} else if (type="newBall") {
type = "scoreUp"
}
Powerups.push({
"x": randInt(20,360),
"y": 345 + (j * 240),
"width": 10,
"type": type
})
}
I then use rect circle collision that allows me to detect if the player collides with a powerup. If it does, the following line of code runs Powerups.splice(j, 1)
One thing that I've noticed is that the powerups never change and always increase score when a collision occurs. I think that this is because of the code that I use to remove the power up when colliding.
Is there a way where I could make it work as intended
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var isMenu = true;
var isPlaying = false;
var testing = true;
var gameOver = false;
var pause;
var pressingLeft = false;
var pressingRight = false;
var pressingP = false;
var Platforms = [];
var Powerups = [];
var difficulty = 1;
var playerGravity = 1;
var Player = { color: "red", radius: 7.5, stepY: 1.5, x: 175, y: 75 };
var Score = 0;
var speed = 1;
var type;
var moveR = 2;
var moveL = 2;
function PlayerColliding(circle, rect) {
var distX = Math.abs(circle.x - rect.x - rect.width / 2);
var distY = Math.abs(circle.y - rect.y - 20 / 2);
if (distX > (rect.width / 2 + circle.radius) && (distX) - 70 < (rect.width / 2 + circle.radius)) return false;
if (distY > (20 / 2 + circle.radius)) return false;
if (distX <= (rect.width / 2)) return true;
if (distY >= (20 / 2)) return true;
var dx = distX - rect.width / 2;
var dy = distY - 20 / 2;
return (dx * dx + dy * dy <= (circle.radius * circle.radius));
}
function PowerColliding(circle, rect) {
var distX = Math.abs(circle.x - rect.x - rect.width / 2);
var distY = Math.abs(circle.y - rect.y - 20 / 2);
if (distX > (rect.width / 2 + circle.radius)) return false;
if (distY > (20 / 2 + circle.radius)) return false;
if (distX <= (rect.width / 2)) return true;
if (distY >= (20 / 2)) return true;
var dx = distX - rect.width / 2;
var dy = distY - 20 / 2;
return (dx * dx + dy * dy <= (circle.radius * circle.radius));
}
function drawBackground(Player) {
ctx.fillStyle = "black"; ctx.fillRect(0, 0, canvas.width, canvas.height);
if (isMenu && !isPlaying) {
Score = 0;
createText("60px monospace", "white", "FallDown", 45, 130);
createText("34px Arial", "white", "PLAY", 130, 240);
createText("34px Arial", "white", "LEADERBOARD", 50, 300);
createText("34px Arial", "white", "SETTINGS", 90, 360);
createText("34px Arial", "white", "INFO", 130, 420);
}
if(isMenu && isPlaying) {
createText("60px monospace", "white", "Game Mode", 40, 130);
createText("34px Arial", "white", "CLASSIC", 110, 240);
createText("34px Arial", "white", "VERSUS", 113.5, 300);
}
else if(pause) {
isPlaying = false;
createText("60px monospace", "white", "PAUSED", 90, 130);
createText("34px Arial", "white", "RESUME", 115, 260);
createText("34px Arial", "white", "SETTINGS", 100, 340);
createText("34px Arial", "white", "QUIT", 145, 420);
}
else if(!isMenu && isPlaying) {
if (testing) {
Platforms = [];
for (var i = 0; i < 1300; i++) {
Platforms.push({
"x": 10,
"y": 300 + (i * 60),
"width": (Math.random() * canvas.width) - 60
});
}
testing = false;
Powerups = [];
for(var j = 0; j < 325; j++) {
if (type="undefined"){
type = "scoreUp";
} else if(type="scoreUp"){
type = "horizonUp"
} else if (type="horizonUp"){
type = "newBall"
} else if (type="newBall") {
type = "scoreUp"
}
Powerups.push({
"x": randInt(20,360),
"y": 345 + (j * 240),
"width": 10,
"type": type
})
}
}
if(Player.y<=0) {
restartGame()
}
var playerCollided;
for (var i in Platforms) {
ctx.fillStyle = "#00ffff";
ctx.fillRect(10, Platforms[i].y, Platforms[i].width, 20);
var totalTest = Platforms[i].width + 60;
ctx.fillRect(totalTest + 30, Platforms[i].y, canvas.width - totalTest, 20);
Platforms[i].y -= 1;
if (!playerCollided) {
if (PlayerColliding(Player, Platforms[i])) {
playerGravity = -1;
playerCollided = true;
} else {
playerGravity = 2.5;
}
}
}
var powerCollided;
for (var j in Powerups) {
ctx.fillStyle = "#ff00ff";
ctx.fillRect(Powerups[j].x, Powerups[j].y, Powerups[j].width, 10);
Powerups[j].y -= 1;
if (!powerCollided) {
if (PowerColliding(Player, Powerups[j])) {
powerCollided = true;
Powerups.splice(j, 1)
if(type="scoreUp") {
Score += 75
} else if (type="horizonUp") {
moveR+= 0.5;
moveL+=0.5;
console.log("hup")
}
}
}
}
displayScore();
detectBorderCollision();
detectPlayerCollision();
drawPlayer();
drawBorder();
}
if (Platforms.length === 7) Platforms = [];
}
function displayScore() {
ctx.beginPath();
Score +=1;
ctx.font = "15px arial black";
ctx.fillStyle = 'white';
ctx.strokeStyle = 'black';
ctx.fillText(Score, 180, 50);
ctx.lineWidth = 0.25;
ctx.strokeText(Score, 180, 50);
ctx.fill();
ctx.stroke();
ctx.closePath();
}
function detectBorderCollision() {
if (Player.x > 370 - Player.radius) {
Player.x = 370 - Player.radius;
} else if (Player.x < 3.8 + Player.radius * 2) {
Player.x = 3.8 + Player.radius * 2
}
}
function detectPlayerCollision() {
}
function randInt(min, max) {
return ~~(Math.random() * (max - min + 1) + min);
}
function drawPlayer() {
ctx.beginPath();
ctx.fillStyle = Player.color;
ctx.arc(Player.x, Player.y, Player.radius, 0, 2 * Math.PI);
ctx.fill();
ctx.closePath();
Player.y += playerGravity;
if (pressingRight) {
Player.x += 2;
} else if (pressingLeft) {
Player.x -= 2;
}
/*
ctx.fillStyle = "#00ffff"; ctx.fillRect(10, 160, 300, 20); */ }
function drawBorder() {
ctx.beginPath();
ctx.strokeStyle = "#00ffff";
ctx.lineWidth = 10;
ctx.moveTo(5, 0);
ctx.lineTo(5, 640);
ctx.moveTo(375, 0);
ctx.lineTo(375, 640);
ctx.stroke();
ctx.closePath();
}
function createText(font, color, value, posX, posY) {
ctx.font = font;
ctx.fillStyle = color;
ctx.fillText(value, posX, posY)
}
function isInside(realX, realY, x1, x2, y1, y2) {
return (realX > x1 && realX < x2) && (realY > y1 && realY < y2)
}
function drawGame() {
drawBackground(Player);
}
function startDrawing() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawGame();
requestAnimationFrame(startDrawing);
}
function restartGame() {
isPlaying = false;
isMenu = true;
pause = false;
Player.y= 75;
Player.x = 175
Platforms = [];
var Score = 1;
testing = true;
pressingLeft = false;
pressingRight = false;
var moveR = 2;
var moveL = 2;
}
function Init() {
requestAnimationFrame(startDrawing);
canvas.addEventListener("click", function(evt) {
var rect = canvas.getBoundingClientRect();
var mouseX = evt.clientX - rect.left;
var mouseY = evt.clientY - rect.top;
if (isMenu && !isPlaying) {
if (isInside(mouseX, mouseY, 115, 230, 220, 270)) {
isPlaying = true;
isMenu = false;
} else if (isInside(mouseX, mouseY, 35, 320, 300, 345)) {
console.log("Leaderboard");
} else if (isInside(mouseX, mouseY, 75, 270, 380, 430)) {
console.log("Settings");
}
} else if (pause) {
if(isInside(mouseX, mouseY, 110, 270, 230, 260)) {
pause = false;
isPlaying = true;
} else if (isInside(mouseX, mouseY, 95, 270, 310, 345)) {
console.log('settings')
} else if (isInside(mouseX, mouseY, 140, 230, 390, 425)) {
console.log('quit')
restartGame();
}
}
});
window.addEventListener("keydown", function(evt) {
if (!isMenu && isPlaying || pause) {
if (evt.keyCode === 39) { // right
pressingRight = true;
} else if (evt.keyCode === 37) { // left
pressingLeft = true;
} else if (evt.keyCode === 80) {
pressingP = true;
pause = !pause;
if(!pause) {
isPlaying = true;
}
}
}
});
window.addEventListener("keyup", function(evt) {
if (!isMenu && isPlaying) {
if (evt.keyCode === 39) { // right
pressingRight = false;
} else if (evt.keyCode === 37) { // left
pressingLeft = false;
}
}
});
}
Init();
<html>
<head>
<title>Falldown</title>
</head>
<body>
<canvas id="canvas" width = "380" height= "640"></canvas>
<script src="beta.js"></script>
</body>
</html>

2D platformer game, make player camera view in html5

I want to modify the platformer game that I find in codepen.
http://codepen.io/loktar00/pen/JEdqD
the original is like the below image.
I want to change it to be:
I want to zoom in the viewport to player and making a camera-like view where I could scroll a level within a canvas element.
Like this game http://www.html5quintus.com/quintus/examples/platformer_full/
The viewport and camera is tracking the player.
This is my code:
(function () {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 100,
height = 100,
player = {
x: width / 2,
y: height - 15,
width: 5,
height: 5,
speed: 3,
velX: 0,
velY: 0,
jumping: false,
grounded: false
},
keys = [],
friction = 0.8,
gravity = 0.3;
var boxes = [];
// player's position
var playerX = 20;
var playerY = 20;
// how far offset the canvas is
var offsetX = 0;
var offsetY = 0;
// dimensions
boxes.push({
x: 0,
y: 0,
width: 10,
height: height
});
boxes.push({
x: 0,
y: height - 2,
width: width,
height: 50
});
boxes.push({
x: width - 10,
y: 0,
width: 50,
height: height
});
boxes.push({
x: 120,
y: 10,
width: 80,
height: 80
});
boxes.push({
x: 170,
y: 50,
width: 80,
height: 80
});
boxes.push({
x: 220,
y: 100,
width: 80,
height: 80
});
boxes.push({
x: 270,
y: 150,
width: 40,
height: 40
});
canvas.width = width;
canvas.height = height;
function update() {
// check keys
if (keys[38] || keys[32] || keys[87]) {
// up arrow or space
if (!player.jumping && player.grounded) {
player.jumping = true;
player.grounded = false;
player.velY = -player.speed * 2;
}
}
if (keys[39] || keys[68]) {
// right arrow
if (player.velX < player.speed) {
player.velX++;
offsetX--;
}
}
if (keys[37] || keys[65]) {
// left arrow
if (player.velX > -player.speed) {
player.velX--;
offsetX++;
}
}
player.velX *= friction;
player.velY += gravity;
ctx.clearRect(0, 0, width, height);
ctx.fillStyle = "black";
ctx.beginPath();
player.grounded = false;
for (var i = 0; i < boxes.length; i++) {
ctx.rect(boxes[i].x, boxes[i].y, boxes[i].width, boxes[i].height);
var dir = colCheck(player, boxes[i]);
if (dir === "l" || dir === "r") {
player.velX = 0;
player.jumping = false;
} else if (dir === "b") {
player.grounded = true;
player.jumping = false;
} else if (dir === "t") {
player.velY *= -1;
}
}
if(player.grounded){
player.velY = 0;
}
player.x += player.velX;
player.y += player.velY;
ctx.save();
ctx.translate(offsetX, offsetY);
// clear the viewport
ctx.clearRect(-offsetX, -offsetY, 100,100);
ctx.fill();
ctx.fillStyle = "red";
ctx.fillRect(player.x, player.y, player.width, player.height);
ctx.fillRect(playerX-offsetX, playerY-offsetY, 8, 8);
// draw the other stuff
var l = boxes.length;
for (var i = 0; i < l; i++) {
// we should really only draw the things that intersect the viewport!
// but I am lazy so we are drawing everything here
var x = boxes[i][0];
var y = boxes[i][1];
ctx.fillStyle = 'lightblue';
ctx.fillRect(x, y, 8, 8);
ctx.fillStyle = 'black';
ctx.fillText(x + ', ' + y, x, y) // just to show where we are drawing these things
}
ctx.restore();
requestAnimationFrame(update);
}
function colCheck(shapeA, shapeB) {
// get the vectors to check against
var vX = (shapeA.x + (shapeA.width / 2)) - (shapeB.x + (shapeB.width / 2)),
vY = (shapeA.y + (shapeA.height / 2)) - (shapeB.y + (shapeB.height / 2)),
// add the half widths and half heights of the objects
hWidths = (shapeA.width / 2) + (shapeB.width / 2),
hHeights = (shapeA.height / 2) + (shapeB.height / 2),
colDir = null;
// if the x and y vector are less than the half width or half height, they we must be inside the object, causing a collision
if (Math.abs(vX) < hWidths && Math.abs(vY) < hHeights) {
// figures out on which side we are colliding (top, bottom, left, or right)
var oX = hWidths - Math.abs(vX),
oY = hHeights - Math.abs(vY);
if (oX >= oY) {
if (vY > 0) {
colDir = "t";
shapeA.y += oY;
} else {
colDir = "b";
shapeA.y -= oY;
}
} else {
if (vX > 0) {
colDir = "l";
shapeA.x += oX;
} else {
colDir = "r";
shapeA.x -= oX;
}
}
}
return colDir;
}
document.body.addEventListener("keydown", function (e) {
keys[e.keyCode] = true;
});
document.body.addEventListener("keyup", function (e) {
keys[e.keyCode] = false;
});
window.addEventListener("load", function () {
update();
});
<h3>A, D or Arrow keys to move, W or space to jump</h3>
<canvas id="canvas"></canvas>
But this does not work.
You can use the same code that you had in the codepen, but add a couple lines in the load event, before the first update().
Let's say something like:
window.addEventListener("load", function () {
ctx.scale(2,2);
ctx.translate(-100,-100);
update();
});
This will zoom by two times and center on new coordinates, BUT keep in mind that you have to do it yourself if you want to re-center when the player is going out of the view.
As a partial way of doing this, you can check if the player moved and translate the canvas using the opposite values of player.velX and player.velY. Something like:
var playerMoved = false;
if (keys[38] || keys[32] || keys[87]) {
playerMoved = true;
//...Other stuff
}
if (keys[39] || keys[68]) {
playerMoved = true;
//...Other stuff
}
if (keys[37] || keys[65]) {
playerMoved = true;
//...Other stuff
}
if (playerMoved) {
// You still need to check quite a few things, like
// the player being out of bounds, the view not translating
// when x less than or bigger then a specific value, and so on
ctx.translate(-player.velX, -player.velY);
}
This is not a complete solution because that would require quite some code, but it should get you started.

How to manage multiple ball animations?

I have made a program that is supposed to make several balls move along a path. So far, I have only been able to make one ball successfully traverse the course because whenever I add another ball (from the array of balls) it begins to flicker and spasmodically disappears. I would appreciate any assistance in solving this problem.
JS bin
<!DOCTYPE html>
<html>
<head>
<style>
* {
padding: 0;
margin: 0;
}
canvas {
background: #eee;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<canvas id="Circuit" width="500" height="320"></canvas>
<script>
var dad = [];
var canvas = document.getElementById("Circuit");
var ctx = canvas.getContext("2d");
var bool = false;
var dx1 = 2;
var dx2 = -2;
var dy1 = 0;
var dy2 = 2;
var memes = [{
x: 0,
y: 100,
}, {
x: 0,
y: 100,
}, {
x: 0,
y: 100,
}, {
x: 0,
y: 100,
}];
function drawCircle(index) {
ctx.beginPath();
ctx.arc(memes[index].x, memes[index].y, 10, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function draw(index) {
if (index == 0) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
if (memes[index].x < 490 && memes[index].y < 291 && !bool) {
drawCircle(index);
memes[index].x += dx1;
memes[index].y += dy1;
}
else if (memes[index].x == 490) {
drawCircle(index);
memes[index].x += 1;
}
else if (memes[index].x > 490 && memes[index].y < 291) {
drawCircle(index);
memes[index].y += dy2;
}
else if (memes[index].y == 291) {
drawCircle(index);
memes[index].y += 1;
}
else if (memes[index].y > 291 && memes[index].x > 2) {
drawCircle(index);
bool = true;
memes[index].x -= 2;
}
else if (memes[index].x == 2 && memes[index].y > 291) {
drawCircle(index);
memes[index].x -= 1;
}
else if (memes[index].x < 2) {
drawCircle(index);
memes[index].y -= dy2;
if (memes[index].y < 100) {
clearInterval(dad[index]);
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
}
ctx.strokeStyle = "red";
ctx.strokeRect(2, 101, 490, 190);
ctx.strokeStyle = "blue";
ctx.strokeRect(2, 82, 40, 40);
}
setTimeout(function() {
setTimeout(function() {
dad[1] = setInterval(function() {
draw(1);
}, 20);
}, 1000);
dad[0] = setInterval(function() {
draw(0);
}, 20);
}, 1000);
</script>
</body>
</html>
The flicker happens when the second ball tries to render the frame. You have two sprites (animating things) clearing and drawing the frame. You also have multiple timers and when animating you usually want a nextFrame function that handles movement of the sprites and drawing the frame.
The sprites array is a list of things that need to be moved and drawn. I added some properties to the meme sprites so you can see that their state needs to be internal like with the "bool" value. Without that you end up effecting the other balls. You'll need to figure out how to remove sprites when they're no longer in play.
var dad = [];
var canvas = document.getElementById("Circuit");
var ctx = canvas.getContext("2d");
var bool = false;
var dx1 = 2;
var dx2 = -2;
var dy1 = 0;
var dy2 = 2;
var memes = [{
x: 0,
y: 100,
color: "#0095DD",
draw: drawMeme,
move: moveMeme,
vx: 1.2,
vy: 1.5,
}, {
x: 0,
y: 100,
vx: 1.5,
vy: 1,
color: "#DD9500",
draw: drawMeme,
move: moveMeme
}, {
x: 0,
y: 100,
vx: 2,
vy: 1,
color: "#FF0000",
draw: drawMeme,
move: moveMeme
}, {
x: 0,
y: 100,
vx: 3,
vy: 2,
color: "#009999",
draw: drawMeme,
move: moveMeme
}];
function drawMeme(meme) {
ctx.beginPath();
ctx.arc(meme.x, meme.y, 10, 0, Math.PI * 2);
ctx.fillStyle = meme.color;
ctx.fill();
ctx.closePath();
}
var sprites = [];
function nextFrame () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
var len = sprites.length;
for (var i = 0; i < len; i++) {
var sprite = sprites[i];
sprite.move(sprite);
sprite.draw(sprite);
}
ctx.strokeStyle = "red";
ctx.strokeRect(2, 101, 490, 190);
ctx.strokeStyle = "blue";
ctx.strokeRect(2, 82, 40, 40);
requestAnimationFrame(nextFrame);
}
function moveMeme(meme) {
if (meme.x < 490 && meme.y < 291 && !meme.bool) {
meme.x += dx1 * meme.vx;
meme.y += dy1 * meme.vy;
}
else if (meme.x == 490) {
meme.x += 1 * meme.vx;
}
else if (meme.x > 490 && meme.y < 291) {
meme.y += dy2 * meme.vy;
}
else if (meme.y == 291) {
meme.y += 1 * meme.vy;
}
else if (meme.y > 291 && meme.x > 2) {
meme.bool = true;
meme.x -= 2 * meme.vx;
}
else if (meme.x == 2 && meme.y > 291) {
meme.x -= 1 * meme.vx;
}
else if (meme.x < 2) {
meme.y -= dy2 * meme.vy;
if (meme.y < 100) {
// stop drawing this sprite
meme.draw = function(){};
meme.delete = 1; // for a cleanup function
}
}
}
nextFrame();
function startMeme(index) {
var meme = memes[index];
sprites.push(meme);
}
setTimeout(function() {
setTimeout(function() {
startMeme(1);
}, 1000);
startMeme(0);
startMeme(2);
startMeme(3);
}, 1000);
<canvas id="Circuit" width="500" height="320"></canvas>

Categories