|
|
|
@ -1,4 +1,4 @@ |
|
|
|
|
const [EMPTY, FOOD, SUPER_FOOD, WALL, FIRE, HOLE, HOLE_S, SNAKE]=Array(7).keys(); |
|
|
|
|
const [EMPTY, FOOD, SUPER_FOOD, DECAY_FOOD, WALL, FIRE, HOLE, HOLE_S, SNAKE]=Array(255).keys(); |
|
|
|
|
|
|
|
|
|
class SnekGame { |
|
|
|
|
constructor(settings, canvas, rules) { |
|
|
|
@ -18,6 +18,7 @@ class SnekGame { |
|
|
|
|
case ' ': return EMPTY; |
|
|
|
|
case 'f': return FOOD; |
|
|
|
|
case 'F': return SUPER_FOOD; |
|
|
|
|
case 'd': return DECAY_FOOD; |
|
|
|
|
case 'w': return WALL; |
|
|
|
|
case 'o': return HOLE; |
|
|
|
|
case 'i': return FIRE; |
|
|
|
@ -37,6 +38,15 @@ class SnekGame { |
|
|
|
|
if(c==FOOD) this.fruits.push([x, y]); |
|
|
|
|
} |
|
|
|
|
)); |
|
|
|
|
|
|
|
|
|
// extract the decaying fruits
|
|
|
|
|
this.decayFood=[]; |
|
|
|
|
this.world |
|
|
|
|
.forEach((l, x) => l.forEach( |
|
|
|
|
(c, y) => { |
|
|
|
|
if(c==DECAY_FOOD) this.decaying.push([x, y, 0]); |
|
|
|
|
} |
|
|
|
|
)); |
|
|
|
|
} else { // dimension and objects
|
|
|
|
|
|
|
|
|
|
// get the dimensions
|
|
|
|
@ -64,6 +74,14 @@ class SnekGame { |
|
|
|
|
|
|
|
|
|
// add the super food
|
|
|
|
|
if(settings.superFood) settings.superFood.forEach(([x, y]) => this.world[x][y]=SUPER_FOOD); |
|
|
|
|
|
|
|
|
|
// add the decaying food
|
|
|
|
|
if(settings.decayFood) { |
|
|
|
|
settings.decayFood.forEach(([x, y]) => this.world[x][y]=DECAY_FOOD); |
|
|
|
|
this.decayFood=settings.decayFood.map(([x, y]) => [x, y, 0]); |
|
|
|
|
} else { |
|
|
|
|
this.decayFood=[]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// add the snake to the world
|
|
|
|
@ -93,6 +111,7 @@ class SnekGame { |
|
|
|
|
this.rules=Object.assign({ |
|
|
|
|
fruitRegrow: true, |
|
|
|
|
superFruitGrow: false, |
|
|
|
|
decayingFruitGrow: false, |
|
|
|
|
speedIncrease: true, |
|
|
|
|
worldWrap: true, |
|
|
|
|
winCondition: 'none', |
|
|
|
@ -151,6 +170,7 @@ class SnekGame { |
|
|
|
|
const hole=assets.get('hole'); |
|
|
|
|
const fire=assets.get('fire'); |
|
|
|
|
const superFruit=assets.get('superFruit'); |
|
|
|
|
const decayFruit=assets.get('decayFruit'); |
|
|
|
|
const putTile=(x, y, tile) => this.ctx.drawImage( |
|
|
|
|
tile, |
|
|
|
|
offsetX+cellSize*x, |
|
|
|
@ -161,6 +181,9 @@ class SnekGame { |
|
|
|
|
const putTileAnim=(x, y, tile) => putTile(x, y, tile[ |
|
|
|
|
Math.floor(Date.now()/1000*60+x+y)%tile.length |
|
|
|
|
]); |
|
|
|
|
const putTileAnimPercent=(x, y, tile, percent) => putTile(x, y, tile[ |
|
|
|
|
Math.min(Math.round(percent*tile.length), tile.length-1) |
|
|
|
|
]); |
|
|
|
|
const checkAdj=(x, y) => { |
|
|
|
|
let adj={}; |
|
|
|
|
adj.u=this.world[x][y-1]; |
|
|
|
@ -204,6 +227,11 @@ class SnekGame { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// draw our decaying fruits
|
|
|
|
|
this.decayFood.forEach(([x, y, birth]) => |
|
|
|
|
putTileAnimPercent(x, y, decayFruit, (this.playTime-birth)/2000) |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// draw our snake
|
|
|
|
|
const snake=assets.get('snake'); |
|
|
|
|
this.ctx.fillStyle=snake.color; |
|
|
|
@ -377,6 +405,14 @@ class SnekGame { |
|
|
|
|
this.score+=10; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
// you eat, you get a small score boost
|
|
|
|
|
case DECAY_FOOD: |
|
|
|
|
this.score+=5; |
|
|
|
|
this.decayFood=this.decayFood.filter( |
|
|
|
|
([x, y, _]) => !(x==head[0] && y==head[1]) |
|
|
|
|
); |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
// you eat, you grow
|
|
|
|
|
case FOOD: |
|
|
|
|
// re-grow the snake
|
|
|
|
@ -421,6 +457,15 @@ class SnekGame { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(this.rules.decayingFruitGrow) { |
|
|
|
|
if(Math.random()<.2) { // 20% chance
|
|
|
|
|
const emptyCells=getEmptyCells(); |
|
|
|
|
const cell=emptyCells[Math.floor(Math.random()*emptyCells.length)]; |
|
|
|
|
this.world[cell[0]][cell[1]]=DECAY_FOOD; |
|
|
|
|
this.decayFood.push([cell[0], cell[1], this.playTime]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if(this.rules.speedIncrease) { |
|
|
|
|
this.delay*=this.rules.speedMultiplier; |
|
|
|
|
if(this.delay<this.rules.speedCap) this.delay=this.rules.speedCap; |
|
|
|
@ -437,6 +482,16 @@ class SnekGame { |
|
|
|
|
} |
|
|
|
|
this.snake.unshift(head); |
|
|
|
|
|
|
|
|
|
// decay decaying food
|
|
|
|
|
this.decayFood.forEach( |
|
|
|
|
([x, y, birth]) => { |
|
|
|
|
if(this.playTime>=birth+2000) this.world[x][y]=EMPTY; |
|
|
|
|
} |
|
|
|
|
); |
|
|
|
|
this.decayFood=this.decayFood.filter( |
|
|
|
|
([_, __, birth]) => this.playTime<birth+2000 |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// automatic speed increase
|
|
|
|
|
if(this.rules.autoSpeedIncrease) { |
|
|
|
|
if(this.delay>50 && this.tickId%this.rules.autoSpeadIncreaseTicks==0) this.delay--; |
|
|
|
|