Doodle jump
Материал из Department of Theoretical and Applied Mechanics
Описание
Реализация и визуализация игры Doodle Jump с добавлением авторского дизайна: "Doodle Jump: doodler with luv edition".
Автор: Зеленкина Екатерина
Группа 3630103/00001
Игра
Управление:
- [A] [D] / [←] [→] - движение вправо-влево
- левая кнопка мыши - испускание лучей любви в указанное место
- [W] / [ ↑ ] - испускание лучей любви вверх
Начисление очков:
- платформа - 80
- пружина - 120
- розовый platform monster - 250
- голубой flying monster - 400
- зелёный levitating monster - 650
Код программы
HTML:
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <meta charset="utf-8">
5 <script src = "doodle.js"></script>
6 <style type="text/css">
7 canvas {
8 padding-left: 0;
9 padding-right: 0;
10 display: block;
11 background-color: RGB(247, 239, 231);
12 }
13 </style>
14 </head>
15 <body style='margin: 0px;'>
16 <span style="position: absolute; top: 16px; left: 80px; font-family: fantasy;" id="scoretext"></span>
17 <span style="position: absolute; top: 16px; left: 315px; font-family: fantasy;" id="highscoretext"></span>
18 <canvas id = "ccanvas"
19 width = 400 height = 50
20 style = "border: #000000 solid 1px";>
21 </canvas>
22 <canvas id = "canvas"
23 width = 400 height = 600
24 style = "border: #000000 solid 1px";>
25 </canvas>
26 </body>
27 </html>
JavaScript:
1 window.addEventListener('load', main, false);
2
3 var background = new Image;
4 background.onload = function() {
5 console.log('Loaded')
6 }
7 background.src = 'back.jpg';
8
9 var menu = new Image;
10 menu.onload = function() {
11 console.log('Loaded')
12 }
13 menu.src = 'menu2.png';
14
15 var head = new Image;
16 head.onload = function() {
17 console.log('Loaded')
18 }
19 head.src = 'head.png';
20
21 var doodlerImage = new Image;
22 doodlerImage.onload = function() {
23 console.log('Loaded')
24 }
25 doodlerImage.src = 'doodler.png';
26
27 var platImage = new Image;
28 platImage.onload = function() {
29 console.log('Loaded')
30 }
31 platImage.src = 'plat.png';
32
33 var PlatMonsterImage = new Image;
34 PlatMonsterImage.onload = function() {
35 console.log('Loaded')
36 }
37 PlatMonsterImage.src = 'monsterA.png';
38
39 var FlyMonsterImage = new Image;
40 FlyMonsterImage.onload = function() {
41 console.log('Loaded')
42 }
43 FlyMonsterImage.src = 'monsterB.png';
44
45 var FlyMonsterMirrorImage = new Image;
46 FlyMonsterMirrorImage.onload = function() {
47 console.log('Loaded')
48 }
49 FlyMonsterMirrorImage.src = 'monsterBm.png';
50
51 var LeviMonsterImage = new Image;
52 LeviMonsterImage.onload = function() {
53 console.log('Loaded')
54 }
55 LeviMonsterImage.src = 'monsterC.png';
56
57 var HoleImage = new Image;
58 HoleImage.onload = function() {
59 console.log('Loaded')
60 }
61 HoleImage.src = 'hole.png';
62
63 var SpringImage = new Image;
64 SpringImage.onload = function() {
65 console.log('Loaded')
66 }
67 SpringImage.src = 'spring.png';
68
69 var PewImage = new Image;
70 PewImage.onload = function() {
71 console.log('Loaded')
72 }
73 PewImage.src = 'pew.png';
74
75
76 function main() {
77
78 console.log('connected');
79
80 var ctxh = ccanvas.getContext('2d');
81 var hh = ccanvas.height;
82 var wh = ccanvas.width;
83
84 ctxh.drawImage(head, 0, 0, wh, hh);
85
86 var ctx = canvas.getContext('2d');
87 var h = canvas.height;
88 var w = canvas.width;
89
90 var gameStarted = true;
91 var platList = [];
92 var bullets=[];
93 var dt = 0.25;
94 var t = 0;
95 var g = 20;
96 var gap = h/5;
97 var pause = true;
98 var score = 0;
99 var highscore = 0;
100 var isLose = false;
101
102 const doodler = {
103 x: 0,
104 y: 450,
105 vy: -80,
106 vx: 50,
107 w: 40,
108 h: 40,
109 move: 'none',
110 draw: ()=>{
111 ctx.drawImage(doodlerImage, doodler.x, doodler.y, doodler.w, doodler.h);
112 },
113 isHit: false,
114 }
115
116 // пули
117 function b(){
118 this.x;
119 this.y;
120 this.r = 7;
121 this.vx = 10;
122 this.vy = 10;
123 this.dx;
124 this.dy;
125 this.angle;
126 this.arg;
127 this.draw = ()=>{
128 ctx.drawImage(PewImage, this.x-7, this.y-7, 2*this.r, 2*this.r);
129 };
130 this.m = {};
131 this.target = (e)=>{
132 this.m.x = e.offsetX;
133 this.m.y = e.offsetY;
134 return this.m;
135 }
136 }
137
138
139 function setupPlat(){
140 for (var i=0; i<5; i++){
141 var PlatY = i*gap;
142 var plat = new Platform(PlatY);
143 platList.push(plat);
144 }
145 doodler.x = plat.x + 24;
146 }
147
148 function PlatformMonster(x, y) {
149 this.x = x;
150 this.y = y;
151 this.w = 75;
152 this.h = 50;
153 this.vx = 30;
154 this.draw = () => {
155 ctx.drawImage(PlatMonsterImage, this.x, this.y, this.w, this.h);
156 }
157 this.moveY = (dy) => {
158 this.y -= dy;
159 }
160 }
161
162 function LevitatingMonster(x, y){
163 this.x = x;
164 this.y = y;
165 this.w = 50;
166 this.h = 50;
167 this.vx;
168 this.vy;
169 this.currentAngle = 0;
170 this.draw = () => {
171 ctx.drawImage(LeviMonsterImage, this.x, this.y, this.w, this.h);
172 }
173 this.moveY = (dy) => {
174 this.y -= dy;
175 }
176 }
177
178 function FlyingMonster(x, y) {
179 this.x = x;
180 this.y = y;
181 this.w = 45;
182 this.h = 45;
183 this.vx = 30;
184 this.draw = () => {
185 if( this.vx<0){
186 ctx.drawImage(FlyMonsterImage, this.x, this.y, this.w, this.h);
187 } else {
188 ctx.drawImage(FlyMonsterMirrorImage, this.x, this.y, this.w, this.h);
189 }
190 }
191 this.moveY = (dy) => {
192 this.y -= dy;
193 }
194 }
195
196 function BlackHole(x, y){
197 this.x = x;
198 this.y = y;
199 this.r = 37;
200 this.draw = () => {
201 ctx.drawImage(HoleImage, this.x-37, this.y-37, 2*this.r, 2*this.r);
202 }
203 this.moveY = (dy) => {
204 this.y -= dy;
205 }
206 }
207
208 function Platform(PlatY){
209 this.x = Math.floor(((Math.random()*286) + 15))
210 this.y = PlatY;
211 this.w = 85;
212 this.h = 17;
213 this.firstHit = 0;
214 this.firstSpring = 0;
215 // пружина
216 this.sprX = this.x+Math.floor(Math.random() * 55);
217 this.isSpring = Math.random() < 0.2;
218 // монстры
219 if (!this.isSpring && score > 1500){
220 this.isMonster = Math.random() < 0.3;
221 }
222 if (!this.isSpring && score > 3000){
223 this.isMonster = Math.random() < 0.5;
224 }
225 if (!this.isSpring && score > 5000){
226 this.isMonster = Math.random() < 0.7;
227 }
228 if (this.isMonster) {
229 this.kind = Math.floor((Math.random()*3)+1);
230 if (this.kind == 1){
231 this.pmonster = new PlatformMonster(this.x+5, this.y-70);
232 } else if (this.kind == 2){
233 this.fmonster = new FlyingMonster(this.x, this.y-80);
234 } else if(score > 2700 && this.kind == 3 && this.x > 50 && this.x+this.w<250){
235 this.lmonster = new LevitatingMonster (this.x+15, this.y-90);
236 }
237 }
238 this.move = (dy) => {
239 this.y -= dy;
240 if (this.isMonster) {
241 if (this.pmonster){
242 this.pmonster.moveY(dy);
243 }
244 if (this.lmonster){
245 this.lmonster.moveY(dy);
246 }
247 if(this.fmonster){
248 this.fmonster.moveY(dy);
249 }
250 }
251 if(this.hole){
252 this.hole.moveY(dy);
253 }
254 }
255 // черные дыры
256 if (!this.isMonster && !this.isSpring && score>3000){
257 this.isHole = Math.random()<0.1;
258 }
259 if (!this.isMonster && !this.isSpring && score>8000){
260 this.isHole = Math.random()<0.3;
261 }
262 if(this.isHole){
263 if (this.x > 70 && this.x < 260){
264 this.bla = Math.random();
265 if(this.bla <=0.5){
266 this.hole = new BlackHole((this.x-(Math.random()*15+1)), (this.y-(Math.random()*11+50)))
267 } else {
268 this.hole = new BlackHole((this.x+this.w+(Math.random()*15+1)),(this.y-(Math.random()*11+50)))
269 }
270 }
271 }
272 // прорисовка
273 this.draw = () => {
274 if (this.isSpring){
275 ctx.drawImage(SpringImage, this.sprX, this.y-17, 17, 17);
276 }
277 ctx.drawImage(platImage, this.x, this.y, this.w, this.h);
278 if (this.pmonster) {
279 this.pmonster.draw();
280 }
281 if (this.lmonster){
282 this.lmonster.draw();
283 }
284 if (this.fmonster){
285 this.fmonster.draw();
286 }
287 if(this.hole){
288 this.hole.draw();
289 }
290 }
291 }
292
293 function draw(){
294 scoretext.innerHTML = score;
295 highscoretext.innerHTML = highscore;
296 if (pause) {
297 ctx.drawImage(menu, 0, 0, w, h);
298 } else {
299 ctx.clearRect(0, 0, w, h);
300 ctx.drawImage(background, 0, 0, w, h);
301 for (const plat of platList) {
302 plat.draw();
303 }
304 doodler.draw();
305 for (const pew of bullets){
306 pew.draw();
307 }
308 }
309 }
310
311 function loosing(){
312 if(highscore<score){
313 highscore = score;
314 }
315 ctx.clearRect(0, 0, w, h);
316 pause = true;
317 doodler.x = 0;
318 doodler.y = 450;
319 doodler.w = 40;
320 doodler.h = 40;
321 doodler.vy = -80;
322 doodler.vx = 50;
323 doodler.isHit = false;
324 score = 0;
325 bullets = [];
326 platList = [];
327 isLose = false;
328
329 }
330
331 function collision(monster){
332 if
333 (((monster.y+monster.h>doodler.y && monster.y+monster.h<doodler.y+doodler.h) &&
334 (monster.x<doodler.x+doodler.w && monster.x+monster.w>doodler.x))
335 ||
336 ((monster.x+monster.w>doodler.x && monster.x+monster.w<doodler.x+doodler.w) &&
337 (monster.y+monster.h>doodler.y && monster.y<doodler.y+doodler.h))
338 ||
339 ((monster.x<doodler.x+doodler.w && monster.x>doodler.x) &&
340 (monster.y+monster.h> doodler.y && monster.y<doodler.y+doodler.h)))
341 {
342 doodler.isHit = true;
343 doodler.vy = 60;
344 }
345 }
346
347 function upcollision(monster){
348 if(doodler.isHit == false){
349 if (doodler.y+doodler.h>monster.y && doodler.y+doodler.h < monster.y+monster.h) {
350 if ((doodler.x+doodler.w-monster.x<monster.w && doodler.x+doodler.w-monster.x>0) ||
351 (monster.x+monster.w-doodler.x>0 && monster.x+monster.w-doodler.x<monster.w)) {
352 doodler.isHit = true;
353 doodler.vy = -60;
354 }
355 }
356 }
357 }
358
359 function shooting(plat, bullet, points){
360 var monster = plat.pmonster || plat.fmonster || plat.lmonster
361 if
362 // монстр над
363 (((monster.y + monster.h>bullet.y-bullet.r && monster.y+monster.h<bullet.y+bullet.r) &&
364 (monster.x<bullet.x+bullet.r && monster.x+monster.w>bullet.x-bullet.r))
365 ||
366 // монстр левее
367 ((monster.x+monster.w>bullet.x-bullet.r && monster.x+monster.w<bullet.x+bullet.r) &&
368 (monster.y+monster.h>bullet.y-bullet.r && monster.y<bullet.y+bullet.r))
369 ||
370 // монстр правее
371 ((monster.x<bullet.x+bullet.r && monster.x>bullet.x-bullet.r) &&
372 (monster.y+monster.h>bullet.y-bullet.r && monster.y<bullet.y+bullet.r)))
373 {
374 plat.pmonster = 0; //исчезает
375 plat.fmonster = 0;
376 plat.lmonster = 0;
377 score+=points;
378 }
379 }
380
381 function physics(){
382 if (!pause) {
383 //перемещение вверх
384 doodler.vy += g*dt;
385 //перемещение влево-вправо
386 if (doodler.move=='left') {
387 doodler.x -= doodler.vx*dt;
388 } else if (doodler.move=='right') {
389 doodler.x += doodler.vx*dt;
390 }
391 //столкновение с платформой
392 if (!doodler.isHit){
393 if (doodler.vy>0) {
394 for (const plat of platList) {
395 if (doodler.y+doodler.h>plat.y && doodler.y+doodler.h < plat.y+plat.h) {
396 if ((doodler.x+doodler.w-plat.x<plat.w && doodler.x+doodler.w-plat.x>0) ||
397 (plat.x+plat.w-doodler.x>0 && plat.x+plat.w-doodler.x<plat.w)) {
398 doodler.vy = -80;
399 plat.firstHit +=1;
400 if(plat.firstHit == 1){
401 plat.firstHit = -100000000;
402 score += 80;
403 }
404 }
405 }
406 if (plat.isSpring){
407 if (doodler.y+doodler.h>plat.y-17 && doodler.y+doodler.h < plat.y-17+17) {
408 if (doodler.x<plat.sprX+17 && doodler.x + doodler.w > plat.sprX) {
409 doodler.vy = -120;
410 plat.firstSpring +=1;
411 if(plat.firstSpring == 1){
412 plat.firstSpring = -100000000;
413 score += 120;
414 }
415 }
416 }
417 }
418 }
419 }
420 }
421 //перемещение платформ
422 if (doodler.y<350 && doodler.vy<0) {
423 for (const plat of platList) {
424 plat.move(doodler.vy*dt);
425 }
426 } else {
427 doodler.y += doodler.vy*dt;
428 }
429 //новые платформы
430 if (platList[0].y>gap) {
431 platList.unshift(new Platform(-17));
432 }
433 //удаление старых
434 for (const plat of platList){
435 if (plat.y-100 > h){
436 platList.pop();
437 }
438 }
439 // перемещение дудлера за пределы канваса
440 if (doodler.x < -doodler.w) {
441 doodler.x = w;
442 } else if (doodler.x > w){
443 doodler.x = -doodler.w
444 }
445 // проигрыш
446 if (doodler.y > h){
447 isLose = true;
448 loosing();
449 }
450 // монстры + пули
451 for (const plat of platList){
452 if(plat.isMonster){
453 // МОНСТР 1
454 if(plat.pmonster){
455 plat.pmonster.x += plat.pmonster.vx*dt/10;
456 if( plat.pmonster.x < plat.x+3 || plat.pmonster.x+75 > plat.x+82){
457 plat.pmonster.vx *= -1;
458 }
459 for(const pew of bullets){
460 shooting(plat, pew, 250)
461 }
462 collision(plat.pmonster);
463 if (doodler.isHit == false){
464 if (doodler.y+doodler.h>plat.pmonster.y && doodler.y+doodler.h < plat.pmonster.y+plat.pmonster.h) {
465 if ((doodler.x+doodler.w-plat.pmonster.x<plat.pmonster.w && doodler.x+doodler.w-plat.pmonster.x>0) ||
466 (plat.pmonster.x+plat.pmonster.w-doodler.x>0 && plat.pmonster.x+plat.w-doodler.x<plat.pmonster.w)) {
467 doodler.isHit = false;
468 doodler.vy = -120;
469 plat.pmonster = 0;
470 score += 250;
471 }
472 }
473 }
474 }
475
476 // МОНСТР 2
477 if(plat.fmonster){
478 plat.fmonster.x += plat.fmonster.vx*0.15;
479 if( plat.fmonster.x < 3 || plat.fmonster.x+50 > w-3){
480 plat.fmonster.vx *= -1;
481 }
482 for(const pew of bullets){
483 shooting(plat, pew, 400)
484 }
485 collision(plat.fmonster);
486 upcollision(plat.fmonster);
487 }
488
489 // МОНСТР 3
490 if(plat.lmonster){
491 plat.lmonster.vx = Math.cos(plat.lmonster.currentAngle)*30;
492 plat.lmonster.vy = Math.sin(plat.lmonster.currentAngle)*30;
493 plat.lmonster.currentAngle += 0.1;
494 plat.lmonster.x += plat.lmonster.vx*dt;
495 plat.lmonster.y += plat.lmonster.vy*dt;
496 for(const pew of bullets){
497 shooting(plat, pew, 650)
498 }
499 collision(plat.lmonster);
500 upcollision(plat.lmonster);
501 }
502 }
503 if (plat.hole){
504 if
505 (((doodler.x>plat.hole.x-plat.hole.r && doodler.x< plat.hole.x+plat.hole.r) &&
506 (doodler.y>plat.hole.y-plat.hole.r && doodler.y<plat.hole.y+plat.hole.r))
507 ||
508 ((doodler.x+doodler.w>plat.hole.x-plat.hole.r && doodler.x+doodler.w< plat.hole.x+plat.hole.r) &&
509 (doodler.y>plat.hole.y-plat.hole.r && doodler.y<plat.hole.y+plat.hole.r))
510 ||
511 ((doodler.x>plat.hole.x-plat.hole.r && doodler.x< plat.hole.x+plat.hole.r) &&
512 (doodler.y+doodler.h>plat.hole.y-plat.hole.r && doodler.y+doodler.h<plat.hole.y+plat.hole.r))
513 ||
514 ((doodler.x+doodler.w>plat.hole.x-plat.hole.r && doodler.x+doodler.w< plat.hole.x+plat.hole.r) &&
515 (doodler.y+doodler.h>plat.hole.y-plat.hole.r && doodler.y+doodler.h<plat.hole.y+plat.hole.r)))
516 {
517 isLose = true;
518 for (var i=0; i<doodler.w; i++){
519 doodler.vy = 0;
520 doodler.y = plat.hole.y-doodler.h/2;
521 doodler.x = plat.hole.x-doodler.w/2;
522 doodler.w -= 0.08;
523 doodler.h -= 0.08;
524 if(doodler.w <=0){
525 loosing();
526 }
527 }
528 }
529 }
530 }
531
532 // запуск пуль
533 for (const pew of bullets){
534 if(pew.dx>0){
535 pew.x += 10*dt*pew.vx*(Math.cos(pew.angle));
536 pew.y += 10*dt*pew.vy*-1*Math.sin(pew.angle);
537 }
538 if(pew.dx<0){
539 pew.x -= 10*dt*pew.vx*(Math.cos(pew.angle));
540 pew.y -= 10*dt*pew.vy*-1*Math.sin(pew.angle);
541 }
542 if(pew.x == 0){
543 pew.y -= 4*dt*pew.vy*-1
544 }
545 if(pew.x> w+5 || pew.x < -5 || pew.y < -5){
546 bullets.shift();
547 }
548 }
549 }
550 }
551
552 document.onkeydown = function (e) {
553 if (e.keyCode==65 || e.keyCode==37) {
554 // move left
555 doodler.move = 'left';
556 } else
557 if (e.keyCode==68 || e.keyCode==39) {
558 //move right
559 doodler.move = 'right';
560 }
561 }
562
563 document.onkeyup = function (e) {
564 if ((e.keyCode==65 || e.keyCode==37)&&doodler.move=='left') {
565 // move left
566 doodler.move = 'none';
567 } else
568 if ((e.keyCode==68 || e.keyCode==39)&&doodler.move=='right') {
569 //move right
570 doodler.move = 'none';
571 }
572 if (e.keyCode == 87 || e.keyCode == 38 ){
573 const p = {
574 offsetX: doodler.x+18,
575 offsetY: 20,
576 }
577 shoot(p);
578 }
579 }
580
581 function shoot(e){
582 if(isLose==false){
583 var pew = new b();
584 pew.target(e);
585 if (pew.m.x == doodler.x){
586 pew.m.x = doodler.x-1;
587 }
588 pew.y = doodler.y -10;
589 pew.dy = doodler.y - pew.m.y;
590 pew.dx = pew.m.x - doodler.x;
591 if(pew.dx<0){
592 pew.x = doodler.x;
593 } else {
594 pew.x = doodler.x + 40;
595 }
596 pew.arg = pew.dy/pew.dx;
597 if(pew.dy == 0){
598 pew.dy = Math.abs(pew.dx)*1.5;
599 }
600 // левая половина
601 if(pew.dx<0 && pew.dy<0){
602 pew.dy = Math.abs(pew.dy);
603 if(pew.arg>-0.5){
604 pew.arg = -0.5;
605 }
606 if(pew.arg<-10){
607 pew.x = doodler.x+20;
608 }
609 }
610 if(pew.dx<0 && pew.dy>0){
611 if(pew.arg>-0.5){
612 pew.arg = -0.5;
613 }
614 if(pew.arg<-10){
615 pew.x = doodler.x+20;
616 }
617 }
618 // правая половина
619 if(pew.dx>0 && pew.dy<0){
620 pew.dy = Math.abs(pew.dy);
621 if(pew.arg<0.5){
622 pew.arg = 0.5;
623 }
624 if(pew.arg>10){
625 pew.x = doodler.x+20;
626 }
627 }
628 if(pew.dx>0 && pew.dy>0){
629 if(pew.arg<0.5){
630 pew.arg = 0.5;
631 }
632 if(pew.arg>10){
633 pew.x = doodler.x+20;
634 }
635 }
636 pew.angle = Math.atan(pew.arg);
637 bullets.push(pew);
638 }
639 }
640
641 canvas.onmouseup = function(e) {
642 if (pause) {
643 pause = false;
644 setupPlat();
645 for (const plat of platList) {
646 plat.draw();
647 }
648 doodler.draw();
649 } else {
650 shoot(e);
651 }
652 }
653
654 function control(){
655 physics();
656 draw();
657 }
658
659 setInterval(control, 1000/30);
660
661 }