added decaying fruit

This commit is contained in:
Nathan DECHER 2020-04-06 15:17:21 +02:00
parent bf06218815
commit 530260ac54
4 changed files with 62 additions and 4 deletions

View file

@ -1,7 +1,7 @@
.PHONY: all clean .PHONY: all clean
FIRE_ANIM = $(foreach angle, $(shell seq 0 6 359), build/fire$(angle).png) FIRE_ANIM = $(foreach angle, $(shell seq 0 6 359), build/fire$(angle).png)
PEACH_DECAY_ANIM = $(foreach percent, $(shell seq 100 -1 0), build/peach-decay$(percent).png) PEACH_DECAY_ANIM = $(foreach percent, $(shell seq 99 -1 0), build/peach-decay$(percent).png)
PEACH_RAINBOW_ANIM = $(foreach percent, $(shell seq 100 2 299), build/peach-rainbow$(percent).png) PEACH_RAINBOW_ANIM = $(foreach percent, $(shell seq 100 2 299), build/peach-rainbow$(percent).png)
IMAGES = $(foreach name, apple wall, public/assets/$(name)32.png) IMAGES = $(foreach name, apple wall, public/assets/$(name)32.png)

View file

@ -10,6 +10,7 @@
[16, 10] [16, 10]
], ],
"rules": { "rules": {
"superFruitGrow": true "superFruitGrow": true,
"decayingFruitGrow": true
} }
} }

View file

@ -3,6 +3,7 @@ const ProgressBar=require('progress');
const assetSpecs=[ const assetSpecs=[
{ name: 'fruit', filename: 'apple32.png', type: 'image' }, { name: 'fruit', filename: 'apple32.png', type: 'image' },
{ name: 'superFruit', filename: 'peach-rainbow-anim.png', type: 'image' }, { name: 'superFruit', filename: 'peach-rainbow-anim.png', type: 'image' },
{ name: 'decayFruit', filename: 'peach-decay-anim.png', type: 'image' },
{ name: 'wall', filename: 'wall32.png', type: 'image' }, { name: 'wall', filename: 'wall32.png', type: 'image' },
{ name: 'hole', filename: 'hole-ts.png', type: 'image' }, { name: 'hole', filename: 'hole-ts.png', type: 'image' },
{ name: 'fire', filename: 'fire-anim.png', type: 'image' }, { name: 'fire', filename: 'fire-anim.png', type: 'image' },
@ -15,7 +16,8 @@ const assetSpecs=[
const tasks=[ const tasks=[
{ from: 'hole', type: 'tileset', steps: 3, tiles: ['base', 'ul', 'dr', 'dl', 'ur', 'l', 'r', 'd', 'u'] }, { from: 'hole', type: 'tileset', steps: 3, tiles: ['base', 'ul', 'dr', 'dl', 'ur', 'l', 'r', 'd', 'u'] },
{ from: 'fire', type: 'animation', steps: 6 }, { from: 'fire', type: 'animation', steps: 6 },
{ from: 'superFruit', type: 'animation', steps: 5 } { from: 'superFruit', type: 'animation', steps: 5 },
{ from: 'decayFruit', type: 'animation', steps: 5 }
]; ];
const cvs=document.createElement('canvas'); const cvs=document.createElement('canvas');

View file

@ -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 { class SnekGame {
constructor(settings, canvas, rules) { constructor(settings, canvas, rules) {
@ -18,6 +18,7 @@ class SnekGame {
case ' ': return EMPTY; case ' ': return EMPTY;
case 'f': return FOOD; case 'f': return FOOD;
case 'F': return SUPER_FOOD; case 'F': return SUPER_FOOD;
case 'd': return DECAY_FOOD;
case 'w': return WALL; case 'w': return WALL;
case 'o': return HOLE; case 'o': return HOLE;
case 'i': return FIRE; case 'i': return FIRE;
@ -37,6 +38,15 @@ class SnekGame {
if(c==FOOD) this.fruits.push([x, y]); 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 } else { // dimension and objects
// get the dimensions // get the dimensions
@ -64,6 +74,14 @@ class SnekGame {
// add the super food // add the super food
if(settings.superFood) settings.superFood.forEach(([x, y]) => this.world[x][y]=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 // add the snake to the world
@ -93,6 +111,7 @@ class SnekGame {
this.rules=Object.assign({ this.rules=Object.assign({
fruitRegrow: true, fruitRegrow: true,
superFruitGrow: false, superFruitGrow: false,
decayingFruitGrow: false,
speedIncrease: true, speedIncrease: true,
worldWrap: true, worldWrap: true,
winCondition: 'none', winCondition: 'none',
@ -151,6 +170,7 @@ class SnekGame {
const hole=assets.get('hole'); const hole=assets.get('hole');
const fire=assets.get('fire'); const fire=assets.get('fire');
const superFruit=assets.get('superFruit'); const superFruit=assets.get('superFruit');
const decayFruit=assets.get('decayFruit');
const putTile=(x, y, tile) => this.ctx.drawImage( const putTile=(x, y, tile) => this.ctx.drawImage(
tile, tile,
offsetX+cellSize*x, offsetX+cellSize*x,
@ -161,6 +181,9 @@ class SnekGame {
const putTileAnim=(x, y, tile) => putTile(x, y, tile[ const putTileAnim=(x, y, tile) => putTile(x, y, tile[
Math.floor(Date.now()/1000*60+x+y)%tile.length 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) => { const checkAdj=(x, y) => {
let adj={}; let adj={};
adj.u=this.world[x][y-1]; 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 // draw our snake
const snake=assets.get('snake'); const snake=assets.get('snake');
this.ctx.fillStyle=snake.color; this.ctx.fillStyle=snake.color;
@ -377,6 +405,14 @@ class SnekGame {
this.score+=10; this.score+=10;
break; 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 // you eat, you grow
case FOOD: case FOOD:
// re-grow the snake // 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) { if(this.rules.speedIncrease) {
this.delay*=this.rules.speedMultiplier; this.delay*=this.rules.speedMultiplier;
if(this.delay<this.rules.speedCap) this.delay=this.rules.speedCap; if(this.delay<this.rules.speedCap) this.delay=this.rules.speedCap;
@ -437,6 +482,16 @@ class SnekGame {
} }
this.snake.unshift(head); 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 // automatic speed increase
if(this.rules.autoSpeedIncrease) { if(this.rules.autoSpeedIncrease) {
if(this.delay>50 && this.tickId%this.rules.autoSpeadIncreaseTicks==0) this.delay--; if(this.delay>50 && this.tickId%this.rules.autoSpeadIncreaseTicks==0) this.delay--;