diff --git a/Makefile b/Makefile index 6a8c669..8f8dc79 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,12 @@ .PHONY: all clean 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_RAINBOW_ANIM = $(foreach percent, $(shell seq 100 2 299), build/peach-rainbow$(percent).png) IMAGES = $(foreach name, apple wall, public/assets/$(name)32.png) TILESETS = $(foreach name, hole, public/assets/$(name)-ts.png) -ANIMATIONS = $(foreach name, fire, public/assets/$(name)-anim.png) +ANIMATIONS = $(foreach name, fire peach-decay peach-rainbow, public/assets/$(name)-anim.png) JSON = $(foreach name, snake levelList config metaConfig, public/assets/$(name).json) ICON = public/assets/icon32.png public/assets/icon256.png public/favicon.ico CSS = public/css/snek.css @@ -44,6 +46,18 @@ public/assets/fire-anim.png: $(FIRE_ANIM) build/fire%.png: assets/fire.png convert $^ -distort ScaleRotateTranslate $(shell echo $@ | sed 's/[^0-9]*//g') -resize 32x $@ +public/assets/peach-decay-anim.png: $(PEACH_DECAY_ANIM) + convert $^ -append $@ + +build/peach-decay%.png: assets/peach.png + convert $^ -modulate 100,$(shell echo $@ | sed 's/[^0-9]*//g') -resize 32x $@ + +public/assets/peach-rainbow-anim.png: $(PEACH_RAINBOW_ANIM) + convert $^ -append $@ + +build/peach-rainbow%.png: assets/peach.png + convert $^ -modulate 100,100,$(shell echo $@ | sed 's/[^0-9]*//g') -resize 32x $@ + public/assets/%.json: assets/%.json cp $^ $@ diff --git a/assets/peach.png b/assets/peach.png new file mode 100644 index 0000000..970e31f Binary files /dev/null and b/assets/peach.png differ diff --git a/levels/arcade-arcade.json b/levels/arcade-arcade.json index 26a509e..29319b1 100644 --- a/levels/arcade-arcade.json +++ b/levels/arcade-arcade.json @@ -8,5 +8,8 @@ [16, 12], [16, 11], [16, 10] - ] + ], + "rules": { + "superFruitGrow": true + } } diff --git a/src/js/assets.js b/src/js/assets.js index 3c06c5d..211fa74 100644 --- a/src/js/assets.js +++ b/src/js/assets.js @@ -1,19 +1,21 @@ const ProgressBar=require('progress'); const assetSpecs=[ - { name: 'fruit', filename: 'apple32.png', type: 'image' }, - { name: 'wall', filename: 'wall32.png', type: 'image' }, - { name: 'hole', filename: 'hole-ts.png', type: 'image' }, - { name: 'fire', filename: 'fire-anim.png', type: 'image' }, - { name: 'snake', filename: 'snake.json', type: 'json' }, - { name: 'levelList', filename: 'levelList.json', type: 'json' }, - { name: 'config', filename: 'config.json', type: 'json' }, - { name: 'metaConfig', filename: 'metaConfig.json', type: 'json' } + { name: 'fruit', filename: 'apple32.png', type: 'image' }, + { name: 'superFruit', filename: 'peach-rainbow-anim.png', type: 'image' }, + { name: 'wall', filename: 'wall32.png', type: 'image' }, + { name: 'hole', filename: 'hole-ts.png', type: 'image' }, + { name: 'fire', filename: 'fire-anim.png', type: 'image' }, + { name: 'snake', filename: 'snake.json', type: 'json' }, + { name: 'levelList', filename: 'levelList.json', type: 'json' }, + { name: 'config', filename: 'config.json', type: 'json' }, + { name: 'metaConfig', filename: 'metaConfig.json', type: 'json' } ]; const tasks=[ - { from: 'hole', type: 'tileset', tiles: ['base', 'ul', 'dr', 'dl', 'ur', 'l', 'r', 'd', 'u'], steps: 3 }, - { from: 'fire', type: 'animation', steps: 6 } + { from: 'hole', type: 'tileset', steps: 3, tiles: ['base', 'ul', 'dr', 'dl', 'ur', 'l', 'r', 'd', 'u'] }, + { from: 'fire', type: 'animation', steps: 6 }, + { from: 'superFruit', type: 'animation', steps: 5 } ]; const cvs=document.createElement('canvas'); diff --git a/src/js/snek.js b/src/js/snek.js index ae94181..792b537 100644 --- a/src/js/snek.js +++ b/src/js/snek.js @@ -1,4 +1,4 @@ -const [EMPTY, FOOD, WALL, FIRE, HOLE, HOLE_S, SNAKE]=Array(7).keys(); +const [EMPTY, FOOD, SUPER_FOOD, WALL, FIRE, HOLE, HOLE_S, SNAKE]=Array(7).keys(); class SnekGame { constructor(settings, canvas, rules) { @@ -17,6 +17,7 @@ class SnekGame { switch(settings.world[y][x]) { case ' ': return EMPTY; case 'f': return FOOD; + case 'F': return SUPER_FOOD; case 'w': return WALL; case 'o': return HOLE; case 'i': return FIRE; @@ -60,6 +61,9 @@ class SnekGame { // add the food settings.food.forEach(([x, y]) => this.world[x][y]=FOOD); this.fruits=[...settings.food]; + + // add the super food + if(settings.superFood) settings.superFood.forEach(([x, y]) => this.world[x][y]=SUPER_FOOD); } // add the snake to the world @@ -88,6 +92,7 @@ class SnekGame { // load the custom rules this.rules=Object.assign({ fruitRegrow: true, + superFruitGrow: false, speedIncrease: true, worldWrap: true, winCondition: 'none', @@ -145,6 +150,7 @@ class SnekGame { const wall=assets.get('wall'); const hole=assets.get('hole'); const fire=assets.get('fire'); + const superFruit=assets.get('superFruit'); const putTile=(x, y, tile) => this.ctx.drawImage( tile, offsetX+cellSize*x, @@ -190,6 +196,10 @@ class SnekGame { // technically, this works for all shapes // however, the tileset only handles convex shapes } + + case SUPER_FOOD: + putTileAnim(x, y, superFruit); + break; } } } @@ -362,7 +372,12 @@ class SnekGame { ) return this.die(); break; - // you eat, you don't die + // you eat, you get a massive score boost + case SUPER_FOOD: + this.score+=10; + break; + + // you eat, you grow case FOOD: // re-grow the snake this.snake.push(tail); @@ -377,9 +392,9 @@ class SnekGame { // increase score this.score++; - // custom rules - if(this.rules.fruitRegrow) { - const emptyCells=this.world + // list empty cells + const getEmptyCells=() => + this.world .map( (l, x) => l .map( @@ -388,11 +403,24 @@ class SnekGame { a => a ) ).flat(); + + // custom rules + if(this.rules.fruitRegrow) { + const emptyCells=getEmptyCells(); + const cell=emptyCells[Math.floor(Math.random()*emptyCells.length)]; this.fruits.push(cell); this.world[cell[0]][cell[1]]=FOOD; } + if(this.rules.superFruitGrow) { + if(Math.random()<.1) { // 10% chance + const emptyCells=getEmptyCells(); + const cell=emptyCells[Math.floor(Math.random()*emptyCells.length)]; + this.world[cell[0]][cell[1]]=SUPER_FOOD; + } + } + if(this.rules.speedIncrease) { this.delay*=this.rules.speedMultiplier; if(this.delay