added portals (closes #4) and first level of puzzle mode
This commit is contained in:
parent
52a2e41e05
commit
a27b8fcd9e
7 changed files with 230 additions and 26 deletions
31
Makefile
31
Makefile
|
@ -3,10 +3,14 @@
|
||||||
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 99 -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)
|
||||||
|
PORTAL_A_ANIM = $(foreach angle, $(shell seq 0 6 359), build/portal-a$(angle).png)
|
||||||
|
PORTAL_B_ANIM = $(foreach angle, $(shell seq 0 6 359), build/portal-b$(angle).png)
|
||||||
|
PORTAL_C_ANIM = $(foreach angle, $(shell seq 0 6 359), build/portal-c$(angle).png)
|
||||||
|
PORTAL_D_ANIM = $(foreach angle, $(shell seq 0 6 359), build/portal-d$(angle).png)
|
||||||
|
|
||||||
IMAGES = $(foreach name, apple wall oil, public/assets/$(name)32.png)
|
IMAGES = $(foreach name, apple wall oil, 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 peach-decay peach-rainbow, public/assets/$(name)-anim.png)
|
ANIMATIONS = $(foreach name, fire peach-decay peach-rainbow portal-a portal-b portal-c portal-d, 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
|
||||||
|
@ -58,6 +62,31 @@ public/assets/peach-rainbow-anim.png: $(PEACH_RAINBOW_ANIM)
|
||||||
build/peach-rainbow%.png: assets/peach.png
|
build/peach-rainbow%.png: assets/peach.png
|
||||||
convert $^ -modulate 100,100,$(shell echo $@ | sed 's/[^0-9]*//g') -resize 32x $@
|
convert $^ -modulate 100,100,$(shell echo $@ | sed 's/[^0-9]*//g') -resize 32x $@
|
||||||
|
|
||||||
|
build/portal-b.png: assets/portal.png
|
||||||
|
convert $^ -modulate 100,100,200 $@
|
||||||
|
build/portal-c.png: assets/portal.png
|
||||||
|
convert $^ -modulate 100,100,150 $@
|
||||||
|
build/portal-d.png: assets/portal.png
|
||||||
|
convert $^ -modulate 100,100,50 $@
|
||||||
|
|
||||||
|
build/portal-a%.png: assets/portal.png
|
||||||
|
convert $^ -distort ScaleRotateTranslate $(shell echo $@ | sed 's/[^0-9]*//g') -resize 32x $@
|
||||||
|
build/portal-b%.png: build/portal-b.png
|
||||||
|
convert $^ -distort ScaleRotateTranslate $(shell echo $@ | sed 's/[^0-9]*//g') -resize 32x $@
|
||||||
|
build/portal-c%.png: build/portal-c.png
|
||||||
|
convert $^ -distort ScaleRotateTranslate $(shell echo $@ | sed 's/[^0-9]*//g') -resize 32x $@
|
||||||
|
build/portal-d%.png: build/portal-d.png
|
||||||
|
convert $^ -distort ScaleRotateTranslate $(shell echo $@ | sed 's/[^0-9]*//g') -resize 32x $@
|
||||||
|
|
||||||
|
public/assets/portal-a-anim.png: $(PORTAL_A_ANIM)
|
||||||
|
convert $^ -append $@
|
||||||
|
public/assets/portal-b-anim.png: $(PORTAL_B_ANIM)
|
||||||
|
convert $^ -append $@
|
||||||
|
public/assets/portal-c-anim.png: $(PORTAL_C_ANIM)
|
||||||
|
convert $^ -append $@
|
||||||
|
public/assets/portal-d-anim.png: $(PORTAL_D_ANIM)
|
||||||
|
convert $^ -append $@
|
||||||
|
|
||||||
public/assets/%.json: assets/%.json
|
public/assets/%.json: assets/%.json
|
||||||
cp $^ $@
|
cp $^ $@
|
||||||
|
|
||||||
|
|
2
api.js
2
api.js
|
@ -78,7 +78,7 @@ api.post('/leaderboards/:category/:id', (req, res) => {
|
||||||
err: 'Invalid time'
|
err: 'Invalid time'
|
||||||
});
|
});
|
||||||
const speed=req.body.speed;
|
const speed=req.body.speed;
|
||||||
if((typeof speed)!='number' || speed%1 || speed<1) return res.status(400).json({
|
if((typeof speed)!='number' || speed%1 || speed<0) return res.status(400).json({
|
||||||
ok: false,
|
ok: false,
|
||||||
err: 'Invalid speed'
|
err: 'Invalid speed'
|
||||||
});
|
});
|
||||||
|
|
|
@ -41,5 +41,25 @@
|
||||||
"Get a score as high as you can in 30 seconds",
|
"Get a score as high as you can in 30 seconds",
|
||||||
"Survive for as long as you can in an increasingly difficult game"
|
"Survive for as long as you can in an increasingly difficult game"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"puzzle": {
|
||||||
|
"desc": "Time doesn't flow in these puzzles. Try getting the fruits in as little moves as possible",
|
||||||
|
"rules": {
|
||||||
|
"fruitRegrow": false,
|
||||||
|
"timeFlow": false,
|
||||||
|
"speedIncrease": false,
|
||||||
|
"worldWrap": false,
|
||||||
|
"winCondition": "fruit",
|
||||||
|
"scoreSystem": "moves",
|
||||||
|
"moveCount": 50,
|
||||||
|
"uploadOnDeath": false,
|
||||||
|
"leaderboardsSort": "score"
|
||||||
|
},
|
||||||
|
"levelFilename": "puzzle<n>.json",
|
||||||
|
"levelDisplay": "Level <n>",
|
||||||
|
"levels": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"nextLevel": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
assets/portal.png
Executable file
BIN
assets/portal.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
21
levels/puzzle1.json
Normal file
21
levels/puzzle1.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"dimensions": [15, 10],
|
||||||
|
"walls": [
|
||||||
|
[5, 0], [5, 1], [5, 2], [5, 3], [5, 4], [5, 5], [5, 6], [5, 7], [5, 8], [5, 9],
|
||||||
|
[10, 0], [10, 1], [10, 2], [10, 3], [10, 4], [10, 5], [10, 6], [10, 7], [10, 8], [10, 9]
|
||||||
|
],
|
||||||
|
"food": [
|
||||||
|
[4, 5],
|
||||||
|
[8, 7],
|
||||||
|
[14, 9]
|
||||||
|
],
|
||||||
|
"snake": [
|
||||||
|
[0, 0]
|
||||||
|
],
|
||||||
|
"portals": {
|
||||||
|
"a": [4, 9],
|
||||||
|
"b": [6, 0],
|
||||||
|
"c": [9, 9],
|
||||||
|
"d": [11, 0]
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,10 @@ const assetSpecs=[
|
||||||
{ name: 'flammable', filename: 'oil32.png', type: 'image' },
|
{ name: 'flammable', filename: 'oil32.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' },
|
||||||
|
{ name: 'portalA', filename: 'portal-a-anim.png', type: 'image' },
|
||||||
|
{ name: 'portalB', filename: 'portal-b-anim.png', type: 'image' },
|
||||||
|
{ name: 'portalC', filename: 'portal-c-anim.png', type: 'image' },
|
||||||
|
{ name: 'portalD', filename: 'portal-d-anim.png', type: 'image' },
|
||||||
{ name: 'snake', filename: 'snake.json', type: 'json' },
|
{ name: 'snake', filename: 'snake.json', type: 'json' },
|
||||||
{ name: 'levelList', filename: 'levelList.json', type: 'json' },
|
{ name: 'levelList', filename: 'levelList.json', type: 'json' },
|
||||||
{ name: 'config', filename: 'config.json', type: 'json' },
|
{ name: 'config', filename: 'config.json', type: 'json' },
|
||||||
|
@ -16,7 +20,11 @@ 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: 3 },
|
||||||
|
{ from: 'portalA', type: 'animation', steps: 3 },
|
||||||
|
{ from: 'portalB', type: 'animation', steps: 3 },
|
||||||
|
{ from: 'portalC', type: 'animation', steps: 3 },
|
||||||
|
{ from: 'portalD', type: 'animation', steps: 3 },
|
||||||
{ from: 'superFruit', type: 'animation', steps: 5 },
|
{ from: 'superFruit', type: 'animation', steps: 5 },
|
||||||
{ from: 'decayFruit', type: 'animation', steps: 5 }
|
{ from: 'decayFruit', type: 'animation', steps: 5 }
|
||||||
];
|
];
|
||||||
|
|
166
src/js/snek.js
166
src/js/snek.js
|
@ -1,9 +1,12 @@
|
||||||
const [EMPTY, FOOD, SUPER_FOOD, DECAY_FOOD, WALL, FIRE, FLAMMABLE, FLAMMABLE_S, HOLE, HOLE_S, SNAKE]=Array(255).keys();
|
const [EMPTY, FOOD, SUPER_FOOD, DECAY_FOOD, WALL, FIRE, FLAMMABLE, FLAMMABLE_S, HOLE, HOLE_S, PORTAL_A, PORTAL_A_S, PORTAL_B, PORTAL_B_S, PORTAL_C, PORTAL_C_S, PORTAL_D, PORTAL_D_S, SNAKE]=Array(255).keys();
|
||||||
|
|
||||||
class SnekGame {
|
class SnekGame {
|
||||||
constructor(settings, canvas, rules) {
|
constructor(settings, canvas, rules) {
|
||||||
// setup the delay
|
// setup the delay
|
||||||
this.delay=settings.delay;
|
this.delay=settings.delay || Infinity;
|
||||||
|
|
||||||
|
// score starts at 0
|
||||||
|
this.score=0;
|
||||||
|
|
||||||
// world is given in the level
|
// world is given in the level
|
||||||
if(settings.world) { // explicitly
|
if(settings.world) { // explicitly
|
||||||
|
@ -23,6 +26,10 @@ class SnekGame {
|
||||||
case 'o': return HOLE;
|
case 'o': return HOLE;
|
||||||
case 'i': return FIRE;
|
case 'i': return FIRE;
|
||||||
case 'I': return FLAMMABLE;
|
case 'I': return FLAMMABLE;
|
||||||
|
case 'A': return PORTAL_A;
|
||||||
|
case 'B': return PORTAL_B;
|
||||||
|
case 'C': return PORTAL_C;
|
||||||
|
case 'D': return PORTAL_D;
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
@ -32,22 +39,21 @@ class SnekGame {
|
||||||
this.dimensions=[this.world.length, this.world[0].length];
|
this.dimensions=[this.world.length, this.world[0].length];
|
||||||
|
|
||||||
// extract the fruits
|
// extract the fruits
|
||||||
this.fruits=[];
|
this.fruits=this.getTilesOfType(FOOD);
|
||||||
this.world
|
|
||||||
.forEach((l, x) => l.forEach(
|
|
||||||
(c, y) => {
|
|
||||||
if(c==FOOD) this.fruits.push([x, y]);
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
// extract the decaying fruits
|
// extract the decaying fruits
|
||||||
this.decayFood=[];
|
this.decayFood=this.getTilesOfType(DECAY_FOOD);
|
||||||
this.world
|
|
||||||
.forEach((l, x) => l.forEach(
|
// extract the portals
|
||||||
(c, y) => {
|
this.portals={};
|
||||||
if(c==DECAY_FOOD) this.decaying.push([x, y, 0]);
|
this.world.forEach((l, x) =>
|
||||||
}
|
l.forEach((c, y) => {
|
||||||
));
|
if(c==PORTAL_A) this.portals.a=[x, y];
|
||||||
|
if(c==PORTAL_B) this.portals.b=[x, y];
|
||||||
|
if(c==PORTAL_C) this.portals.c=[x, y];
|
||||||
|
if(c==PORTAL_D) this.portals.d=[x, y];
|
||||||
|
})
|
||||||
|
);
|
||||||
} else { // dimension and objects
|
} else { // dimension and objects
|
||||||
|
|
||||||
// get the dimensions
|
// get the dimensions
|
||||||
|
@ -84,6 +90,17 @@ class SnekGame {
|
||||||
} else {
|
} else {
|
||||||
this.decayFood=[];
|
this.decayFood=[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add the portals
|
||||||
|
if(settings.portals) {
|
||||||
|
if(settings.portals.a) this.world[settings.portals.a[0]][settings.portals.a[1]]=PORTAL_A;
|
||||||
|
if(settings.portals.b) this.world[settings.portals.b[0]][settings.portals.b[1]]=PORTAL_B;
|
||||||
|
if(settings.portals.c) this.world[settings.portals.c[0]][settings.portals.c[1]]=PORTAL_C;
|
||||||
|
if(settings.portals.d) this.world[settings.portals.d[0]][settings.portals.d[1]]=PORTAL_D;
|
||||||
|
this.portals={...settings.portals};
|
||||||
|
} else {
|
||||||
|
this.portals={};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the snake to the world
|
// add the snake to the world
|
||||||
|
@ -121,8 +138,20 @@ class SnekGame {
|
||||||
scoreSystem: 'fruit',
|
scoreSystem: 'fruit',
|
||||||
fireTickSpeed: 10,
|
fireTickSpeed: 10,
|
||||||
autoSizeGrow: false,
|
autoSizeGrow: false,
|
||||||
autoSpeedIncrease: false
|
autoSpeedIncrease: false,
|
||||||
|
timeFlow: true
|
||||||
}, rules, settings.rules || {});
|
}, rules, settings.rules || {});
|
||||||
|
|
||||||
|
// reset direction if time doesn't flow
|
||||||
|
if(!this.rules.timeFlow) {
|
||||||
|
this.lastDirection=[0, 0];
|
||||||
|
this.direction=[0, 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// set score if move-based
|
||||||
|
if(this.rules.scoreSystem=='moves') {
|
||||||
|
this.score=this.rules.moveCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get playTime() {
|
get playTime() {
|
||||||
|
@ -192,6 +221,10 @@ class SnekGame {
|
||||||
const flammable=assets.get('flammable');
|
const flammable=assets.get('flammable');
|
||||||
const superFruit=assets.get('superFruit');
|
const superFruit=assets.get('superFruit');
|
||||||
const decayFruit=assets.get('decayFruit');
|
const decayFruit=assets.get('decayFruit');
|
||||||
|
const portalA=assets.get('portalA');
|
||||||
|
const portalB=assets.get('portalB');
|
||||||
|
const portalC=assets.get('portalC');
|
||||||
|
const portalD=assets.get('portalD');
|
||||||
const putTile=(x, y, tile) => this.ctx.drawImage(
|
const putTile=(x, y, tile) => this.ctx.drawImage(
|
||||||
tile,
|
tile,
|
||||||
offsetX+cellSize*x,
|
offsetX+cellSize*x,
|
||||||
|
@ -249,6 +282,23 @@ class SnekGame {
|
||||||
case SUPER_FOOD:
|
case SUPER_FOOD:
|
||||||
putTileAnim(x, y, superFruit);
|
putTileAnim(x, y, superFruit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PORTAL_A:
|
||||||
|
case PORTAL_A_S:
|
||||||
|
putTileAnim(x, y, portalA);
|
||||||
|
break;
|
||||||
|
case PORTAL_B:
|
||||||
|
case PORTAL_B_S:
|
||||||
|
putTileAnim(x, y, portalB);
|
||||||
|
break;
|
||||||
|
case PORTAL_C:
|
||||||
|
case PORTAL_C_S:
|
||||||
|
putTileAnim(x, y, portalC);
|
||||||
|
break;
|
||||||
|
case PORTAL_D:
|
||||||
|
case PORTAL_D_S:
|
||||||
|
putTileAnim(x, y, portalD);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,6 +308,32 @@ class SnekGame {
|
||||||
putTileAnimPercent(x, y, decayFruit, (this.playTime-birth)/2000)
|
putTileAnimPercent(x, y, decayFruit, (this.playTime-birth)/2000)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// draw the lines between portals
|
||||||
|
if(Object.keys(this.portals).length) {
|
||||||
|
this.ctx.strokeStyle='rgba(128, 128, 128, 20%)';
|
||||||
|
this.ctx.lineCap='round';
|
||||||
|
this.ctx.lineWidth=cellSize*.15;
|
||||||
|
const drawTunnel=([xa, ya], [xb, yb]) => {
|
||||||
|
const angle=(Math.floor(Date.now()/10)%360)*(Math.PI/180);
|
||||||
|
for(let i=0; i<=1; i++) {
|
||||||
|
const dx=cellSize/3*Math.cos(angle+i*Math.PI);
|
||||||
|
const dy=cellSize/3*Math.sin(angle+i*Math.PI);
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.moveTo(
|
||||||
|
offsetX+cellSize*(xa+1/2)+dx,
|
||||||
|
offsetY+cellSize*(ya+1/2)+dy
|
||||||
|
);
|
||||||
|
this.ctx.lineTo(
|
||||||
|
offsetX+cellSize*(xb+1/2)+dx,
|
||||||
|
offsetY+cellSize*(yb+1/2)+dy
|
||||||
|
);
|
||||||
|
this.ctx.stroke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(this.portals.a && this.portals.b) drawTunnel(this.portals.a, this.portals.b);
|
||||||
|
if(this.portals.c && this.portals.d) drawTunnel(this.portals.c, this.portals.d);
|
||||||
|
}
|
||||||
|
|
||||||
// draw our snake (it gets drawn completely differently, so here it goes)
|
// draw our snake (it gets drawn completely differently, so here it goes)
|
||||||
const snake=assets.get('snake');
|
const snake=assets.get('snake');
|
||||||
this.ctx.fillStyle=snake.color;
|
this.ctx.fillStyle=snake.color;
|
||||||
|
@ -381,10 +457,21 @@ class SnekGame {
|
||||||
this.lastDirection=this.direction;
|
this.lastDirection=this.direction;
|
||||||
|
|
||||||
// compute our new head
|
// compute our new head
|
||||||
const head=[
|
let head;
|
||||||
|
if(!this.portaled && [PORTAL_A_S, PORTAL_B_S, PORTAL_C_S, PORTAL_D_S].includes(this.world[this.snake[0][0]][this.snake[0][1]])) {
|
||||||
|
const tile=this.world[this.snake[0][0]][this.snake[0][1]];
|
||||||
|
if(tile==PORTAL_A_S) head=this.portals.b;
|
||||||
|
if(tile==PORTAL_B_S) head=this.portals.a;
|
||||||
|
if(tile==PORTAL_C_S) head=this.portals.d;
|
||||||
|
if(tile==PORTAL_D_S) head=this.portals.c;
|
||||||
|
this.portaled=true;
|
||||||
|
} else {
|
||||||
|
head=[
|
||||||
this.snake[0][0]+this.direction[0],
|
this.snake[0][0]+this.direction[0],
|
||||||
this.snake[0][1]+this.direction[1]
|
this.snake[0][1]+this.direction[1]
|
||||||
];
|
];
|
||||||
|
this.portaled=false;
|
||||||
|
}
|
||||||
|
|
||||||
// get our tail out of the way
|
// get our tail out of the way
|
||||||
const tail=this.snake.pop();
|
const tail=this.snake.pop();
|
||||||
|
@ -395,6 +482,18 @@ class SnekGame {
|
||||||
case FLAMMABLE_S:
|
case FLAMMABLE_S:
|
||||||
this.world[tail[0]][tail[1]]=FLAMMABLE;
|
this.world[tail[0]][tail[1]]=FLAMMABLE;
|
||||||
break;
|
break;
|
||||||
|
case PORTAL_A_S:
|
||||||
|
this.world[tail[0]][tail[1]]=PORTAL_A;
|
||||||
|
break;
|
||||||
|
case PORTAL_B_S:
|
||||||
|
this.world[tail[0]][tail[1]]=PORTAL_B;
|
||||||
|
break;
|
||||||
|
case PORTAL_C_S:
|
||||||
|
this.world[tail[0]][tail[1]]=PORTAL_C;
|
||||||
|
break;
|
||||||
|
case PORTAL_D_S:
|
||||||
|
this.world[tail[0]][tail[1]]=PORTAL_D;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
this.world[tail[0]][tail[1]]=EMPTY;
|
this.world[tail[0]][tail[1]]=EMPTY;
|
||||||
}
|
}
|
||||||
|
@ -416,6 +515,10 @@ class SnekGame {
|
||||||
case SNAKE:
|
case SNAKE:
|
||||||
case HOLE_S:
|
case HOLE_S:
|
||||||
case FLAMMABLE_S:
|
case FLAMMABLE_S:
|
||||||
|
case PORTAL_A_S:
|
||||||
|
case PORTAL_B_S:
|
||||||
|
case PORTAL_C_S:
|
||||||
|
case PORTAL_D_S:
|
||||||
return this.die("achieved every dog's dream", "ate their own tail");
|
return this.die("achieved every dog's dream", "ate their own tail");
|
||||||
|
|
||||||
// if either 3 consecutive segments or the whole snake is on a hole, you die
|
// if either 3 consecutive segments or the whole snake is on a hole, you die
|
||||||
|
@ -498,6 +601,18 @@ class SnekGame {
|
||||||
case FLAMMABLE:
|
case FLAMMABLE:
|
||||||
this.world[head[0]][head[1]]=FLAMMABLE_S;
|
this.world[head[0]][head[1]]=FLAMMABLE_S;
|
||||||
break;
|
break;
|
||||||
|
case PORTAL_A:
|
||||||
|
this.world[head[0]][head[1]]=PORTAL_A_S;
|
||||||
|
break;
|
||||||
|
case PORTAL_B:
|
||||||
|
this.world[head[0]][head[1]]=PORTAL_B_S;
|
||||||
|
break;
|
||||||
|
case PORTAL_C:
|
||||||
|
this.world[head[0]][head[1]]=PORTAL_C_S;
|
||||||
|
break;
|
||||||
|
case PORTAL_D:
|
||||||
|
this.world[head[0]][head[1]]=PORTAL_D_S;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
this.world[head[0]][head[1]]=SNAKE;
|
this.world[head[0]][head[1]]=SNAKE;
|
||||||
}
|
}
|
||||||
|
@ -538,6 +653,12 @@ class SnekGame {
|
||||||
this.getTilesOfType(FLAMMABLE).filter(touchingFire).forEach(([x, y]) => this.world[x][y]=FIRE);
|
this.getTilesOfType(FLAMMABLE).filter(touchingFire).forEach(([x, y]) => this.world[x][y]=FIRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// THE WORLD!
|
||||||
|
if(!this.rules.timeFlow) {
|
||||||
|
this.lastDirection=[0, 0];
|
||||||
|
this.direction=[0, 0];
|
||||||
|
}
|
||||||
|
|
||||||
// victory condition
|
// victory condition
|
||||||
if(this.rules.winCondition=='fruit') {
|
if(this.rules.winCondition=='fruit') {
|
||||||
if(!this.fruits.length) return this.win();
|
if(!this.fruits.length) return this.win();
|
||||||
|
@ -548,6 +669,9 @@ class SnekGame {
|
||||||
if(this.rules.winCondition=='score') {
|
if(this.rules.winCondition=='score') {
|
||||||
if(this.score>=this.rules.scoreObjective) return this.win();
|
if(this.score>=this.rules.scoreObjective) return this.win();
|
||||||
}
|
}
|
||||||
|
if(this.rules.scoreSystem=='moves') {
|
||||||
|
if(this.score) this.score--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tick() {
|
tick() {
|
||||||
|
@ -555,10 +679,13 @@ class SnekGame {
|
||||||
if(!this.lastStep) this.lastStep=this.firstStep;
|
if(!this.lastStep) this.lastStep=this.firstStep;
|
||||||
this.draw();
|
this.draw();
|
||||||
if(this.callback) this.callback('tick');
|
if(this.callback) this.callback('tick');
|
||||||
if(this.lastStep+this.delay<Date.now()) {
|
if(this.rules.timeFlow && this.lastStep+this.delay<Date.now()) {
|
||||||
this.lastStep+=this.delay;
|
this.lastStep+=this.delay;
|
||||||
this.step();
|
this.step();
|
||||||
}
|
}
|
||||||
|
if(!this.rules.timeFlow && (this.direction[0]!=0 || this.direction[1]!=0)) {
|
||||||
|
this.step();
|
||||||
|
}
|
||||||
requestAnimationFrame(() => this.tick());
|
requestAnimationFrame(() => this.tick());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,7 +742,6 @@ class SnekGame {
|
||||||
this.firstStep=Date.now();
|
this.firstStep=Date.now();
|
||||||
this.tickId=0;
|
this.tickId=0;
|
||||||
this.playing=true;
|
this.playing=true;
|
||||||
this.score=0;
|
|
||||||
requestAnimationFrame(() => this.tick());
|
requestAnimationFrame(() => this.tick());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue