base game working
This commit is contained in:
+65
-15
@@ -5,11 +5,15 @@ const [EMPTY, FOOD, WALL, SNAKE]=Array(4).keys();
|
||||
const ifNaN=(v, r) => isNaN(v)?r:v;
|
||||
|
||||
class SnekGame {
|
||||
constructor(settings, canvas) {
|
||||
constructor(settings, canvas, rules) {
|
||||
// build the world
|
||||
this.dimensions=[...settings.dimensions];
|
||||
this.world=Array(settings.dimensions[0])
|
||||
.forEach((_, i, a) => a[i]=Array(settings.dimensions[1]).fill(EMPTY));
|
||||
this.world=Array(settings.dimensions[0]);
|
||||
for(let i=0; i<settings.dimensions[0]; i++) {
|
||||
this.world[i]=Array(settings.dimensions[1]);
|
||||
this.world[i].fill(EMPTY);
|
||||
}
|
||||
console.log(this);
|
||||
settings.walls.forEach(([x, y]) => this.world[x][y]=WALL);
|
||||
settings.food.forEach(([x, y]) => this.world[x][y]=FOOD);
|
||||
settings.snake.forEach(([x, y]) => this.world[x][y]=SNAKE);
|
||||
@@ -20,8 +24,8 @@ class SnekGame {
|
||||
// get the head and initial direction
|
||||
this.head=[...settings.snake[0]];
|
||||
this.direction=[
|
||||
ifNaN(settings.snake[1][0]-settings.snake[0][0], 1),
|
||||
ifNaN(settings.snake[1][1]-settings.snake[0][1], 0)
|
||||
ifNaN(settings.snake[0][0]-settings.snake[1][0], 1),
|
||||
ifNaN(settings.snake[0][1]-settings.snake[1][1], 0)
|
||||
];
|
||||
|
||||
// get the snake and the fruits themselves
|
||||
@@ -32,24 +36,40 @@ class SnekGame {
|
||||
this.canvas=canvas;
|
||||
this.ctx=canvas.getContext('2d');
|
||||
//TODO this.gl=canvas.getContext('webgl');
|
||||
|
||||
// load the custom rules
|
||||
this.rules=Object.assign({
|
||||
fruitRegrow: true,
|
||||
speedIncrease: true,
|
||||
worldWrap: true,
|
||||
winCondition: 'none',
|
||||
scoreSystem: 'fruit'
|
||||
}, rules, settings);
|
||||
}
|
||||
|
||||
draw() {
|
||||
// clear the canvas, because it's easier than having to deal with everything
|
||||
this.ctx.clearRect(0, 0, this.canvas.with, this.canvas.height);
|
||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
// get the cell size and offset
|
||||
const cellSize=Math.min(
|
||||
this.canvas.with/this.dimensions[0],
|
||||
this.canvas.width/this.dimensions[0],
|
||||
this.canvas.height/this.dimensions[1]
|
||||
);
|
||||
const offsetX=(this.canvas.width-cellSize*this.dimensions[0])/2;
|
||||
const offsetY=(this.canvas.height-cellSize*this.dimensions[1])/2;
|
||||
|
||||
// draw the border around our game area
|
||||
this.ctx.fillStyle='black';
|
||||
this.ctx.fillRect(0, 0, this.canvas.width, offsetY);
|
||||
this.ctx.fillRect(0, 0, offsetX, this.canvas.height);
|
||||
this.ctx.fillRect(offsetX+cellSize*this.dimensions[0], 0, offsetX, this.canvas.height);
|
||||
this.ctx.fillRect(0, offsetY+cellSize*this.dimensions[1], this.canvas.width, offsetY);
|
||||
|
||||
// draw our walls
|
||||
const wall=assets.get('wall');
|
||||
for(let x=0; x<this.dimensions[0]; x++) {
|
||||
for(let y=0; x<this.dimensions[1]; y++) {
|
||||
for(let y=0; y<this.dimensions[1]; y++) {
|
||||
switch(this.world[x][y]) {
|
||||
case WALL:
|
||||
this.ctx.drawImage(
|
||||
@@ -95,7 +115,7 @@ class SnekGame {
|
||||
|
||||
// our fruit has a nice animation to it between .8 and 1.2 scale
|
||||
const ms=Date.now();
|
||||
const fruitScale=Math.sin(ms/1000*Math.PI)*.2+1
|
||||
const fruitScale=Math.sin(ms/400*Math.PI)*.2+1
|
||||
const fruit=assets.get('fruit');
|
||||
this.fruits.forEach(([x, y]) => {
|
||||
this.ctx.drawImage(
|
||||
@@ -119,6 +139,16 @@ class SnekGame {
|
||||
const tail=this.snake.pop();
|
||||
this.world[tail[0]][tail[1]]=EMPTY;
|
||||
|
||||
// check for out of world conditions
|
||||
if(head[0]<0 || head[0]>=this.dimensions[0] || head[1]<0 || head[1]>=this.dimensions[1]) {
|
||||
if(this.rules.worldWrap) {
|
||||
head[0]=(head[0]+this.dimensions[0])%this.dimensions[0];
|
||||
head[1]=(head[1]+this.dimensions[1])%this.dimensions[1];
|
||||
} else {
|
||||
return this.die();
|
||||
}
|
||||
}
|
||||
|
||||
switch(this.world[head[0]][head[1]]) {
|
||||
// you hit, you die
|
||||
case WALL:
|
||||
@@ -126,7 +156,7 @@ class SnekGame {
|
||||
return this.die();
|
||||
|
||||
// you eat, you don't die
|
||||
case FRUIT:
|
||||
case FOOD:
|
||||
// re-grow the snake
|
||||
this.snake.push(tail);
|
||||
this.world[tail[0]][tail[1]]=SNAKE;
|
||||
@@ -141,7 +171,7 @@ class SnekGame {
|
||||
);
|
||||
|
||||
// custom rules
|
||||
if(this.rules.regrowFruits) {
|
||||
if(this.rules.fruitRegrow) {
|
||||
const emptyCells=this.world
|
||||
.map(
|
||||
(l, x) => l
|
||||
@@ -153,7 +183,7 @@ class SnekGame {
|
||||
).flat();
|
||||
const cell=emptyCells[Math.floor(Math.random()*emptyCells.length)];
|
||||
this.fruits.push(cell);
|
||||
this.world[cell[0]][cell[1]]=FRUIT;
|
||||
this.world[cell[0]][cell[1]]=FOOD;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,12 +196,14 @@ class SnekGame {
|
||||
}
|
||||
|
||||
tick() {
|
||||
if(!this.playing) return;
|
||||
if(!this.lastStep) this.lastStep=this.firstStep;
|
||||
if(this.lastStep+delay<Date.now()) {
|
||||
this.lastStep+=delay;
|
||||
this.draw();
|
||||
if(this.callback) this.callback();
|
||||
if(this.lastStep+this.delay<Date.now()) {
|
||||
this.lastStep+=this.delay;
|
||||
this.step();
|
||||
}
|
||||
this.draw();
|
||||
requestAnimationFrame(() => this.tick());
|
||||
}
|
||||
|
||||
@@ -188,8 +220,26 @@ class SnekGame {
|
||||
console.log("You bad lol");
|
||||
}
|
||||
|
||||
handleInputs(inputs) {
|
||||
const trySet=(dir) => {
|
||||
if(!(this.direction[0]==-dir[0] && this.direction[1]==-dir[1])) this.direction=dir;
|
||||
}
|
||||
if(inputs.left) {
|
||||
trySet([-1, 0]);
|
||||
} else if(inputs.right) {
|
||||
trySet([ 1, 0]);
|
||||
} else if(inputs.up) {
|
||||
trySet([ 0,-1]);
|
||||
} else if(inputs.down) {
|
||||
trySet([ 0, 1]);
|
||||
}
|
||||
|
||||
Object.keys(inputs).forEach(k => delete inputs[k]);
|
||||
}
|
||||
|
||||
start() {
|
||||
this.firstStep=Date.now();
|
||||
this.playing=true;
|
||||
requestAnimationFrame(() => this.tick());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user