相信大家都玩过飞翔的小鸟吧,当然,可能已经有很多人因为这个游戏砸了不少手机。吼吼。
废话不多说,回到主题,源码如下。
博客园上传空间大小有限制,没法上传了,需要打包源码的朋友们请留言邮箱地址。当然还有,不要忘了点赞哦~谢谢大家的支持。
直接上源码:一共是三个文件:页面、js、css。
HTML(index.html)页面源码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>飞翔的字母 - 孤影</title> 6 <link rel="stylesheet" href="style.css" media="screen" type="text/css" /> 7 </head> 8 9 <body> 10 <div id="canvasContainer"></div> 11 <span id="textInputSpan"> 12 1.输入内容,2.点击屏幕开始游戏,请输入内容(最大8个字符): 13 <input id="textInput" maxlength="10" type="text" width="150" /> 14 <button onclick="changeText()">确定!</button> 15 </span> 16 <script src="index.js"></script> 17 </body> 18 </html>
JavaScript脚本文件(index.js)如下:
1 2 (function (window){ 3 4 var Sakri = window.Sakri || {}; 5 window.Sakri = window.Sakri || Sakri; 6 7 Sakri.MathUtil = {}; 8 9 //used for radiansToDegrees and degreesToRadians 10 Sakri.MathUtil.PI_180 = Math.PI/180; 11 Sakri.MathUtil.ONE80_PI = 180/Math.PI; 12 13 //precalculations for values of 90, 270 and 360 in radians 14 Sakri.MathUtil.PI2 = Math.PI*2; 15 Sakri.MathUtil.HALF_PI = Math.PI/2; 16 17 18 //return number between 1 and 0 19 Sakri.MathUtil.normalize = function(value, minimum, maximum){ 20 return (value - minimum) / (maximum - minimum); 21 }; 22 23 //map normalized number to values 24 Sakri.MathUtil.interpolate = function(normValue, minimum, maximum){ 25 return minimum + (maximum - minimum) * normValue; 26 }; 27 28 //map a value from one set to another 29 Sakri.MathUtil.map = function(value, min1, max1, min2, max2){ 30 return Sakri.MathUtil.interpolate( Sakri.MathUtil.normalize(value, min1, max1), min2, max2); 31 }; 32 33 Sakri.MathUtil.getRandomNumberInRange = function(min, max){ 34 return min + Math.random() * (max - min); 35 }; 36 37 Sakri.MathUtil.getRandomIntegerInRange = function(min, max){ 38 return Math.round(Sakri.MathUtil.getRandomNumberInRange(min, max)); 39 }; 40 41 42 }(window)); 43 44 (function (window){ 45 46 var Sakri = window.Sakri || {}; 47 window.Sakri = window.Sakri || Sakri; 48 49 Sakri.Geom = {}; 50 51 //================================================== 52 //=====================::POINT::==================== 53 //================================================== 54 55 Sakri.Geom.Point = function (x,y){ 56 this.x = isNaN(x) ? 0 : x; 57 this.y = isNaN(y) ? 0 : y; 58 }; 59 60 Sakri.Geom.Point.prototype.clone = function(){ 61 return new Sakri.Geom.Point(this.x,this.y); 62 }; 63 64 Sakri.Geom.Point.prototype.update = function(x, y){ 65 this.x = isNaN(x) ? this.x : x; 66 this.y = isNaN(y) ? this.y : y; 67 }; 68 69 Sakri.Geom.Point.prototype.equals = function(point){ 70 return this.x==point.x && this.y==point.y; 71 }; 72 73 Sakri.Geom.Point.prototype.toString = function(){ 74 return "{x:"+this.x+" , y:"+this.y+"}"; 75 }; 76 77 78 79 //================================================== 80 //===================::RECTANGLE::================== 81 //================================================== 82 83 Sakri.Geom.Rectangle = function (x, y, width, height){ 84 this.update(x, y, width, height); 85 }; 86 87 Sakri.Geom.Rectangle.prototype.update = function(x, y, width, height){ 88 this.x = isNaN(x) ? 0 : x; 89 this.y = isNaN(y) ? 0 : y; 90 this.width = isNaN(width) ? 0 : width; 91 this.height = isNaN(height) ? 0 : height; 92 }; 93 94 95 Sakri.Geom.Rectangle.prototype.getRight = function(){ 96 return this.x + this.width; 97 }; 98 99 Sakri.Geom.Rectangle.prototype.getBottom = function(){ 100 return this.y + this.height; 101 }; 102 103 Sakri.Geom.Rectangle.prototype.getCenterX = function(){ 104 return this.x + this.width/2; 105 }; 106 107 Sakri.Geom.Rectangle.prototype.getCenterY = function(){ 108 return this.y + this.height/2; 109 }; 110 111 Sakri.Geom.Rectangle.prototype.containsPoint = function(x, y){ 112 return x >= this.x && y >= this.y && x <= this.getRight() && y <= this.getBottom(); 113 }; 114 115 116 Sakri.Geom.Rectangle.prototype.clone = function(){ 117 return new Sakri.Geom.Rectangle(this.x, this.y, this.width, this.height); 118 }; 119 120 Sakri.Geom.Rectangle.prototype.toString = function(){ 121 return "Rectangle{x:"+this.x+" , y:"+this.y+" , width:"+this.width+" , height:"+this.height+"}"; 122 }; 123 124 }(window)); 125 126 (function (window){ 127 128 var Sakri = window.Sakri || {}; 129 window.Sakri = window.Sakri || Sakri; 130 131 Sakri.CanvasTextUtil = {}; 132 133 //returns the biggest font size that best fits into rect 134 Sakri.CanvasTextUtil.getFontSizeForRect = function(string, fontProps, rect, canvas, fillStyle){ 135 if(!canvas){ 136 var canvas = document.createElement("canvas"); 137 } 138 if(!fillStyle){ 139 fillStyle = "#000000"; 140 } 141 var context = canvas.getContext('2d'); 142 context.font = fontProps.getFontString(); 143 context.textBaseline = "top"; 144 145 var copy = fontProps.clone(); 146 //console.log("getFontSizeForRect() 1 : ", copy.fontSize); 147 context.font = copy.getFontString(); 148 var width = context.measureText(string).width; 149 //console.log(width, rect.width); 150 151 //SOME DISAGREEMENT WHETHER THIS SHOOULD BE WITH && or || 152 if(width < rect.width){ 153 while(context.measureText(string).width < rect.width || copy.fontSize*1.5 < rect.height){ 154 copy.fontSize++; 155 context.font = copy.getFontString(); 156 } 157 }else if(width > rect.width){ 158 while(context.measureText(string).width > rect.width || copy.fontSize*1.5 > rect.height){ 159 copy.fontSize--; 160 context.font = copy.getFontString(); 161 } 162 } 163 //console.log("getFontSizeForRect() 2 : ", copy.fontSize); 164 return copy.fontSize; 165 } 166 167 //========================================================================================= 168 //==============::CANVAS TEXT PROPERTIES::==================================== 169 //======================================================== 170 171 Sakri.CanvasTextProperties = function(fontWeight, fontStyle, fontSize, fontFace){ 172 this.setFontWeight(fontWeight); 173 this.setFontStyle(fontStyle); 174 this.setFontSize(fontSize); 175 this.fontFace = fontFace ? fontFace : "sans-serif"; 176 }; 177 178 Sakri.CanvasTextProperties.NORMAL = "normal"; 179 Sakri.CanvasTextProperties.BOLD = "bold"; 180 Sakri.CanvasTextProperties.BOLDER = "bolder"; 181 Sakri.CanvasTextProperties.LIGHTER = "lighter"; 182 183 Sakri.CanvasTextProperties.ITALIC = "italic"; 184 Sakri.CanvasTextProperties.OBLIQUE = "oblique"; 185 186 187 Sakri.CanvasTextProperties.prototype.setFontWeight = function(fontWeight){ 188 switch (fontWeight){ 189 case Sakri.CanvasTextProperties.NORMAL: 190 case Sakri.CanvasTextProperties.BOLD: 191 case Sakri.CanvasTextProperties.BOLDER: 192 case Sakri.CanvasTextProperties.LIGHTER: 193 this.fontWeight = fontWeight; 194 break; 195 default: 196 this.fontWeight = Sakri.CanvasTextProperties.NORMAL; 197 } 198 }; 199 200 Sakri.CanvasTextProperties.prototype.setFontStyle = function(fontStyle){ 201 switch (fontStyle){ 202 case Sakri.CanvasTextProperties.NORMAL: 203 case Sakri.CanvasTextProperties.ITALIC: 204 case Sakri.CanvasTextProperties.OBLIQUE: 205 this.fontStyle = fontStyle; 206 break; 207 default: 208 this.fontStyle = Sakri.CanvasTextProperties.NORMAL; 209 } 210 }; 211 212 Sakri.CanvasTextProperties.prototype.setFontSize = function(fontSize){ 213 if(fontSize && fontSize.indexOf && fontSize.indexOf("px")>-1){ 214 var size = fontSize.split("px")[0]; 215 fontProperites.fontSize = isNaN(size) ? 24 : size;//24 is just an arbitrary number 216 return; 217 } 218 this.fontSize = isNaN(fontSize) ? 24 : fontSize;//24 is just an arbitrary number 219 }; 220 221 Sakri.CanvasTextProperties.prototype.clone = function(){ 222 return new Sakri.CanvasTextProperties(this.fontWeight, this.fontStyle, this.fontSize, this.fontFace); 223 }; 224 225 Sakri.CanvasTextProperties.prototype.getFontString = function(){ 226 return this.fontWeight + " " + this.fontStyle + " " + this.fontSize + "px " + this.fontFace; 227 }; 228 229 }(window)); 230 231 232 window.requestAnimationFrame = 233 window.__requestAnimationFrame || 234 window.requestAnimationFrame || 235 window.webkitRequestAnimationFrame || 236 window.mozRequestAnimationFrame || 237 window.oRequestAnimationFrame || 238 window.msRequestAnimationFrame || 239 (function () { 240 return function (callback, element) { 241 var lastTime = element.__lastTime; 242 if (lastTime === undefined) { 243 lastTime = 0; 244 } 245 var currTime = Date.now(); 246 var timeToCall = Math.max(1, 33 - (currTime - lastTime)); 247 window.setTimeout(callback, timeToCall); 248 element.__lastTime = currTime + timeToCall; 249 }; 250 })(); 251 252 var readyStateCheckInterval = setInterval( function() { 253 if (document.readyState === "complete") { 254 clearInterval(readyStateCheckInterval); 255 init(); 256 } 257 }, 10); 258 259 //======================== 260 //general properties for demo set up 261 //======================== 262 263 var canvas; 264 var context; 265 var canvasContainer; 266 var htmlBounds; 267 var bounds; 268 var minimumStageWidth = 300; 269 var minimumStageHeight = 300; 270 var maxStageWidth = 800; 271 var maxStageHeight = 1100; 272 var resizeTimeoutId = -1; 273 //var stats; 274 275 function init(){ 276 canvasContainer = document.getElementById("canvasContainer"); 277 window.onresize = resizeHandler; 278 //stats = new Stats(); 279 //canvasContainer.appendChild( stats.getDisplayElement() ); 280 window.addEventListener( "keydown", keyUpEventHandler, false ) 281 commitResize(); 282 } 283 284 function getWidth( element ){return Math.max(element.scrollWidth,element.offsetWidth,element.clientWidth );} 285 function getHeight( element ){return Math.max(element.scrollHeight,element.offsetHeight,element.clientHeight );} 286 287 //avoid running resize scripts repeatedly if a browser window is being resized by dragging 288 function resizeHandler(){ 289 context.clearRect(0,0,canvas.width, canvas.height); 290 clearTimeout(resizeTimeoutId); 291 clearTimeoutsAndIntervals(); 292 resizeTimeoutId = setTimeout(commitResize, 300 ); 293 } 294 295 function commitResize(){ 296 if(canvas){ 297 canvasContainer.removeChild(canvas); 298 } 299 canvas = document.createElement('canvas'); 300 canvas.style.position = "absolute"; 301 context = canvas.getContext("2d"); 302 canvasContainer.appendChild(canvas); 303 304 htmlBounds = new Sakri.Geom.Rectangle(0,0, getWidth(canvasContainer) , getHeight(canvasContainer)); 305 if(htmlBounds.width >= maxStageWidth){ 306 canvas.width = maxStageWidth; 307 canvas.style.left = htmlBounds.getCenterX() - (maxStageWidth/2)+"px"; 308 }else{ 309 canvas.width = htmlBounds.width; 310 canvas.style.left ="0px"; 311 } 312 if(htmlBounds.height > maxStageHeight){ 313 canvas.height = maxStageHeight; 314 canvas.style.top = htmlBounds.getCenterY() - (maxStageHeight/2)+"px"; 315 }else{ 316 canvas.height = htmlBounds.height; 317 canvas.style.top ="0px"; 318 } 319 bounds = new Sakri.Geom.Rectangle(0,0, canvas.width, canvas.height); 320 context.clearRect(0,0,canvas.width, canvas.height); 321 322 if(bounds.width<minimumStageWidth || bounds.height<minimumStageHeight){ 323 stageTooSmallHandler(); 324 return; 325 } 326 327 var textInputSpan = document.getElementById("textInputSpan"); 328 var textInputSpanY = (canvas.height - canvas.height*.85)/2 + 15;//15 is an estimate for half of textInputHeight 329 textInputSpan.style.top = htmlBounds.getCenterY() + (bounds.height/2) - textInputSpanY +"px"; 330 textInputSpan.style.left = (htmlBounds.getCenterX() - getWidth(textInputSpan)/2)+"px"; 331 332 startDemo(); 333 } 334 335 function stageTooSmallHandler(){ 336 var warning = "Sorry, bigger screen required :("; 337 context.font = "bold normal 24px sans-serif"; 338 context.fillText(warning, bounds.getCenterX() - context.measureText(warning).width/2, bounds.getCenterY()-12); 339 } 340 341 342 343 344 //======================== 345 //Demo specific properties 346 //======================== 347 348 349 var HOME = 0; 350 var GAME = 1; 351 var GAME_OVER = 2; 352 var gameState; 353 var scrollSpeed = 3; 354 var score; 355 var fontProperties = new Sakri.CanvasTextProperties(Sakri.CanvasTextProperties.BOLD, null, 100); 356 357 var word = "张董"; 358 359 function startDemo(){ 360 canvas.addEventListener('touchstart', handleUserTap, false); 361 canvas.addEventListener('mousedown', handleUserTap, false); 362 363 var logoText = "飞翔的字母"; 364 if(!logoCanvas){ 365 logoCanvas = document.createElement("canvas"); 366 logoCanvasBG = document.createElement("canvas"); 367 } 368 createLogo("飞翔的字母", logoCanvas, logoCanvasBG); 369 if(!gameOverCanvas){ 370 gameOverCanvas = document.createElement("canvas"); 371 gameOverCanvasBG = document.createElement("canvas"); 372 } 373 createLogo("行了 到此为止吧", gameOverCanvas, gameOverCanvasBG); 374 375 createGroundPattern(); 376 createBird(); 377 createTubes(); 378 createCityGraphic(); 379 score = 0; 380 gameState = HOME; 381 loop(); 382 } 383 384 function loop(){ 385 switch(gameState){ 386 case HOME: 387 renderHome(); 388 break; 389 case GAME : 390 renderGame(); 391 break; 392 case GAME_OVER: 393 renderGameOver(); 394 break; 395 } 396 //stats.tick(); 397 } 398 399 function handleUserTap(event){ 400 switch(gameState){ 401 case HOME: 402 gameState = GAME; 403 break; 404 case GAME : 405 birdYSpeed = -tapBoost; 406 break; 407 case GAME_OVER: 408 commitResize(); 409 break; 410 } 411 if(event){ 412 event.preventDefault(); 413 } 414 } 415 416 function keyUpEventHandler(event){ 417 //event.keyCode == 32 -> Space 418 if(event.keyCode == 38){ 419 handleUserTap(event); 420 } 421 } 422 423 function renderHome(){ 424 context.clearRect(0, 0, canvas.width, canvas.height); 425 renderGroundPattern(); 426 renderLogo(); 427 renderInstructions(); 428 window.requestAnimationFrame(loop, canvas); 429 } 430 431 function renderGame(){ 432 context.clearRect(0, 0, canvas.width, canvas.height); 433 updateTubes(); 434 renderTubes(); 435 updateBird(); 436 if(!characters.length){ 437 gameOverHandler(); 438 return; 439 } 440 renderBird(); 441 renderGroundPattern(); 442 updateScore(); 443 renderScore(); 444 window.requestAnimationFrame(loop, canvas); 445 } 446 447 function gameOverHandler(){ 448 context.clearRect(0, 0, canvas.width, canvas.height); 449 gameState = GAME_OVER; 450 renderGameOver(); 451 } 452 453 function renderGameOver(){ 454 455 //game over logo 456 context.drawImage(gameOverCanvas, bounds.getCenterX() - logoCanvas.width/2, canvas.height *.2); 457 458 var instruction = "点击重新任性、"; 459 context.font = "bold normal 24px sans-serif"; 460 context.fillStyle = "#FFFFFF"; 461 context.fillText(instruction, bounds.getCenterX() - context.measureText(instruction).width/2, canvas.height *.25 + gameOverCanvas.height); 462 renderScore(); 463 464 //window.requestAnimationFrame(loop, canvas); 465 } 466 467 function renderLogo(){ 468 logoCurrentY += logoDirection; 469 context.drawImage(logoCanvas, bounds.getCenterX() - logoCanvas.width/2, logoCurrentY); 470 if(logoCurrentY <= logoY || logoCurrentY >= logoMaxY){ 471 logoDirection *= -1; 472 } 473 } 474 475 function renderInstructions(){ 476 var instruction = "飞翔的字母 - 孤影"; 477 context.font = "bold normal 24px sans-serif"; 478 context.fillStyle = "#FFFFFF"; 479 context.fillText(instruction, bounds.getCenterX() - context.measureText(instruction).width/2, canvas.height *.2); 480 } 481 482 function renderScore(){ 483 context.font = fontProperties.getFontString(); 484 context.fillStyle = "#FFFFFF"; 485 context.strokeStyle = "#000000"; 486 context.lineWidth = 3; 487 var x = bounds.getCenterX() - context.measureText(score).width/2; 488 var y = bounds.height*.1; 489 context.fillText(score, x, y); 490 context.strokeText(score, x, y); 491 } 492 493 //======================================================================== 494 //========================:: LOGO ::====================================== 495 //======================================================================== 496 497 var logoCanvas; 498 var logoCanvasBG; 499 500 var gameOverCanvas; 501 var gameOverCanvasBG; 502 503 var logoY; 504 var logoCurrentY; 505 var logoMaxY; 506 var logoDirection; 507 508 function createLogo(logoText, logoCanvas, logoCanvassBG){ 509 logoCanvas.width = logoCanvasBG.width = canvas.width; 510 logoCanvas.height = logoCanvasBG.height = canvas.height / 4; 511 logoCurrentY = logoY = canvas.height * .25; 512 logoMaxY = canvas.height * .35; 513 logoDirection = 1; 514 var logoContext = logoCanvas.getContext("2d"); 515 logoContext.textBaseline = "top"; 516 var textRect = new Sakri.Geom.Rectangle(0, 0, logoCanvas.width * .8, logoCanvas.height); 517 var logoFontProps = fontProperties.clone(); 518 logoFontProps.fontSize = Sakri.CanvasTextUtil.getFontSizeForRect(logoText, fontProperties, textRect); 519 520 521 var logoBGContext = logoCanvasBG.getContext("2d"); 522 logoBGContext.fillStyle = "#f5eea5"; 523 logoBGContext.fillRect(0, 0, logoCanvasBG.width, logoCanvasBG.height); 524 logoBGContext.fillStyle = "#9ce358"; 525 logoBGContext.fillRect(0, logoFontProps.fontSize/2, logoCanvasBG.width, logoCanvasBG.height); 526 527 logoContext.font = logoFontProps.getFontString(); 528 logoContext.fillStyle = logoContext.createPattern(logoCanvasBG, "repeat-x"); 529 logoContext.strokeStyle = "#000000"; 530 logoContext.lineWidth = 3; 531 var x = logoCanvas.width/2 - logoContext.measureText(logoText).width/2; 532 var y = logoFontProps.fontSize/2; 533 logoContext.fillText(logoText, x, 0); 534 logoContext.strokeText(logoText, x, 0); 535 } 536 537 //======================================================================== 538 //========================:: BIRD ::================================== 539 //======================================================================== 540 541 var birdCanvas; 542 var birdYSpeed = 0; 543 var gravity = 1; 544 var tapBoost = 12; 545 var birdSize = 60; 546 547 function updateBird(){ 548 characters[0].y += birdYSpeed; 549 birdYSpeed += gravity; 550 551 //floor 552 if(characters[0].y >= groundGraphicRect.y - birdCanvas.height){ 553 characters[0].y = groundGraphicRect.y - birdCanvas.height; 554 birdYSpeed = 0; 555 } 556 //celing 557 if(characters[0].y<=0){ 558 characters[0].y = 1; 559 birdYSpeed = 0; 560 } 561 //tube collision 562 if(!isHit && checkTubesCollision()){ 563 context.fillStyle = "#FFFFFF"; 564 context.fillRect(0,0,canvas.width, canvas.height); 565 removeCharacter(); 566 isHit = true; 567 } 568 } 569 570 var currentTube; 571 var isHit = false; 572 var ffScoreBugFix = 0;// for some reason the score would fire multiple times on firefox 573 574 function updateScore(){ 575 if(ffScoreBugFix>10 && currentTube.topRect.getRight() < characters[0].x){ 576 if(!isHit){ 577 score++; 578 } 579 isHit = false; 580 var index = tubes.indexOf(currentTube) + 1; 581 index %= tubes.length; 582 currentTube = tubes[index]; 583 ffScoreBugFix = 0; 584 } 585 ffScoreBugFix++; 586 } 587 588 function renderBird(){ 589 context.drawImage(characters[0].image, characters[0].x, characters[0].y ); 590 for(var i = 1; i < characters.length; i++){ 591 characters[i].y = characters[i-1].y - (characters[i-1].y - characters[i].y) * .9; 592 context.drawImage(characters[i].image, characters[i].x, characters[i].y ); 593 } 594 } 595 596 function removeCharacter(){ 597 if(characters.length==1){ 598 //game over 599 gameState = GAME_OVER; 600 } 601 for(var i=0; i<characters.length-1;i++){ 602 characters[i].image = characters[i+1].image; 603 } 604 characters.pop(); 605 } 606 607 function checkTubesCollision(){ 608 for(var i= 0; i<tubes.length;i++){ 609 if(checkTubeCollision(tubes[i])){ 610 return true; 611 } 612 } 613 return false; 614 } 615 616 617 var collisionPoint = new Sakri.Geom.Point(); 618 var birdPoints = []; 619 620 function checkTubeCollision(tube){ 621 birdPoints[0] = characters[0].x; 622 birdPoints[1] = characters[0].y; 623 birdPoints[2] = characters[0].x + birdSize; 624 birdPoints[3] = characters[0].y; 625 birdPoints[4] = characters[0].x + birdSize; 626 birdPoints[5] = characters[0].y + birdSize; 627 birdPoints[6] = characters[0].x; 628 birdPoints[7] = characters[0].y + birdSize; 629 for(var i=0; i<8; i+=2){ 630 collisionPoint.x = birdPoints[i]; 631 collisionPoint.y = birdPoints[i+1]; 632 if(tube.topRect.containsPoint(collisionPoint.x, collisionPoint.y) || tube.bottomRect.containsPoint(collisionPoint.x, collisionPoint.y)){ 633 return true; 634 } 635 } 636 return false; 637 } 638 639 var characters; 640 var birdFontProperties = new Sakri.CanvasTextProperties(Sakri.CanvasTextProperties.BOLD, null, 50); 641 642 function createBird(){ 643 644 if(!birdCanvas){ 645 birdCanvas = document.createElement("canvas"); 646 } 647 birdCanvas.width = birdSize; 648 birdCanvas.height = birdSize; 649 650 characters = []; 651 characters[0] = {} 652 characters[0].x = canvas.width / 3; 653 characters[0].y = groundGraphicRect.y / 2; 654 characters[0].image = createCharacterImage(word.charAt(word.length - 1)); 655 656 var x = characters[0].x -(birdCanvas.width + birdCanvas.width*.2); 657 for(var i=1; i<word.length ; i++){ 658 characters[i] = {}; 659 characters[i].x = x; 660 characters[i].y = characters[0].y; 661 x -= (birdCanvas.width + birdCanvas.width*.2); 662 characters[i].image = createCharacterImage(word.charAt(word.length - i - 1)); 663 } 664 } 665 666 function createCharacterImage(character){ 667 var birdContext = birdCanvas.getContext("2d"); 668 birdContext.textBaseline = "top"; 669 670 birdContext.font = birdFontProperties.getFontString(); 671 birdContext.fillStyle = "#d5bb22"; 672 birdContext.fillRect(0, 0, birdSize, birdSize/2); 673 birdContext.fillStyle = "#e97b13"; 674 birdContext.fillRect(0, birdSize/2, birdSize, birdSize/2); 675 //hilite 676 birdContext.fillStyle = "#e0e9a9"; 677 birdContext.fillRect(0, 0, birdSize, 6); 678 //"mouth" 679 birdContext.fillStyle = "#da473b"; 680 birdContext.fillRect(0, birdSize - 10, birdSize, birdSize); 681 682 birdContext.lineWidth = 3; 683 birdContext.strokeStyle = "#4d2f3b"; 684 birdContext.strokeRect(2, 2, birdSize-4, birdSize-4); 685 686 birdContext.fillStyle = "#e8fcd6"; 687 birdContext.fillText(character, birdSize/2 - birdContext.measureText(character).width/2, 0); 688 birdContext.strokeText(character, birdSize/2 - birdContext.measureText(character).width/2, 0); 689 690 var image = new Image(); 691 image.width = birdSize; 692 image.height = birdSize; 693 image.src = birdCanvas.toDataURL(); 694 return image; 695 } 696 697 698 //======================================================================== 699 //========================:: TUBES ::================================== 700 //======================================================================== 701 702 var tubeGapHeight = 230;//needs some logic 703 var tubesGapWidth; 704 var tubes; 705 var tubeWidth = 100;//needs some logic 706 var minTubeHeight = 50;//needs some logic 707 708 function updateTubes(){ 709 for(var i= 0; i<tubes.length;i++){ 710 updateTube(tubes[i]); 711 } 712 } 713 714 function updateTube(tube){ 715 tube.topRect.x -= scrollSpeed; 716 tube.bottomRect.x = tube.topRect.x; 717 if(tube.topRect.x <= -tubeWidth ){ 718 tube.topRect.x = tube.bottomRect.x = canvas.width; 719 renderTube(tube); 720 } 721 } 722 723 724 function renderTubes(){ 725 for(var i= 0; i<tubes.length;i++){ 726 context.drawImage(tubes[i].canvas, tubes[i].bottomRect.x, 0); 727 } 728 } 729 730 function createTubes(){ 731 tubes = []; 732 var totalTubes = 2; 733 tubesGapWidth = Math.floor(canvas.width/totalTubes); 734 735 for(var i = 0; i < totalTubes; i++){ 736 tubes[i] = {}; 737 tubes[i].canvas = document.createElement("canvas"); 738 tubes[i].topRect = new Sakri.Geom.Rectangle(canvas.width+(i * tubesGapWidth)); 739 tubes[i].bottomRect = new Sakri.Geom.Rectangle(canvas.width+(i * tubesGapWidth)); 740 renderTube(tubes[i]); 741 } 742 currentTube = tubes[0]; 743 } 744 745 var tubeOutlineColor = "#534130"; 746 var tubeMainColor = "#75be2f"; 747 var tubeCapHeight = 40; 748 749 function renderTube(tube){ 750 tube.canvas.width = tubeWidth; 751 tube.canvas.height = groundGraphicRect.y; 752 753 tube.bottomRect.width = tube.topRect.width = tubeWidth; 754 tube.topRect.y = 0; 755 tube.topRect.height = minTubeHeight + Math.round(Math.random()*(groundGraphicRect.y-tubeGapHeight-minTubeHeight*2)); 756 757 tube.bottomRect.y = tube.topRect.getBottom() + tubeGapHeight; 758 tube.bottomRect.height = groundGraphicRect.y - tube.bottomRect.y - 1;//minus one for stroke 759 760 var tubeContext = tube.canvas.getContext("2d"); 761 tubeContext.lineWidth = 2; 762 //top tube 763 renderTubeElement(tubeContext , 3, 0, tubeWidth-6, tube.topRect.height); 764 renderTubeElement(tubeContext , 1, tube.topRect.getBottom() - tubeCapHeight, tubeWidth-2, tubeCapHeight); 765 766 //bottom tube 767 renderTubeElement(tubeContext , 3, tube.bottomRect.y, tubeWidth-6, tube.bottomRect.height); 768 renderTubeElement(tubeContext , 1, tube.bottomRect.y, tubeWidth-2, tubeCapHeight); 769 } 770 771 function renderTubeElement(ctx, x, y, width, height){ 772 ctx.fillStyle = tubeMainColor; 773 ctx.fillRect(x, y, width, height); 774 ctx.fillStyle = "#9de85a"; 775 ctx.fillRect(x, y, width*.25, height); 776 777 ctx.fillStyle = "#d9f881"; 778 ctx.fillRect(x+width *.05, y, width *.05, height); 779 780 ctx.fillStyle = "#547e25"; 781 ctx.fillRect(x+width- width * .1, y, width *.1, height); 782 ctx.fillRect(x+width- width * .2, y, width *.05, height); 783 784 ctx.strokeRect(x, y, width, height); 785 } 786 787 788 //======================================================================== 789 //========================:: CITY BG ::================================== 790 //======================================================================== 791 792 var cityGraphicCanvas; 793 794 function createCityGraphic(){ 795 796 if(cityGraphicCanvas){ 797 canvasContainer.removeChild(cityGraphicCanvas); 798 } 799 cityGraphicCanvas = document.createElement("canvas"); 800 cityGraphicCanvas.style.position = "absolute"; 801 cityGraphicCanvas.style.left = canvas.style.left; 802 cityGraphicCanvas.style.top = canvas.style.top; 803 cityGraphicCanvas.width = canvas.width; 804 cityGraphicCanvas.height = canvas.height; 805 var cgContext = cityGraphicCanvas.getContext("2d"); 806 var cityGraphicHeight = canvas.height * .25; 807 808 //fill with blue sky 809 cgContext.fillStyle = "#71c5cf"; 810 cgContext.fillRect(0, 0, canvas.width, canvas.height); 811 812 cgContext.fillStyle = "#e9fad8"; 813 814 cgContext.save(); 815 cgContext.translate(0, groundGraphicRect.y - cityGraphicHeight); 816 817 //CLOUDS 818 var maxCloudRadius = cityGraphicHeight * .4; 819 var minCloudRadius = maxCloudRadius * .5; 820 821 for(iterator=0; iterator<canvas.width; iterator+=minCloudRadius){ 822 cgContext.beginPath(); 823 cgContext.arc( iterator , maxCloudRadius, Sakri.MathUtil.getRandomNumberInRange(minCloudRadius, maxCloudRadius), 0, Sakri.MathUtil.PI2); 824 cgContext.closePath(); 825 cgContext.fill(); 826 } 827 828 cgContext.fillRect(0,maxCloudRadius, canvas.width, cityGraphicHeight ); 829 830 //HOUSES 831 var houseWidth; 832 var houseHeight; 833 cgContext.fillStyle = "#deefcb"; 834 for(iterator=0; iterator<canvas.width; iterator+=(houseWidth+8)){ 835 houseWidth = 20 + Math.floor(Math.random()*30); 836 houseHeight = Sakri.MathUtil.getRandomNumberInRange(cityGraphicHeight *.5 , cityGraphicHeight - maxCloudRadius *.8); 837 cgContext.fillRect(iterator, cityGraphicHeight - houseHeight, houseWidth, houseHeight); 838 } 839 840 cgContext.fillStyle = "#dff1c4"; 841 cgContext.strokeStyle = "#9fd5d5"; 842 cgContext.lineWidth = 3; 843 for(iterator=0; iterator<canvas.width; iterator+=(houseWidth+8)){ 844 houseWidth = 20 + Math.floor(Math.random()*30); 845 houseHeight = Sakri.MathUtil.getRandomNumberInRange(cityGraphicHeight *.5 , cityGraphicHeight - maxCloudRadius *.8); 846 cgContext.fillRect(iterator, cityGraphicHeight - houseHeight, houseWidth, houseHeight); 847 cgContext.strokeRect(iterator, cityGraphicHeight - houseHeight, houseWidth, houseHeight); 848 } 849 850 //TREES 851 var maxTreeRadius = cityGraphicHeight * .3; 852 var minTreeRadius = maxTreeRadius * .5; 853 var radius; 854 var strokeStartRadian = Math.PI + Math.PI/4; 855 var strokeEndRadian = Math.PI + Math.PI/4; 856 cgContext.fillStyle = "#81e18b"; 857 cgContext.strokeStyle = "#72c887"; 858 for(iterator=0; iterator<canvas.width; iterator+=minTreeRadius){ 859 cgContext.beginPath(); 860 radius = Sakri.MathUtil.getRandomNumberInRange(minCloudRadius, maxCloudRadius) 861 cgContext.arc( iterator , cityGraphicHeight, radius, 0, Sakri.MathUtil.PI2); 862 cgContext.closePath(); 863 cgContext.fill(); 864 865 cgContext.beginPath(); 866 cgContext.arc( iterator , cityGraphicHeight, radius, strokeStartRadian, strokeEndRadian); 867 cgContext.closePath(); 868 cgContext.stroke(); 869 } 870 871 cgContext.restore(); 872 //sand 873 cgContext.fillStyle = sand; 874 cgContext.fillRect(0,groundGraphicRect.y, canvas.width, canvas.height); 875 876 canvasContainer.insertBefore(cityGraphicCanvas, canvasContainer.firstChild); 877 } 878 879 880 //======================================================================== 881 //========================:: GROUND ::================================== 882 //======================================================================== 883 884 var groundX = 0; 885 function renderGroundPattern(){ 886 context.drawImage(groundPatternCanvas, groundX, groundGraphicRect.y); 887 groundX -= scrollSpeed; 888 groundX %= 16; 889 } 890 891 892 //colors 893 var groundLightGreen = "#97e556"; 894 var groundDarkGreen = "#73be29"; 895 var groundDarkerGreen = "#4b7e19"; 896 var groundShadow = "#d1a649"; 897 var groundBorder = "#4c3f48"; 898 var sand = "#dcd795"; 899 var groundGraphicRect = new Sakri.Geom.Rectangle(); 900 var groundPatternCanvas; 901 902 function createGroundPattern(){ 903 groundGraphicRect.y = canvas.height*.85; 904 if(!groundPatternCanvas){ 905 groundPatternCanvas = document.createElement("canvas"); 906 } 907 groundPatternCanvas.width = 16; 908 groundPatternCanvas.height = 16; 909 var groundContext = groundPatternCanvas.getContext("2d"); 910 groundContext.fillStyle = groundLightGreen; 911 groundContext.fillRect(0,0,16,16); 912 913 //diagonal graphic 914 groundContext.fillStyle = groundDarkGreen; 915 groundContext.beginPath(); 916 groundContext.moveTo(8,3); 917 groundContext.lineTo(16,3); 918 groundContext.lineTo(8,13); 919 groundContext.lineTo(0,13); 920 groundContext.closePath(); 921 groundContext.fill(); 922 923 //top border 924 groundContext.fillStyle = groundBorder; 925 groundContext.globalAlpha = .2; 926 groundContext.fillRect(0,0,16,1); 927 groundContext.globalAlpha = 1; 928 groundContext.fillRect(0,1,16,1); 929 groundContext.globalAlpha = .6; 930 groundContext.fillRect(0,2,16,1); 931 932 //hilite 933 groundContext.fillStyle = "#FFFFFF"; 934 groundContext.globalAlpha = .3; 935 groundContext.fillRect(0,3,16,2); 936 937 //bottom border 938 groundContext.fillStyle = groundDarkerGreen; 939 groundContext.globalAlpha = .3; 940 groundContext.fillRect(0,10,16,3); 941 groundContext.globalAlpha = 1; 942 groundContext.fillRect(0,11,16,1); 943 944 //shadow 945 groundContext.fillStyle = groundShadow; 946 groundContext.fillRect(0,13,16,3); 947 948 var groundPattern = context.createPattern(groundPatternCanvas, "repeat-x"); 949 950 groundPatternCanvas.width = canvas.width + 16; 951 groundPatternCanvas.height = 16; 952 953 groundContext.fillStyle = groundPattern; 954 groundContext.fillRect(0, 0, groundPatternCanvas.width, 16); 955 956 } 957 958 function clearTimeoutsAndIntervals(){ 959 gameState = -1; 960 } 961 962 var maxCharacters = 8; 963 964 function changeText(){ 965 var textInput = document.getElementById("textInput"); 966 if(textInput.value && textInput.text!=""){ 967 if(textInput.value.length > maxCharacters){ 968 alert("Sorry, there is only room for "+maxCharacters+" characters. Try a shorter name."); 969 return; 970 } 971 if(textInput.value.indexOf(" ")>-1){ 972 alert("Sorry, no support for spaces right now :("); 973 return; 974 } 975 word = textInput.value; 976 clearTimeoutsAndIntervals(); 977 animating = false; 978 setTimeout(commitResize, 100); 979 } 980 }
CSS页面样式文件(style.css)如下:
1 html, body{ 2 margin : 0px; 3 width : 100%; 4 height : 100%; 5 overflow: hidden; 6 background-color: #FFFFFF; 7 } 8 9 #canvasContainer{ 10 margin : 0px; 11 width : 100%; 12 height : 100%; 13 } 14 15 #textInputSpan{ 16 position: absolute; 17 color: #000000; 18 font-family: sans-serif; 19 }
如果需要源码 复制不了代码的,留言邮箱我给大家打包发过去。
当然还有,不要忘了点赞哦~谢谢大家的支持。谢谢大家了,哈哈。
(*^_^*)
原程序来自:HTML5资源教程
【来自:张董'Blogs:http://www.cnblogs.com/LonelyShadow,转载请注明出处。】
亲们。码字不容易,觉得不错的话记得点赞哦。。