Лабиринт

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск

Описание[править]

Реализация компьютерной игры Лабиринт на языке программирования JavaScript

Правила игры:

1. Перед пользователем появляется клетчатое поле, пустое окно для ввода чисел снизу и кнопка «Start»

2. Задача нарисовать лабиринт. Используя правую кнопку мыши, игрок нажимает на ребра сетки или около него, чтобы создать стенку в лабиринте. Повторное нажатие убирает, нарисованный объект. Далее игрок вводит число объектов (шаров), которое не должно превышать 25, в специальном поле, расположенным ниже лабиринта, и нажимает «Start», чтобы запустить игру.

3. После старта частицы начинают двигаться, отталкиваясь от стенок лабиринта, самого поля и от друг друга абсолютно упруго. Игра заканчивается тогда, когда первая из частиц попадает в определенную область, произвольно генерирующуюся в поле и проявляющуюся на мониторе по окончании игры.

4. После окончание на экран игрока выводится слова о его победе и время движения выигравшей частицы.

Реализация[править]

Перечень функций, которые были использованы для написания программы:

• В основе визуализации каждого метода используется элемент <canvas>

• Для создания элементов управления используется форма <input>

• Код программы на языке JavaScript разбит на несколько основных поочередно вызываемых функций: ввод, подсчёты, рисование; используются различные циклы для проверки нажатия при построении лабиринта и нахождения частиц в поле.

Авторы[править]

Разработчики: Бутузова Евдокия, Галанина Екатерина

Группа 3630103/90003 Кафедра Теоретической механики

Визуализация[править]

Код программы[править]

Код программы на языке JavaScript:
  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 }
Код подпрограммы на языке JavaScript:
  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 }
Код программы на языке HTML:
 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>