Лабиринт
Содержание
Описание
Реализация компьютерной игры Лабиринт на языке программирования JavaScript
Правила игры:
1. Перед пользователем появляется клетчатое поле, пустое окно для ввода чисел снизу и кнопка «Start»
2. Задача нарисовать лабиринт. Используя правую кнопку мыши, игрок нажимает на ребра сетки или около него, чтобы создать стенку в лабиринте. Повторное нажатие убирает, нарисованный объект. Далее игрок вводит число объектов (шаров), которое не должно превышать 25, в специальном поле, расположенным ниже лабиринта, и нажимает «Start», чтобы запустить игру.
3. После старта частицы начинают двигаться, отталкиваясь от стенок лабиринта, самого поля и от друг друга абсолютно упруго. Игра заканчивается тогда, когда первая из частиц попадает в определенную область, произвольно генерирующуюся в поле и проявляющуюся на мониторе по окончании игры.
4. После окончание на экран игрока выводится слова о его победе и время движения выигравшей частицы.
Реализация
Перечень функций, которые были использованы для написания программы:
• В основе визуализации каждого метода используется элемент <canvas>
• Для создания элементов управления используется форма <input>
• Код программы на языке JavaScript разбит на несколько основных поочередно вызываемых функций: ввод, подсчёты, рисование; используются различные циклы для проверки нажатия при построении лабиринта и нахождения частиц в поле.
Авторы
Исполнители: Бутузова Е.С., Галанина Е.В.
Группа 3630103/90003 Кафедра Теоретической механики
Визуализация
Код программы
1 var N = 600;
2 var x ;
3 var y ;
4 const eps = 7;
5 var edge_vert = [];
6 var edge_hor = [];
7 var IsBelongs_vert = false;
8 var IsBelongs_hor = false;
9 var start_pressed = false;
10 var winFlag = false;
11 var mousecoords = [];
12 var start;
13
14 window.addEventListener('load', main, false);
15 function main() {
16 var ctx = canvas_example.getContext('2d');
17 var w = canvas_example.width;
18 var h = canvas_example.height;
19
20 //рисует сетку
21 function Plot(x,y){
22 ctx.beginPath();
23 ctx.width = 2;
24 for (var i = 0; i<N; i+=50){
25 var x = i;
26 var y = 600;
27 ctx.moveTo(x,0);
28 ctx.lineTo(x,y);
29 ctx.stroke();
30 }
31 for (var j = 0; j<N; j+=50) {
32 var x = 600;
33 var y = j;
34 ctx.moveTo(0,y);
35 ctx.lineTo(x,y);
36 ctx.stroke();
37 }
38 }
39
40 function abs(x)
41 {
42 if(x < 0){
43 return -x;
44 }
45 else{
46 return x;
47 }
48 }
49 //возвращает координаты точки
50 function set_point(_x, _y) {
51 return {
52 x: _x,
53 y: _y,
54 }
55 }
56 //возвращает координаты ребра
57 function set_edge(a,b,c,d){
58 return{
59 beg: set_point(a,b),
60 end: set_point(c,d)
61 }
62 }
63 //возвращает последний элемент массива
64 function last(array)
65 {
66 if(array.length != 0)
67 {
68 return array[array.length - 1];
69 }
70 }
71 //отрисовывает ребра
72 function draw(m, color)
73 {
74 ctx.width = 1;
75 ctx.beginPath()
76 ctx.moveTo(m.beg.x, m.beg.y);
77 ctx.lineTo(m.end.x, m.end.y);
78 ctx.strokeStyle = color;
79 ctx.fillStyle = "rgba(0, 0, 200, 1)";
80 ctx.lineWidth =3 ;
81 ctx.stroke();
82 }
83
84 // only for edge_vert and edge_hor, проверяет есть ли уже такое ребро в массиве
85 function is_in(arr, x1, y1, x2, y2)
86 {
87 for(var i = 0; i < arr.length; i++)
88 {
89 if(arr[i].beg.x == x1 && arr[i].beg.y == y1
90 && arr[i].end.x == x2 && arr[i].end.y == y2)
91 {
92 return true;
93 }
94 }
95 return false;
96 }
97 //аналогично is_in, но возвращает индекс
98 function find(arr, x1, y1, x2, y2)
99 {
100 for(var i = 0; i < arr.length; i++)
101 {
102 if(arr[i].beg.x == x1 && arr[i].beg.y == y1
103 && arr[i].end.x == x2 && arr[i].end.y == y2)
104 {
105 return i;
106 }
107 }
108 return -1;
109 }
110
111 //проверка нажатия
112 function check(m) {
113 for(var i = 0; i < N; i += 50){
114 if(abs(m.x - i) < eps)
115 {
116 if( !is_in(edge_vert, i, m.y - m.y%50, i, m.y - m.y%50 + 50) )
117 {
118 edge_vert.push(set_edge(i, m.y - m.y%50, i, m.y - m.y%50 + 50));
119 IsBelongs_vert = true;
120 }
121 else
122 {
123 var ind = find(edge_vert, i, m.y - m.y%50, i, m.y - m.y%50 + 50);
124 var m = edge_vert[ind];
125 draw(m, "black");
126 edge_vert.splice(ind, 1);
127 }
128 }
129 if (abs(m.y - i) < eps)
130 {
131 if( !is_in(edge_hor, m.x - m.x%50, i, m.x - m.x%50 + 50, i) )
132 {
133 edge_hor.push(set_edge(m.x - m.x%50, i, m.x - m.x%50 + 50, i)) ;
134 IsBelongs_hor = true;
135 }
136 else
137 {
138 var ind = find(edge_hor, m.x - m.x%50, i, m.x - m.x%50 + 50, i);
139 var m = edge_hor[ind];
140 draw(m, "black");
141 edge_hor.splice(ind, 1);
142 }
143 }
144 }
145 //console.log(edge_hor);
146 //console.log(edge_vert);
147 //console.log(mousecoords);
148 }
149 //определяет координаты мышки
150 function getMouseCoords(e) {
151 var m = {};
152 var rect = canvas_example.getBoundingClientRect();
153 m.x = e.clientX - rect.left;
154 m.y = e.clientY- rect.top;
155 return m;
156 }
157
158 canvas_example.onmousedown = function(e) {
159 if(!start_pressed)
160 {
161 var m = getMouseCoords(e);
162 check(m);
163 //console.log(edge_vert);
164 //console.log(edge_hor);
165 }
166 }
167
168 //рисуем выбранные ребра
169 canvas_example.onmouseup = function(e){
170 if(!start_pressed)
171 {
172 var m;
173 if(IsBelongs_vert){
174
175 m = last(edge_vert);
176 draw(m, "red");
177 }
178 if(IsBelongs_hor){
179 m = last(edge_hor);
180 draw(m, "red");
181 }
182 IsBelongs_hor = false;
183 IsBelongs_vert = false;
184 }
185 }
186 //привязываем появление частиц к нажатию кнопки старт
187 button_start.onclick = function() {
188 if(!start_pressed)
189 {
190 var particles = new Particles_generate(edge_vert,edge_hor);
191 var dt = 1 / particles.get_fps();
192 start_pressed = true;
193 setInterval(control.bind(this, particles), 1000 * dt);
194 start = new Date().getTime();
195
196 }
197 }
198 //отрисовывает выбранные ребра лабиринта
199 function Draw_labirint () {
200 ctx.clearRect(0,0,w,h);
201 var k;
202 for(var i = 0; i< edge_vert.length; i++){
203 k = edge_vert[i];
204 ctx.beginPath()
205 ctx.moveTo(k.beg.x, k.beg.y);
206 ctx.lineTo(k.end.x, k.end.y);
207 ctx.strokeStyle="red";
208 ctx.fillStyle = "rgba(0, 0, 200, 1)";
209 ctx.lineWidth=3;
210
211 ctx.stroke();
212 }
213
214 var n;
215 for(var j = 0; j < edge_hor.length; j++){
216 n = edge_hor[j];
217 ctx.beginPath()
218 ctx.moveTo(n.beg.x,
219
220 n.beg.y);
221 ctx.lineTo(n.end.x, n.end.y);
222 ctx.strokeStyle="red";
223 ctx.fillStyle = "rgba(0, 0, 200, 1)";
224 ctx.lineWidth=3;
225 ctx.stroke();
226 }
227 }
228
229 Plot(x,y);
230 //Particle();
231
232 function control(particles) {
233 if(!particles.stopped){
234 ctx.clearRect(0, 0, w, h);
235 Draw_labirint();
236 particles.Check_standoff();
237 particles.control();
238 particles.win();
239 //setInterval(control.bind(this, particles), 1000 * dt);
240 }
241 }
242 }
1 function is_in(arr, x1, y1) {
2 for (var i = 0; i < arr.length; i++) {
3 if (arr[i].x == x1 && arr[i].y == y1) {
4 return true;
5 }
6 }
7 return false;
8 }
9
10 function Particles_generate(edge_vert, edge_hor) {
11 var fps = 120;
12 var dt = 1 / fps;
13 var ctx = canvas_example.getContext('2d');
14 var w = canvas_example.width;
15 var h = canvas_example.height;
16 /*максимум может быть 25 частиц, поэтому возвращаем остаток от деления на 25
17 если пользователь ввел число больше 25*/
18 var N = parseInt(document.getElementById('n').value);
19 if(N % 25 == 0 && N != 0){
20 N = 25;
21 }
22 else if (N == 0){
23 N = 0;
24 }
25 else {
26 N = N%25;
27 }
28 var particles = [];
29 var r = 4;
30 var cells = 12;
31 var small_cells = 5;
32 var r_max = 5;
33 var that_2 = this;
34
35 that_2.stopped = false;
36
37 function abs(x)
38 {
39 if(x < 0){
40 return -x;
41 }
42 else{
43 return x;
44 }
45 }
46 //проверка столкновений
47 function standoff (part1, part2 )
48 {
49 if((part1.x - part2.x)*(part1.x - part2.x) +
50 (part1.y - part2.y)*(part1.y - part2.y) <= 4*r*r )
51 {
52 var m = part1.vx;
53 var t = part1.vy;
54 part1.vx = part2.vx;
55 part1.vy = part2.vy;
56 part2.vx = m;
57 part2.vy = t;
58 }
59 }
60 //проверка столкновений с ребрами
61 function Edge_standoff( arr1, arr2, arr3){
62 for ( var i = 0; i < arr1.length; i++){
63 for ( var j = 0; j < arr2.length; j++){
64 if( abs(arr1[i].x - arr2[j].beg.x) <= r &&
65 arr1[i].y < Math.max(arr2[j].beg.y, arr2[j].end.y) &&
66 arr1[i].y > Math.min(arr2[j].beg.y, arr2[j].end.y) )
67 {
68 arr1[i].vx = -arr1[i].vx;
69 }
70 if(Math.min((arr1[i].x - arr2[j].beg.x)*(arr1[i].x - arr2[j].beg.x) +
71 (arr1[i].y - arr2[j].beg.y)*(arr1[i].y - arr2[j].beg.y),
72 (arr1[i].x - arr2[j].end.x)*(arr1[i].x - arr2[j].end.x) +
73 (arr1[i].y - arr2[j].end.y)*(arr1[i].y - arr2[j].end.y)) <= r*r &&
74 (arr1[i].y >= Math.max(arr2[j].beg.y, arr2[j].end.y) ||
75 arr1[i].y <= Math.min(arr2[j].beg.y, arr2[j].end.y) ))
76
77 {
78 arr1[i].vx = -arr1[i].vx;
79 arr1[i].vy = -arr1[i].vy;
80 }
81 }
82 for( var j = 0; j < arr3.length; j++)
83 {
84 if( abs(arr1[i].y - arr3[j].beg.y) <= r &&
85 arr1[i].x < Math.max(arr3[j].beg.x, arr3[j].end.x) &&
86 arr1[i].x > Math.min(arr3[j].beg.x, arr3[j].end.x) )
87 {
88 arr1[i].vy = -arr1[i].vy;
89 }
90
91 }
92
93 }
94
95 }
96
97 that_2.get_fps = function() {
98 return fps;
99 };
100
101 that_2.Particle = function(x , y , vx , vy ) {
102 this.x = x;
103 this.y = y;
104 this.vx = vx;
105 this.vy = vy;
106 var that = this;
107
108 this.info = function() {
109 console.log(
110 'Position: (' + that.x + ', ' + that.y + ')\nVelocity: (' + that.vx +
111 ',' + that.vy + ')');
112 };
113 //движение+ проверка стокновений с границами
114 this.move = function() {
115
116 if( that.x >= w-r || that.x <= r){
117 that.vx = -that.vx;
118 }
119 if( that.y >= h-r || that.y <= r){
120 that.vy = -that.vy;
121 }
122 that.x += that.vx * dt;
123 that.y += that.vy * dt;
124 };
125
126 this.draw = function() {
127 ctx.strokeStyle="green";
128 ctx.beginPath();
129 ctx.arc(that.x, that.y, r, 0, 2 * Math.PI);
130 ctx.stroke();
131 }
132 };
133
134 that_2.generate = function() {
135 return (Math.floor(Math.random() * small_cells * small_cells) % (small_cells * small_cells));
136 };
137
138 that_2.Phys = function() {
139 for (var i = 0; i < particles.length; i++) {
140 particles[i].move();
141 }
142 };
143
144 that_2.draw = function() {
145 //ctx.clearRect(0, 0, w, h);
146 for (var i = 0; i < particles.length; i++) {
147 // console.log(particles.length);
148 particles[i].draw();
149 }
150 };
151
152 that_2.Check_standoff = function (){
153 console.log(particles);
154 for (var i = 0; i < particles.length; i++){
155 for (var j = i+1; j < particles.length; j++){
156 standoff (particles[i], particles[j]);
157 }
158 }
159 Edge_standoff( particles, edge_vert,edge_hor);
160 }
161 that_2.control = function() {
162 that_2.Phys();
163 that_2.draw();
164 console.log(N);
165 };
166 //проверка попала ли частица в выигрышную область, завершение игры
167 that_2.win = function (){
168 for( var i = 0; i < particles.length; i++){
169 if( particles[i].x > 500 + r && particles[i].y > 500 + r){
170 particles.splice(i,1);
171 var end = new Date().getTime();
172 console.log(start);
173 console.log(end);
174 var time = end - start;
175 var time_sec = time/1000;
176 console.log(time);
177 ctx.fillRect(500,500,100,100);
178 that_2.stopped = true;
179 ctx.fillStyle = "blue";
180 setTimeout(function() {
181 alert('You have won!\n Your time is '+time_sec+'sec');
182 ctx.clearRect(0,0,
183
184
185
186 w, h);
187 }, 15);
188 break;
189 }
190 }
191 }
192
193 //генерируем частицы
194 for (var j = 0; j < N; j++) {
195 var fi = Math.random() * Math.PI * 2;
196 var i = that_2.generate();
197 if (!is_in(
198 particles, r_max + 2*r_max * (i % 5),
199 r_max + 2*r_max * Math.floor(i / 5))) {
200 particles.push(new that_2.Particle(
201 r_max + 2*r_max * (i % 5),
202 r_max + 2*r_max * Math.floor(i / 5), 75 * Math.cos(fi),
203 75 * Math.sin(fi)))
204 }
205 else
206 {
207 i1 = i;
208 offset = 1;
209 while(true)
210 {
211 i1 += offset;
212 if(i1 == small_cells*small_cells)
213 {
214 i1 = i - 1;
215 offset = -1;
216 }
217 if(!is_in(particles,r_max + 2*r_max * (i1 % 5),
218 r_max+ 2*r_max * Math.floor(i1 / 5)))
219 {
220 particles.push(new that_2.Particle(
221 r_max + 2*r_max * (i1 % 5),
222 r_max + 2*r_max * Math.floor(i1 / 5),
223 100 * Math.cos(fi),
224 100 * Math.sin(fi)
225 ))
226 break;
227 }
228 }
229 }
230 }
231 }
1 <html>
2 <head>
3 <meta charset='utf-8'>
4 <title>ЛАБИРИНТ</title>
5 <script src='project.js'></script>
6 <script src='particles_generate.js'> </script>
7 </head>
8 <body>
9 <canvas id='canvas_example' width=600 height=600 style='border: 1px solid #000000'></canvas>
10 <div align ='left'>
11 <input id='n'type='number'><br/>
12 <input type = 'button' id= 'button_start' value='Start'>
13 </div>
14 </body>
15 </html>