This is my first post so I hope that I put everything correctly down below here! :-P
I have a problem. Currently I'm making a snake game with a school friend of mine. We are making a snake game by using node.js so we can create a multiplayer snake game. Nothing really extreme just the basic snake game but then with more players.
Currently I've created a code that can move the snake and also will place food randomly on the canvas (I'm using the HTML5 Canvas element in which the game is played).
Now I'm stuck because I want to create a function that allows the snake to eat the food and then grow longer. As far as I know I have the function as it should be, but for some reason it does not work. My knowledge of javascript is very basic so what I'm doing here is all new for me. I will put the entire code down below so you can see it through.
I've created 2 javascript files. one that has the snake code in it and the other has the food code in it. The function that I'm referring about is inside the Snake script under Snake.prototype.move
I really hope that someone can help me out so I can proceed with our game.
This is the main code (Snake code):
var game;
$(document).ready(function(){
var canvas = $("#canvas")[0];
var ctx = canvas.getContext("2d");
var w = $("#canvas").width();
var h = $("#canvas").height();
var cw = 10;
ctx.fillStyle = "white";
ctx.fillRect(0, 0, w, h);
ctx.strokeStyle = "black";
ctx.strokeRect(0, 0, w, h);
var GameObject = function() {
this.snakes = [];
this.foods = [];
}
game = new GameObject();
var snake = new Snake(1, 15, 'testnaam');
snake.create();
game.snakes.push(snake);
game.foods.push(new Food(w, cw));
function loop() {
window.setTimeout(loop, 60);
ctx.clearRect(0, 0, w, h);
if(game.snakes.lenght !== 0) {
for(i = 0; i < game.snakes.length; i++) {
var s = game.snakes[i];
s.paint(ctx, game);
}
} else {
}
if(game.foods.length !== 0) {
for(var i = 0; i < game.foods.length; i++) {
var f = game.foods[i];
f.paint(ctx);
}
} else {
}
}
loop();
document.addEventListener('keydown', function(e) {
e.preventDefault();
var key = e.which;
if(key == "37" && snake.direction !="right") snake.direction = "left";
else if(key == "38" && snake.direction !="down") snake.direction = "up";
else if(key == "39" && snake.direction !="left") snake.direction = "right";
else if(key == "40" && snake.direction !="up") snake.direction = "down";
}, false);
});
var Snake = function(player, length, alias){
this.length = length;
this.pieces = [];
this.player = player;
this.position = {x: 0, y: 0};
this.direction = "right";
this.color = this.color();
this.getName = alias;
}
Snake.prototype.create = function(){
for(var i = this.length -1; i >= 0; i--) {
this.pieces.push({x: i, y: 0});
}
};
Snake.prototype.paint = function(ctx, game){
this.move(game);
for(var i = 0; i < this.pieces.length; i++){
var c = this.pieces[i];
ctx.fillStyle = this.color;
ctx.fillRect(c.x*10, c.y*10, 10, 10);
}
};
Snake.prototype.color = function(){
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.round(Math.random() * 15)];
}
return color;
};
Snake.prototype.getName = function() {
return this.alias;
}
Snake.prototype.getPosition = function() {
return {x: this.x, y: this.y }
}
Snake.prototype.move = function(game) {
var nx = this.pieces[0].x;
var ny = this.pieces[0].y;
if(this.direction == "right")nx++;
else if(this.direction == "left")nx--;
else if(this.direction == "up")ny--;
else if(this.direction == "down")ny++;
if(Snake == game.foods[0].position.x && Snake == game.foods[0].position.y){
console.log("raak");
var tail = {
x: nx,
y: ny
};
Food.create();
} else{
var tail = this.pieces.pop();
tail.x = nx;
tail.y = ny;
}
this.pieces.unshift(tail);
};
Snake.prototype.collision = function(x, y, array){
for(var i = 0; i < array.length; i++){
if(array[i].x == x && array[i].y == y)
return true;
}
return false;
};
And This is the code for the food
var Food = function(w, cw){
this.w = w;
this.cw = cw;
this.position = this.create();
console.log(this.position);
};
Food.prototype.create = function(){
var min = 0;
var max = (this.w/this.cw);
return position = {
x: Math.round(min + Math.random()* (Math.abs(min)+(max)))*this.cw,
y: Math.round(min + Math.random()* (Math.abs(min)+(max)))*this.cw
}
};
Food.prototype.paint = function(ctx){
ctx.fillStyle = "#000";
ctx.fillRect(this.position.x,this.position.y,10,10)
};
Thank you very much!
Live demo
I had to fiddle with it a lot.. there is a lot of weirdness going on in the code, but this is the area I messed with primarily to get it working.
Snake.prototype.move = function (game) {
var nx = this.pieces[0].x;
var ny = this.pieces[0].y;
if (this.direction == "right") nx++;
else if (this.direction == "left") nx--;
else if (this.direction == "up") ny--;
else if (this.direction == "down") ny++;
/*
* you werent testing the front pieces x and y, also since your multiplying the snake
* pieces by 10, you need to divide the food positions by 10 for the coords to match up
*/
if (this.pieces[0].x == game.foods[0].position.x / 10 && this.pieces[0].y == game.foods[0].position.y / 10) {
console.log("raak");
var tail = {
x: nx,
y: ny
};
// push your piece
this.pieces.push(tail);
// you have an array for prob to eventually have more than one on the screen.
// for now i set food[0] to be a new piece of food. We dont have ref's to w and cw in this
// func to I passed in the values.
game.foods[0] = new Food(canvas.width, 10);
} else {
var tail = this.pieces.pop();
tail.x = nx;
tail.y = ny;
// only unshift when we havent added a piece
this.pieces.unshift(tail);
}
};
Basically you weren't testing the positions at all and you werent dividing the foods position by 10 when checking so the snake's position could never match the foods.
Related
I recently made this game and wanted to ask how to improve it. I made an alert box inside the javascript for when the game ends. It works but it's not beautiful. so I wanted to ask how can I change the Color and the message on the top of the alert box? right now a webpage message has been written.
And I wanted to add that it could be played from the phone something like the arrow buttons. I found something for java but nothing for javascript and wanted to know if its possible and how do I doit?
here is the code:
<html>
<head>
<meta charset='utf-8'/>
<link rel="stylesheet" href="css/style.css">
<h1> <p align="left"><font color="rebeccapurple"> Snake developed by agente00mcm </font></p> </h1>
</head>
<body>
<div class= 'game'>
<div id = 'home'>
<canvas id='mycanvas' width='800' height='800'>
</canvas>
</div>
<p>Press start to start the game!</p>
<button id='btn'>START</button>
</div>
<script>
var mycanvas = document.getElementById('mycanvas');
var ctx = mycanvas.getContext('2d');
var snakeSize = 10;
var w = 800;
var h = 800;
var score = 0;
var snake;
var snakeSize = 10;
var food;
var drawModule = (function () {
var bodySnake = function(x, y) {
ctx.fillStyle = 'green';
ctx.fillRect(x*snakeSize, y*snakeSize, snakeSize, snakeSize);
ctx.strokeStyle = 'darkgreen';
ctx.strokeRect(x*snakeSize, y*snakeSize, snakeSize, snakeSize);
}
var pizza = function(x, y) {
ctx.fillStyle = 'yellow';
ctx.fillRect(x*snakeSize, y*snakeSize, snakeSize, snakeSize);
ctx.fillStyle = 'red';
ctx.fillRect(x*snakeSize+1, y*snakeSize+1, snakeSize-2, snakeSize-2);
}
var scoreText = function() {
var score_text = "Score: " + score;
ctx.fillStyle = 'blue';
ctx.fillText(score_text, 145, h-5);
}
var drawSnake = function() {
var length = 4;
snake = [];
for (var i = length-1; i>=0; i--) {
snake.push({x:i, y:0});
}
}
var paint = function(){
ctx.fillStyle = 'lightgray';
ctx.fillRect(0, 0, w, h);
ctx.strokeStyle = 'black';
ctx.strokeRect(0, 0, w, h);
btn.setAttribute('disabled', true);
var snakeX = snake[0].x;
var snakeY = snake[0].y;
if (direction == 'right') {
snakeX++; }
else if (direction == 'left') {
snakeX--; }
else if (direction == 'up') {
snakeY--;
} else if(direction == 'down') {
snakeY++; }
if (snakeX == -1 || snakeX == w/snakeSize || snakeY == -1 || snakeY == h/snakeSize || checkCollision(snakeX, snakeY, snake)) {
//restart game
alert("Game Over \nYour Score: "+score);
document.location.reload();
btn.removeAttribute('disabled', true);
ctx.clearRect(0,0,w,h);
gameloop = clearInterval(gameloop);
return;
}
if(snakeX == food.x && snakeY == food.y) {
var tail = {x: snakeX, y: snakeY}; //Create a new head instead of moving the tail
score ++;
createFood(); //Create new food
} else {
var tail = snake.pop(); //pops out the last cell
tail.x = snakeX;
tail.y = snakeY;
}
//The snake can now eat the food.
snake.unshift(tail); //puts back the tail as the first cell
for(var i = 0; i < snake.length; i++) {
bodySnake(snake[i].x, snake[i].y);
}
pizza(food.x, food.y);
scoreText();
}
var createFood = function() {
food = {
x: Math.floor((Math.random() * 30) + 1),
y: Math.floor((Math.random() * 30) + 1)
}
for (var i=0; i>snake.length; i++) {
var snakeX = snake[i].x;
var snakeY = snake[i].y;
if (food.x===snakeX && food.y === snakeY || food.y === snakeY && food.x===snakeX) {
food.x = Math.floor((Math.random() * 30) + 1);
food.y = Math.floor((Math.random() * 30) + 1);
}
}
}
var checkCollision = function(x, y, array) {
for(var i = 0; i < array.length; i++) {
if(array[i].x === x && array[i].y === y)
return true;
}
return false;
}
var init = function(){
direction = 'down';
drawSnake();
createFood();
gameloop = setInterval(paint, 80);
}
return {
init : init
};
}());
(function (window, document, drawModule, undefined) {
var btn = document.getElementById('btn');
btn.addEventListener("click", function(){ drawModule.init();});
document.onkeydown = function(event) {
keyCode = window.event.keyCode;
keyCode = event.keyCode;
switch(keyCode) {
case 37:
if (direction != 'right') {
direction = 'left';
}
console.log('left');
break;
case 39:
if (direction != 'left') {
direction = 'right';
console.log('right');
}
break;
case 38:
if (direction != 'down') {
direction = 'up';
console.log('up');
}
break;
case 40:
if (direction != 'up') {
direction = 'down';
console.log('down');
}
break;
}
}
})(window, document, drawModule);
</script>
</body>
</html>
and besides the Problem I wanted to ask how do you guys find it and if it Needs any improvement beside the alert box style.
thanks for your support!
The alert box is a system object and cannot be styled with css. You need to create an element in your page that replicates the behavior of the alert if you want to style it. You can find plenty of libraries that do this such as:
SweetAlert
jQueryUi dialog
AlertifyJs
Have fun developing games :)
I am new to Javascript. I am trying to make a canvas game similar to Snake, but without the fruits.
The game is over if the player crosses his own path. The following is my code. Do you know how can I determine when the red rectangle crosses its own path and use the game over function?
Thank you!
var player;
var touch = 0;
function startGame() {
myGameArea.start();
player = new component(30, 30, "red", 270, 270);
}
var myGameArea = {
canvas: document.createElement("canvas"),
start: function() {
this.canvas.width = 600;
this.canvas.height = 600;
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.key = e.keyCode;
})
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function component(width, height, color, x, y) {
this.gamearea = myGameArea;
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;
}
}
function updateGameArea() {
/*myGameArea.clear();*/
player.speedX = 0;
player.speedY = 0;
if (myGameArea.key == 37) {
player.speedX = -10;
}
if (myGameArea.key == 39) {
player.speedX = 10;
}
if (myGameArea.key == 38) {
player.speedY = -10;
}
if (myGameArea.key == 40) {
player.speedY = 10;
}
if (player.x <= 0 || player.x >= 570 || player.y <= 0 || player.y >= 570) { //When the player goes out of the canvas
gameOver();
}
player.newPos();
player.update();
}
function gameOver() {
var r = confirm("GAME OVER. Restart?");
if (r == true) {
window.location.reload();
} else {
window.open("https://www.google.ca");
}
}
canvas {
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
background-color: #000;
}
<body onload="startGame()">
</body>
Array as a Queue.
The way this game is traditionally done is using a special array type called a queue. Like a real queue you have items added at one end and removed at the other, or first in first out.
Javascript does not have a special array type for a queue but it has all the functions needed to implement a queue.
Push and shift
Array.push(item); // pushes an item onto the top of the array
Array.shift(); // removes an item from the start of the queue
So for the snake game imagine the head as the end of the queue. Every time it moves one forward you place another item on the queue. At the other end you remove an item if the length of the array is longer than the snake length;
var snake = [];
var snakeLength = 10;
function snakeMove(x,y){ // position to move head
checkForHit(x,y); // see below
snake.push({x:x,y:y}); // put another headpiece on the queue
if(snake.length > snakeLength){ // is the length longer than it should be
snake.shift(); // remove a tail item
}
}
To draw the snake you just iterate each part drawing it at the X,y position
To test if the snake has run its self over use the following function
function checkForHit(x,y){
for(var i = 0; i < snake.length; i++){
if(snake[i].x === x && snake[i].y === y){
// Snake has hit its self
}
}
}
When the snake eats something it traditionally grows in length. this is easily done by simply increasing the length variable. snakeLength += 1 makes the queue longer.
And a demo as i have not played the game in so long why not.
"use strict";
var score = 0;
var canvas = document.createElement("canvas");
var scoreE = document.createElement("div");
scoreE.style.color = "white";
scoreE.style.font = "16px arial";
scoreE.style.position = "absolute";
scoreE.style.top = "10px";
scoreE.style.left = "10px";
scoreE.style.width = "600px";
scoreE.style.textAlign = "center";
scoreE.textContent = "Click canvas area to get focus";
canvas.width = 600;
canvas.height = 200;
var ctx = this.canvas.getContext("2d");
document.body.appendChild(canvas);
document.body.appendChild(scoreE);
var lastKeyDown = 0;
window.addEventListener('keydown', function(e) {
lastKeyDown = e.keyCode;
e.preventDefault()
})
var snakePartSize = 8;
var playWidth = canvas.width /snakePartSize;
var playHeight = canvas.height /snakePartSize;
var snake = [];
var snakeLength = 10;
var snakePosX = 0;
var snakePosY = 0;
var snakeDirX = 0;
var snakeDirY = 0;
var snakeSpeed = 16; // number of frame between moves
var gameOver = true;
var instDrawn = false;
var food = [];
var foodFreq = 60;
var yum = 0;
var yumCol = ["red","orange","yellow"];
function startSnake(){
ctx.fillStyle = "black";
ctx.fillRect(0,0,canvas.width,canvas.height);
snakePosX = Math.floor(playWidth / 2);
snakePosY = Math.floor(playHeight / 2);
snakeDirX = 0;
snakeDirY = 0;
snakeLength = 10;
snake = [];
snakeSpeed = 16;
move(snakePosX,snakePosY); // set first pos
food = [];
score = 0;
}
function testHit(x,y){
if(x < 0 || y < 0 || y >= playHeight || x >= playWidth ){
return true;
}
for(var i = 0; i < snake.length; i ++){
if(snake[i].x === x && snake[i].y === y){
return true;
}
}
}
function testFood(x,y){
for(var i = 0; i < food.length; i ++){
if(food[i].x === x && food[i].y === y){
food.splice(i,1);
i --;
yum = 4;
score += 100;
snakeLength += 1;
if(snakeLength % 4 === 0){
snakeSpeed -= snakeSpeed > 1 ? 1:0;
}
}
}
}
function addFood(){
var x = Math.floor(Math.random() * playWidth );
var y = Math.floor(Math.random() * playHeight );
if(!testHit(x,y)){
food.push({x:x,y:y});
drawFood();
}
}
function move(x,y){
if(testHit(x,y)){
gameOver = true;
return;
}
testFood(x,y);
snake.push({x : x, y : y});
drawSnakeHead();
if(snake.length > snakeLength){
drawSnakeTail();
snake.shift();
}
}
function drawYum(){
for(var i = 0; i < snake.length; i ++){
ctx.fillStyle = yumCol[yum];
ctx.fillRect(snake[i].x*snakePartSize, snake[i].y*snakePartSize, snakePartSize, snakePartSize);
}
}
function drawFood(){
var f = food[food.length-1];
ctx.fillStyle = "green";
ctx.fillRect(f.x*snakePartSize, f.y*snakePartSize, snakePartSize, snakePartSize);
}
function drawSnakeHead(){
var head = snake[snake.length-1];
ctx.fillStyle = "red";
ctx.fillRect(head.x*snakePartSize, head.y*snakePartSize, snakePartSize, snakePartSize);
}
function drawSnakeTail(){
var head = snake[0];
ctx.fillStyle = "black";
ctx.fillRect(head.x*snakePartSize, head.y*snakePartSize, snakePartSize, snakePartSize);
}
var counter = 0;
function update(){
counter += 1;
if(!gameOver){
if(snakeDirX === 0){
if(lastKeyDown === 37){ // left
snakeDirX = -1;
snakeDirY = 0;
}
if(lastKeyDown === 39){ // right
snakeDirX = 1;
snakeDirY = 0;
}
}
if(snakeDirY === 0){
if(lastKeyDown === 38){ // up
snakeDirY = -1;
snakeDirX = 0;
}
if(lastKeyDown === 40){ // down
snakeDirY = 1;
snakeDirX = 0;
}
}
lastKeyDown = 0;
if(counter % foodFreq ===0){
addFood();
}
if(counter % snakeSpeed === 0){
snakePosX += snakeDirX;
snakePosY += snakeDirY;
score += 1;
move(snakePosX ,snakePosY);
}
if((counter % 2 === 0) && yum > 0){
yum -= 1;
drawYum();
}
scoreE.textContent = "Score : "+ score;
}
if(gameOver){
if(!instDrawn){
instDrawn = true;
ctx.fillStyle = "white";
ctx.font = "32px arial";
ctx.textAlign = "center";
ctx.fillText("GAME OVER",canvas.width /2, canvas.height /2);
ctx.font = "16px arial";
ctx.fillText("Press a direction key to start.",canvas.width /2, canvas.height /2+32);
}
if(lastKeyDown >= 37 && lastKeyDown <= 40){
gameOver = false;
instDrawn = false;
counter = -1;
startSnake();
}
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);
startSnake();
I am trying to build a snake game from a tutorial in JavaScript and Canvas. And at this moment I am a receiving an error of (TypeError: y is undefined) on this line:
return this._grid[x][y];
which is part of the var grid object. Would really appreciate it if someone could point me in the right direction so I can finish the game!!!
Thanks.
<script>
//Constants
var COLS = 26, ROWS = 26;
// IDs
var EMPTY=0, SNAKE = 1, FRUIT = 2;
// Directions
var LEFT = 0, UP = 1, RIGHT = 2, DOWN = 3;
// KeyCodes
var KEY_LEFT=37, KEY_UP=38, KEY_RIGHT=39, KEY_DOWN=40;
var grid = {
width: null,
height: null,
_grid: null,
init: function(d,c,r){
this.width = c;
this.height = r;
this._grid = [];
for(var x=0; x<c; x++){
this._grid.push([]);
for(var y=0; y < r; y++){
this._grid[x].push(d);
}
}
},
set: function(val,x,y){
this._grid[x][y] = val;
},
get: function(x,y){
return this._grid[x][y];
}
}
var snake = {
direction: null,
last: null,
_queue: null,
init: function(d,x,y){
this.direction = d;
this._queue = [];
this.insert(x,y);
},
insert: function(x,y){
this._queue.unshift({x:x, y:y});
this.last = this._queue[0];
},
remove: function(){
return this._queue.pop();
}
}
function setFood() {
var empty = [];
for (var x = 0; x < grid.width; x++) {
for (var y = 0; y < grid.height; y++) {
if (grid.get(x, y) === EMPTY) {
empty.push({x:x, y:y});
}
}
}
var randpos = empty[Math.floor(Math.random()*empty.length)];
grid.set(FRUIT, randpos.x, randpos.y);
}
//Game objects
var canvas, ctx, keystate, frames, score;
function main() {
canvas = document.createElement("canvas");
canvas.width = COLS*20;
canvas.height = ROWS*20;
ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
ctx.font = "12px Helvetica"
frames = 0;
keystate = {};
document.addEventListener("keydown", function(evt) {
keystate[evt.keyCode] = true;
});
document.addEventListener("keyup", function(evt) {
delete keystate[evt.keyCode];
});
init();
loop();
}
function init(){
grid.init(EMPTY, COLS, ROWS);
var sp = {x:Math.floor(COLS/2), y:ROWS-1};
snake.init(UP, sp.x, sp.y);
grid.set(SNAKE, sp.x, sp.y);
setFood();
}
function loop(){
update();
draw();
window.requestAnimationFrame(loop, canvas);
}
function update() {
frames++;
if (keystate[KEY_LEFT] && snake.direction !== RIGHT)
snake.direction = LEFT;
if (keystate[KEY_UP] && snake.direction !== DOWN)
snake.direction = UP;
if (keystate[KEY_RIGHT] && snake.direction !== LEFT)
snake.direction = RIGHT;
if (keystate[KEY_DOWN] && snake.direction !== UP)
snake.direction = DOWN;
if (frames%5 === 0) {
var nx = snake.last.x;
var ny = snake.last.y;
switch (snake.direction) {
case LEFT:
nx--;
break;
case UP:
ny--;
break;
case RIGHT:
nx++;
break;
case DOWN:
ny++;
break;
}
if (grid.get(nx, ny) === FRUIT) {
var tail = {x:nx, y:ny};
score++;
setFood();
} else {
var tail = snake.remove();
grid.set(EMPTY, tail.x, tail.y);
tail.x = nx;
tail.y = ny;
}
grid.set(SNAKE, tail.x, tail.y);
snake.insert(tail.x, tail.y);
}
if (0 > nx || nx > grid.width-1 ||
0 > ny || ny > grid.height-1
|| grid.get(nx, ny) === SNAKE
) {
return init();
}
}
function draw() {
var tw = canvas.width/grid.width;
var th = canvas.height/grid.height;
for (var x = 0; x < grid.width; x++) {
for (var y = 0; y < grid.height; y++) {
switch (grid.get(x, y)) {
case EMPTY:
ctx.fillStyle = "#fff";
break;
case SNAKE:
ctx.fillStyle = "#0ff";
break;
case FRUIT:
ctx.fillStyle = "#f00";
break;
}
ctx.fillRect(x*tw, y*th, tw, th);
}
}
ctx.fillStyle = "#000";
ctx.fillText("SCORE: " + score, 10, canvas.height-10);
};
main();
</script>
If you are passing data that is not guaranteed to be in the correct range you need to vet or trap the out of range value/s..
If you believe the data does not need vetting you need to find the source of the bad value x that is indexing an undefined array item.
For debugging either add a breakpoint in the getter and use the debugger to find out what value of x is incorrect and throwing the error or Set the debugger to "break on error" and examine the value of x that is giving you the bad referance.
Change your get function to
get: function(x,y){
try{
return this._grid[x][y];
} catch(e){
console.error("access to _grid["+x+ "][" + y +"] failed");
throw e;
}
}
So you can see what the x value is when the error is throw.
Once you find out why and fix the problem you can remove the try catch
I used this tutorial: Snake Game HTML5 Game Programming Tutorial javascript to make a similar game.
The problem is about the movement of the snake:
The snake should move properly after pressing a arrow key but it doesn't and it moves automatically by itself.
At the same time, the food (apple) is not visible in the game.
Here is the JS Fiddle with CSS and HTML file included:
https://jsfiddle.net/L734u1y9/#&togetherjs=SeiyP5qa1m
Can somebody help me to find the error?
//Constants
var COLS= 26, ROWS = 26;
//IDs
var EMPTY = 0, SNAKE = 1, FRUIT = 2;
//Directions
var LEFT = 0, UP = 1, RIGHT = 2, DOWN = 3;
//KeyCodes
var KEY_LEFT = 27, KEY_UP = 38, KEY_RIGHT = 39, KEY_DOWN = 40;
var grid= {
width: null,
height:null,
_grid: null,
init: function(d, c, r) {
this.width = c;
this.height = r;
this._grid = [];
for (var x = 0; x < c; x++) {
this._grid.push([]);
for (var y = 0; y < r; y++){
this._grid[x].push(d);
}
}
},
set: function(val, x, y) {
this._grid[x][y] = val;
},
get: function (x, y) {
return this._grid[x][y];
}
};
var snake= {
direction:null,
last: null,
_queue: null,
init: function (d, x, y) {
this.direction = d;
this._queue = [];
this.insert (x, y);
},
insert: function(x, y) {
this._queue.unshift({x:x, y:y});
this.last = this._queue[0];
},
remove: function() {
return this._queue.pop();
}
};
function setFood() {
var empty = [];
for (var x = 0; x < grid.width; x++) {
for (var y = 0; y < grid.height; y++) {
if(grid.get(x, y) === EMPTY) {
empty.push({x:x, y:y});
}
}
}
var randpos = empty[Math.floor(Math.random()*empty.length)];
grid.set(FRUIT, randpos.y);
}
//Game Objects
var canvas, ctx, keystate, frames;
function main() {
canvas = document.createElement("canvas");
canvas.width =COLS*20;
canvas.height = ROWS*20;
ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
frames = 0;
keystate = {};
document.addEventListener("keydown", function(evt) {
keystate[evt.keyCode] = true;
});
document.addEventListener("keyup", function(evt) {
delete keystate[evt.keyCode];
});
init();
loop();
}
function init () {
grid.init(EMPTY,COLS, ROWS);
var sp = {x:Math.floor(COLS/2), y:ROWS-1};
snake.init (UP, sp.x, sp.y);
grid.set(SNAKE, sp.x, sp.y);
setFood();
}
function loop() {
update();
draw();
window.requestAnimationFrame(loop, canvas);
}
function update() {
frames++;
if (keystate[KEY_LEFT] && snake.direction !== RIGHT)
snake.direction = LEFT;
if (keystate[KEY_UP] && snake.direction !== DOWN)
snake.direction = UP;
if (keystate[KEY_RIGHT] && snake.direction !== LEFT)
snake.direction = RIGHT;
if (keystate[KEY_DOWN] && snake.direction !== UP)
snake.direction = DOWN;
if (frames%5 === 0 ) {
var nx = snake.last.x;
var ny = snake.last.x;
switch (snake.direction) {
case LEFT:
nx--;
break;
case UP:
ny--;
break;
case RIGHT:
nx++;
break;
case DOWN:
ny++;
break;
}
if (nx < 0 || nx > grid.width-1 ||
ny < 0 || ny > grid.height-1 ||
grid.get(nx, ny) === SNAKE
) {
return init();
}
if (grid.get(nx, ny) === FRUIT) {
var tail = {x:nx, y:ny};
setFood();
} else {
var tail = snake.remove();
grid.set(EMPTY, tail.x, tail.y);
tail.x = nx;
tail.y = ny;
}
grid.set(SNAKE, tail.x, tail.y);
snake.insert(tail.x, tail.y);
}
}
function draw() {
var tw = canvas.width/grid.width;
var th = canvas.height/grid.height;
for (var x = 0; x < grid.width; x++) {
for (var y = 0; y < grid.height; y++) {
switch (grid.get(x, y)) {
case EMPTY:
ctx.fillStyle = "#fff";
break;
case SNAKE:
ctx.fillStyle = "#0ff";
break;
case FRUIT:
ctx.fillStyle = "#f00";
break;
}
ctx.fillRect(x*tw, y*th, y*th, tw, th);
}
}
}
main();
Alright, I found part of your problem:
if (nx < 0 || nx > grid.width-1 ||
ny < 0 || ny > grid.height-1 ||
grid.get(nx, ny) === SNAKE
) {
return init();
This constantly calls init over and over which restores your snake to the default position.
Removing this line and your snake stays still until movement starts.
It still pulls down and two the right -- which hints to me that you want to check the direction handling code. Use either the debugging tools built into the browser (or console.log) to ensure those values are what you think they are.
So I have a simple snake game set up in which the score increments +1 every time the player collides with the right piece(you all the know the game). Anyway.
I want the background to change image every multiple of 5 on the score to represent a new level. Is this possible? I'm assuming it would be something along the lines of;
if score > = 5 then
var img = document.getElementById("anid");
ctx.drawImage(img, 0, 0, w, h);
I know the syntax there is very wrong but is the thinking behind it right?
// JavaScript Document
$(document).ready(function(){
//Canvas stuff
var canvas = $("#canvas")[0];
var ctx = canvas.getContext("2d");
var w = $("#canvas").width();
var h = $("#canvas").height();
//Lets save the cell width in a var for easy control
var cw =10;
var d;
var food;
var score;
if (score % 5 == 0) {
//Score is a divisor of 5, new level!
var img = document.getElementById("scream1");
ctx.drawImage(img, 0, 0, w, h);
//do what you want
}
var obstacle;
var snd = new Audio("sfx1.wav"); // buffers automatically when created
var snd2 = new Audio("sfx2.wav");
var snd3 = new Audio("sfx.wav");
var snd4 = new Audio("poke.mp3");
snd4.play();
//Timer
var max_timer = 15;
var current_timer;
var show_timer = (function () {
current_timer--;
$("#timer").text(current_timer);
if (current_timer < 0) {
$("#bonus").empty();
init();
return;
}
});
var timer_interval = setInterval(show_timer, 1000);
//Lets create the snake now
var snake_array; // an array of cells to make up the snake
function init()
{
d = "right";//default direction
create_snake();
create_food();
create_obstacle();
create_obstacle2();
create_obstacle3();
create_obstacle4();
score = 0;
current_timer = max_timer;
//Lets move the snake now using a timer
//Which will trigger the paint function
//Eevery 60ms
if(typeof game_loop != "undefined")
clearinterval(game_loop);
game_loop =setInterval(paint, 60);
}
init();
function create_snake()
{
var length = 5; //Length of the snake
snake_array = []; //Empty array to start with
for(var i = length-1; i>=0; i--)
{
//This will create a horizontal snake starting from the top left
snake_array.push({x: i,y:0});
}
}
//Lets create the food now
function create_food()
{
food = {
x: Math.round(Math.random()*(w-cw)/cw),
y: Math.round(Math.random()*(h-cw)/cw),
};
//This will create a well with x/y between 0-44
//Because there are 45(450/10) positions
//Accross the rows and columns
}
//Create next level function
function next_level()
{
var img = document.getElementById("scream1");
ctx.drawImage(img, 0, 0, w, h);
}
//Lets create the obstacle now
function create_obstacle()
{
obstacle = {
x: Math.round(Math.random()*(w-cw)/cw),
y: Math.round(Math.random()*(h-cw)/cw),
};
}
//Lets create a second obstacle
function create_obstacle2()
{
obstacle2 = {
x: Math.round(Math.random()*(w-cw)/cw),
y: Math.round(Math.random()*(h-cw)/cw),
};
}
//Lets create a third obstacle
function create_obstacle3()
{
obstacle3 = {
x: Math.round(Math.random()*(w-cw)/cw),
y: Math.round(Math.random()*(h-cw)/cw),
};
}
//Lets create a fourth obstacle
function create_obstacle4()
{
obstacle4 = {
x: Math.round(Math.random()*(w-cw)/cw),
y: Math.round(Math.random()*(h-cw)/cw),
};
}
//Lets paint the snake now
function paint()
{
//To avoid the snake trail we need to paint
//the BGon every frame
//Lets paint the canvas now
var img = document.getElementById("scream");
ctx.drawImage(img, 0, 0, w, h);
//The movement code for the snake to come here
//The logic is simple
//Pop out the tail cell
//Place it in front of the head cell
var nx = snake_array[0].x;
var ny = snake_array[0].y;
//These were the posiiton of the head cell.
//We will increment it to get the new position
//Lets add proper direction based movement now
if(d == "right")nx++;
else if(d == "left")nx--;
else if(d == "up") ny--;
else if(d == "down") ny ++;
//Lets add the game over clauses now
//This will restart the game if the snake hits the wall
//Lets add the code for the body collision
if(nx == -1 || nx == w/cw || ny == -1|| ny == h/cw||
check_collision(nx,ny, snake_array))
{
//restart game
$("#bonus").empty();
snd3.play();
init();
//Lets organise the code a bit now
return;
}
//If snake collides with obstacle, restart game
if (nx == obstacle.x && ny == obstacle.y)
{
$("#bonus").empty();
snd3.play();
init();
return;
}
//If snake collides with obstacle, restart game
if (nx == obstacle3.x && ny == obstacle3.y)
{
$("#bonus").empty();
snd3.play();
init();
return;
}
//If snake collides with obstacle, restart game
if (nx == obstacle4.x && ny == obstacle4.y)
{
$("#bonus").empty();
snd3.play();
init();
return;
}
//If snake collides with obstacle, get more time
if (nx == obstacle2.x && ny == obstacle2.y)
{
current_timer = max_timer
create_obstacle2();
snd2.play();
$("#bonus").append("<h2>Time Bonus!</h2>");
$( '#bonus' ).show(function(){
$(this).fadeOut(2000);
});
}
//Lets write the code to make the snake eat the food
//The logic is simple
//If the new head position matches with that of the food
//Create a new head instead of moving the tail
if(nx == food.x && ny == food.y)
{
var tail = {x:nx, y:ny};
score++;
if (score % 2 == 0) {
next_level();
}
create_food();
create_obstacle();
create_obstacle3();
create_obstacle4();
snd.play();
$("#bonus").empty();
}
else
{
var tail = snake_array.pop();//pops out the last cell
tail.x = nx;tail.y = ny;
}
//The snake can now eat the food
snake_array.unshift(tail);//puts the tail as the first cell
for(var i= 0;i<snake_array.length; i++)
{
var c = snake_array[i];
//Lets paint 10px wide cells
paint_cell(c.x, c.y);
}
//Lets paint the food
paint_cell(food.x, food.y);
//Lets paint the obstacle
paint_cell2(obstacle.x, obstacle.y);
//Lets paint the second obstacle
paint_cell3(obstacle2.x, obstacle2.y);
//Lets paint the third obstacle
paint_cell2(obstacle3.x, obstacle3.y);
//Lets paint the fourth obstacle
paint_cell2(obstacle4.x, obstacle4.y);
//Lets paint the score
var score_text = "Score:" + score;
ctx.fillText(score_text, 5, h-5);
}
//Lets first create a generic function to paint cells
function paint_cell(x,y)
{
ctx.fillStyle="white";
ctx.fillRect(x*cw,y*cw, cw, cw);
ctx.strokeStyle = "black";
ctx.strokeRect(x*cw,y*cw, cw, cw);
}
function paint_cell2(x,y)
{
ctx.fillStyle="orange";
ctx.fillRect(x*cw,y*cw, cw, cw);
ctx.strokeStyle = "black";
ctx.strokeRect(x*cw,y*cw, cw, cw);
}
function paint_cell3(x,y)
{
ctx.fillStyle="red";
ctx.fillRect(x*cw,y*cw, cw, cw);
ctx.strokeStyle = "black";
ctx.strokeRect(x*cw,y*cw, cw, cw);
}
function check_collision(x, y, array)
{
//This function will check the provided x/y
//coordinates exist in an array of cells or not
for(var i = 0; i<array.length; i++)
{
if(array[i].x == x && array[i].y == y)
return true;
}
return false;
}
//Lets addd the keyboard controls now
$(document).keydown(function(e){
var key = e.which;
//We will add another clause to prevent reverse gear
if(key == "37" && d!= "right") d = "left";
else if(key == "38" && d!= "down") d="up";
else if(key == "39" && d!= "left") d="right";
else if(key == "40" && d!= "up") d="down";
//The snake is now keyboard controllable
})
})
You can use the % operator to solve this. MSDN: http://msdn.microsoft.com/en-us/library/ie/9f59bza0(v=vs.94).aspx
Code
if (score % 5 == 0) {
//Score is a divisor of 5, new level!
var img = document.getElementById("anid");
//do what you want
}
Here's a fiddle demonstrating the concept: http://jsfiddle.net/vCHCG/