Snake moves horizontally - javascript

I am trying to create a simple snake game.
(function() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
x = 0,
y = 0,
speed = 2;
x_move = speed,
y_move = 0,
food_position_x = Math.floor(Math.random() * canvas.width / 10) * 10,
food_position_y = Math.floor(Math.random() * canvas.height / 10) * 10,
size_x = 10;
function eat() {
console.log('food_x:' + food_position_x + ' x:' + x + ' / food_y:' + food_position_y + ' y:' + y);
if (Math.floor(y / 10) * 10 == food_position_y && Math.floor(x / 10) *10 == food_position_x) {
size_x += 2;
//throw new Error("MATCH!"); // This is not an error. Just trying to stop the script
}
}
// Drawing
function draw() {
eat();
requestAnimationFrame(function() {
draw();
});
// Draw the snake
ctx.beginPath();
ctx.rect(Math.floor(x/10)*10, Math.floor(y/10)*10, size_x, 10);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.closePath();
// Draw the food
ctx.beginPath();
ctx.rect(Math.floor(food_position_x/10)*10, Math.floor(food_position_y/10)*10, 10, 10);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
// Increase the value of x and y in order to animate
x = x + x_move;
y = y + y_move;
}
draw();
// Key Pressing
document.addEventListener('keydown', function(event) {
switch(event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = speed;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = speed;
y_move = 0;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -speed;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -speed;
y_move = 0;
}
break;
}
});
})();
canvas { background-color: #000022 }
<canvas id="canvas" width="400" height="400"></canvas>
jsfiddle
The problem
Every time when I catch the food, the snake becomes longer but when you press the down or up key, it moves horizontally.
Maybe a solution
This is what I believe the solution could be:
The snake should be an array! Every time when the key is pressed, define the position of HEAD of snake and move the snake step by step, because it is an array. So the body follows the head. But in this case, I have no idea how to make an array from it.
Maybe there are other solutions. Any helps would be appreciated!

You need to maintain an array of the points currently occupied by the snake body, and add new point (unshift) to the array as the snake approaches and remove point from the back of the array (pop). The following code is a starter, you need to make it your own :).
(function () {
const COLORS={ SNAKE:'#ff7bf5', FOOD:'blue' };
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
var snake=[], score=0;
var x, y, food_position_x, food_position_y, x_move, y_move;
var frameCount=0, framesRequiredToMove=10;
//the less the framesToMove the faster the sname moves
function draw(){
if(++frameCount==framesRequiredToMove){
frameCount=0;
move();
}
requestAnimationFrame(draw);
}
function init(){
snake = [{x:3,y:0},{x:2,y:0},{x:1,y:0},{x:0,y:0}];
snake.forEach((p)=>{plot(p.x,p.y,COLORS.SNAKE)})
x=snake[0].x;y=snake[0].y;
score=0;x_move=1;y_move=0;
scoreboard.innerText=score;
newfood();
setTimeout(draw,1000);
}
function plot(x,y,color){
ctx.beginPath();
ctx.rect(x * 10, y * 10, 10, 10);
ctx.fillStyle = color;
ctx.fill();
ctx.closePath();
}
function move(){
snakepx.innerText = x;
snakepy.innerText = y;
x = x + x_move;
y = y + y_move;
// Advance The Snake
plot(x,y,COLORS.SNAKE);
snake.unshift({x:x,y:y});
// Check food encounter
if(x==food_position_x && y==food_position_y){
scoreboard.innerText=++score;
newfood();
}
else{
var last=snake.pop();
ctx.clearRect(last.x * 10, last.y * 10, 10, 10);
}
}
function newfood(){
food_position_x=Math.floor(Math.random() * canvas.width / 10);
food_position_y=Math.floor(Math.random() * canvas.height / 10);
plot(food_position_x,food_position_y,COLORS.FOOD);
foodpx.innerText = food_position_x;
foodpy.innerText = food_position_y;
}
init();
// Key Pressing
document.addEventListener('keydown', function (event) {
event.preventDefault();
switch (event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = 1;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = 1;
y_move = 0;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -1;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -1;
y_move = 0;
}
break;
}
});
})();
canvas {
background-color: #000022;
float: left;
}
<canvas id="canvas" width="400" height="180"></canvas>
<div style="margin-left: 410px">
Snake: (<span id="snakepx"></span>, <span id="snakepy"></span>)<br>
Food: (<span id="foodpx"></span>, <span id="foodpy"></span>)<br>
Score: <span id="scoreboard"></span>
</div>

Well as I had some free time to spare I created my own JS snake to demonstrate you how it can be done. Most important parts are in this.snakeBody where array of body is stored and this.moveForward() where you can see how body is updated.
https://jsfiddle.net/nooorz24/p8xtdv3h/13/
moveForward: function() {
var next = this.getNextfieldValue();
if (next == "frame" || next == "body") {
console.log("You lose!")
this.isAlive = false;
} else {
var newHead = this.getNextfieldCoords();
this.draw.snake(newHead.x, newHead.y);
this.body.unshift(newHead);
if (next == "food") {
this.generateFood();
this.snakeSize++;
} else {
var last = this.body.pop();
this.draw.empty(last.x, last.y);
}
}
},
I tried to make it as readable as I could, but note that this is unfinished example and would need need loads of improvements to be a playable game

I think that you have hit on the answer with an array. In the past, I have found that Snake works best with an array, tracking each block of the snake and checking for any two blocks being in the same position. For movement, however, you must directly control the head, and have the body follow based on the position of the array space one ahead of it. The snake head would be the first item in the array. I am not sure what you mean about not understanding the implementation of the array, but the coordinates for each block would be an item in the array.

Have a length variable and make that the x or y size based on direction, like this:
(function() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
x = 0,
y = 0,
speed = 2,
x_move = speed,
y_move = 0,
food_position_x = Math.floor(Math.random() * canvas.width / 10) * 10,
food_position_y = Math.floor(Math.random() * canvas.height / 10) * 10,
size_x = 10,
size_y = 10,
snake_length = 10;
function eat() {
console.log('food_x:' + food_position_x + ' x:' + x + ' / food_y:' + food_position_y + ' y:' + y);
if (Math.floor(y / 10) * 10 == food_position_y && Math.floor(x / 10) *10 == food_position_x) {
snake_length += 2;
//throw new Error("MATCH!"); // This is not an error. Just trying to stop the script
}
}
// Drawing
function draw() {
eat();
requestAnimationFrame(function() {
draw();
});
// Draw the snake
ctx.beginPath();
ctx.rect(Math.floor(x/10)*10, Math.floor(y/10)*10, size_x, size_y);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.closePath();
// Draw the food
ctx.beginPath();
ctx.rect(Math.floor(food_position_x/10)*10, Math.floor(food_position_y/10)*10, 10, 10);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
// Increase the value of x and y in order to animate
x = x + x_move;
y = y + y_move;
}
draw();
// Key Pressing
document.addEventListener('keydown', function(event) {
switch(event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = speed;
size_x = 10;
size_y = snake_length;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = speed;
y_move = 0;
size_x = snake_length;
size_y = 10;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -speed;
size_x = 10;
size_y = snake_length;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -speed;
y_move = 0;
size_x = snake_length;
size_y = 10;
}
break;
}
});
})();
canvas { background-color: #000022 }
<canvas id="canvas" width="400" height="400"></canvas>

I make the game using C++ soi can advice make a new object for every snake tile and on move set it to parent position
function Tile(x, y)
{
this.x = x;
this.y = y;
}

To debug your down or up problem, I would add some console.log('message') calls in your code for debugging.
Specifically, add some console messages in the switch statement so that you know the correct event and branch is firing. For Example:
switch(event.keyCode) {
case 40:
console.log('down');
...
case 39:
console.log('right');
...
}
Then add more and more debugging log messages until you find your problem.
You can view the console messages in the F12 developer tools in your browser of choice while running your game.
Also make sure you are not calling ctx.translate(...) on the canvas context to flip the canvas, this would change the direction of the x and/or y axis.

Related

2d moving squares collision detection

There are two squares, they are moved with the arrows and asdw, and I have been trying to get this collision detection down for ages, it's killing me. Anyways, I have tried so many methods, I got really really close with one method, and everything was fine with it, until I found out that when you jumped next to it, it didn't complete the full jump because one of the sides was able to go through the other square. After a long time, I found out that method wouldn't work because with GetContext.2d, you cannot reference the bottom left of a square. There also was the issue that one corner could touch two different sides, which would set off conflicting messages. My solution for that was to make a third condition to specify which side the corner was touching, weather the top/bottom or left/right. I made a model of how the code would be structured:
The code I have currently looks like this:
const context = document.getElementById("canvasmulti").getContext("2d");
canvasmulti.width = window.innerWidth;
canvasmulti.height = window.innerHeight;
//CHARACTER:
const square = {
height: 75,
jumping: true,
width: 75,
x: canvasmulti.width - 75,
xVelocity: 0,
y: canvasmulti.height / 2,
yVelocity: 0,
jumpHeight: 30
};
const square2 = {
height: 75,
jumping: true,
width: 75,
x: 0,
xVelocity: 0,
y: canvasmulti.height / 2,
yVelocity: 0,
jumpHeight: 30
};
//MOVEMENT:
const controller = {
left: false,
right: false,
up: false,
keyListener: function (event) {
let key_state = (event.type == "keydown") ? true : false;
switch (event.keyCode) {
case 37: // left arrow
controller.left = key_state;
break;
case 38: // up arrow
controller.up = key_state;
break;
case 39: // right arrow
controller.right = key_state;
break;
}
}
};
const controller2 = {
left: false,
right: false,
up: false,
keyListener: function (event) {
let key_state = (event.type == "keydown") ? true : false;
switch (event.keyCode) {
case 65: // left arrow
controller2.left = key_state;
break;
case 87: // up arrow
controller2.up = key_state;
break;
case 68: // right arrow
controller2.right = key_state;
break;
}
}
};
const loop = function () {
//controller one
if (controller.up && square.jumping == false) {
square.yVelocity -=square.jumpHeight;
square.jumping = true;}
if (controller.left) {
square.xVelocity -= 0.5;}
if (controller.right) {
square.xVelocity += 0.5;}
//controller two
if (controller2.up && square2.jumping == false) {
square2.yVelocity -= square2.jumpHeight;
square2.jumping = true;}
if (controller2.left) {
square2.xVelocity -= 0.5;}
if (controller2.right) {
square2.xVelocity += 0.5;}
//controller one
square.yVelocity += 1.5;// gravity
square.x += square.xVelocity;
square.y += square.yVelocity;
square.xVelocity *= 0.9;// friction
square.yVelocity *= 0.9;// friction
//controller two
square2.yVelocity += 1.5;// gravity
square2.x += square2.xVelocity;
square2.y += square2.yVelocity;
square2.xVelocity *= 0.9;// friction
square2.yVelocity *= 0.9;// friction
// if square1 is falling below floor line
if (square.y > canvasmulti.height - 75) {
square.jumping = false;
square.y = canvasmulti.height - 75;
square.yVelocity = 0;
}
// if square2 is falling below floor line
if (square2.y > canvasmulti.height - 75) {
square2.jumping = false;
square2.y = canvasmulti.height - 75;
square2.yVelocity = 0;
}
// if square1 is going off the left of the screen
if (square.x < 0) {
square.x = 0;
} else if (square.x > canvasmulti.width - 75) {// if square goes past right boundary
square.x = canvasmulti.width - 75;
}
// if square2 is going off the left of the screen
if (square2.x < 0) {square2.x = 0;}
else if (square2.x > canvasmulti.width - 75) {// if square goes past right boundary
square2.x = canvasmulti.width - 75;
}
// Creates the backdrop for each frame
context.fillStyle = "#394129";
context.fillRect(0, 0, canvasmulti.width, canvasmulti.height); // x, y, width, height
// Creates and fills square1 for each frame
context.fillStyle = "#8DAA9D"; // hex for cube color
context.beginPath();
context.rect(square.x, square.y, square.width, square.height);
context.fill();
// Creates and fills square2 for each frame
context.fillStyle = "#781818"; // hex for cube color
context.beginPath();
context.rect(square2.x, square2.y, square2.width, square2.height);
context.fill();
// Collision detection of squares
if (square.x <= square2.x + square2.width && square.x >= square2.x &&
square.y >= square2.y && square.y <= square2.y + square2.height &&
square2.y + square2.height >= square.y && square2.y + square2.height <= square.y + square.height)
{square.y = square2.y - square.height; //set it to a position where they don't overlap
square.yVelocity = 0;}; //One move down
if (square.x <= square2.x + square2.width && square.x >= square2.x &&
square.y >= square2.y && square.y <= square2.y + square2.height &&
square2.x + square2.width >= square.x && square2.x + square2.width <= square.x + square.width);
{square.x = square2.x + square2.width; // set it to a position where they don't overlap
square.xVelocity = 0;}; //One move right
if (square2.x >= square.x && square2.x <= square.x + square.width &&
square2.y >= square.y && square2.y <= square.y + square.heights &&
square.y + square.height >= square2.y && square.y + square.height <= square2.y + square2.height)
{square.y = square2.y - square.height; // set it to a position where they don't overlap
square.yVelocity = 0;}; //One move up
if (square2.x >= square.x && square2.x <= square.x + square.width &&
square2.y >= square.y && square2.y <= square.y + square.heights &&
square.x + square.width >= square2.y && square.x + square.width <= square2.y + square2.height)
{square.x = square2.x - square.width; // set it to a position where they don't overlap
square.xVelocity = 0;}; //One move left
// call update when the browser is ready to draw again
window.requestAnimationFrame(loop);
};
//square1
window.addEventListener("keydown", controller.keyListener)
window.addEventListener("keyup", controller.keyListener);
//square2
window.addEventListener("keydown", controller2.keyListener)
window.addEventListener("keyup", controller2.keyListener);
window.requestAnimationFrame(loop);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height">
<title>ToneMain</title>
<style>
body {
height:100vh;
width:100vh;
margin: 0;
}
</style>
</head>
<body>
<canvas id="canvasmulti"></canvas>
<script src="ToneMainMulti.js"></script>
</body>
</html>
For the love of my sanity this was the last time in a month I tried to fix this. This was my last blow. I would really apprestiate any effort or advice to solve my problem, this is tough to wrap your head around and may take a long time, thxxx <3
I feel your pain. CD is not as easy as one would hope. I was unable to get your code working so I rewrote it using ES6 classes because I like them. I also don't put everything into a loop function but rather place controlling parameters into separate functions and call those functions in the animate loop. Hopefully it isn't confusing from how you write.
The CD portion calculates the distance between the different sides of the blocks and determines which sides from each block are the closest and will collide. By doing this only one function will get called at a time. This prevents any of the unwanted behavior you get because of the blocks having a slight overlap and causing other functions to trigger also. i.e. colliding on the X but having the Y trigger too. I've also set it to where if the blocks are stacked only the top one can jump.
You can tailor this to whatever suits your needs.
const canvas = document.getElementById('canvasmulti');
const context = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 500;
let gravity = 1.5;
let friction = 0.9;
//CHARACTER:
class Player {
constructor(x, y, vx, vy, c, j) {
//each player must have separate values for control purposes i.e. velocity/jump/attack etc.
this.x = x;
this.y = y;
this.w = 50;
this.h = 50;
this.vx = vx;
this.vy = vy;
this.color = c;
this.jumping = j;
}
draw() {
context.fillStyle = this.color;
context.fillRect(this.x, this.y, this.w, this.h);
}
canvasCollision() {
if (this.x <= 0) this.x = 0;
if (this.y <= 0) this.y = 0;
if (this.x + this.w >= canvas.width) this.x = canvas.width - this.w;
if (this.y + this.h >= canvas.height) {this.y = canvas.height - this.h; this.vy = 0; this.jumping = false};
}
update() {
this.draw();
this.vy += gravity;
this.x += this.vx;
this.y += this.vy;
this.vx *= friction;
this.vy *= friction;
this.canvasCollision() //must be after other updates
}
}
let player1 = new Player(0, 0, 0, 0, 'red', false); //must have separate variables like jump/attack etc
let player2 = new Player(canvasmulti.width - 50, 0, 0, 0, 'blue', false);
function controlPlayer1(obj) {
//this order matters. If update is before jump then obj won't jump when on top of other block.
if (controller1.up1 && !obj.jumping) { obj.vy -= 25; obj.jumping = true };
if (controller1.left1) { obj.vx -= 0.5 };
if (controller1.right1) { obj.vx += 0.5 };
obj.update();
}
function controlPlayer2(obj) {
if (controller2.up2 && !obj.jumping) { obj.vy -= 25; obj.jumping = true };
if (controller2.right2) { obj.vx += 0.5 };
if (controller2.left2) { obj.vx -= 0.5 };
obj.update();
}
//MOVEMENT:
class Controller {
constructor() {
this.left1 = false;
this.up1 = false;
this.right1 = false;
this.left2 = false;
this.up2 = false;
this.right2 = false;
let controller1 = (e) => {
if (e.code === 'ArrowRight') { this.right1 = e.type === 'keydown' }
if (e.code === 'ArrowLeft') { this.left1 = e.type === 'keydown' }
if (e.code === 'ArrowUp') { this.up1 = e.type === 'keydown' }
}
let controller2 = (e) => {
if (e.code === 'KeyD') { this.right2 = e.type === 'keydown' }
if (e.code === 'KeyA') { this.left2 = e.type === 'keydown' }
if (e.code === 'KeyW') { this.up2 = e.type === 'keydown' }
}
window.addEventListener('keydown', controller1);
window.addEventListener('keyup', controller1);
window.addEventListener('keydown', controller2);
window.addEventListener('keyup', controller2);
}
}
let controller1 = new Controller();
let controller2 = new Controller();
function collisionDetection(obj, obj2) {
//center point of each side of obj1
let objLeft = {x: obj.x, y: obj.y + obj.h/2};
let objTop = {x: obj.x + obj.w/2, y: obj.y};
let objRight = {x: obj.x + obj.w, y: obj.y + obj.h/2};
let objBottom = {x: obj.x + obj.w/2, y: obj.y + obj.h};
//center point of each side a obj2
let obj2Left = {x: obj2.x, y: obj2.y + obj2.h/2};
let obj2Top = {x: obj2.x + obj2.w/2, y: obj2.y};
let obj2Right = {x: obj2.x + obj2.w, y: obj2.y + obj2.h/2};
let obj2Bottom = {x: obj2.x + obj2.w/2, y: obj2.y + obj2.h};
//distance between obj1 and obj2 opposing sides
let rightDistX = objRight.x - obj2Left.x;
let rightDistY = objRight.y - obj2Left.y;
let leftDistX = objLeft.x - obj2Right.x;
let leftDistY = objLeft.y - obj2Right.y;
let topDistX = objTop.x - obj2Bottom.x;
let topDistY = objTop.y - obj2Bottom.y;
let bottomDistX = objBottom.x - obj2Top.x;
let bottomDistY = objBottom.y - obj2Top.y;
//pythagorean theorem for distance. dRight is from the right side of obj1 to the left of obj2. the rest follow suit.
let dRight = Math.sqrt(rightDistX*rightDistX + rightDistY*rightDistY);
let dLeft = Math.sqrt(leftDistX*leftDistX + leftDistY*leftDistY);
let dTop = Math.sqrt(topDistX*topDistX + topDistY*topDistY);
let dBottom = Math.sqrt(bottomDistX*bottomDistX + bottomDistY*bottomDistY);
//Math.min return the smallest value thus variable minimum will be which ever sides are closest together
let minimum = Math.min(dRight, dLeft, dBottom, dTop);
let val = 0;
//compare minimum to d*** and set val based on which ever side is closest
if (dTop == minimum) {
val = 1;
//the context stuff can be deleted. It's just here for visual. The if statements can be one line each.
context.lineWidth = 2;
context.strokeStyle = 'blue';
context.beginPath();
context.moveTo(objTop.x, objTop.y);
context.lineTo(obj2Bottom.x, obj2Bottom.y);
context.stroke();
}
else if (dRight == minimum) {
val = 2;
context.strokeStyle = 'orange';
context.beginPath();
context.moveTo(objRight.x, objRight.y);
context.lineTo(obj2Left.x, obj2Left.y);
context.stroke();
}
else if (dBottom == minimum) {
val = 3;
context.strokeStyle = 'green';
context.beginPath();
context.moveTo(objBottom.x, objBottom.y);
context.lineTo(obj2Top.x, obj2Top.y);
context.stroke();
}
else if (dLeft == minimum) {
val = 4;
context.strokeStyle = 'pink';
context.beginPath();
context.moveTo(objLeft.x, objLeft.y);
context.lineTo(obj2Right.x, obj2Right.y);
context.stroke();
}
//pass the objects and val to collisionActions
collisionActions(obj, obj2, val)
}
function collisionActions(obj, obj2, val) {
//player1 top to player2 bottom
if (obj.y <= obj2.y + obj2.h && obj2.y + obj2.h >= obj.y && val == 1) {
obj2.y = obj.y - obj2.h;
obj.y = obj2.y + obj2.h;
obj.vy = 0;
obj2.vy = 0;
obj2.jumping = false;
obj.jumping = true;
}
//player1 right to player2 left
if (obj.x + obj.w >= obj2.x && obj2.x <= obj.x + obj.w && val == 2) {
obj2.x = obj.x + obj.w;
obj.x = obj2.x - obj.w - 1;
obj.vx = 0;
obj2.vx = 0;
}
//player1 bottom to player2 top
if (obj.y + obj.h >= obj2.y && obj2.y <= obj.y + obj.h && val == 3) {
obj.y = obj2.y - obj.h;
obj2.y = obj.y + obj.h;
obj.vy = 0;
obj2.vy = 0;
obj.jumping = false;
obj2.jumping = true;
}
//player1 left to player2 right
if (obj.x <= obj2.x + obj2.w && obj2.x + obj2.w >= obj.x && val == 4) {
obj2.x = obj.x - obj2.w;
obj.x = obj2.x + obj2.w + 1;
obj.vx = 0;
obj2.vx = 0;
}
}
function loop() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = 'grey';
context.fillRect(0, 0, canvas.width, canvas.height);
controlPlayer1(player1);
controlPlayer2(player2);
collisionDetection(player1, player2)
requestAnimationFrame(loop)
}
loop();
It may seem like a lot but it's really not and it works very well. I was having the same issues a while back and came up with this to use on a collision map because my character would randomly shoot of in the wrong direction or jumping next to a block wouldn't work. I have modified that code to be used here with just 2 moving blocks. Let me know if this works for you.

How to rotate/transform image using arrow keys

I'm relatively new to canvas and I'm trying to make a space ship type game. I have everything else I'd like down, except for the ship turning itself. I want to make the image of the ship rotate when the arrow keys are clicked.
So if the left arrow key is clicked, it will turn to face the left, and the right arrow key is clicked it will turn to face the right, and so on. I really can't figure this out, if anyone can show me how to do this I would really appreciate it.
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
/*Variable to store score*/
var score = 0;
/*Variable that stores the players object properties*/
var x = 50;
var y = 100;
var speed = 6;
var sideLength = 50;
/*Flags to track when keypress is active*/
var down = false;
var up = false;
var left = false;
var right = false;
/*Variables that store target position and size*/
var targetX = 0;
var targetY = 0;
var targetLength = 25;
/*If a number is within range b to c*/
function isWithin(a, b, c) {
return (a > b && a < c)
}
var countDown = 30;
/*Id to track set time*/
var id = null;
/*Listening for if one of the keys is pressed*/
canvas.addEventListener('keydown', function (event) {
event.preventDefault();
console.log(event.key, event.keyCode);
if (event.keyCode === 40) {
down = true;
}
if (event.keyCode === 38) {
up = true;
}
if (event.keyCode === 37) {
left = true;
}
if (event.keyCode === 39) {
right = true;
}
});
/*Listening for if one of the keys is released*/
canvas.addEventListener('keyup', function (event) {
event.preventDefault();
console.log(event.key, event.keyCode);
if (event.keyCode === 40) {
down = false;
}
if (event.keyCode === 38) {
up = false;
}
if (event.keyCode === 37) {
left = false;
}
if (event.keyCode === 39) {
right = false;
}
});
/*Function to show menu*/
function menu() {
erase();
context.fillStyle = '#000000';
context.font = '36px Arial';
context.textAlign = 'center';
context.fillText('Collect The Thing', canvas.width / 2, canvas.height / 4);
context.font = '30px Arial';
context.fillText('Press to Start', canvas.width / 2, canvas.height / 2);
/*Listen for click to start game*/
canvas.addEventListener('click', startGame);
}
/*Function to start the game*/
function startGame() {
/*reduce the countdown timer every 1 second*/
id = setInterval(function () {
countDown--;
}, 1000)
/*remove click events*/
canvas.removeEventListener('click', startGame);
moveTarget();
draw();
}
/*Show game over screen*/
function endGame() {
/*stop the countdown*/
clearInterval(id);
/*clear game board*/
erase();
context.fillStyle = '#000000';
context.font = '36px Arial';
context.textAlign = 'center';
context.fillText('Finale Score: ' + score, canvas.width / 2, canvas.height / 4);
}
/*Move target to random location in canvas*/
function moveTarget() {
targetX = Math.round(Math.random() * canvas.width - targetLength);
targetY = Math.round(Math.random() * canvas.height - targetLength);
}
/*Clear the Canvas*/
function erase() {
context.fillStyle = '#FFFFFF';
context.fillRect(0, 0, 600, 500);
}
/*Main animation drawing loop with game logic*/
function draw() {
erase();
/*Move the player sqaure*/
if (down) {
y += speed;
}
if (up) {
y -= speed;
}
if (right) {
x += speed;
}
if (left) {
x -= speed;
}
if (y + sideLength > canvas.height) {
y = canvas.height - sideLength;
}
if (y < 0) {
y = 0;
}
if (x < 0) {
x = 0;
}
if (x + sideLength > canvas.width) {
x = canvas.width - sideLength;
}
/*Collide with target*/
if (isWithin(targetX, x, x + sideLength) || isWithin(targetX + targetLength, x, x + sideLength)) {
if (isWithin(targetY, y, y + sideLength) || isWithin(targetY + targetLength, y, y + sideLength)) {
/*respawn target in a random location*/
moveTarget();
/*Increase score by 1*/
score++;
}
}
//Draw player object
context.fillRect(x, y, sideLength, sideLength);
context.drawImage(baseImage, x, y, sideLength, sideLength);
/*Draw target sqaure*/
context.fillStyle = '#00FF00';
context.fillRect(targetX, targetY, targetLength, targetLength);
//Timer and Score
context.fillStyle = '#000000';
context.font = '24px Arial';
context.textAlign = 'left';
context.fillText('Score: ' + score, 10, 24);
context.fillText('Time Remaining: ' + countDown, 10, 50);
if (countDown <= 0) {
endGame();
} else {
window.requestAnimationFrame(draw);
}
}
baseImage= new Image();
baseImage.src='xwing3.png';
baseImage.onload= function() {
menu();
}
canvas.focus();
I think in this regard you have two options.
You could have a sprite for every direction that you want the ship to face, then when you draw the image, you could choose the sprite that matches.
if(left == true) {baseImage.src='xwing3left.png';}
You could use the canvas rotate() method. This would make things more complicated, but it actually rotates the canvas and could give more opportunity to experiment.
It actually applies a transformation matrix to the canvas before it draws so you could do things like:
context.rotate(45);
context.fillRect(x,y,width,height);
Just be careful, because rotate always occurs around the origin, so you might need to use translate() as well to make it work the way you expect.
Hope this helps! :)

Let the snake catch his food

I am trying to create a simple snake game. For now I am trying to catch the food but the position of the snake is never the same as the position of food.
(function() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
x = 0,
y = 0,
speed = 2;
x_move = speed,
y_move = 0,
food_position_x = Math.floor(Math.random() * canvas.width);
food_position_y = Math.floor(Math.random() * canvas.height);
function eat() {
console.log('food_x:' + food_position_x + ' x:' + x + ' / food_y:' + food_position_y + ' y:' + y);
if (y == food_position_y && x == food_position_x) {
throw new Error("MATCH!"); // This is not an error. Just trying to stop the script
}
}
// Drawing
function draw() {
eat();
requestAnimationFrame(function() {
draw();
});
// Draw the snake
ctx.beginPath();
ctx.rect(Math.floor(x/10)*10, Math.floor(y/10)*10, 10, 10);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.closePath();
// Draw the food
ctx.beginPath();
ctx.rect(Math.floor(food_position_x/10)*10, Math.floor(food_position_y/10)*10, 10, 10);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
// Increase the value of x and y in order to animate
x = x + x_move;
y = y + y_move;
}
draw();
// Key Pressing
document.addEventListener('keydown', function(event) {
switch(event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = speed;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = speed;
y_move = 0;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -speed;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -speed;
y_move = 0;
}
break;
}
});
})();
canvas { background-color: #000022 }
<canvas id="canvas" width="400" height="400"></canvas>
console.log() will return all positions.
jsfiddle
Am I calculating something wrong? Maybe I have to change the variables food_position_x and food_position_y. If not, I have no idea why the positions are never the same.
Your game area is supposed to be a grid of cells with widths and heights of 10. That's why you do this: Math.floor(x/10)*10 when drawing the snake.
To make the eat function work you just need to draw the food in the same way:
food_position_x = Math.floor(Math.random() * canvas.width / 10) * 10;
food_position_y = Math.floor(Math.random() * canvas.height / 10) * 10;
and add the same thing to the if condition of the eat function:
if (Math.floor(y/10)*10 == food_position_y && Math.floor(x/10)* 10 == food_position_x)
(function() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
x = 0,
y = 0,
speed = 2;
x_move = speed,
y_move = 0,
food_position_x = Math.floor(Math.random() * canvas.width / 10) * 10;
food_position_y = Math.floor(Math.random() * canvas.height / 10) * 10;
function eat() {
//console.log('food_x:' + food_position_x + ' x:' + x + ' / food_y:' + food_position_y + ' y:' + y);
if (Math.floor(y/10)*10 == food_position_y && Math.floor(x/10)* 10 == food_position_x) {
throw new Error("MATCH!"); // This is not an error. Just trying to stop the script
}
}
// Drawing
function draw() {
eat();
requestAnimationFrame(function() {
draw();
});
// Increase the value of x and y in order to animate
x = x + x_move;
y = y + y_move;
if (x > canvas.width) x = 0;
if (y > canvas.height) y = 0;
if (y < 0) y = canvas.height;
if (x < 0) x = canvas.width;
// Draw the snake
ctx.beginPath();
ctx.rect(Math.floor(x/10)*10, Math.floor(y/10)*10, 10, 10);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.closePath();
// Draw the food
ctx.beginPath();
ctx.rect(Math.floor(food_position_x/10)*10, Math.floor(food_position_y/10)*10, 10, 10);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
}
draw();
// Key Pressing
document.addEventListener('keydown', function(event) {
switch(event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = speed;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = speed;
y_move = 0;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -speed;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -speed;
y_move = 0;
}
break;
}
});
})();
canvas { background-color: #000022 }
<canvas id="canvas" width="400" height="400"></canvas>
Your game looks like it's on big chunky grid, but it really isn't, that's only in the graphics. The state variables, which are what matter, are little fiddly small numbers.
Instead of drawing the snake like this:
ctx.rect(Math.floor(x/10)*10, Math.floor(y/10)*10, 10, 10);
Try drawing it like this:
ctx.rect( x, y, 1, 1 );
And you'll see the real state of the game. This is what you're really playing: https://jsfiddle.net/xeyrmsLc/11/ - and that's why it's hard to get the food.
The main problem is that there are so many possibilities for x and food_position_x, and precise control is difficult, that it's very difficult to land exactly on an X that matches in combination with a Y that matches. You have to move back and forth a lot around the same area to get an exact match for X or an exact match for Y (from which you can then proceed to go in some orthogonal direction to land on the food).
But your code does work at a base level. You might consider reducing the speed and making the visual square location exactly match the internal numbers (less visual granularity which doesn't match the underlying state).

increment then decrement radius of arc canvas html5

hi i am trying to gat an arc to resize as it moves across the screen.
I cant seem to asign the value of increment to the radius of the arc for it to get bigger and then smaller.
please see below for the code block in question and then the entire code.
resize(){
this.up = true;
this.r = 0;
this.increment = 10;
this.ceiling = 100;
function PerformCalc() {
if (this.up == true && this.r <= this.ceiling) {
this.r += increment
if (this.r == ceiling) {
this.up = false;
}
} else {
this.up = false
this.r -= increment;
if (this.r == 0) {
this.up = true;
}
}
console.log(this.r);
}
setInterval(PerformCalc, 1000);
}
When i log out the radius to the console it gives nan for some reason.
Any help would be greatly appreciated.
<!DOCTYPE html>
<html>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<head>
<meta charset="UTF-8">
<title>Canvas</title>
<style type="text/css">
canvas {
border: 1px solid grey;
}
</style>
</head>
<body>
<canvas id="canvas-for-ball"></canvas>
<script type="text/javascript">
// Gets a handle to the element with id canvasOne.
var canvas = document.getElementById("canvas-for-ball");
// Get a 2D context for the canvas.
var ctx = canvas.getContext("2d");
function init(){
canvas.width = 500;
canvas.height = 500;
}
init();
//angle defining spin and sections of ball
var theta = 0;
//for the sections of the ball
var theta2 = 0;
//fort he amount of sections needed
var seventh = (Math.PI*2)/7
//to control the amount of spin the ball has
var thetaInc = 0.0029;
//ball object
class Ball {
constructor(x,y,r,xvel,yvel,mass){
this.x =x;
this.y = y;
this.r =r;
this.xvel = xvel;
this.yvel = yvel;
this.mass = mass;
}
draw(){
// Update the y location.
this.x = this.x + this.xvel;
this.y = this.y + this.yvel;
//draw circle
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
ctx.stroke();
//fill the circle
ctx.fillStyle = "orange";
ctx.fill();
//draw inner circle of ball
ctx.beginPath();
ctx.arc(this.x,this.y,this.r*.9,0,Math.PI*2,false);
ctx.stroke();
//spin control
theta += thetaInc;
//loop for adding sections to pie
for( var n = 0; n < 7; ++n) { // add loop to draw radii
theta2 = theta + n * seventh;
ctx.moveTo( this.x, this.y);
ctx.lineTo( this.x + this.r*Math.cos(theta2), this.y + this.r*Math.sin(theta2));
}
ctx.lineWidth = "2";
ctx.lineCap = "round";
ctx.strokeStyle = "black";
ctx.stroke();
}
move(){
//condition take into account the this.r of the ball so
//it bounces at the edge of the canvas instead
//of going off of the screen to its center point.
if(this.y > canvas.height - this.r || this.y - this.r <0){
this.yvel = -1*this.yvel;
//to reverse the direction of the ball when hitting walls
if((this.xvel<0 && this.yvel >0) && thetaInc <0){
thetaInc = -1*thetaInc;
}
else if((this.xvel <0 && this.yvel>0) && thetaInc >0){
thetaInc = -1*thetaInc
}
else if((this.xvel >0 && this.yvel >0) && thetaInc >0){
thetaInc = -1 * thetaInc;
}
else if((this.xvel > 0 && this.yvel < 0)&& thetaInc <0){
thetaInc = -1 * thetaInc;
}
}
if(this.x > canvas.width - this.r || this.x - this.r < 0){
this.xvel = -1*this.xvel;
}
}
resize(){
this.up = true;
this.r = 0;
this.increment = 10;
this.ceiling = 100;
function PerformCalc() {
if (this.up == true && this.r <= this.ceiling) {
this.r += increment
if (this.r == ceiling) {
this.up = false;
}
} else {
this.up = false
this.r -= increment;
if (this.r == 0) {
this.up = true;
}
}
console.log(this.r);
}
setInterval(PerformCalc, 1000);
}
colour(){
}
}
//Intersect function takes a ball as a perameter
//ball will be the the object used to test if the two are touching.
function intersect(ball,ball1) {
//the x and y cordinates of the first ball are subtracted from the test ball and stored
//in productX and productY
var productX = ball1.x - ball.x;
var productY = ball1.y - ball.y;
//pythagoras theorem is used to get the distance between both center points of each circle.
var distance = Math.sqrt(productX * productX + productY * productY);
//A condition is used to check if the distance between both bencer point of each circle
//is less than or equal to the sum of both radii the circles are touching.
//the result is p[rinted out to the console
if (distance <= (ball1.r + ball.r)) {
dx = ball.x-ball1.x;
dy = ball.y-ball1.y;
collision_angle = Math.atan2(dy,dx);
magnitude_1 = Math.sqrt(ball.xvel*ball.xvel+ball.yvel*ball.yvel);
magnitude_2 = Math.sqrt(ball1.xvel*ball1.xvel+ball1.yvel*ball1.yvel);
direction_1 = Math.atan2(ball.yvel, ball.xvel);
direction_2 = Math.atan2(ball1.yvel, ball1.xvel);
new_xvel_1 = magnitude_1 * Math.cos(direction_1-collision_angle);
new_yvel_1 = magnitude_1 * Math.sin(direction_1-collision_angle);
new_xvel_2 = magnitude_2 * Math.cos(direction_2-collision_angle);
new_yvel_2 = magnitude_1 * Math.sin(direction_2-collision_angle);
final_xvel_1 = ((ball.mass-ball1.mass)*new_xvel_1+(ball1.mass+ball1.mass)*new_xvel_2)/(ball.mass+ball1.mass);
final_xvel_2 = ((ball.mass+ball.mass)*new_xvel_1+(ball1.mass-ball.mass)*new_xvel_2)/(ball.mass+ball1.mass);
final_yvel_1 = new_yvel_1;
final_yvel_2 = new_yvel_2;
ball.xvel = Math.cos(collision_angle)*final_xvel_1+Math.cos(collision_angle+Math.PI/2)*final_yvel_1;
ball.yvel = Math.sin(collision_angle)*final_xvel_1+Math.sin(collision_angle+Math.PI/2)*final_yvel_1;
ball1.xvel = Math.cos(collision_angle)*final_xvel_2+Math.cos(collision_angle+Math.PI/2)*final_yvel_2;
ball1.yvel = Math.sin(collision_angle)*final_xvel_2+Math.sin(collision_angle+Math.PI/2)*final_yvel_2;
}
}
canvas.addEventListener("click", function(event) {
var clickX = event.clientX - canvas.offsetLeft;
var clickY = event.clientY- canvas.offsetTop;
b1.x = clickX;
b1.y = clickY;
});
// Add a Javascript event listener to the keypress event.
window.addEventListener("keypress", function(event) {
// Just log the event to the console.
console.log(event);
});
//keypresses with jQuery
$(document.body).on('keydown', function(e) {
console.log(e.which);
switch (e.which) {
// key code for left arrow
case 37:
console.log('left arrow key pressed!');
b1.xvel --;
break;
//keycode for up
case 38:
console.log('up key pressed');
b1.yvel++;
break;
//key code for right
case 39:
console.log('right arrow key pressed!');
b1.xvel++;
break;
//key code for down
case 40:
console.log('down arrow key pressed!');
b1.yvel--;
break;
//key code for + key to increase spin
case 107:
console.log('down arrow key pressed!');
thetaInc +=.001;
break;
//key code for - key to decrease spin
case 109:
console.log('down arrow key pressed!');
thetaInc -=.001;
break;
}
});
b1 = new Ball(200,200,40,1,1,50);
b2 = new Ball(100,100,40,2,2,5);
b1.resize();
// A function to repeat every time the animation loops.
function repeatme() {
//clear canvas for each frame of the animation.
ctx.clearRect(0,0,500,500);
// Draw the ball (stroked, not filled).
b1.draw();
b2.draw();
b1.move();
b2.move();
intersect(b1,b2);
//put repeatme function into the animation frame and store it in animate
animate = window.requestAnimationFrame(repeatme);
}
// Get the animation going.
repeatme();
</script>
</body>
</html>
There is a reference error for increment, e.g. you didn't use this.increment, same for ceiling, should be this.ceiling.
this is used by the setInterval so you save this as that so you can use them. this removes the NaN.
<!DOCTYPE html>
<html>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<head>
<meta charset="UTF-8">
<title>Canvas</title>
<style type="text/css">
canvas {
border: 1px solid grey;
}
</style>
</head>
<body>
<canvas id="canvas-for-ball"></canvas>
<script type="text/javascript">
// Gets a handle to the element with id canvasOne.
var canvas = document.getElementById("canvas-for-ball");
// Get a 2D context for the canvas.
var ctx = canvas.getContext("2d");
function init(){
canvas.width = 500;
canvas.height = 500;
}
init();
//angle defining spin and sections of ball
var theta = 0;
//for the sections of the ball
var theta2 = 0;
//fort he amount of sections needed
var seventh = (Math.PI*2)/7
//to control the amount of spin the ball has
var thetaInc = 0.0029;
//ball object
class Ball {
constructor(x,y,r,xvel,yvel,mass){
this.x =x;
this.y = y;
this.r =r;
this.xvel = xvel;
this.yvel = yvel;
this.mass = mass;
}
draw(){
// Update the y location.
this.x = this.x + this.xvel;
this.y = this.y + this.yvel;
//draw circle
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
ctx.stroke();
//fill the circle
ctx.fillStyle = "orange";
ctx.fill();
//draw inner circle of ball
ctx.beginPath();
ctx.arc(this.x,this.y,this.r*.9,0,Math.PI*2,false);
ctx.stroke();
//spin control
theta += thetaInc;
//loop for adding sections to pie
for( var n = 0; n < 7; ++n) { // add loop to draw radii
theta2 = theta + n * seventh;
ctx.moveTo( this.x, this.y);
ctx.lineTo( this.x + this.r*Math.cos(theta2), this.y + this.r*Math.sin(theta2));
}
ctx.lineWidth = "2";
ctx.lineCap = "round";
ctx.strokeStyle = "black";
ctx.stroke();
}
move(){
//condition take into account the this.r of the ball so
//it bounces at the edge of the canvas instead
//of going off of the screen to its center point.
if(this.y > canvas.height - this.r || this.y - this.r <0){
this.yvel = -1*this.yvel;
//to reverse the direction of the ball when hitting walls
if((this.xvel<0 && this.yvel >0) && thetaInc <0){
thetaInc = -1*thetaInc;
}
else if((this.xvel <0 && this.yvel>0) && thetaInc >0){
thetaInc = -1*thetaInc
}
else if((this.xvel >0 && this.yvel >0) && thetaInc >0){
thetaInc = -1 * thetaInc;
}
else if((this.xvel > 0 && this.yvel < 0)&& thetaInc <0){
thetaInc = -1 * thetaInc;
}
}
if(this.x > canvas.width - this.r || this.x - this.r < 0){
this.xvel = -1*this.xvel;
}
}
resize(){
var that = this;
that.up = true;
that.r = 0;
that.increment = 10;
that.ceiling = 100;
function PerformCalc() {
if (that.up == true && that.r <= that.ceiling) {
that.r += that.increment
if (that.r == that.ceiling) {
that.up = false;
}
} else {
that.up = false
that.r -= that.increment;
if (that.r == 0) {
that.up = true;
}
}
console.log(that.r);
}
setInterval(PerformCalc, 1000);
}
colour(){
}
}
//Intersect function takes a ball as a perameter
//ball will be the the object used to test if the two are touching.
function intersect(ball,ball1) {
//the x and y cordinates of the first ball are subtracted from the test ball and stored
//in productX and productY
var productX = ball1.x - ball.x;
var productY = ball1.y - ball.y;
//pythagoras theorem is used to get the distance between both center points of each circle.
var distance = Math.sqrt(productX * productX + productY * productY);
//A condition is used to check if the distance between both bencer point of each circle
//is less than or equal to the sum of both radii the circles are touching.
//the result is p[rinted out to the console
if (distance <= (ball1.r + ball.r)) {
dx = ball.x-ball1.x;
dy = ball.y-ball1.y;
collision_angle = Math.atan2(dy,dx);
magnitude_1 = Math.sqrt(ball.xvel*ball.xvel+ball.yvel*ball.yvel);
magnitude_2 = Math.sqrt(ball1.xvel*ball1.xvel+ball1.yvel*ball1.yvel);
direction_1 = Math.atan2(ball.yvel, ball.xvel);
direction_2 = Math.atan2(ball1.yvel, ball1.xvel);
new_xvel_1 = magnitude_1 * Math.cos(direction_1-collision_angle);
new_yvel_1 = magnitude_1 * Math.sin(direction_1-collision_angle);
new_xvel_2 = magnitude_2 * Math.cos(direction_2-collision_angle);
new_yvel_2 = magnitude_1 * Math.sin(direction_2-collision_angle);
final_xvel_1 = ((ball.mass-ball1.mass)*new_xvel_1+(ball1.mass+ball1.mass)*new_xvel_2)/(ball.mass+ball1.mass);
final_xvel_2 = ((ball.mass+ball.mass)*new_xvel_1+(ball1.mass-ball.mass)*new_xvel_2)/(ball.mass+ball1.mass);
final_yvel_1 = new_yvel_1;
final_yvel_2 = new_yvel_2;
ball.xvel = Math.cos(collision_angle)*final_xvel_1+Math.cos(collision_angle+Math.PI/2)*final_yvel_1;
ball.yvel = Math.sin(collision_angle)*final_xvel_1+Math.sin(collision_angle+Math.PI/2)*final_yvel_1;
ball1.xvel = Math.cos(collision_angle)*final_xvel_2+Math.cos(collision_angle+Math.PI/2)*final_yvel_2;
ball1.yvel = Math.sin(collision_angle)*final_xvel_2+Math.sin(collision_angle+Math.PI/2)*final_yvel_2;
}
}
canvas.addEventListener("click", function(event) {
var clickX = event.clientX - canvas.offsetLeft;
var clickY = event.clientY- canvas.offsetTop;
b1.x = clickX;
b1.y = clickY;
});
// Add a Javascript event listener to the keypress event.
window.addEventListener("keypress", function(event) {
// Just log the event to the console.
console.log(event);
});
//keypresses with jQuery
$(document.body).on('keydown', function(e) {
console.log(e.which);
switch (e.which) {
// key code for left arrow
case 37:
console.log('left arrow key pressed!');
b1.xvel --;
break;
//keycode for up
case 38:
console.log('up key pressed');
b1.yvel++;
break;
//key code for right
case 39:
console.log('right arrow key pressed!');
b1.xvel++;
break;
//key code for down
case 40:
console.log('down arrow key pressed!');
b1.yvel--;
break;
//key code for + key to increase spin
case 107:
console.log('down arrow key pressed!');
thetaInc +=.001;
break;
//key code for - key to decrease spin
case 109:
console.log('down arrow key pressed!');
thetaInc -=.001;
break;
}
});
b1 = new Ball(200,200,40,1,1,50);
b2 = new Ball(100,100,40,2,2,5);
b1.resize();
// A function to repeat every time the animation loops.
function repeatme() {
//clear canvas for each frame of the animation.
ctx.clearRect(0,0,500,500);
// Draw the ball (stroked, not filled).
b1.draw();
b2.draw();
b1.move();
b2.move();
intersect(b1,b2);
//put repeatme function into the animation frame and store it in animate
animate = window.requestAnimationFrame(repeatme);
}
// Get the animation going.
repeatme();
</script>
</body>
</html>

Function works only sometimes. How could this be?

In my snake game I am trying to catch the y-coordinate of a rectangle (food).
Now check out this function:
function eat() {
console.log('food_x:' + food_position_x + ' x:' + x + ' / food_y:' + food_position_y + ' y:' + y);
if (y == food_position_y) {
throw new Error("MATCH!"); // This is not an error. Just trying to stop the script
}
}
Pretty simple, huh?
Now the weird thing about this story is: y is not always equal food_position_y!
You may want to check the full script:
(function() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
x = 0,
y = 0,
speed = 2;
x_move = speed,
y_move = 0,
food_position_x = Math.floor(Math.random() * canvas.width);
food_position_y = Math.floor(Math.random() * canvas.height);
function eat() {
console.log('food_x:' + food_position_x + ' x:' + x + ' / food_y:' + food_position_y + ' y:' + y);
if (y == food_position_y) {
throw new Error("MATCH!"); // This is not an error. Just trying to stop the script
}
}
// Drawing
function draw() {
eat();
requestAnimationFrame(function() {
draw();
});
// Draw the snake
ctx.beginPath();
ctx.rect(Math.floor(x/10)*10, Math.floor(y/10)*10, 10, 10);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.closePath();
// Draw the food
ctx.beginPath();
ctx.rect(Math.floor(food_position_x/10)*10, Math.floor(food_position_y/10)*10, 10, 10);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
// Increase the value of x and y in order to animate
x = x + x_move;
y = y + y_move;
}
draw();
// Key Pressing
document.addEventListener('keydown', function(event) {
switch(event.keyCode) {
case 40: // Moving down
if (x_move != 0 && y_move != -1) {
x_move = 0;
y_move = speed;
}
break;
case 39: // Moving right
if (x_move != -1 && y_move != 0) {
x_move = speed;
y_move = 0;
}
break;
case 38: // Moving top
if (x_move != 0 && y_move != 1) {
x_move = 0;
y_move = -speed;
}
break;
case 37: // Moving left
if (x_move != 1 && y_move != 0) {
x_move = -speed;
y_move = 0;
}
break;
}
});
})();
What do I mean by "y is not always equal food_position_y"?
Please go ahead and make yourself an impression of it. Try to run this script a multiple times.
For now, don't worry about x. Just try to catch the food and you will notice, that sometimes you will get an "error" (which is good!) and the game stops but sometimes when the snake is even on the same height as the food, you won't get this fancy error and the game goes on.
Question: Why?
As 4castle explained,
The amount it is moving is dictated by speed. Speed is set to 2. If the y coordinate for the "snake" is an odd number, then it will be incremented by two each time and will never reach the same y-coordinate for the "food" (if food is even). A way to see this is to switch the speed to 1. This of course will make your snake move at half speed, so after you visually see your program working - switch back to speed = 2 and tweak the food's y-coordinate variable to be an odd number as well.
Look closely at the console output, because it shows the culprit:
food_x:31 x:34 / food_y:97 y:98
food_x:31 x:34 / food_y:97 y:96
Your snake is just never on the same exact position as the food. The eat() function is called every time. However, your condition isn't always true.
The solution to this problem would be to just check if y somewhat equal (within tolerance of speed) to food_position_y:
if (Math.abs(y - food_position_y) <= Math.abs(speed)) {
throw;
}

Categories