C语言学习教程:超级玛丽游戏开发源码分享
程序员文章站
2022-07-02 12:53:45
c语言写的超级玛丽游戏源代码,学习之余还可以重温一下儿时的经典。益智游戏,较为广泛的流通。马里奥是站在游戏界顶峰的超人气多面角色 ......
c语言写的超级玛丽游戏源代码,学习之余还可以重温一下儿时的经典。
益智游戏,较为广泛的流通。马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带工作服、还留着胡子。与他的双胞胎兄弟路易一起,长年担任任天堂的超级大牌角色。这款很经典的红白机游戏,唤起了大家儿时的快乐时光。快点来尝试下吧!此次推出的是完美版,完美音效、键盘操作更加灵敏、玛丽生命无限
这里推荐一下我建的c/c++语言学习交流秋秋裙,前三位是:110,中间三位是:355,最后三位是:025,为了让学习变得轻松,高效!给大家分享一套教学资源,帮助大家在成为c/c++语言开发高手的道路上披荆斩棘,群内每晚八点免费直播授课,讲解c/c++语言案例,同时还有c/c++语言大牛在线解答问题!虽然说c/c++语言开发发展前景好,但易学难精。由于入门容易这也导致了市场上人员泛滥、人才稀缺的局面产生。但是在互联网越来越强烈的竞争下,这样的人也最终会被市场淘汰。
超级玛丽游戏开发源码
1 <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> 2 <html> 3 <head> 4 <title> new document </title> 5 <meta name="generator" content="editplus"> 6 <meta name="author" content=""> 7 <meta name="keywords" content=""> 8 <meta name="description" content=""> 9 <style type="text/css"> 10 *body{margin:0 auto;} 11 #status{ 12 position: absolute; 13 left: 50%; 14 top: 170px; 15 margin-left: 60px; 16 } 17 .background { 18 background: rgb(52, 166, 251); 19 table-layout: fixed; 20 border-spacing: 0; 21 } 22 .background td { padding: 0; } 23 .lava { background: rgb(255, 100, 100); } 24 .wall { background: white; } 25 .actor { position: absolute; } 26 .coin { background: rgb(241, 229, 89); } 27 .player { background: rgb(64, 64, 64); } 28 .lost .player { background: rgb(160, 64, 64); } 29 .won .player { 30 box-shadow: -4px -7px 8px white, 4px -7px 8px white; 31 } 32 .game { 33 overflow: hidden; 34 max-width: 600px; 35 max-height: 450px; 36 position: relative; 37 } 38 </style> 39 </head> 40 41 <body> 42 <!--<img style="position: absolute;right: 0;top: 0;" src=" http://a4.qpic.cn/psb?/v13id91s0o4nyt/y9r.1dx5wxfyfzzdqbmg2hsjlt7lizjpocpyg.6gxhk!/b/dembaaaaaaaa&ek=1&kp=1&pt=0&bo=lagyaqaaaaarf74!&vuin=206105759&tm=1522486800&sce=60-2-2&rf=viewer_4">--> 43 <div id='status'>how many lives you have left: <span id="lives"></span></div> 44 <script type="text/javascript"> 45 46 /* 47 based on dark blue by thomas palef. 48 plans are submitted as an array of strings that forms a grid. 49 @ = player start position 50 o = coins 51 x = solid surfaces 52 ! = non-moving lava 53 = = vertical moving lava 54 v = dripping lava 55 | = horizontal moving lava 56 */ 57 var simplelevelplan = [ 58 " ", 59 " ", 60 " x = x ", 61 " x o o x ", 62 " x @ xxxxx x ", 63 " xxxxx x ", 64 " x!!!!!!!!!!!!x ", 65 " xxxxxxxxxxxxxx ", 66 " " 67 ]; 68 69 var game_levels = [ 70 [" ", 71 " ", 72 " ", 73 " ", 74 " ", 75 " ", 76 " xxx ", 77 " xx xx xx!xx ", 78 " o o xx x!!!x ", 79 " xx!xx ", 80 " xxxxx xxx ", 81 " xx ", 82 " xx o o x ", 83 " x o x ", 84 " x xxxxx o x ", 85 " x xxxx o x ", 86 " x @ x x xxxxx x ", 87 " xxxxxxxxxxxx xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxx xxxxxxx xxxxxxxxx ", 88 " x x x x ", 89 " x!!!x xooooox ", 90 " xooox xooooox ", 91 " xxxxx xxxxxxx ", 92 " ", 93 " "], 94 [" x!!x xxxxxxx x!x ", 95 " x!!x xxxx xxxx x!x ", 96 " x!!xxxxxxxxxx xx xx x!x ", 97 " xx!!!!!!!!!!xx xx xx x!x ", 98 " xxxxxxxxxx!!x x o o o x!x ", 99 " xx!x x o o xx!x ", 100 " x!x x xxxxxxxxxxxxxxx!!x ", 101 " xvx x x x !!!!!!!!!!!!!!xx ", 102 " xx | | | xx xxxxxxxxxxxxxxxxxxxxx ", 103 " xx!!!!!!!!!!!xx v ", 104 " xxxx!!!!!xxxx ", 105 " x x xxxxxxx xxx xxx ", 106 " x x x x x x ", 107 " x x x x ", 108 " x x xx x ", 109 " xx x x x ", 110 " x x o o x x x x ", 111 " xxxxxxx xxx xxx x x x x x x ", 112 " xx xx x x x x xxxxxx x x xxxxxxxxx x ", 113 " xx xx x o x x xx x x x x ", 114 " @ x x x x x x x x x x ", 115 " xxx x x x x x x x xxxxx xxxxxx x ", 116 " x x x x xx o xx x x x o x x x ", 117 "!!!!x x!!!!!!x x!!!!!!xx xx!!!!!!!!xx x!!!!!!!!!! x = x x x ", 118 "!!!!x x!!!!!!x x!!!!!xx xxxxxxxxxx x!!!!!!!xx! xxxxxxxxxxxxx xx o o xx ", 119 "!!!!x x!!!!!!x x!!!!!x o xx!!!!!!xx ! xx xx ", 120 "!!!!x x!!!!!!x x!!!!!x xx!!!!!!xx ! xxxxxxx ", 121 "!!!!x x!!!!!!x x!!!!!xx xxxxxxxxxxxxxx!!!!!!xx ! ", 122 "!!!!x x!!!!!!x x!!!!!!xxxxxxxxx!!!!!!!!!!!!!!!!!!xx ! ", 123 "!!!!x x!!!!!!x x!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!xx ! "], 124 [" ", 125 " ", 126 " ", 127 " ", 128 " ", 129 " o ", 130 " ", 131 " x ", 132 " x ", 133 " x ", 134 " x ", 135 " xxx ", 136 " x x !!! !!! xxx ", 137 " x x !x! !x! ", 138 " xxx xxx x x ", 139 " x x x oooo x xxx ", 140 " x x x x x!!!x ", 141 " x x xxxxxxxxxxxx xxx ", 142 " xx xx x x x ", 143 " x xxxxxxxxx xxxxxxxx x x ", 144 " x x x x!!!x ", 145 " x x x xxx ", 146 " xx xx x ", 147 " x x= = = = x xxx ", 148 " x x x x!!!x ", 149 " x x = = = =x o xxx xxx ", 150 " xx xx x x!!!x ", 151 " o o x x x x xxv xxx ", 152 " x x x x x!!!x ", 153 " xxx xxx xxx xxx o o x!!!!!!!!!!!!!!x vx ", 154 " x xxx x x xxx x x!!!!!!!!!!!!!!x ", 155 " x x xxxxxxxxxxxxxxxxxxxxxxx ", 156 " xx xx xxx ", 157 " xxx x x x x!!!x xxx ", 158 " x x x xxx x xxx x x ", 159 " x x xxx xxxxxxx xxxxx x ", 160 " x x x x x x ", 161 " x xx x x x x x ", 162 " x x |xxxx| |xxxx| xxx xxx x ", 163 " x xxx o o x x xxx x ", 164 " x xxxxx xx x xxx x!!!x x x ", 165 " x oxxxo x xxx x x x xxx xxx x ", 166 " x xxx xxxxxxxxxxxxx x oo x x oo x x oo xx xx xxx x ", 167 " x @ x x x!!x x!!!!x x!!!!x xx xx x x ", 168 " xxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ", 169 " ", 170 " "], 171 [" xxx x ", 172 " x ", 173 " xxxxx ", 174 " x ", 175 " x xxx ", 176 " o x x x ", 177 " o o oxxx x ", 178 " xxx x ", 179 " ! o ! xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx ", 180 " x x x x x x x x x x x x x x x ", 181 " x= o x x xxx x xxx x xxx x xxx x xxx x xxx x xxxxx ", 182 " x x x x x x x x x x x x x x x ", 183 " ! o ! o xxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxxxx ", 184 " ", 185 " o xxx xx ", 186 " ", 187 " ", 188 " xx ", 189 " xxx xxx ", 190 " ", 191 " o x x ", 192 " xx xx ", 193 " xxx xxx xxx x x ", 194 " ", 195 " || ", 196 " xxxxxxxxxxx ", 197 " x x o xxxxxxxxx o xxxxxxxxx o xx x ", 198 " x x x x x x x || x x ", 199 " x @ xxxxx o xxxxx o xxxxx ", 200 " xxxxxxx xxxxx xx xx xxx ", 201 " x= = =x x xxx ", 202 " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x!!!!!!!!!!!!!!!!!!!!!xxx!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", 203 " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 204 " "] 205 ]; 206 207 // assumes the plan is valid (add validation for production) 208 function level(plan) { 209 this.width = plan[0].length; 210 this.height = plan.length; 211 // array of arrays, each position containing null or a character 212 this.grid = []; 213 // contains all of the dynamic objects (lava, coin or player), 214 // along with their position and state 215 this.actors = []; 216 217 for (var y = 0; y < this.height; y++) { 218 var line = plan[y], gridline = []; 219 for (var x = 0; x < this.width; x++) { 220 var ch = line[x], fieldtype = null; 221 var actor = actorchars[ch]; 222 if (actor) 223 // this constructs the referenced moving object in 224 // actorchars and pushes it to the actors array 225 this.actors.push(new actor(new vector(x, y), ch)); 226 else if (ch == 'x') 227 // wall 228 fieldtype = 'wall'; 229 else if (ch == '!') 230 // stationary lava 231 fieldtype = 'lava'; 232 gridline.push(fieldtype); 233 } 234 this.grid.push(gridline); 235 } 236 // find the player actor 237 this.player = this.actors.filter(function(actor) { 238 return actor.type == 'player'; 239 })[0]; 240 // track whether the player has won or lost; 241 // finishdelay keeps the level active for a brief period of time 242 this.status = this.finishdelay = null; 243 } 244 // figure out if the level is finished 245 level.prototype.isfinished = function() { 246 return this.status != null && this.finishdelay < 0; 247 }; 248 // figure out the collision area of an actor 249 level.prototype.obstacleat = function(pos, size) { 250 var xstart = math.floor(pos.x); 251 var xend = math.ceil(pos.x + size.x); 252 var ystart = math.floor(pos.y); 253 var yend = math.ceil(pos.y + size.y); 254 255 // the upper and side bounds of the level return a wall 256 if (xstart < 0 || xend > this.width || ystart < 0) 257 return 'wall'; 258 // the bottom bound returns lava 259 if (yend > this.height) 260 return 'lava'; 261 // check what's on the grid around the collision box 262 for (var y = ystart; y < yend; y++) { 263 for (var x = xstart; x < xend; x++) { 264 var fieldtype = this.grid[y][x]; 265 // returns 'wall' or 'lava' 266 if (fieldtype) return fieldtype; 267 } 268 } 269 }; 270 // track what actors overlap a given actor 271 level.prototype.actorat = function(actor) { 272 for (var i = 0; i < this.actors.length; i++) { 273 var other = this.actors[i]; 274 if (other != actor && 275 actor.pos.x + actor.size.x > other.pos.x && 276 actor.pos.x < other.pos.x + other.size.x && 277 actor.pos.y + actor.size.y > other.pos.y && 278 actor.pos.y < other.pos.y + other.size.y) 279 return other; 280 } 281 }; 282 // time increment for level.animate() 283 var maxstep = 0.05; 284 // animate the level 285 // step will be given in seconds, keys is an object that 286 // contains info about the arrow keys the player has pressed. 287 level.prototype.animate = function(step, keys) { 288 // used for the delay at the end of a game 289 if (this.status != null) 290 this.finishdelay -= step; 291 292 while (step > 0) { 293 var thisstep = math.min(step, maxstep); 294 this.actors.foreach(function(actor) { 295 actor.act(thisstep, this, keys); 296 }, this); 297 step -= thisstep; 298 } 299 }; 300 // handle collisions between actors 301 level.prototype.playertouched = function(type, actor) { 302 // lava's been touched 303 if (type == 'lava' && this.status == null) { 304 this.status = 'lost'; 305 this.finishdelay = 1; 306 } else if (type == 'coin') { // a coin's been touched 307 // remove the coin that's been collected from actors array 308 this.actors = this.actors.filter(function(other) { 309 return other != actor; 310 }); 311 // no more coins = you've won 312 if (!this.actors.some(function(actor) { 313 return actor.type == 'coin'; 314 })) { 315 this.status = 'won'; 316 this.finishdelay = 1; 317 } 318 } 319 } 320 321 var actorchars = { 322 '@': player, 323 'o': coin, 324 '=': lava, '|': lava, 'v': lava 325 }; 326 327 // vector stores the position and size of an actor 328 function vector(x, y) { 329 this.x = x; this.y = y; 330 } 331 vector.prototype.plus = function(other) { 332 return new vector(this.x + other.x, this.y + other.y); 333 } 334 vector.prototype.times = function(factor) { 335 return new vector(this.x * factor, this.y * factor); 336 } 337 338 // player constructor 339 function player(pos) { 340 // this properly aligns the bottom of the player 341 // to the square below (adjusts for player height) 342 this.pos = pos.plus(new vector(0, -0.5)); 343 this.size = new vector(0.8, 1.5); 344 this.speed = new vector(0, 0); 345 } 346 player.prototype.type = 'player'; 347 // x and y movement are handled independently because 348 // a wall shouldn't stop the up and down motion of jumping 349 // and a floor shouldn't stop side to side movement 350 var playerxspeed = 7; 351 player.prototype.movex = function(step, level, keys) { 352 this.speed.x = 0; 353 if (keys.left) this.speed.x -= playerxspeed; 354 if (keys.right) this.speed.x += playerxspeed; 355 356 var motion = new vector(this.speed.x * step, 0); 357 var newpos = this.pos.plus(motion); 358 var obstacle = level.obstacleat(newpos, this.size); 359 if (obstacle) 360 level.playertouched(obstacle); 361 else 362 this.pos = newpos; 363 }; 364 var gravity = 30; 365 var jumpspeed = 17; 366 player.prototype.movey = function(step, level, keys) { 367 this.speed.y += step * gravity; 368 var motion = new vector(0, this.speed.y * step); 369 var newpos = this.pos.plus(motion); 370 var obstacle = level.obstacleat(newpos, this.size); 371 if (obstacle) { 372 level.playertouched(obstacle); 373 if (keys.up && this.speed.y > 0) 374 this.speed.y = -jumpspeed; 375 else 376 this.speed.y = 0; 377 } else { 378 this.pos = newpos; 379 } 380 }; 381 player.prototype.act = function(step, level, keys) { 382 this.movex(step, level, keys); 383 this.movey(step, level, keys); 384 385 var otheractor = level.actorat(this); 386 if (otheractor) 387 level.playertouched(otheractor.type, otheractor); 388 389 // losing animation 390 if (level.status == 'lost') { 391 this.pos.y += step; 392 this.size.y -=step; 393 } 394 }; 395 396 // lava constructor 397 function lava(pos, ch) { 398 this.pos = pos; 399 this.size = new vector(1, 1); 400 if (ch == "=") { 401 // i'm guessing that speed will be added to this.pos 402 // in a moving method added later 403 this.speed = new vector(2, 0); 404 } else if (ch == '|') { 405 this.speed = new vector(0, 2); 406 } else if (ch == 'v') { 407 this.speed = new vector(0, 3); 408 this.repeatpos = pos; 409 } 410 } 411 lava.prototype.type = 'lava'; 412 // action 413 lava.prototype.act = function(step, level) { 414 var newpos = this.pos.plus(this.speed.times(step)); 415 if (!level.obstacleat(newpos, this.size)) 416 this.pos = newpos; 417 else if (this.repeatpos) 418 this.pos = this.repeatpos; 419 else 420 this.speed = this.speed.times(-1); 421 }; 422 423 // coin constructor 424 function coin(pos) { 425 this.basepos = this.pos = pos.plus(new vector(0.2, 0.1)); 426 this.size = new vector(0.6, 0.6); 427 this.wobble = math.random() * math.pi * 2; 428 } 429 coin.prototype.type = 'coin'; 430 var wobblespeed = 8, wobbledist = 0.07; 431 // action 432 coin.prototype.act = function(step) { 433 this.wobble += step * wobblespeed; 434 var wobblepos = math.sin(this.wobble) * wobbledist; 435 this.pos = this.basepos.plus(new vector(0, wobblepos)); 436 }; 437 438 // helper function that creates an element 439 // and gives it a class 440 function elt(name, classname) { 441 var elt = document.createelement(name); 442 if (classname) elt.classname = classname; 443 return elt; 444 } 445 446 // tracking keypresses for player movement 447 var arrowcodes = {37: 'left', 38: 'up', 39: 'right'}; 448 449 function trackkeys(codes) { 450 var pressed = object.create(null); 451 function handler(event) { 452 if (codes.hasownproperty(event.keycode)) { 453 var down = event.type == 'keydown'; 454 pressed[codes[event.keycode]] = down; 455 event.preventdefault(); 456 } 457 } 458 addeventlistener('keydown', handler); 459 addeventlistener('keyup', handler); 460 461 pressed.unregister = function() { 462 removeeventlistener('keydown', handler); 463 removeeventlistener('keyup', handler); 464 }; 465 466 return pressed; 467 } 468 469 // run the animation 470 function runanimation(framefunc) { 471 var lasttime = null; 472 function frame(time) { 473 var stop = false; 474 if (lasttime != null) { 475 var timestep = math.min(time - lasttime, 100) / 1000; 476 stop = framefunc(timestep) === false; 477 } 478 lasttime = time; 479 if (!stop) 480 requestanimationframe(frame); 481 } 482 requestanimationframe(frame); 483 } 484 485 // run the level 486 var arrows = trackkeys(arrowcodes); 487 488 function runlevel(level, display, andthen) { 489 var display = new display(document.body, level); 490 // used for storing pause state of the game 491 var running = 'yes'; 492 493 function handlekey(event) { 494 if (event.keycode == 27) { 495 if (running == 'no') { 496 running = 'yes'; 497 runanimation(animation); 498 } else if (running == 'pausing') { 499 running = 'yes'; 500 } else if (running == 'yes') { 501 running = 'pausing'; 502 } 503 } 504 } 505 addeventlistener('keydown', handlekey); 506 507 function animation(step) { 508 if (running == 'pausing') { 509 running = 'no'; 510 return false; 511 } 512 513 level.animate(step, arrows); 514 display.drawframe(step); 515 if (level.isfinished()) { 516 display.clear(); 517 // remove the watch on the esc key 518 //removeeventlistener('keydown', handlekey); 519 // unregister the arrow key listeners 520 //arrows.unregister(); 521 if (andthen) 522 andthen(level.status); 523 return false; 524 } 525 } 526 527 runanimation(animation); 528 } 529 530 // run the game 531 function rungame(plans, display) { 532 var lives = 3; 533 var livesspan = document.getelementbyid('lives'); 534 var gamestatus = document.getelementbyid('status'); 535 536 function startlevel(n) { 537 livesspan.textcontent = lives; 538 runlevel(new level(plans[n]), display, function(status) { 539 if (status == 'lost') { 540 lives--; 541 if (lives == 0) { 542 gamestatus.textcontent = 'game over'; 543 console.log('game over'); 544 } 545 else 546 startlevel(n); 547 } 548 else if (n < plans.length - 1) 549 startlevel(n + 1); 550 else 551 console.log('you win!'); 552 }); 553 } 554 startlevel(0); 555 } 556 557 558 // domdisplay uses the dom to draw the program out 559 function domdisplay(parent, level) { 560 this.wrap = parent.appendchild(elt('div', 'game')); 561 this.level = level; 562 563 // background is drawn only once 564 this.wrap.appendchild(this.drawbackground()); 565 // the actorlayer is animated in the drawframe() method 566 this.actorlayer = null; 567 this.drawframe(); 568 } 569 // set the scale of 1 grid unit 570 var scale = 20; 571 // draw the background 572 domdisplay.prototype.drawbackground = function() { 573 var table = elt('table', 'background'); 574 table.style.width = this.level.width * scale + 'px'; 575 this.level.grid.foreach(function(row) { 576 var rowelt = table.appendchild(elt('tr')); 577 rowelt.style.height = scale + 'px'; 578 row.foreach(function(type) { 579 rowelt.appendchild(elt('td', type)); 580 }); 581 }); 582 return table; 583 }; 584 // draw the actors 585 domdisplay.prototype.drawactors = function() { 586 var wrap = elt('div'); 587 this.level.actors.foreach(function(actor) { 588 var rect = wrap.appendchild(elt('div', 'actor ' + actor.type)); 589 rect.style.width = actor.size.x * scale + 'px'; 590 rect.style.height = actor.size.y * scale + 'px'; 591 rect.style.left = actor.pos.x * scale + 'px'; 592 rect.style.top = actor.pos.y * scale + 'px'; 593 }); 594 return wrap; 595 }; 596 // redraw the actors 597 domdisplay.prototype.drawframe = function() { 598 if (this.actorlayer) 599 this.wrap.removechild(this.actorlayer); 600 this.actorlayer = this.wrap.appendchild(this.drawactors()); 601 // the status class is used to style the player based on 602 // the state of the game (won or lost) 603 this.wrap.classname = 'game ' + (this.level.status || ''); 604 this.scrollplayerintoview(); 605 }; 606 // make sure the player's always on screen 607 domdisplay.prototype.scrollplayerintoview = function() { 608 var width = this.wrap.clientwidth; 609 var height = this.wrap.clientheight; 610 var margin = width / 3; 611 612 // the viewport 613 var left = this.wrap.scrollleft, right = left + width; 614 var top = this.wrap.scrolltop, bottom = top + height; 615 616 // center makes use of the vector methods defined earlier 617 var player = this.level.player; 618 var center = player.pos.plus(player.size.times(0.5)) 619 .times(scale); 620 621 if (center.x < left + margin) 622 this.wrap.scrollleft = center.x - margin; 623 else if (center.x > right - margin) 624 this.wrap.scrollleft = center.x + margin - width; 625 if (center.y < top + margin) 626 this.wrap.scrolltop = center.y - margin; 627 else if (center.y > bottom - margin) 628 this.wrap.scrolltop = center.y + margin - height; 629 } 630 // clear the level 631 domdisplay.prototype.clear = function() { 632 this.wrap.parentnode.removechild(this.wrap); 633 }; 634 635 // canvas api helper function 636 function fliphorizontally(context, around) { 637 context.translate(around, 0); 638 context.scale(-1, 1); 639 context.translate(-around, 0); 640 } 641 // use canvas api to draw game 642 function canvasdisplay(parent, level) { 643 // set up the canvas element 644 this.canvas = document.createelement('canvas'); 645 this.canvas.width = math.min(1000, level.width * scale); 646 this.canvas.height = math.min(1000, level.height * scale); 647 this.canvas.style.display = 'block'; 648 this.canvas.style.margin = '200px auto 0'; 649 parent.appendchild(this.canvas); 650 this.cx = this.canvas.getcontext('2d'); 651 652 this.level = level; 653 // uses the step size passed to drawframe() 654 this.animationtime = 0; 655 this.flipplayer = false; 656 657 this.viewport = { 658 left: 0, 659 top: 0, 660 width: this.canvas.width / scale, 661 height: this.canvas.height / scale 662 }; 663 664 this.drawframe(0); 665 } 666 canvasdisplay.prototype.clear = function() { 667 this.canvas.parentnode.removechild(this.canvas); 668 }; 669 // draw the frame 670 canvasdisplay.prototype.drawframe = function(step) { 671 this.animationtime += step; 672 673 // update the current player position for the viewport 674 this.updateviewport(); 675 // clear current frame 676 this.cleardisplay(); 677 // draw the background 678 this.drawbackground(); 679 // draw the actors 680 this.drawactors(); 681 }; 682 // scrolls the viewport depending on the player position 683 canvasdisplay.prototype.updateviewport = function() { 684 var view = this.viewport, margin = view.width / 3; 685 var player = this.level.player; 686 var center = player.pos.plus(player.size.times(0.5)); 687 688 // compare the center.x of player to the viewport 689 // player is less than the left of the viewport plus margin 690 if (center.x < view.left + margin) 691 // scroll left until less than 0 692 view.left = math.max(center.x - margin, 0); 693 // player is further right than the right of the viewport plus margin 694 else if (center.x > view.left + view.width - margin) 695 // scroll right until greater than the edge of the level 696 view.left = math.min(center.x + margin - view.width, 697 this.level.width - view.width); 698 if (center.y < view.top + margin) 699 view.top = math.max(center.y - margin, 0); 700 else if (center.y > view.top + view.height - margin) 701 view.top = math.min(center.y + margin - view.height, 702 this.level.height - view.height); 703 }; 704 canvasdisplay.prototype.cleardisplay = function() { 705 if (this.level.status == 'won') 706 this.cx.fillstyle = 'rgb(68, 191, 255)'; 707 else if (this.level.status == 'lost') 708 this.cx.fillstyle = 'rgb(44, 136, 214)'; 709 else 710 this.cx.fillstyle = 'rgb(52, 166, 251)'; 711 this.cx.fillrect(0, 0, 712 this.canvas.width, this.canvas.height); 713 }; 714 var othersprites = document.createelement('img'); 715 othersprites.src = 'http://eloquentjavascript.net/img/sprites.png'; 716 // draw the background 717 canvasdisplay.prototype.drawbackground = function() { 718 var view = this.viewport; 719 var xstart = math.floor(view.left); 720 var xend = math.ceil(view.left + view.width); 721 var ystart = math.floor(view.top); 722 var yend = math.ceil(view.top + view.height); 723 724 for (var y = ystart; y < yend; y++) { 725 for (var x = xstart; x < xend; x++) { 726 var tile = this.level.grid[y][x]; 727 if (tile == null) continue; 728 var screenx = (x - view.left) * scale; 729 var screeny = (y - view.top) * scale; 730 var tilex = tile == 'lava' ? scale : 0; 731 this.cx.drawimage(othersprites, 732 tilex, 0, scale, scale, 733 screenx, screeny, scale, scale); 734 } 735 } 736 }; 737 // draw the player (called by drawactors()) 738 var playersprites = document.createelement('img'); 739 playersprites.src = 'http://eloquentjavascript.net/img/player.png'; 740 var playerxoverlap = 4; 741 canvasdisplay.prototype.drawplayer = function(x, y, width, height) { 742 var sprite = 8, player = this.level.player; 743 width += playerxoverlap * 2; 744 x -= playerxoverlap; 745 if (player.speed.x != 0) 746 this.flipplayer = player.speed.x < 0; 747 748 if (player.speed.y != 0) 749 sprite = 9; 750 else if (player.speed.x != 0) 751 sprite = math.floor(this.animationtime * 12) % 8; 752 753 this.cx.save(); 754 if (this.flipplayer) 755 fliphorizontally(this.cx, x + width / 2); 756 757 this.cx.drawimage(playersprites, 758 sprite * width, 0, width, height, 759 x, y, width, height); 760 this.cx.restore(); 761 } 762 // draw the actors 763 canvasdisplay.prototype.drawactors = function() { 764 this.level.actors.foreach(function(actor) { 765 var width = actor.size.x * scale; 766 var height = actor.size.y * scale; 767 var x = (actor.pos.x - this.viewport.left) * scale; 768 var y = (actor.pos.y - this.viewport.top) * scale; 769 if (actor.type == 'player') { 770 this.drawplayer(x, y, width, height); 771 } else { 772 var tilex = (actor.type == 'coin' ? 2 : 1) * scale; 773 this.cx.drawimage(othersprites, 774 tilex, 0, width, height, 775 x, y, width, height); 776 } 777 }, this); 778 }; 779 780 781 // run game with domdisplay 782 // rungame(game_levels, domdisplay); 783 784 // run game with canvasdisplay 785 rungame(game_levels, canvasdisplay); 786 </script> 787 788 </body> 789 </html>