-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmainLoop.js
More file actions
232 lines (213 loc) · 8.27 KB
/
mainLoop.js
File metadata and controls
232 lines (213 loc) · 8.27 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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// Getting reference to the info label
var label = document.getElementById("label");
// Track map definition
// 1 - wall, 0 - road
var racingTrack = [
[1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 0, 0, 0, 0, 0, 1, 1],
[1, 0, 0, 1, 1, 1, 0, 0, 1],
[1, 1, 0, 0, 0, 0, 0, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1]
]
// Getting map dimensions
var width = racingTrack[0].length
var height = racingTrack.length
// Defining initial state of two players
// other parameters are initialized in initPlayer function
var player = [ { wins: 0 }, { wins: 0 } ];
// Counter until game restart
var RESTART_COUNTER_VALUE = 100;
var restartCounter;
// Initialize player parameters for the start of the race
var initPlayers = function() {
player[0].y = 1.3;
player[1].y = 1.6;
for (var i = 0; i < 2; i++) {
player[i].x = 4.0;
player[i].vel = 0.0;
player[i].dir = 0.0;
player[i].left = false;
player[i].right = false;
player[i].break = false;
player[i].accel = false;
player[i].lost = false;
player[i].firstCell = true;
player[i].laps = 0;
}
};
// Init now
initPlayers();
// Laps to win
var LAPS_GOAL = 5;
// On key pressed down, recored it is down
document.onkeydown = function(event) {
if (event.key === 'a') player[0].left = true;
if (event.key === 's') player[0].break = true;
if (event.key === 'd') player[0].right = true;
if (event.key === 'w') player[0].accel = true;
if (event.key === 'j') player[1].left = true;
if (event.key === 'k') player[1].break = true;
if (event.key === 'l') player[1].right = true;
if (event.key === 'i') player[1].accel = true;
};
// On key released, recored it is not down
document.onkeyup = function(event) {
if (event.key === 'a') player[0].left = false;
if (event.key === 's') player[0].break = false;
if (event.key === 'd') player[0].right = false;
if (event.key === 'w') player[0].accel = false;
if (event.key === 'j') player[1].left = false;
if (event.key === 'k') player[1].break = false;
if (event.key === 'l') player[1].right = false;
if (event.key === 'i') player[1].accel = false;
};
// Function updating info lable to display number
// of wins and laps completed by both players
var updateLabel = function() {
label.innerHTML = "(" + (player[0].laps + 1) + "/" + LAPS_GOAL +
") P1 " + player[0].wins + " : " + player[1].wins + " P2 (" +
(player[1].laps + 1) + "/" + LAPS_GOAL + ")";
}
// Update now
updateLabel();
// Function drawing object using prepared transformation matrix
// Drawing on gl contex with id=0/1
var drawObject = function (texture, id) {
// Prepare or "bind" desired object and texture
gl[id].bindBuffer(gl[id].ARRAY_BUFFER, objs["square"].VBO[id]);
gl[id].bindBuffer(gl[id].ELEMENT_ARRAY_BUFFER, objs["square"].IBO[id]);
gl[id].bindTexture(gl[id].TEXTURE_2D, shapeTextures[id][texture]);
gl[id].activeTexture(gl[id].TEXTURE0);
gl[id].uniform1i(programInfo[id].samplerUnifLoc, 0);
gl[id].vertexAttribPointer(
programInfo[id].posAttribLoc, 3, gl[id].FLOAT, gl[id].FALSE,
5 * Float32Array.BYTES_PER_ELEMENT, 0
);
gl[id].vertexAttribPointer(
programInfo[id].coordAttribLoc, 2, gl[id].FLOAT, gl[id].FALSE,
5 * Float32Array.BYTES_PER_ELEMENT, 3 * Float32Array.BYTES_PER_ELEMENT
);
// Calculate view matrix so that iy is looking at the car from up and behind
mat4.lookAt(self.viewMatrix,
[
player[id].x - Math.cos(Math.PI * player[id].dir / 180.0) * 2,
player[id].y - Math.sin(Math.PI * player[id].dir / 180.0) * 2,
1.0
],
[
player[id].x + Math.cos(Math.PI * player[id].dir / 180.0) * 0.5,
player[id].y + Math.sin(Math.PI * player[id].dir / 180.0) * 0.5,
0.0
],
[0, 0, 1]
);
// Copy uniform data to GPU
gl[id].uniformMatrix4fv(programInfo[id].matProjUnifLoc, gl[id].FALSE, self.projMatrix);
gl[id].uniformMatrix4fv(programInfo[id].matViewUnifLoc, gl[id].FALSE, self.viewMatrix);
gl[id].uniformMatrix4fv(programInfo[id].matTranUnifLoc, gl[id].FALSE, self.tranMatrix);
// Run shaders and draw object
gl[id].drawElements(gl[id].TRIANGLES, squareShape.ind.length, gl[id].UNSIGNED_SHORT, 0);
}
// Function rendering the scene
function drawGame() {
// Clearing both contextes
gl[0].clear(gl[0].DEPTH_BUFFER_BIT | gl[0].COLOR_BUFFER_BIT);
gl[1].clear(gl[1].DEPTH_BUFFER_BIT | gl[1].COLOR_BUFFER_BIT);
// Draw cars
for (var i = 0; i < 2; i++) {
mat4.fromTranslation(self.tranMatrix, [player[i].x, player[i].y, 0.0]);
mat4.rotate(self.tranMatrix, self.tranMatrix, Math.PI * player[i].dir / 180.0, [0.0, 0.0, 1.0]);
mat4.scale(self.tranMatrix, self.tranMatrix, [0.2, 0.1, 1.0]);
// Draw car on both contextes (canvases)
for (var j = 0; j < 2; j++) {
if (i == 0) drawObject("green", j);
else drawObject("red", j);
}
}
// Go through the track map and draw all the walls
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
if (racingTrack[y][x] === 0) continue;
mat4.fromTranslation(self.tranMatrix, [x + 0.5, y + 0.5, 0.0]);
mat4.scale(self.tranMatrix, self.tranMatrix, [0.9, 0.9, 1.0]);
for (var j = 0; j < 2; j++) {
drawObject("white", j);
}
}
}
}
// Main loop, called whe system signals it is ready to draw to screen
var mainLoop = function(){
// Run only is the game is not ower
if ((!player[0].lost) && (!player[1].lost)) {
// Do the same for both players
for (var i = 0; i < 2; i++) {
// Read stored info about user input and
// update player speed and direction
if (player[i].left) {
player[i].dir += 2;
if (player[i].dir > 360) player[i].dir -= 360;
}
if (player[i].right) {
player[i].dir -= 2;
if (player[i].dir < 0) player[i].dir += 360;
}
if (player[i].accel) {
player[i].vel += 0.001;
}
if (player[i].break) {
player[i].vel -= 0.001;
}
// Decrease velocity by little
player[i].vel *= 0.995;
// Update player position on the map
player[i].x += player[i].vel * Math.cos(Math.PI * player[i].dir / 180.0);
player[i].y += player[i].vel * Math.sin(Math.PI * player[i].dir / 180.0);
matX = Math.floor(player[i].x);
matY = Math.floor(player[i].y);
// If player has collided with wall, he lost
if (racingTrack[matY][matX] === 1) {
player[i].lost = true;
}
// Check if player has completed the whole lap
// (not perfect solution, can be cheated)
if (matX !== 4 || matY !== 1) {
player[i].firstCell = false;
}
if (matX === 4 && matY === 1 && !player[i].firstCell) {
player[i].laps++;
// Update ino label
updateLabel();
if (player[i].laps >= LAPS_GOAL) {
player[(i + 1) % 2].lost = true;
}
}
if (matX === 4 && matY === 1) {
player[i].firstCell = true;
}
}
// If the game is over, displey the info message
if (player[0].lost && player[1].lost) {
restartCounter = RESTART_COUNTER_VALUE;
label.innerHTML = "Both players lose!";
} else if (player[0].lost) {
player[1].wins++;
restartCounter = RESTART_COUNTER_VALUE;
label.innerHTML = "Player 2 won!";
} else if (player[1].lost) {
player[0].wins++;
restartCounter = RESTART_COUNTER_VALUE;
label.innerHTML = "Player 1 won!";
}
drawGame();
} else {
// When game is over, drecrease restart counter
// When it gets to 0, restart player info
if (--restartCounter <= 0) {
initPlayers();
updateLabel();
}
}
window.requestAnimationFrame(mainLoop);
};
window.requestAnimationFrame(mainLoop);