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 }