-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlevel.js
More file actions
116 lines (100 loc) · 3.44 KB
/
level.js
File metadata and controls
116 lines (100 loc) · 3.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
const ACTORS = {
'o': Coin,
'@': Player,
'=': Lava,
'|': Lava,
'v': Lava
};
const MAX_STEP = 0.05;
const AUDIO_COIN = new Audio('./sounds/coin.wav');
const AUDIO_WIN = new Audio('./sounds/win.wav');
const AUDIO_LOSE = new Audio('./sounds/lose.flac');
function Level(plan) {
if (!validateLevel(plan)) throw new Error('You need a player and a coin');
this.width = plan[0].length;
this.height = plan.length;
this.status = null;
this.finishDelay = null;
this.grid = [];
this.actors = [];
for (let y = 0; y < this.height; y++) {
let line = plan[y];
let gridLine = [];
for (let x = 0; x < this.width; x++) {
let character = line[x];
let characterType = null;
let Actor = ACTORS[character];
if (Actor) this.actors.push(new Actor(new Vector(x, y), character));
if (character === 'x') characterType = 'wall';
else if (character === '!') characterType = 'lava'
gridLine.push(characterType);
}
this.grid.push(gridLine);
}
this.player = this.actors.filter(actor => actor.type === 'player')[0];
}
Level.prototype.isFinished = function () {
return (this.status !== null && this.finishDelay < 0)
}
Level.prototype.animate = function (step, keys) {
if (this.status !== null) this.finishDelay -= step;
while (step > 0) {
let thisStep = Math.min(step, MAX_STEP);
this.actors.forEach(actor => actor.act(thisStep, this, keys));
step -= thisStep;
}
}
Level.prototype.obstacleAt = function (position, size) {
let xStart = Math.floor(position.x);
let xEnd = Math.ceil(position.x + size.x);
let yStart = Math.floor(position.y);
let yEnd = Math.ceil(position.y + size.y);
if (xStart < 0 || xEnd >= this.width || yStart < 0 ) return 'wall';
if (yEnd >= this.height) return 'lava';
for (let y = yStart; y < yEnd; y++) {
for (let x = xStart; x < xEnd; x++) {
let fieldType = this.grid[y][x];
if (fieldType) return fieldType;
}
}
}
Level.prototype.playerTouched = function (type, actor) {
if (type === 'lava' && this.status === null) {
ambientSound.pause();
playAudio(AUDIO_LOSE);
ambientStarted = false;
this.status = 'lost';
this.finishDelay = 1;
} else if (type === 'coin') {
playAudio(AUDIO_COIN);
this.actors = this.actors.filter(otherActor => otherActor !== actor);
if (!remainingCoins(this.actors)) {
ambientSound.pause();
playAudio(AUDIO_WIN);
ambientStarted = false;
this.status = 'won';
this.finishDelay = 2;
}
}
}
Level.prototype.actorAt = function (actor) {
for (let i = 0; i < this.actors.length; i++) {
let other = this.actors[i];
if (actor !== other && actor.position.x + actor.size.x > other.position.x &&
actor.position.x < other.position.x + other.size.x &&
actor.position.y + actor.size.y > other.position.y &&
actor.position.y < other.position.y + other.size.y) return other;
}
}
function remainingCoins(actors) {
return actors.some(actor => actor.type === 'coin');
}
function validateLevel(level) {
return (level.some(row => row.indexOf('@') !== -1) &&
level.some(row => row.indexOf('o') !== -1));
}
function playAudio(track) {
track.pause();
track.currentTime = 0;
track.play();
}