I was putting in practice the HTML Game for the first time.
I managed to get through with my game just having the https://www.w3schools.com/graphics/game_intro.asp as my only guide.
The game is very simple: Random objects (green squares) fall from above. The player (red square) moves right and left. The main goal here in the game is for the player to collect/collide with as many as falling objects. Every time the collision happens with 1 object, the player earns 1 point.
Now, how can i destroy the object(green square) that collides with the player and set 1 point at a time?
Here is the code:
<!DOCTYPE html>
<html>
<head>
<title>Food Game v1</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<style>
canvas {
border:1px solid #d3d3d3;
background-image: linear-gradient(#FFFDF0, white);
}
/* buttons align in center*/
.center {
margin: auto;
width: 90%;
padding: 10px;
}
</style>
</head>
<body onload="startGame()">
<script>
var myGamePiece;
var myFallenObj_ = []; //array of fallen objects
var myScore;
function startGame() {
myGamePiece = new component(30, 30, "red", 130, 300);
myScore = new component("10px", "Consolas", "black", 100, 345,"text");
myGameArea.start();
}
var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 300;
this.canvas.height = 350;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0; //if we use an array
this.interval = setInterval(updateGameArea, 20);
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop: function(){
clearInterval(this.interval);
}
}
function component(width, height, color, x, y, type) {
this.type = type;
this.width = width;
this.height = height;
this.score = 0;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
if(this.type == "text"){ //check on text object
ctx.font = this.width + " " + this.height;
ctx.fillStyle = color;
ctx.fillText(this.text, this.x, this.y);
}else {
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
this.crashWith = function(otherobj){
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if((myright < otherleft) || (myleft > otherright) || (mybottom < othertop) || (mytop > otherbottom)) {
crash = false;
}
return crash;
}
}
function updateGameArea() {
myGameArea.clear();
myGamePiece.newPos();
myGamePiece.update();
var width_, minWidth_, maxWidth_;
var x,y;
for (i=0;i<myFallenObj_.length; i++){
if(myGamePiece.crashWith(myFallenObj_[i])){ //if collision happens
myScore.score ++;
//destroy(myFallenObj_[i]);
}
}
myScore.text = "SCORE: " + myScore.score;
//check myGamePiece not go over the left border
if(myGamePiece.x <= 0)
myGamePiece.x = 1;
//check myGamePiece not go over the right border
if(myGamePiece.x > 265)
myGamePiece.x = 260;
myScore.update();
myGameArea.frameNo +=1;
if (myGameArea.frameNo == 1 || everyinterval(150)){
//x = 10;
minWidth_=0;
maxWidth_=300;
width_ = Math.floor(Math.random()*(maxWidth_-minWidth_+1)+minWidth_);
y = - 50;
myFallenObj_.push(new component (30,30,"green", width_, y));
}
for (i=0; i<myFallenObj_.length; i++){
myFallenObj_[i].x +=0;
myFallenObj_[i].y +=1;
myFallenObj_[i].update();
}
}
function everyinterval(n){
if((myGameArea.frameNo /n) % 1 == 0)
return true;
return false;
}
function moveleft() {
myGamePiece.speedX = - 2;
}
function moveright() {
myGamePiece.speedX = 2;
}
function clearmove() {
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
}
</script>
<div class="center">
<button onmousedown="moveleft()" onmouseup="clearmove()" ontouchstart="moveleft()">LEFT</button>
<button onmousedown="moveright()" onmouseup="clearmove()" ontouchstart="moveright()">RIGHT</button><br><br>
</div>
</body>
</html>
What i've done so far is to apply that collision and count the score, but the score counts for as long as the red and green keep touching themselves repeatedly (which is wrong).
Any suggestions are more than welcome, thx!
Add scorable attribute to your component:
function component(...) {
...
this.scorable = true;
...
}
Then use the attribute to flag if it still scorable, if not skip:
for (i=0;i<myFallenObj_.length; i++){
if(myGamePiece.crashWith(myFallenObj_[i]) && myFallenObj_[i].scorable){ //if collision happens
myScore.score ++;
myFallenObj_[i].scorable = false;
//destroy(myFallenObj_[i]);
}
}
Thanks to #ACD i solved half of my problem concerning the points' count.
The other half of my answer was how to handle my (green) component: get the point when the green component crashes on to the red one and then disappears.
Well, i couldn't handle properly the destroy attribute of my object (in this case my component). Too much JS with Unity, i suppose :p . I don't know if there is such an attribute for the HTML Canvas' philosophy. To "apply" in a way the destroy attribute to my problem here (as to make my green component to disappear from the canvas) i had to create an "illusion" that came to my mind at first. Basically, playing with the component's positioning around the canvas.
Mainly, i had to set a variable var garbagePOS = 2000; //any possible measure out of my canvas size.
And then i set the position x of my crashed green component into its new positioning equals 2000 (visually, out of my content) myFallenObj_[i].x = garbagePOS; And just like that it creates the illusion. Probably, not an ideal solution. However it works fine for me at the moment. Any more suggestions for the above?
Related
I am very new to coding. I am trying to make a game using java in notepad++. I cant seem to get it so that when the red square (player) hits the purple (TopEdge) the red square will not stop completely but also wont travel through the purple. Like a wall. Right now when the red square hits the purple, you cant move it anymore. I have tried almost everything i could find on the internet. Here is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta charset="utf-8">
<style>
canvas {
border:4px solid #000000;
background-color: #1FB026;
}
</style>
</head>
<body onload="startGame()">
<script>
var player;
var TopEdge;
function startGame() {
player = new component(30, 30, "red", 10, 120);
TopEdge = new component(10000, 300, "purple", 0, -200);
myGameArea.start();
}
var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 1150;
this.canvas.height = 500;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas,
document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 10);
window.addEventListener('keydown', function (e) {
myGameArea.keys = (myGameArea.keys || []);
myGameArea.keys[e.keyCode] = (e.type == "keydown");
})
window.addEventListener('keyup', function (e) {
myGameArea.keys[e.keyCode] = (e.type == "keydown");
})
},
clear : function(){
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop : function(){
clearInterval(this.interval);
}
}
function component(width, height, color, x, y) {
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.newPos = function() {
this.X += this.speedX;
this.Y += this.speedY;
let playerX = this.X + this.speedX;
let playerY = this.Y + this.speedY;
if (playerX >= 0 && this.width + playerX <= this.gamearea.canvas.width)
{
this.X = playerX;
}
if (playerY >= 0 && this.height + playerY <= this.gamearea.canvas.height)
{
this.Y = playerY;
}
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) ||
(mytop > otherbottom) ||
(myright < otherleft) ||
(myleft > otherright)) {
crash = false;
}
return crash;
}
}
function stopY() {
player.speedY = 0;
}
function updateGameArea() {
if (player.crashWith(TopEdge)) {
} else {
myGameArea.clear();
TopEdge.update();
player.x += player.speedX;
player.y += player.speedY;
player.update();
}
TopEdge.update();
player.speedX = 0;
player.speedY = 0;
if (myGameArea.keys && myGameArea.keys[65]) {player.speedX = -2.5; }
if (myGameArea.keys && myGameArea.keys[68]) {player.speedX = 2.5; }
if (myGameArea.keys && myGameArea.keys[87]) {player.speedY = -2.5; }
if (myGameArea.keys && myGameArea.keys[83]) {player.speedY = 2.5; }
player.newPos();
player.update();
}
</script>
</body>
</html>
The problem starts with your updateGameArea() function.
If your the player crashes with the TopEdge then you do nothing. Your creating a problem with your else-part over there. It will never reach the else like this, so nothing while change, so next time it still won't move and again it will not reach the else.....
How about removing the else part. Just check for everything all the time, but don't allow it to move up when it reached the TopEdge.
This should help.
function updateGameArea() {
// I'd prefer these calls at the end of the function block
// but right now your program would start kinda buggy then
myGameArea.clear();
player.newPos();
player.update();
TopEdge.update();
// In default state (nothing pressed) player shouldn't move up or down
player.speedX = 0;
player.speedY = 0;
// If the player does press a key set correct speed/direction
if (myGameArea.keys[65]) {player.speedX = -2.5; }
if (myGameArea.keys[68]) {player.speedX = 2.5; }
if (myGameArea.keys[87]) {player.speedY = -2.5; }
if (myGameArea.keys[83]) {player.speedY = 2.5; }
// Check if player reached the top
// If it did, then it shouldn't be able to climb any higher.
// So even if the player presses the up-button,
// the vertical speed should still not be aloud to change.
if (player.crashWith(TopEdge) && myGameArea.keys[87]) {
player.speedY = 0;
}
// Move the position of the player
player.x += player.speedX; //
player.y += player.speedY;
}
I've making a breakout game and I had to make some blocks and give them random colors defined in a array, but for making more blocks I had to use a for loop. So, when I add them to my update function, colors are flashing at frame rate. I think you'll understand better if you run the snippet
one more thing: that canvasRendering...rundedRectangle is a function that draws rounded edge rectangles someone please find a solution!
CanvasRenderingContext2D.prototype.roundedRectangle = function(x, y, width, height, rounded) {
const radiansInCircle = 2 * Math.PI;
const halfRadians = (2 * Math.PI)/2;
const quarterRadians = (2 * Math.PI)/4 ;
// top left arc
this.arc(rounded + x, rounded + y, rounded, -quarterRadians, halfRadians, true);
// line from top left to bottom left
this.lineTo(x, y + height - rounded);
// bottom left arc
this.arc(rounded + x, height - rounded + y, rounded, halfRadians, quarterRadians, true) ;
// line from bottom left to bottom right
this.lineTo(x + width - rounded, y + height);
// bottom right arc
this.arc(x + width - rounded, y + height - rounded, rounded, quarterRadians, 0, true) ;
// line from bottom right to top right
this.lineTo(x + width, y + rounded) ;
// top right arc
this.arc(x + width - rounded, y + rounded, rounded, 0, -quarterRadians, true) ;
// line from top right to top left
this.lineTo(x + rounded, y) ;
};
var canvas= document.getElementById("gameCanvas");
var ctx = canvas.getContext("2d");
function Player(x,y,w,h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.show = function(){
ctx.beginPath();
ctx.rect(this.x, this.y, this.w, this.h);
ctx.fillStyle = "#ffff";
ctx.fill();
ctx.closePath();
};
this.move = function(speed){
this.x += speed;
};
}
function Ball(x,y,r){
this.x = x;
this.y = y;
this.r = r;
this.show = function(){
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0,2* Math.PI);
ctx.fillStyle = "tomato";
ctx.fill();
ctx.closePath();
};
this.move= function(speedX,speedY){
this.show();
this.speed = 2;
this.x += speedX;
this.y += speedY;
};
}
var colors = ['#A5E75A','#7254AD','#FFD606','#FF093D'];
function Block(x,y,w,h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.status =1;
this.show= function(color){
ctx.beginPath();
ctx.roundedRectangle(this.x,this.y,this.w,this.h,5);
//ctx.arc(this.x,this.y,10,0,2*Math.PI);
//ctx.fillStyle = colors[Math.floor(Math.random()*colors.length)];
ctx.fillStyle = color;
ctx.fill();
ctx.closePath();
};
}
var player = new Player(canvas.width/2-50,780,100,20);
var ball = new Ball(player.x+player.w/2, player.y,15);
var rigthPressed = false;
var leftPressed = false;
var blocks = [];
var rowCount = 5;
var columnCount = 6;
var noInRow = 6;
var blockCount = (rowCount*columnCount)+1;
var rc = {blockRow : 0,
blockCol : 0};
for(let i = 0; i < blockCount; i++){
blocks.push(new Block(rc.blockCol*60+25,rc.blockRow*60-30,50,50));
rc.blockCol++;
if(i % noInRow === 0){
rc.blockRow++;
rc.blockCol = 0;
}
}
window.addEventListener("keydown", function(e){
if(e.keyCode == 39){
rigthPressed = true;
}
if(e.keyCode == 37){
leftPressed = true;
}
});
window.addEventListener("keyup", function(e){
if(e.keyCode == 39){
rigthPressed = false;
}
if(e.keyCode == 37){
leftPressed = false;
}
});
function objMovement(){
if(rigthPressed){
player.move(5);
if (player.x > canvas.width-player.w){
player.x = canvas.width-player.w;
}
}
if(leftPressed){
player.move(-5);
if(player.x < 0){
player.x = 0;
}
}
if(ball.x > canvas.width-ball.r || ball.x < 0+ball.r){
ballSpeedX = -ballSpeedX;
}
if (/*ball.y > canvas.height-ball.r ||*/ball.y < 0+ball.r){
ballSpeedY = -ballSpeedY;
}
if(ball.x<player.x+player.w &&ball.x>player.x && ball.y>player.y && ball.y<player.y+player.h){
ballSpeedY = -ballSpeedY;
ballSpeedX= ballSpeedX;
}
function Bump(){
if (ball.x>player.x && ball.x<player.x+player.w/2){
if (ball.y >= player.y){
ballSpeedX = -5;
}
}
if(ball.x>player.x+player.w/2 && ball.x<player.x+player.w){
if(ball.y >= player.y){
ballSpeedX = 5;
}
}
}
//Bump();
}
function reload(){
if (ball.y>canvas.height){
//alert('gameOver');
ball.x =player.x+player.w/2;
ball.y = player.y-ball.r;
ballSpeedX = 0;
ballSpeedY = 0;
}
}
var ballSpeedX = 0;
var ballSpeedY = -0;
function collision(){
for(let i=1;i<blockCount;i++){
if(ball.x>blocks[i].x &&
ball.x<blocks[i].x+blocks[i].w &&
ball.y>blocks[i].y &&
ball.y<blocks[i].y+blocks[i].h){
blocks[i].status = 0;
ballSpeedY = -ballSpeedY;
blocks.splice(i,1);
blockCount--;
//ballSpeedX = 0;
//ballSpeedY = 0;
console.log('hit');
}
}
}
function update(){
ctx.clearRect(0,0,canvas.width,canvas.height);
objMovement();
for(let i=1;i<blockCount;i++){
if(blocks[i].status == 1){
blocks[i].show(colors[Math.floor(Math.random()*colors.length)]);
}
}
collision();
ball.show();
ball.move(ballSpeedX,ballSpeedY);
player.show();
reload();
window.requestAnimationFrame(update);
}
update();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>🌝🌝</title>
<style>
#body{
background-color: rgb(31, 30, 30);
}
#gameCanvas{
border: 15px solid rgb(44, 44, 44);
border-radius: 20px;
background-color:rgb(19, 18, 18);
margin: 250px;
}
</style>
</head>
<body id="body">
<canvas id="gameCanvas" width=400 height=800></canvas>
<script type="text/javascript" src="./index.js"></script>
</body>
</html>
Because you remove and redraw all rectangles from the canvas each update and assign a new color on show, they get assigned a new color each update. You might be able to avert this by adding a property color to the rectangle, which is initialised (once, so in the initial for loop) with a random color, and alter the show function to use this.color rather than accept a color as an argument. This way, you don't assign a new color to a rectangle each update, and it won't change color each update.
I am trying to make a game in HTML with Java at the same time, and I do not know exactly how to color/paint the <canvas> element. Here is what I have so far with my game:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<style>
canvas {
border:1px solid #d3d3d3;
background-color: #f1f1f1;
}
</style>
</head>
<body onload="startGame()">
<script>
var myGamePiece;
var myObstacles = [];
var myScore;
function startGame() {
myGamePiece = new component(30, 30, "red", 10, 120);
myGamePiece.gravity = 0.05;
myScore = new component("30px", "Consolas", "black", 280, 40, "text");
myGameArea.start();
}
var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
this.canvas.width = 480;
this.canvas.height = 270;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.frameNo = 0;
this.interval = setInterval(updateGameArea, 20);
},
clear : function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function component(width, height, color, x, y, type) {
this.type = type;
this.score = 0;
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.gravity = 0;
this.gravitySpeed = 0;
this.update = function() {
ctx = myGameArea.context;
if (this.type == "text") {
ctx.font = this.width + " " + this.height;
ctx.fillStyle = color;
ctx.fillText(this.text, this.x, this.y);
} else {
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
}
this.newPos = function() {
this.gravitySpeed += this.gravity;
this.x += this.speedX;
this.y += this.speedY + this.gravitySpeed;
this.hitBottom();
}
this.hitBottom = function() {
var rockbottom = myGameArea.canvas.height - this.height;
if (this.y > rockbottom) {
this.y = rockbottom;
this.gravitySpeed = 0;
}
}
this.crashWith = function(otherobj) {
var myleft = this.x;
var myright = this.x + (this.width);
var mytop = this.y;
var mybottom = this.y + (this.height);
var otherleft = otherobj.x;
var otherright = otherobj.x + (otherobj.width);
var othertop = otherobj.y;
var otherbottom = otherobj.y + (otherobj.height);
var crash = true;
if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {
crash = false;
}
return crash;
}
}
function updateGameArea() {
var x, height, gap, minHeight, maxHeight, minGap, maxGap;
for (i = 0; i < myObstacles.length; i += 1) {
if (myGamePiece.crashWith(myObstacles[i])) {
return;
}
}
myGameArea.clear();
myGameArea.frameNo += 1;
if (myGameArea.frameNo == 1 || everyinterval(150)) {
x = myGameArea.canvas.width;
minHeight = 20;
maxHeight = 200;
height = Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight);
minGap = 50;
maxGap = 200;
gap = Math.floor(Math.random()*(maxGap-minGap+1)+minGap);
myObstacles.push(new component(10, height, "green", x, 0));
myObstacles.push(new component(10, x - height - gap, "green", x, height + gap));
}
for (i = 0; i < myObstacles.length; i += 1) {
myObstacles[i].x += -1;
myObstacles[i].update();
}
myScore.text="SCORE: " + myGameArea.frameNo;
myScore.update();
myGamePiece.newPos();
myGamePiece.update();
}
function everyinterval(n) {
if ((myGameArea.frameNo / n) % 1 == 0) {return true;}
return false;
}
function accelerate(n) {
myGamePiece.gravity = n;
}
</script>
<br>
<button onmousedown="accelerate(-0.2)" onmouseup="accelerate(0.05)">ACCELERATE</button>
<p>Use the ACCELERATE button to stay in the air</p>
<p>How long can you stay alive?</p>
</body>
Why I want to color the canvas
The reason WHY i want to color the canvas is because I want to add a background, because this WILL be a public unofficial game. You can clearly see that the popular game: "Doodle Jump" (No clickbait) has a decent background color.
I want to be creative with my game, not lazy.
All in all, is <canvas> the best element? If so, how can I change the color of the background with CSS?
I made a fiddle with your code. In the fiddle I changed the background-color to yellow and it works.
You can also make the background of the canvas a different color by drawing a colored rectangle onto the canvas which has the same width and height as the canvas element. Just make sure to draw this rectangle before you draw anything else. Here's an example of what I mean:
// specify color
this.context.fillStyle = "red";
// draw a rectangle with the same width and height as canvas
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
My game components won't draw onto the canvas after adding if/else statement.
The statement only checks if the game piece hit the game obstacle.
I tried changing attributes and rewrite some functions but it seems the problem hasn't been fixed.
Whenever I remove the if/else function, the components draw.
Here is part of the code that holds that if/else function:
if(gamePieceBorder.crashGame(gameObstacle) || gamePieceRed.crashGame(gameObstacle))
{
gameArea.stop();
}
else
{
obstacle.update();
gamePieceBorder.pos();
gamePieceBorder.move();
gamePieceBorder.update();
gamePieceRed.pos();
gamePieceRed.move();
gamePieceRed.update();
gameArea.clear();
}
For me not pasting an entire code, here is the pastebin link to the code: https://pastebin.com/HuiR7r7D
How can I get the components to draw? If someone fixes the code, what was the issue? I am not an expert at javascript but only a beginner.
There are several problems:
window.EventListener should be window.addEventListener
keyup and keydown should have no upper case letters
gameObstacle in that if is undefined (should be obstacle probably)
clear method should be called before drawing, not after it
Here is the corrected script: https://pastebin.com/bXpQ2qvB
//-----------------------------------------Variables
var gamePieceRed;
var gamePieceBorder;
var gameObstacle;
//-----------------------------------------
//-----------------------------------------Main game function
function startGame()
{
gamePieceRed = new component(22, 22, "rgb(255, 132, 156)", 10, 120);
gamePieceBorder = new component(24, 24, "black", 9, 119);
obstacle = new component(10, 200, "rgb(64, 0 ,12)", 300, 120)
gameArea.start();
}
//-----------------------------------------
//-----------------------------------------Creating game area and applying controls
var gameArea =
{
canvas : document.createElement("canvas"), start : function()
{
this.canvas.width = 510;
this.canvas.height = 280;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.interval = setInterval(gameUpdate, 20);
window.addEventListener("keydown", function (e)
{
gameArea.keys = (gameArea.keys || []);
gameArea.keys[e.keyCode] = true;
}, true)
window.addEventListener("keyup", function (e)
{
gameArea.keys[e.keyCode] = false;
}, true)
},
clear : function()
{
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
stop : function()
{
clearInterval(this.interval);
},
keyboard: function() {
if (this.keys) {
if (this.keys[37]) {gamePieceBorder.speedX = gamePieceRed.speedX = -2;}
else if (this.keys[39]) {gamePieceBorder.speedX = gamePieceRed.speedX = 2;}
else {gamePieceBorder.speedX = gamePieceRed.speedX = 0;}
if (this.keys[38]) {gamePieceBorder.speedY = gamePieceRed.speedY = -2;}
else if (this.keys[40]) {gamePieceBorder.speedY = gamePieceRed.speedY = 2;}
else {gamePieceBorder.speedY = gamePieceRed.speedY = 0;}
}
}
}
//-----------------------------------------
//-----------------------------------------Game component
function component(width, height, color, x, y)
{
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.speedX = 0;
this.speedY = 0;
this.update = function()
{
ctx = gameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height)
}
this.move = function()
{
this.x += this.speedX;
this.y += this.speedY;
}
this.crashGame = function(obj)
{
var left = this.x;
var right = this.x + (this.width);
var top = this.y;
var bottom = this.y + (this.height);
var otherLeft = obj.x;
var otherRight = obj.x + (obj.width);
var otherTop = obj.y;
var otherBottom = obj.y + (obj.height);
var crash = true;
if (bottom < otherTop || top > otherBottom || right < otherLeft || left > otherRight)
{
crash = false;
}
return crash;
}
}
//-----------------------------------------
//-----------------------------------------Game area updater
function gameUpdate()
{
if(gamePieceBorder.crashGame(obstacle) || gamePieceRed.crashGame(obstacle))
{
gameArea.stop();
}
else
{
gameArea.clear();
obstacle.update();
gameArea.keyboard();
gamePieceBorder.move();
gamePieceBorder.update();
gamePieceRed.move();
gamePieceRed.update();
}
}
//-----------------------------------------
<html>
<style>
canvas
{
border: 1px solid #d3d3d3;
background-image: url("https://ak0.picdn.net/shutterstock/videos/22492090/thumb/1.jpg");
}
</style>
<body onload = "startGame()">
</body>
</html>
So im trying to learn about canvas and canvas games and im currently (more or less) following the W3Schools tutorial on canvas games.
At some point in the tutorial i had the idea to make 2 players, which should both be controled on the same keyboard (NOT online multiplayer).
So i followed the logic given by the tutorial and found the key codes for both WASD and the arrows.
I understand 95% of my code, which means i did not just copy everything without understanding it. (I will comeback to this soon)
The problem with my code is that when i add another player to the system i can move them freely when i only control one player at a time, when i try to move both players at the same time, they cannot be moved freely and i can only press a total of 4 buttons at a time.
Tryout the snippet and play around with the cubes with WASD and the arrows to see what im talking about.
As i said there is a part i do not understand 100% which might be the place for this error? I marked it out anyway on the code snippet.
So all in all my question is: Why can i not move both players freely at the same time?
The whole code is as following and i marked the part i do not understand:
For best experience, use the full screen function
{
function startGame() {
myGameArea.start();
myStick = new component(100, 100, 200, 200, "red");
myStick2 = new component(100, 100, 600, 200, "green");
}
var myGameArea = {
canvas : document.createElement("canvas"),
start : function() {
var bodyID = document.getElementById("body");
this.canvas.width = bodyID.offsetWidth;
this.canvas.height = (bodyID.offsetHeight);
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[2]);
this.interval = setInterval(updateGameArea, (1000 / 60));
//The part i do not understand
window.addEventListener('keydown', function (e) {
myGameArea.keys = (myGameArea.keys || []);
myGameArea.keys[e.keyCode] = true;
});
window.addEventListener('keyup', function (e) {
myGameArea.keys[e.keyCode] = false;
});
//End
},
clear : function(){
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
};
function component(width, height, x, y, color, mLeft, mRight, mUpLeft, mUpRigth){
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.speedX = 0;
this.speedY = 0;
this.update = function(){
ctx = myGameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
};
this.newPos = function(){
this.x += this.speedX;
this.y += this.speedY;
};
this.player1 = function(){
this.speedX = 0;
this.speedY = 0;
if (myGameArea.keys && myGameArea.keys[65]) {this.speedX = -2; } // Left
if (myGameArea.keys && myGameArea.keys[68]) {this.speedX = 2; } // Right
if (myGameArea.keys && myGameArea.keys[87]) {this.speedY = -2; } // Up
if (myGameArea.keys && myGameArea.keys[83]) {this.speedY = 2; } // Down
};
this.player2 = function(){
this.speedX = 0;
this.speedY = 0;
if (myGameArea.keys && myGameArea.keys[37]) {this.speedX = -2; } // Left
if (myGameArea.keys && myGameArea.keys[39]) {this.speedX = 2; } // Right
if (myGameArea.keys && myGameArea.keys[38]) {this.speedY = -2; } // Up
if (myGameArea.keys && myGameArea.keys[40]) {this.speedY = 2; } // Down
};
}
function updateGameArea(){
myGameArea.clear();
myStick.player1();
myStick.newPos();
myStick2.player2();
myStick2.newPos();
myStick.update();
myStick2.update();
}
}
.nm{
margin: 0;
padding: 0;
}
canvas{
display: block;
background-color: lightgray;
}
<html>
<head>
<meta charset="UTF-8">
<title>Canvas stick game!</title>
<link rel="stylesheet" href="css/standard.css">
</head>
<body id="body" onload="startGame()" class="nm" style="height: 100vh">
</body>
</html>
<script src="js/canvas.js"></script>
I know this is redundant (anyone who reads the comments below your question will figure this out), but just so it's here as an answer, your problem is a keyboard bug.
Because of the way (some) non-digital keyboards work, certain keyboard combinations do not work properly. (ie. Certain keys will cancel each other out.)
(This is just another reason to supply customizable game controls, customizable program shortcuts, etc. Another reason is the fact that people with DVORAK keyboards are likely to find your QWERTY optimized game controls to be cumbersome.)
Other:
PS: I cannot reproduce your problem, and if you tried it on another computer, it is likely that you could not reproduce it either.
PPS: For more information check out the following article: Keyboards are evil.
Not sure what the bug was, looked ok as it was but as there were several issues. Saddly W3Schools is not what I would consider a uptodate, but I can offer no alternative.
I made changes to improve the whole thing but you will still lose keys, I am not sure why as the standard says nothing about loss of keys (It says all keys MUST be reported)
When hitting 4 or more keys at the same time (within 1/60th second) none of them are reported. This is highly unlikely when two people are playing, but when one person is testing both direction pads it happens often. I am unaware of a solution.
The key event keyCode has depreciated and you should be using event.key which is a string but event.key is only partially supported.
{
// key maps
const KEY_UP = 38;
const KEY_DOWN = 40;
const KEY_LEFT = 37;
const KEY_RIGHT = 39;
const KEY_W = 87;
const KEY_S = 83;
const KEY_A = 65;
const KEY_D = 68;
const DIR_KEY_MAP2 = [KEY_W, KEY_S, KEY_A, KEY_D];
const DIR_KEY_MAP1 = [KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT];
const BLOCK_DEFAULT_FOR = [KEY_W, KEY_S, KEY_A, KEY_D, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT];
const keyEvents = function(event){ // keyboard event listener sets the key array to true if keydown false if not
if(!event.repeat){ // ignore repeating key events
myGameArea.keys[event.keyCode] = event.type === "keydown";
}
// block default action for keys in array BLOCK_DEFAULT_FOR
if(BLOCK_DEFAULT_FOR.indexOf(event.keyCode) > -1){
event.preventDefault();
}
}
function startGame() {
myGameArea.start();
myStick = new Component(100, 100, 200, 200, "red", DIR_KEY_MAP2);
myStick2 = new Component(100, 100, 600, 200, "green", DIR_KEY_MAP1);
}
var myGameArea = {
canvas : document.createElement("canvas"),
keys : [], // create the key array
start : function() {
var bodyID = document.getElementById("body");
this.canvas.width = bodyID.offsetWidth;
this.canvas.height = (bodyID.offsetHeight);
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[2]);
requestAnimationFrame(updateGameArea); // request the first animation frame don't use setInterval
window.addEventListener('resize', function () { // for stackoverflow
myGameArea.canvas.width = bodyID.offsetWidth;
myGameArea.canvas.height = bodyID.offsetHeight;
});
window.addEventListener('keydown', keyEvents); // this is called once for every key down
window.addEventListener('keyup', keyEvents); // this is called once for every key up.
},
clear : function () {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
};
function Component(width, height, x, y, color, keyMap){ // key map is the keys used to control
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.speedX = 0;
this.speedY = 0;
// get reference to context
var ctx = myGameArea.context;
// clear the keys
var i = 3;
while(i >= 0){ myGameArea.keys[keyMap[i--]] = false; }
this.update = function(){
this.userInput();
this.x += this.speedX;
this.y += this.speedY;
}
this.display = function(){
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
};
this.userInput = function(){ // keyMap is accessed via closure
this.speedY = this.speedX = 0;
if (myGameArea.keys[keyMap[2]]) {this.speedX = -2; } // Left
if (myGameArea.keys[keyMap[3]]) {this.speedX = 2; } // Right
if (myGameArea.keys[keyMap[0]]) {this.speedY = -2; } // Up
if (myGameArea.keys[keyMap[1]]) {this.speedY = 2; } // Down
};
}
function updateGameArea(){
myGameArea.clear();
myStick.update();
myStick2.update();
myStick.display();
myStick2.display();
requestAnimationFrame(updateGameArea); // request the next animation frame in 1/60th second
}
}
.nm{
margin: 0;
padding: 0;
}
canvas{
display: block;
background-color: lightgray;
}
<html>
<head>
<meta charset="UTF-8">
<title>Canvas stick game!</title>
<link rel="stylesheet" href="css/standard.css">
</head>
<body id="body" onload="startGame()" class="nm" style="height: 100vh">
</body>
</html>
<script src="js/canvas.js"></script>