added super fruit (closes #8)
This commit is contained in:
parent
2a9418c9c4
commit
bf06218815
5 changed files with 64 additions and 17 deletions
16
Makefile
16
Makefile
|
@ -1,10 +1,12 @@
|
||||||
.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_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)
|
||||||
TILESETS = $(foreach name, hole, public/assets/$(name)-ts.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)
|
JSON = $(foreach name, snake levelList config metaConfig, public/assets/$(name).json)
|
||||||
ICON = public/assets/icon32.png public/assets/icon256.png public/favicon.ico
|
ICON = public/assets/icon32.png public/assets/icon256.png public/favicon.ico
|
||||||
CSS = public/css/snek.css
|
CSS = public/css/snek.css
|
||||||
|
@ -44,6 +46,18 @@ public/assets/fire-anim.png: $(FIRE_ANIM)
|
||||||
build/fire%.png: assets/fire.png
|
build/fire%.png: assets/fire.png
|
||||||
convert $^ -distort ScaleRotateTranslate $(shell echo $@ | sed 's/[^0-9]*//g') -resize 32x $@
|
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
|
public/assets/%.json: assets/%.json
|
||||||
cp $^ $@
|
cp $^ $@
|
||||||
|
|
||||||
|
|
BIN
assets/peach.png
Normal file
BIN
assets/peach.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
|
@ -8,5 +8,8 @@
|
||||||
[16, 12],
|
[16, 12],
|
||||||
[16, 11],
|
[16, 11],
|
||||||
[16, 10]
|
[16, 10]
|
||||||
]
|
],
|
||||||
|
"rules": {
|
||||||
|
"superFruitGrow": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
const ProgressBar=require('progress');
|
const ProgressBar=require('progress');
|
||||||
|
|
||||||
const assetSpecs=[
|
const assetSpecs=[
|
||||||
{ name: 'fruit', filename: 'apple32.png', type: 'image' },
|
{ name: 'fruit', filename: 'apple32.png', type: 'image' },
|
||||||
{ name: 'wall', filename: 'wall32.png', type: 'image' },
|
{ name: 'superFruit', filename: 'peach-rainbow-anim.png', type: 'image' },
|
||||||
{ name: 'hole', filename: 'hole-ts.png', type: 'image' },
|
{ name: 'wall', filename: 'wall32.png', type: 'image' },
|
||||||
{ name: 'fire', filename: 'fire-anim.png', type: 'image' },
|
{ name: 'hole', filename: 'hole-ts.png', type: 'image' },
|
||||||
{ name: 'snake', filename: 'snake.json', type: 'json' },
|
{ name: 'fire', filename: 'fire-anim.png', type: 'image' },
|
||||||
{ name: 'levelList', filename: 'levelList.json', type: 'json' },
|
{ name: 'snake', filename: 'snake.json', type: 'json' },
|
||||||
{ name: 'config', filename: 'config.json', type: 'json' },
|
{ name: 'levelList', filename: 'levelList.json', type: 'json' },
|
||||||
{ name: 'metaConfig', filename: 'metaConfig.json', type: 'json' }
|
{ name: 'config', filename: 'config.json', type: 'json' },
|
||||||
|
{ name: 'metaConfig', filename: 'metaConfig.json', type: 'json' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const tasks=[
|
const tasks=[
|
||||||
{ from: 'hole', type: 'tileset', tiles: ['base', 'ul', 'dr', 'dl', 'ur', 'l', 'r', 'd', 'u'], steps: 3 },
|
{ 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 }
|
||||||
];
|
];
|
||||||
|
|
||||||
const cvs=document.createElement('canvas');
|
const cvs=document.createElement('canvas');
|
||||||
|
|
|
@ -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 {
|
class SnekGame {
|
||||||
constructor(settings, canvas, rules) {
|
constructor(settings, canvas, rules) {
|
||||||
|
@ -17,6 +17,7 @@ class SnekGame {
|
||||||
switch(settings.world[y][x]) {
|
switch(settings.world[y][x]) {
|
||||||
case ' ': return EMPTY;
|
case ' ': return EMPTY;
|
||||||
case 'f': return FOOD;
|
case 'f': return FOOD;
|
||||||
|
case 'F': return SUPER_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;
|
||||||
|
@ -60,6 +61,9 @@ class SnekGame {
|
||||||
// add the food
|
// add the food
|
||||||
settings.food.forEach(([x, y]) => this.world[x][y]=FOOD);
|
settings.food.forEach(([x, y]) => this.world[x][y]=FOOD);
|
||||||
this.fruits=[...settings.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
|
// add the snake to the world
|
||||||
|
@ -88,6 +92,7 @@ class SnekGame {
|
||||||
// load the custom rules
|
// load the custom rules
|
||||||
this.rules=Object.assign({
|
this.rules=Object.assign({
|
||||||
fruitRegrow: true,
|
fruitRegrow: true,
|
||||||
|
superFruitGrow: false,
|
||||||
speedIncrease: true,
|
speedIncrease: true,
|
||||||
worldWrap: true,
|
worldWrap: true,
|
||||||
winCondition: 'none',
|
winCondition: 'none',
|
||||||
|
@ -145,6 +150,7 @@ class SnekGame {
|
||||||
const wall=assets.get('wall');
|
const wall=assets.get('wall');
|
||||||
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 putTile=(x, y, tile) => this.ctx.drawImage(
|
const putTile=(x, y, tile) => this.ctx.drawImage(
|
||||||
tile,
|
tile,
|
||||||
offsetX+cellSize*x,
|
offsetX+cellSize*x,
|
||||||
|
@ -190,6 +196,10 @@ class SnekGame {
|
||||||
// technically, this works for all shapes
|
// technically, this works for all shapes
|
||||||
// however, the tileset only handles convex 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();
|
) return this.die();
|
||||||
break;
|
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:
|
case FOOD:
|
||||||
// re-grow the snake
|
// re-grow the snake
|
||||||
this.snake.push(tail);
|
this.snake.push(tail);
|
||||||
|
@ -377,9 +392,9 @@ class SnekGame {
|
||||||
// increase score
|
// increase score
|
||||||
this.score++;
|
this.score++;
|
||||||
|
|
||||||
// custom rules
|
// list empty cells
|
||||||
if(this.rules.fruitRegrow) {
|
const getEmptyCells=() =>
|
||||||
const emptyCells=this.world
|
this.world
|
||||||
.map(
|
.map(
|
||||||
(l, x) => l
|
(l, x) => l
|
||||||
.map(
|
.map(
|
||||||
|
@ -388,11 +403,24 @@ class SnekGame {
|
||||||
a => a
|
a => a
|
||||||
)
|
)
|
||||||
).flat();
|
).flat();
|
||||||
|
|
||||||
|
// custom rules
|
||||||
|
if(this.rules.fruitRegrow) {
|
||||||
|
const emptyCells=getEmptyCells();
|
||||||
|
|
||||||
const cell=emptyCells[Math.floor(Math.random()*emptyCells.length)];
|
const cell=emptyCells[Math.floor(Math.random()*emptyCells.length)];
|
||||||
this.fruits.push(cell);
|
this.fruits.push(cell);
|
||||||
this.world[cell[0]][cell[1]]=FOOD;
|
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) {
|
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;
|
||||||
|
|
Loading…
Reference in a new issue