I am trying to create a simple HTML5 Canvas football game. The game has three options, The player chooses left, right or centre to kick a ball, the goal keeper is random and will dive left, right or stay in the centre. I want the user to press the left, right or up arrow keys to trigger the player to kick the ball but I can't get my code to recognise when the arrow keys are pressed. I have tried different keys which will work ie, the return key.
function canvasApp(){
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//Other Var's
document.onkeypress = function doKeyDown( e ) {
var key = e.keyCode;
if ( key == 37 ){
userChoice = key;
} else if (key == 38){
userChoice = key;
} else if (key == 39){
userChoice = key;
}
}
function draw() {
ctx.clearRect( 0, 0, canvas.width, canvas.height );
//------------------------------------------------
//Player shoots left
if ( userChoice == 37 ){
//More code
//------------------------------------------------
//Player shoots right
} else if ( userChoice == 39 ){
//More code
//------------------------------------------------
//Player shoots centre
} else if ( userChoice == 38 ) {
//More code
}
//------------------------------------------------
}
function gameLoop(){
window.setTimeout(gameLoop, framerate);
draw()
}
gameLoop();
}
document.onclick = function( e ){
window.clearTimeout();
}
If you need to see the full code let me know and I'll put a link up to a JSFiddle.
You're triggering the wrong event: use keydown even instead:
Check this page: http://help.dottoro.com/ljlkwans.php
The following is a snippet with jquery: if you use the keypress event it does not work.
<html>
<head>
<title></title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
</head>
<body>
</body>
<script type="text/javascript">
$(document).ready(function(){
$(document).keydown(function(e){
var key = e.keyCode;
if ( key == 37 ){
console.log("left");
} else if (key == 38){
console.log("center");
} else if (key == 39){
console.log("right");
}
});
});
</script>
</html>
Related
I am learning JavaScript and I am trying to program a small game.
I want that something in my game moves consistently while I hold down a key.
This is what I came up with so far:
document.onkeydown = onKeyDownListener;
function onKeyDownListener(evt) {
var keyCode = evt.which || evt.keyCode;
if(keyCode == 37) {
move();
}
}
My problem is that when I press down the key move gets called once, then there is a pause and after that pause move gets called repeatedly as I intend. It goes
like this: m......mmmmmmmmm when 'm' stands for move and'.' is the pause.
Is there a way to get rid of the pause?
Here is a GIF of what happens:
I'm pretty sure you have this problem because you're not depending on a game loop to run your game. If you were, you wouldn't be running into this problem because the game loop at each interval would check if the key is pressed. Your web app is only reacting to each key press as they happen.
I highly recommend you read this tutorial:
W3 HTML Game - Game Controllers
https://www.w3schools.com/graphics/game_movement.asp
Read the "Keyboard as Controller" section. The "setInterval" method induces the game loop in this example.
I used it as a reference to write game code for myself.
This is code from the W3 tutorial. It also goes on to teach collision detection as well.
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.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
myGameArea.keys = (myGameArea.keys || []);
myGameArea.keys[e.keyCode] = true;
})
window.addEventListener('keyup', function (e) {
myGameArea.keys[e.keyCode] = false;
})
},
clear : function(){
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function updateGameArea() {
myGameArea.clear();
myGamePiece.speedX = 0;
myGamePiece.speedY = 0;
if (myGameArea.keys && myGameArea.keys[37]) {myGamePiece.speedX = -1; }
if (myGameArea.keys && myGameArea.keys[39]) {myGamePiece.speedX = 1; }
if (myGameArea.keys && myGameArea.keys[38]) {myGamePiece.speedY = -1; }
if (myGameArea.keys && myGameArea.keys[40]) {myGamePiece.speedY = 1; }
myGamePiece.newPos();
myGamePiece.update();
}
You could try this:
document.onkeydown = onKeyDownListener;
var keyDown = false;
function onKeyDownListener(evt) {
if(evt.keyCode == 37) {
keyDown = true;
}
}
document.onkeyup = function(evt){
if(evt.keyCode == 37) {
keyDown = false;
}
}
setInterval(function(){
if(keyDown){
player.x--;
}
},20)
It's not ideal, I know, but my best guess is it's an issue with keydown detection. This way, for as long as you're holding down that key, it will move until you let go of the key.
As the title suggests, I am having trouble with object collision...
I am currently working on a 2d Html5 canvas game using JavaScript. I know how to keep the "player" object from going outside the width/height of the game canvas, and i know how to do something when the player collides with an object (such as a power up or enemy or whatever) but i just don't know how to make a "solid" object meaning when the player hits the solid object, the player just stops, and cannot go through the solid object.
This is what I have now (not all the code just what I feel is relevant, sorry if it's too much/too little.:
var canvasPlayer = document.getElementById('canvasPlayer');
var ctxPlayer = canvasPlayer.getContext('2d');
var canvasWalls = document.getElementById('canvasWalls');
var ctxWalls = canvasWalls.getContext('2d');
function checkKeyDown(e) {
var keyID = (e.keyCode) || e.which;
if (keyID === 38 || keyID === 87) { // up arrow OR W key
if (!player1.isDownKey && !player1.isLeftKey && !player1.isRightKey) {
player1.isUpKey = true;
e.preventDefault();
} }
if (keyID === 39 || keyID === 68) { //right arrow OR D key
if (!player1.isDownKey && !player1.isLeftKey && !player1.isUpKey) {
player1.isRightKey = true;
e.preventDefault();
} }
if (keyID === 40 || keyID === 83) {//down arrow OR S key
if (!player1.isUpKey && !player1.isLeftKey && !player1.isRightKey) {
player1.isDownKey = true;
e.preventDefault();
} }
if (keyID === 37 || keyID === 65) {//left arrow OR A key
if (!player1.isDownKey && !player1.isUpKey && !player1.isRightKey) {
player1.isLeftKey = true;
e.preventDefault();
}
}
}
Walls.prototype.draw = function (){
ctxWalls.drawImage(imgSprite,this.srcX,this.srcY,this.width,this.height,this.drawX,this.drawY,this.width,this.height);
this.checkHitPlayer();
};
Walls.prototype.checkHitPlayer = function() {
if (this.drawX > player1.drawX &&
this.drawX <= player1.drawX + player1.width &&
this.drawY >= player1.drawY &&
this.drawY < player1.drawY + player1.height) {
player1.isUpKey = false;
player1.isDownKey = false;
player1.isRightKey = false;
player1.isLeftKey = false;
}
};
This works... except when trying to go up or left, the player only moves maybe 2-3 pixels, so it takes 3 left or up arrows to go left or up. As well the player can move straight through the wall which is not what i want. Any help is much appreciated sorry if i included too much or not enough code. Oh, i also forgot to mention the game is a puzzle game, and I have it set-up so a player can only move one direction at a time until hitting a wall.
If you just want your player to stop when the reach a wall, you can apply some math:
For example: assume your player is a 10px by 10px rectangle and the right wall's X position is 200.
The X position of the right side of the rectangle is calculated like this:
var playerRightSide = player.x + player.width;
You can test if the player has reached the wall like this:
if( playerRightSide >= 200 )
If the user tries to push their player beyond the wall, you would hold the player to the left of the wall using the players X position.
if( playerRightSide >= 200 ) { player.x = 190; }
The 190 is the wall's X position (200) minus the player's width (10).
Read further if you're interested in doing more advanced collision testing.
Many basic game collisions can be classified into 3 types:
Circle versus Circle collision
Rectangle versus Rectangle collision
Rectangle versus Circle collision
Here’s an illustration of how to detect each of these common collisions.
Assume you define a circle like this:
var circle1={
x:30,
y:30,
r:10
};
Assume you define a rectangle like this:
var rect1={
x:20,
y:100,
w:20,
h:20
};
You can detect Circle vs Circle collisions like this...
...Using this Circle vs Circle collision-test code:
// return true if the 2 circles are colliding
// c1 and c2 are circles as defined above
function CirclesColliding(c1,c2){
var dx=c2.x-c1.x;
var dy=c2.y-c1.y;
var rSum=c1.r+c2.r;
return(dx*dx+dy*dy<=rSum*rSum);
}
You can detect Rectangle vs Rectangle collisions like this...
...Using this Rectangle vs Rectangle collision-test code:
// return true if the 2 rectangles are colliding
// r1 and r2 are rectangles as defined above
function RectsColliding(r1,r2){
return !(r1.x>r2.x+r2.w || r1.x+r1.w<r2.x || r1.y>r2.y+r2.h || r1.y+r1.h<r2.y);
}
You can detect Rectangle vs Circle collisions like this...
...Using this Rectangle vs Circle collision-test code:
// return true if the rectangle and circle are colliding
// rect and circle are a rectangle and a circle as defined above
function RectCircleColliding(rect,circle){
var dx=Math.abs(circle.x-(rect.x+rect.w/2));
var dy=Math.abs(circle.y-(rect.y+rect.y/2));
if( dx > circle.r+rect.w2 ){ return(false); }
if( dy > circle.r+rect.h2 ){ return(false); }
if( dx <= rect.w ){ return(true); }
if( dy <= rect.h ){ return(true); }
var dx=dx-rect.w;
var dy=dy-rect.h
return(dx*dx+dy*dy<=circle.r*circle.r);
}
For example, you can use these collision tests to respond to a player touching a power-up cube:
// create a circular player object
// that's located at [30,30] and has a radius of 10px
var player={x:30,y:30,r:10};
// create a rectangular power-up at position [200,30]
var powerup={x:200, y:30, w:20, h:20};
// Let's say the user keys the player to coordinate [200,35]
// (touching the power-up)
player.x = 220;
player.y = 35;
// you can test if the circular player is touching the rectangular power-up
if( RectCircleColliding(powerup,player) ) {
// the player has collided with the power-up, give bonus power!
player.power += 100;
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/u6t48/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; padding:20px; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
ctx.fillStyle="lightgray";
ctx.strokeStyle="skyblue";
// top collision circle vs circle
var circle1={x:30,y:30,r:10};
var circle2={x:70,y:40,r:10};
var circle3={x:100,y:30,r:10};
var direction1=1;
// middle collision rect vs rect
var rect1={x:20,y:100,w:20,h:20};
var rect2={x:50,y:110,w:20,h:20};
var rect3={x:90,y:100,w:20,h:20};
var direction2=1;
// bottom collision rect vs circle
var circle4={x:30,y:200,r:10};
var rect4={x:50,y:205,w:20,h:20};
var circle5={x:100,y:200,r:10};
var direction3=1;
function drawAll(){
ctx.clearRect(0,0,canvas.width,canvas.height);
drawCircle(circle1);
drawCircle(circle2);
drawCircle(circle3);
drawCircle(circle4);
drawCircle(circle5);
drawRect(rect1);
drawRect(rect2);
drawRect(rect3);
drawRect(rect4);
}
function drawCircle(c){
ctx.beginPath();
ctx.arc(c.x,c.y,c.r,0,Math.PI*2,false);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
function drawRect(r){
ctx.beginPath();
ctx.rect(r.x,r.y,r.w,r.h);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
// return true if the 2 circles are colliding
function CirclesColliding(c1,c2){
var dx=c2.x-c1.x;
var dy=c2.y-c1.y;
var rSum=c1.r+c2.r;
return(dx*dx+dy*dy<=rSum*rSum);
}
// return true if the 2 rectangles are colliding
function RectsColliding(r1,r2){
return !(r1.x>r2.x+r2.w || r1.x+r1.w<r2.x || r1.y>r2.y+r2.h || r1.y+r1.h<r2.y);
}
// return true if the rectangle and circle are colliding
function RectCircleColliding(rect,circle){
var dx=Math.abs(circle.x-(rect.x+rect.w/2));
var dy=Math.abs(circle.y-(rect.y+rect.h/2));
if( dx > circle.r+rect.w/2 ){ return(false); }
if( dy > circle.r+rect.h/2 ){ return(false); }
if( dx <= rect.w ){ return(true); }
if( dy <= rect.h ){ return(true); }
var dx=dx-rect.w;
var dy=dy-rect.h
return(dx*dx+dy*dy<=circle.r*circle.r);
}
var fps = 15;
function animate() {
setTimeout(function() {
requestAnimFrame(animate);
// circle vs circle
circle2.x = circle2.x+direction1;
if( CirclesColliding(circle2,circle1) || CirclesColliding(circle2,circle3) ){
direction1=-direction1;
}
// rect vs rect
rect2.x = rect2.x+direction2;
if( RectsColliding(rect2,rect1) || RectsColliding(rect2,rect3) ){
direction2=-direction2;
}
// rect vs circle
rect4.x = rect4.x+direction3;
if( RectCircleColliding(rect4,circle4) || RectCircleColliding(rect4,circle5) ){
direction3=-direction3;
}
drawAll();
}, 1000 / fps);
}
animate();
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
Here is my code :
var ctx = document.getElementById("map").getContext("2d");
var ZeroX = 0;
var ZeroY = 0;
ctx.beginPath();
ctx.fillRect(100, 200, 100, 50); //Drawed a black rectangle
function moveMap(evt) {
var key = evt.keyCode || evt.which;
if (key == 38) { //UP
moveDirect(0, 20, false);
}
else if (key == 40) { //DOWN
moveDirect(0, 20, true);
}
else if (key == 39) { //RIGHT
moveDirect(20, 0, true);
}
else if (key == 37) { //LEFT
moveDirect(20, 0, false);
}
}
function moveDirect(X, Y, minus) {
if (minus == false) {
ZeroX -= X;
ZeroY -= Y;
}
else {
ZeroX += X;
ZeroY = Y;
}
var lol = ctx.getImageData(ZeroX, ZeroY, 3000, 3000);
ctx.clearRect(ZeroX, ZeroY, 3000, 3000);
ctx.putImageData(lol, 0, 0);
}
<body onkeypress="moveMap(event)">
<canvas id="map" width="500" height="500">Map </canvas>
</body>
If you run this snippet and click on one of the arrows on the keyboard, you'll see that the rectangle moves in the opposite
direction because I wanted to make like the screen was a camera in a
game. That's done on purpose
But if after you clicked on the arrow's oppsite (Up = Down, Left = Right,
etc), you will see that you must click two times to make it move in
the other direction. Try this with other arrows, still the same.
And if you press the same arrow many times, it's gap travelled becomes
bigger and bigger, but logically it must the same.
I want it to respond directly, not on two clicks and that the gap is always the same. Please explain in your answer why this is happennings. Thaks beforehand!
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to put together a simple "game" in HTML5. However I can't get diagonal movement working.
The "diagonal movement" only works when the two buttons are pressed at exactly the same time. Even then it moves once. Here's the code:
// Getting canvas, and canvas context
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
//Keymap, later passed as method parameter
var map = [false,false,false,false];
// Top, Right, Bottom, Left
// Function for resetting keymap
var resetMap = function() {
for(i=0;i<map.length;i++) {
map[i] = false;
};
};
//Function for clearing the screen before drawing
var clrScrn = function() {
ctx.clearRect(0,0,500,500);
};
// The player character
var character = function() {
this.x = 50;
this.y = 50;
this.h = 50;
this.w = 50;
};
// Draw method of the character class
character.prototype.draw = function() {
ctx.fillRect(this.x,this.y,this.h,this.w);
};
// The move method of the character class
character.prototype.move = function(map) {
if(map[0] === true) {
if(map[1] == true) {
this.x+=5;
this.y-=5;
console.log("Pressed at the same time");
}
else {
this.y-=5;
}
}
else if(map[1] === true) {
this.x+=5;
}
else if(map[2] === true) {
this.y+=5;
}
else if(map[3] === true) {
this.x-=5;
}
};
//Making a new character
var player = new character();
player.draw();
// Drawing everything on screen
var render = function() {
clrScrn();
player.move(map);
player.draw();
resetMap();
requestAnimFrame(render);
};
//Calling the render function
render();
//Binding event listener to window,checking key down, likely the source of the problem
window.addEventListener("keydown",function(e){
if(e.keyCode == 38 && e.keyCode == 39) {
map[0] = true;
map[1] = true;
}
else if(e.keyCode == 38) {
map[0] = true;
}
if(e.keyCode == 39) {
map[1] = true;
}
if(e.keyCode == 40) {
map[2] = true;
}
if(e.keyCode == 37) {
map[3] = true;
}
console.log(e.keyCode);
},false);
//Binding event listener to key up
window.addEventListener("keyup",function(e){
resetMap();
},false);
In your render function:
player.move(map); // you move the player
player.draw(); // you draw the player
resetMap(); // you forget all pressed keys
The resetMap() is the reason you need to press the keys again in order to move just one more step.
Note that horizontal and vertical motions may accidentally work due to keyboard repeat when a key is pressed for a long time. But you shouldn't depend on key repeats for a game. You should detect key down and key up individually for individual keys in order to figure out if a key is pressed or not.
try looking at:
JavaScript multiple keys pressed at once
and then re-work your if/else logic a little bit.
Here's the problem, document.onkeydown = checkkeycode
I'm passing two variable to checkeycode e which is storing the event and hence keycode and the array circle which I want to update with variable c's latest position. when I pass circle to the function, it becomes undefined hence
{circle[4] = c._.ty};
returns an undefined error
I tried putting document.write(circle);
into the document and it just wrote undefined and when I switched it with E it became a keyboard object. What I need solved is:
how do I pass the array circle to the function so that when raphael translates the circle, it updates the values in circle?
in the if (keycode == blah ) do I just do {c.translate(value)} {circle[4] = c._.ty} ?
do I append two different function to a single if event?
<html>
<head>
<script language="javascript" type="text/javascript" src="/home/andrew/Documents/rahpael/raphael-min.js"></script>
</head>
<body>
<script language="javascript">
var paper = Raphael(50, 50, 420, 300);
var d = paper.rect(150, 150, 30, 30);
var c = paper.circle(50, 50, 40);
var circle = [c.attrs.cy, c.attrs.cx, c.attrs.r, c._.tx, c._.ty];
var rectie = [ d.attrs.x, d.attrs.y, d.attrs.height, d.attrs.width];
document.onkeydown = checkKeycode
function checkKeycode(e, circle) {
var keycode;
if (window.event) keycode = window.event.keyCode;
else if (e) keycode = e.which;
if (keycode == 40) { c.translate(0, 10)}; //{circle[4] = c._.ty};// down
if (keycode == 39) { c.translate(10, 0)}; // right
if (keycode == 38) { c.translate(0, -10)}; // up
if (keycode == 37) { c.translate(-10, 0)}; // left
}
// deleted some comments I've made so far.
</script>
</body>
</html>
A couple of issues there:
1) Passing arguments
I'm passing two variable to checkeycode
No, you aren't. The browser will pass one argument to it, the event (unless it's IE, but you've handled that).
If you change:
document.onkeydown = checkKeycode
to
document.onkeydown = function(e) {
checkKeycode(e, circle);
};
...you'll be passing in the circle you defined at global scope.
2) Names
Your checkkeycode function accepts the arguments e and circle, but appears to use e and c instead.
(Your checkkeycode code already closes over the circle at global scope anyway, so you could just drop the circle argument from the definition of checkkeycode and use circle rather than c. But best to keep things modular if you can, by passing the argument into the function.)
So if you're going modular and just closing over circle in the event handler:
var paper = Raphael(50, 50, 420, 300);
var d = paper.rect(150, 150, 30, 30);
var c = paper.circle(50, 50, 40);
var circle = [c.attrs.cy, c.attrs.cx, c.attrs.r, c._.tx, c._.ty];
var rectie = [ d.attrs.x, d.attrs.y, d.attrs.height, d.attrs.width];
document.onkeydown = function(e) {
return checkKeycode(e, circle); // Event handler is closure over `circle`
};
// v-- `c`, not `circle`
function checkKeycode(e, c) {
var keycode;
if (window.event) keycode = window.event.keyCode;
else if (e) keycode = e.which;
if (keycode == 40) { c.translate(0, 10)}; //{circle[4] = c._.ty};// down
if (keycode == 39) { c.translate(10, 0)}; // right
if (keycode == 38) { c.translate(0, -10)}; // up
if (keycode == 37) { c.translate(-10, 0)}; // left
}