HTML5游戏源码 飞翔的字母 可自定义内容

时间:2023-12-23 08:33:26

  相信大家都玩过飞翔的小鸟吧,当然,可能已经有很多人因为这个游戏砸了不少手机。吼吼。

  废话不多说,回到主题,源码如下。

  博客园上传空间大小有限制,没法上传了,需要打包源码的朋友们请留言邮箱地址。当然还有,不要忘了点赞哦~谢谢大家的支持。

HTML5游戏源码 飞翔的字母 可自定义内容

  直接上源码:一共是三个文件:页面、js、css。

HTML(index.html)页面源码如下:

 <!DOCTYPE html>
 <html>
 <head>
   <meta charset="UTF-8">
   <title>飞翔的字母 - 孤影</title>
     <link rel="stylesheet" href="style.css" media="screen" type="text/css" />
 </head>

 <body>
   <div id="canvasContainer"></div>
     <span id="textInputSpan">
       1.输入内容,2.点击屏幕开始游戏,请输入内容(最大8个字符):
       <input id="textInput" maxlength="10" type="text" width="150" />
       <button onclick="changeText()">确定!</button>
     </span>
   <script src="index.js"></script>
 </body>
 </html>

JavaScript脚本文件(index.js)如下:

 (function (window){

   var Sakri = window.Sakri || {};
   window.Sakri = window.Sakri || Sakri;

     Sakri.MathUtil = {};

     //used for radiansToDegrees and degreesToRadians
     Sakri.MathUtil.PI_180 = Math.PI/180;
     Sakri.MathUtil.ONE80_PI = 180/Math.PI;

     //precalculations for values of 90, 270 and 360 in radians
     Sakri.MathUtil.PI2 = Math.PI*2;
     Sakri.MathUtil.HALF_PI = Math.PI/2;

     //return number between 1 and 0
     Sakri.MathUtil.normalize = function(value, minimum, maximum){
         return (value - minimum) / (maximum - minimum);
     };

     //map normalized number to values
     Sakri.MathUtil.interpolate = function(normValue, minimum, maximum){
         return minimum + (maximum - minimum) * normValue;
     };

     //map a value from one set to another
     Sakri.MathUtil.map = function(value, min1, max1, min2, max2){
         return Sakri.MathUtil.interpolate( Sakri.MathUtil.normalize(value, min1, max1), min2, max2);
     };

     Sakri.MathUtil.getRandomNumberInRange = function(min, max){
         return min + Math.random() * (max - min);
     };

     Sakri.MathUtil.getRandomIntegerInRange = function(min, max){
         return Math.round(Sakri.MathUtil.getRandomNumberInRange(min, max));
     };

 }(window));

 (function (window){

     var Sakri = window.Sakri || {};
     window.Sakri = window.Sakri || Sakri;

       Sakri.Geom = {};

     //==================================================
     //=====================::POINT::====================
     //==================================================

     Sakri.Geom.Point = function (x,y){
         this.x = isNaN(x) ? 0 : x;
         this.y = isNaN(y) ? 0 : y;
     };

     Sakri.Geom.Point.prototype.clone = function(){
         return new Sakri.Geom.Point(this.x,this.y);
     };

     Sakri.Geom.Point.prototype.update = function(x, y){
         this.x = isNaN(x) ? this.x : x;
         this.y = isNaN(y) ? this.y : y;
     };

     Sakri.Geom.Point.prototype.equals = function(point){
         return this.x==point.x && this.y==point.y;
     };

     Sakri.Geom.Point.prototype.toString = function(){
         return "{x:"+this.x+" , y:"+this.y+"}";
     };

     //==================================================
     //===================::RECTANGLE::==================
     //==================================================

     Sakri.Geom.Rectangle = function (x, y, width, height){
         this.update(x, y, width, height);
     };

     Sakri.Geom.Rectangle.prototype.update = function(x, y, width, height){
         this.x = isNaN(x) ? 0 : x;
         this.y = isNaN(y) ? 0 : y;
         this.width = isNaN(width) ? 0 : width;
         this.height = isNaN(height) ? 0 : height;
     };

     Sakri.Geom.Rectangle.prototype.getRight = function(){
         return this.x + this.width;
     };

     Sakri.Geom.Rectangle.prototype.getBottom = function(){
         return this.y + this.height;
     };

     Sakri.Geom.Rectangle.prototype.getCenterX = function(){
         return this.x + this.width/2;
     };

     Sakri.Geom.Rectangle.prototype.getCenterY = function(){
         return this.y + this.height/2;
     };

     Sakri.Geom.Rectangle.prototype.containsPoint = function(x, y){
         return x >= this.x && y >= this.y && x <= this.getRight() && y <= this.getBottom();
     };

     Sakri.Geom.Rectangle.prototype.clone = function(){
         return new Sakri.Geom.Rectangle(this.x, this.y, this.width, this.height);
     };

     Sakri.Geom.Rectangle.prototype.toString = function(){
         return "Rectangle{x:"+this.x+" , y:"+this.y+" , width:"+this.width+" , height:"+this.height+"}";
     };

 }(window)); 

 (function (window){

     var Sakri = window.Sakri || {};
     window.Sakri = window.Sakri || Sakri;

     Sakri.CanvasTextUtil = {};

     //returns the biggest font size that best fits into rect
     Sakri.CanvasTextUtil.getFontSizeForRect = function(string, fontProps, rect, canvas, fillStyle){
         if(!canvas){
             var canvas = document.createElement("canvas");
         }
         if(!fillStyle){
             fillStyle = "#000000";
         }
         var context = canvas.getContext('2d');
         context.font = fontProps.getFontString();
         context.textBaseline = "top";

         var copy = fontProps.clone();
         //console.log("getFontSizeForRect() 1  : ", copy.fontSize);
         context.font = copy.getFontString();
         var width = context.measureText(string).width;
         //console.log(width, rect.width);

         //SOME DISAGREEMENT WHETHER THIS SHOOULD BE WITH && or ||
         if(width < rect.width){
             while(context.measureText(string).width < rect.width || copy.fontSize*1.5 < rect.height){
                 copy.fontSize++;
                 context.font = copy.getFontString();
             }
         }else if(width > rect.width){
             while(context.measureText(string).width > rect.width || copy.fontSize*1.5 > rect.height){
                 copy.fontSize--;
                 context.font = copy.getFontString();
             }
         }
         //console.log("getFontSizeForRect() 2  : ", copy.fontSize);
         return copy.fontSize;
     }

     //=========================================================================================
     //==============::CANVAS TEXT PROPERTIES::====================================
     //========================================================

     Sakri.CanvasTextProperties = function(fontWeight, fontStyle, fontSize, fontFace){
         this.setFontWeight(fontWeight);
         this.setFontStyle(fontStyle);
         this.setFontSize(fontSize);
         this.fontFace = fontFace ? fontFace : "sans-serif";
     };

     Sakri.CanvasTextProperties.NORMAL = "normal";
     Sakri.CanvasTextProperties.BOLD = "bold";
     Sakri.CanvasTextProperties.BOLDER = "bolder";
     Sakri.CanvasTextProperties.LIGHTER = "lighter";

     Sakri.CanvasTextProperties.ITALIC = "italic";
     Sakri.CanvasTextProperties.OBLIQUE = "oblique";

     Sakri.CanvasTextProperties.prototype.setFontWeight = function(fontWeight){
         switch (fontWeight){
             case Sakri.CanvasTextProperties.NORMAL:
             case Sakri.CanvasTextProperties.BOLD:
             case Sakri.CanvasTextProperties.BOLDER:
             case Sakri.CanvasTextProperties.LIGHTER:
                 this.fontWeight = fontWeight;
                 break;
             default:
                 this.fontWeight = Sakri.CanvasTextProperties.NORMAL;
         }
     };

     Sakri.CanvasTextProperties.prototype.setFontStyle = function(fontStyle){
         switch (fontStyle){
             case Sakri.CanvasTextProperties.NORMAL:
             case Sakri.CanvasTextProperties.ITALIC:
             case Sakri.CanvasTextProperties.OBLIQUE:
                 this.fontStyle = fontStyle;
                 break;
             default:
                 this.fontStyle = Sakri.CanvasTextProperties.NORMAL;
         }
     };

     Sakri.CanvasTextProperties.prototype.setFontSize = function(fontSize){
         if(fontSize && fontSize.indexOf && fontSize.indexOf("px")>-1){
             var size = fontSize.split("px")[0];
             fontProperites.fontSize = isNaN(size) ? 24 : size;//24 is just an arbitrary number
             return;
         }
         this.fontSize = isNaN(fontSize) ? 24 : fontSize;//24 is just an arbitrary number
     };

     Sakri.CanvasTextProperties.prototype.clone = function(){
         return new Sakri.CanvasTextProperties(this.fontWeight, this.fontStyle, this.fontSize, this.fontFace);
     };

     Sakri.CanvasTextProperties.prototype.getFontString = function(){
         return this.fontWeight + " " + this.fontStyle + " " + this.fontSize + "px " + this.fontFace;
     };

 }(window));

 window.requestAnimationFrame =
         window.__requestAnimationFrame ||
                 window.requestAnimationFrame ||
                 window.webkitRequestAnimationFrame ||
                 window.mozRequestAnimationFrame ||
                 window.oRequestAnimationFrame ||
                 window.msRequestAnimationFrame ||
                 (function () {
                     return function (callback, element) {
                         var lastTime = element.__lastTime;
                         if (lastTime === undefined) {
                             lastTime = 0;
                         }
                         var currTime = Date.now();
                         var timeToCall = Math.max(1, 33 - (currTime - lastTime));
                         window.setTimeout(callback, timeToCall);
                         element.__lastTime = currTime + timeToCall;
                     };
                 })();

 var readyStateCheckInterval = setInterval( function() {
     if (document.readyState === "complete") {
         clearInterval(readyStateCheckInterval);
         init();
     }
 }, 10);

 //========================
 //general properties for demo set up
 //========================

 var canvas;
 var context;
 var canvasContainer;
 var htmlBounds;
 var bounds;
 var minimumStageWidth = 300;
 var minimumStageHeight = 300;
 var maxStageWidth = 800;
 var maxStageHeight = 1100;
 var resizeTimeoutId = -1;
 //var stats;

 function init(){
     canvasContainer = document.getElementById("canvasContainer");
     window.onresize = resizeHandler;
     //stats = new Stats();
     //canvasContainer.appendChild( stats.getDisplayElement() );
     window.addEventListener( "keydown", keyUpEventHandler, false )
     commitResize();
 }

 function getWidth( element ){return Math.max(element.scrollWidth,element.offsetWidth,element.clientWidth );}
 function getHeight( element ){return Math.max(element.scrollHeight,element.offsetHeight,element.clientHeight );}

 //avoid running resize scripts repeatedly if a browser window is being resized by dragging
 function resizeHandler(){
     context.clearRect(0,0,canvas.width, canvas.height);
     clearTimeout(resizeTimeoutId);
     clearTimeoutsAndIntervals();
     resizeTimeoutId = setTimeout(commitResize, 300 );
 }

 function commitResize(){
     if(canvas){
         canvasContainer.removeChild(canvas);
     }
     canvas = document.createElement('canvas');
     canvas.style.position = "absolute";
     context = canvas.getContext("2d");
     canvasContainer.appendChild(canvas);

     htmlBounds = new Sakri.Geom.Rectangle(0,0, getWidth(canvasContainer) , getHeight(canvasContainer));
     if(htmlBounds.width >= maxStageWidth){
         canvas.width = maxStageWidth;
         canvas.style.left = htmlBounds.getCenterX() - (maxStageWidth/2)+"px";
     }else{
         canvas.width = htmlBounds.width;
         canvas.style.left ="0px";
     }
     if(htmlBounds.height > maxStageHeight){
         canvas.height = maxStageHeight;
         canvas.style.top = htmlBounds.getCenterY() - (maxStageHeight/2)+"px";
     }else{
         canvas.height = htmlBounds.height;
         canvas.style.top ="0px";
     }
     bounds = new Sakri.Geom.Rectangle(0,0, canvas.width, canvas.height);
     context.clearRect(0,0,canvas.width, canvas.height);

     if(bounds.width<minimumStageWidth || bounds.height<minimumStageHeight){
         stageTooSmallHandler();
         return;
     }

     var textInputSpan = document.getElementById("textInputSpan");
     var textInputSpanY = (canvas.height - canvas.height*.85)/2 + 15;//15 is an estimate for half of textInputHeight
     textInputSpan.style.top = htmlBounds.getCenterY() + (bounds.height/2) - textInputSpanY +"px";
     textInputSpan.style.left = (htmlBounds.getCenterX() - getWidth(textInputSpan)/2)+"px";

     startDemo();
 }

 function stageTooSmallHandler(){
     var warning = "Sorry, bigger screen required :(";
     context.font = "bold normal 24px sans-serif";
     context.fillText(warning, bounds.getCenterX() - context.measureText(warning).width/2, bounds.getCenterY()-12);
 }

 //========================
 //Demo specific properties
 //========================

     var HOME = 0;
     var GAME = 1;
     var GAME_OVER = 2;
     var gameState;
     var scrollSpeed = 3;
     var score;
     var fontProperties = new Sakri.CanvasTextProperties(Sakri.CanvasTextProperties.BOLD, null, 100);

     var word = "张董";

     function startDemo(){
         canvas.addEventListener('touchstart', handleUserTap, false);
         canvas.addEventListener('mousedown', handleUserTap, false);

         var logoText = "飞翔的字母";
         if(!logoCanvas){
             logoCanvas = document.createElement("canvas");
             logoCanvasBG = document.createElement("canvas");
         }
         createLogo("飞翔的字母", logoCanvas, logoCanvasBG);
         if(!gameOverCanvas){
             gameOverCanvas = document.createElement("canvas");
             gameOverCanvasBG = document.createElement("canvas");
         }
         createLogo("行了 到此为止吧", gameOverCanvas, gameOverCanvasBG);

         createGroundPattern();
         createBird();
         createTubes();
         createCityGraphic();
         score = 0;
         gameState = HOME;
         loop();
     }

     function loop(){
         switch(gameState){
             case HOME:
                 renderHome();
                 break;
             case GAME :
                 renderGame();
                 break;
             case GAME_OVER:
                 renderGameOver();
                 break;
         }
         //stats.tick();
     }

     function handleUserTap(event){
         switch(gameState){
             case HOME:
                 gameState = GAME;
                 break;
             case GAME :
                 birdYSpeed = -tapBoost;
                 break;
             case GAME_OVER:
                 commitResize();
                 break;
         }
         if(event){
             event.preventDefault();
         }
     }

     function keyUpEventHandler(event){
         //event.keyCode == 32 -> Space
         if(event.keyCode == 38){
             handleUserTap(event);
         }
     }

     function renderHome(){
         context.clearRect(0, 0, canvas.width, canvas.height);
         renderGroundPattern();
         renderLogo();
         renderInstructions();
         window.requestAnimationFrame(loop, canvas);
     }

     function renderGame(){
         context.clearRect(0, 0, canvas.width, canvas.height);
         updateTubes();
         renderTubes();
         updateBird();
         if(!characters.length){
             gameOverHandler();
             return;
         }
         renderBird();
         renderGroundPattern();
         updateScore();
         renderScore();
         window.requestAnimationFrame(loop, canvas);
     }

     function gameOverHandler(){
         context.clearRect(0, 0, canvas.width, canvas.height);
         gameState = GAME_OVER;
         renderGameOver();
     }

     function renderGameOver(){

         //game over logo
         context.drawImage(gameOverCanvas, bounds.getCenterX() - logoCanvas.width/2, canvas.height *.2);

         var instruction = "点击重新任性、";
         context.font = "bold normal 24px sans-serif";
         context.fillStyle = "#FFFFFF";
         context.fillText(instruction, bounds.getCenterX() - context.measureText(instruction).width/2, canvas.height *.25 + gameOverCanvas.height);
         renderScore();

         //window.requestAnimationFrame(loop, canvas);
     }

     function renderLogo(){
         logoCurrentY += logoDirection;
         context.drawImage(logoCanvas, bounds.getCenterX() - logoCanvas.width/2, logoCurrentY);
         if(logoCurrentY <= logoY || logoCurrentY >= logoMaxY){
             logoDirection *= -1;
         }
     }

     function renderInstructions(){
         var instruction = "飞翔的字母 - 孤影";
         context.font = "bold normal 24px sans-serif";
         context.fillStyle = "#FFFFFF";
         context.fillText(instruction, bounds.getCenterX() - context.measureText(instruction).width/2, canvas.height *.2);
     }

     function renderScore(){
         context.font = fontProperties.getFontString();
         context.fillStyle = "#FFFFFF";
         context.strokeStyle = "#000000";
         context.lineWidth = 3;
         var x = bounds.getCenterX() - context.measureText(score).width/2;
         var y = bounds.height*.1;
         context.fillText(score, x, y);
         context.strokeText(score, x, y);
     }

     //========================================================================
     //========================:: LOGO ::======================================
     //========================================================================

     var logoCanvas;
     var logoCanvasBG;

     var gameOverCanvas;
     var gameOverCanvasBG;

     var logoY;
     var logoCurrentY;
     var logoMaxY;
     var logoDirection;

     function createLogo(logoText, logoCanvas, logoCanvassBG){
         logoCanvas.width = logoCanvasBG.width = canvas.width;
         logoCanvas.height = logoCanvasBG.height = canvas.height / 4;
         logoCurrentY = logoY = canvas.height * .25;
         logoMaxY = canvas.height * .35;
         logoDirection = 1;
         var logoContext = logoCanvas.getContext("2d");
         logoContext.textBaseline = "top";
         var textRect = new Sakri.Geom.Rectangle(0, 0, logoCanvas.width * .8, logoCanvas.height);
         var logoFontProps = fontProperties.clone();
         logoFontProps.fontSize = Sakri.CanvasTextUtil.getFontSizeForRect(logoText, fontProperties, textRect);

         var logoBGContext = logoCanvasBG.getContext("2d");
         logoBGContext.fillStyle = "#f5eea5";
         logoBGContext.fillRect(0, 0, logoCanvasBG.width, logoCanvasBG.height);
         logoBGContext.fillStyle = "#9ce358";
         logoBGContext.fillRect(0, logoFontProps.fontSize/2, logoCanvasBG.width, logoCanvasBG.height);

         logoContext.font = logoFontProps.getFontString();
         logoContext.fillStyle = logoContext.createPattern(logoCanvasBG, "repeat-x");
         logoContext.strokeStyle = "#000000";
         logoContext.lineWidth = 3;
         var x = logoCanvas.width/2 - logoContext.measureText(logoText).width/2;
         var y = logoFontProps.fontSize/2;
         logoContext.fillText(logoText, x, 0);
         logoContext.strokeText(logoText, x, 0);
     }

     //========================================================================
     //========================:: BIRD ::==================================
     //========================================================================

     var birdCanvas;
     var birdYSpeed = 0;
     var gravity = 1;
     var tapBoost = 12;
     var birdSize = 60;

     function updateBird(){
         characters[0].y += birdYSpeed;
         birdYSpeed += gravity;

         //floor
         if(characters[0].y >= groundGraphicRect.y - birdCanvas.height){
             characters[0].y = groundGraphicRect.y - birdCanvas.height;
             birdYSpeed = 0;
         }
         //celing
         if(characters[0].y<=0){
             characters[0].y = 1;
             birdYSpeed = 0;
         }
         //tube collision
         if(!isHit && checkTubesCollision()){
             context.fillStyle = "#FFFFFF";
             context.fillRect(0,0,canvas.width, canvas.height);
             removeCharacter();
             isHit = true;
         }
     }

     var currentTube;
     var isHit = false;
     var ffScoreBugFix = 0;// for some reason the score would fire multiple times on firefox

     function updateScore(){
         if(ffScoreBugFix>10 && currentTube.topRect.getRight() < characters[0].x){
             if(!isHit){
                 score++;
             }
             isHit = false;
             var index = tubes.indexOf(currentTube) + 1;
             index %= tubes.length;
             currentTube = tubes[index];
             ffScoreBugFix = 0;
         }
         ffScoreBugFix++;
     }

     function renderBird(){
         context.drawImage(characters[0].image, characters[0].x, characters[0].y );
         for(var i = 1; i < characters.length; i++){
              characters[i].y = characters[i-1].y - (characters[i-1].y - characters[i].y) * .9;
              context.drawImage(characters[i].image, characters[i].x, characters[i].y );
         }
     }

     function removeCharacter(){
         if(characters.length==1){
             //game over
             gameState = GAME_OVER;
         }
         for(var i=0; i<characters.length-1;i++){
             characters[i].image = characters[i+1].image;
         }
         characters.pop();
     }

     function checkTubesCollision(){
         for(var i= 0; i<tubes.length;i++){
             if(checkTubeCollision(tubes[i])){
                 return true;
             }
         }
         return false;
     }

     var collisionPoint = new Sakri.Geom.Point();
     var birdPoints = [];

     function checkTubeCollision(tube){
         birdPoints[0] = characters[0].x;
         birdPoints[1] = characters[0].y;
         birdPoints[2] = characters[0].x + birdSize;
         birdPoints[3] = characters[0].y;
         birdPoints[4] = characters[0].x + birdSize;
         birdPoints[5] = characters[0].y + birdSize;
         birdPoints[6] = characters[0].x;
         birdPoints[7] = characters[0].y + birdSize;
         for(var i=0; i<8; i+=2){
             collisionPoint.x = birdPoints[i];
             collisionPoint.y = birdPoints[i+1];
             if(tube.topRect.containsPoint(collisionPoint.x, collisionPoint.y) || tube.bottomRect.containsPoint(collisionPoint.x, collisionPoint.y)){
                 return true;
             }
         }
         return false;
     }

     var characters;
     var birdFontProperties = new Sakri.CanvasTextProperties(Sakri.CanvasTextProperties.BOLD, null, 50);

     function createBird(){

         if(!birdCanvas){
             birdCanvas = document.createElement("canvas");
         }
         birdCanvas.width = birdSize;
         birdCanvas.height = birdSize;

         characters = [];
         characters[0] = {}
         characters[0].x = canvas.width / 3;
         characters[0].y = groundGraphicRect.y / 2;
         characters[0].image = createCharacterImage(word.charAt(word.length - 1));

         var x = characters[0].x -(birdCanvas.width + birdCanvas.width*.2);
         for(var i=1; i<word.length ; i++){
             characters[i] = {};
             characters[i].x = x;
             characters[i].y = characters[0].y;
             x -= (birdCanvas.width + birdCanvas.width*.2);
             characters[i].image = createCharacterImage(word.charAt(word.length - i - 1));
         }
     }

     function createCharacterImage(character){
         var birdContext = birdCanvas.getContext("2d");
         birdContext.textBaseline = "top";

         birdContext.font = birdFontProperties.getFontString();
         birdContext.fillStyle = "#d5bb22";
         birdContext.fillRect(0, 0, birdSize, birdSize/2);
         birdContext.fillStyle = "#e97b13";
         birdContext.fillRect(0, birdSize/2, birdSize, birdSize/2);
         //hilite
         birdContext.fillStyle = "#e0e9a9";
         birdContext.fillRect(0, 0, birdSize, 6);
         //"mouth"
         birdContext.fillStyle = "#da473b";
         birdContext.fillRect(0, birdSize - 10, birdSize, birdSize);

         birdContext.lineWidth = 3;
         birdContext.strokeStyle = "#4d2f3b";
         birdContext.strokeRect(2, 2, birdSize-4, birdSize-4);

         birdContext.fillStyle = "#e8fcd6";
         birdContext.fillText(character, birdSize/2 - birdContext.measureText(character).width/2, 0);
         birdContext.strokeText(character, birdSize/2 - birdContext.measureText(character).width/2, 0);

         var image = new Image();
         image.width = birdSize;
         image.height = birdSize;
         image.src = birdCanvas.toDataURL();
         return image;
     }

     //========================================================================
     //========================:: TUBES ::==================================
     //========================================================================

     var tubeGapHeight = 230;//needs some logic
     var tubesGapWidth;
     var tubes;
     var tubeWidth = 100;//needs some logic
     var minTubeHeight = 50;//needs some logic

     function updateTubes(){
         for(var i= 0; i<tubes.length;i++){
             updateTube(tubes[i]);
         }
     }

     function updateTube(tube){
         tube.topRect.x -= scrollSpeed;
         tube.bottomRect.x = tube.topRect.x;
         if(tube.topRect.x <= -tubeWidth ){
             tube.topRect.x = tube.bottomRect.x = canvas.width;
             renderTube(tube);
         }
     }

     function renderTubes(){
         for(var i= 0; i<tubes.length;i++){
             context.drawImage(tubes[i].canvas, tubes[i].bottomRect.x, 0);
         }
     }

     function createTubes(){
         tubes = [];
         var totalTubes = 2;
         tubesGapWidth = Math.floor(canvas.width/totalTubes);

         for(var i = 0; i < totalTubes; i++){
             tubes[i] = {};
             tubes[i].canvas = document.createElement("canvas");
             tubes[i].topRect = new Sakri.Geom.Rectangle(canvas.width+(i * tubesGapWidth));
             tubes[i].bottomRect = new Sakri.Geom.Rectangle(canvas.width+(i * tubesGapWidth));
             renderTube(tubes[i]);
         }
         currentTube = tubes[0];
     }

     var tubeOutlineColor = "#534130";
     var tubeMainColor = "#75be2f";
     var tubeCapHeight = 40;

     function renderTube(tube){
         tube.canvas.width = tubeWidth;
         tube.canvas.height = groundGraphicRect.y;

         tube.bottomRect.width = tube.topRect.width = tubeWidth;
         tube.topRect.y = 0;
         tube.topRect.height = minTubeHeight + Math.round(Math.random()*(groundGraphicRect.y-tubeGapHeight-minTubeHeight*2));

         tube.bottomRect.y = tube.topRect.getBottom() + tubeGapHeight;
         tube.bottomRect.height = groundGraphicRect.y - tube.bottomRect.y - 1;//minus one for stroke

         var tubeContext = tube.canvas.getContext("2d");
         tubeContext.lineWidth = 2;
         //top tube
         renderTubeElement(tubeContext , 3, 0, tubeWidth-6, tube.topRect.height);
         renderTubeElement(tubeContext , 1, tube.topRect.getBottom() - tubeCapHeight, tubeWidth-2, tubeCapHeight);

         //bottom tube
         renderTubeElement(tubeContext , 3, tube.bottomRect.y, tubeWidth-6, tube.bottomRect.height);
         renderTubeElement(tubeContext , 1, tube.bottomRect.y, tubeWidth-2, tubeCapHeight);
     }

     function renderTubeElement(ctx, x, y, width, height){
         ctx.fillStyle = tubeMainColor;
         ctx.fillRect(x, y, width, height);
         ctx.fillStyle = "#9de85a";
         ctx.fillRect(x, y, width*.25, height);

         ctx.fillStyle = "#d9f881";
         ctx.fillRect(x+width *.05, y, width *.05, height);

         ctx.fillStyle = "#547e25";
         ctx.fillRect(x+width- width * .1, y, width *.1, height);
         ctx.fillRect(x+width- width * .2, y, width *.05, height);

         ctx.strokeRect(x, y, width, height);
     }

     //========================================================================
     //========================:: CITY BG ::==================================
     //========================================================================

 var cityGraphicCanvas;

 function createCityGraphic(){

     if(cityGraphicCanvas){
         canvasContainer.removeChild(cityGraphicCanvas);
     }
     cityGraphicCanvas = document.createElement("canvas");
     cityGraphicCanvas.style.position = "absolute";
     cityGraphicCanvas.style.left = canvas.style.left;
     cityGraphicCanvas.style.top = canvas.style.top;
     cityGraphicCanvas.width = canvas.width;
     cityGraphicCanvas.height = canvas.height;
     var cgContext = cityGraphicCanvas.getContext("2d");
     var cityGraphicHeight = canvas.height * .25;

     //fill with blue sky
     cgContext.fillStyle = "#71c5cf";
     cgContext.fillRect(0, 0, canvas.width, canvas.height);

     cgContext.fillStyle = "#e9fad8";

     cgContext.save();
     cgContext.translate(0, groundGraphicRect.y - cityGraphicHeight);

     //CLOUDS
     var maxCloudRadius = cityGraphicHeight * .4;
     var minCloudRadius = maxCloudRadius * .5;

     for(iterator=0; iterator<canvas.width; iterator+=minCloudRadius){
         cgContext.beginPath();
         cgContext.arc( iterator , maxCloudRadius, Sakri.MathUtil.getRandomNumberInRange(minCloudRadius, maxCloudRadius), 0, Sakri.MathUtil.PI2);
         cgContext.closePath();
         cgContext.fill();
     }

     cgContext.fillRect(0,maxCloudRadius, canvas.width, cityGraphicHeight );

     //HOUSES
     var houseWidth;
     var houseHeight;
     cgContext.fillStyle = "#deefcb";
     for(iterator=0; iterator<canvas.width; iterator+=(houseWidth+8)){
         houseWidth = 20 + Math.floor(Math.random()*30);
         houseHeight = Sakri.MathUtil.getRandomNumberInRange(cityGraphicHeight *.5 , cityGraphicHeight - maxCloudRadius *.8);
         cgContext.fillRect(iterator, cityGraphicHeight - houseHeight, houseWidth, houseHeight);
     }

     cgContext.fillStyle = "#dff1c4";
     cgContext.strokeStyle = "#9fd5d5";
     cgContext.lineWidth = 3;
     for(iterator=0; iterator<canvas.width; iterator+=(houseWidth+8)){
         houseWidth = 20 + Math.floor(Math.random()*30);
         houseHeight = Sakri.MathUtil.getRandomNumberInRange(cityGraphicHeight *.5 , cityGraphicHeight - maxCloudRadius *.8);
         cgContext.fillRect(iterator, cityGraphicHeight - houseHeight, houseWidth, houseHeight);
         cgContext.strokeRect(iterator, cityGraphicHeight - houseHeight, houseWidth, houseHeight);
     }

     //TREES
     var maxTreeRadius = cityGraphicHeight * .3;
     var minTreeRadius = maxTreeRadius * .5;
     var radius;
     var strokeStartRadian = Math.PI + Math.PI/4;
     var strokeEndRadian = Math.PI + Math.PI/4;
     cgContext.fillStyle = "#81e18b";
     cgContext.strokeStyle = "#72c887";
     for(iterator=0; iterator<canvas.width; iterator+=minTreeRadius){
         cgContext.beginPath();
         radius = Sakri.MathUtil.getRandomNumberInRange(minCloudRadius, maxCloudRadius)
         cgContext.arc( iterator , cityGraphicHeight, radius, 0, Sakri.MathUtil.PI2);
         cgContext.closePath();
         cgContext.fill();

         cgContext.beginPath();
         cgContext.arc( iterator , cityGraphicHeight, radius, strokeStartRadian, strokeEndRadian);
         cgContext.closePath();
         cgContext.stroke();
     }

     cgContext.restore();
     //sand
     cgContext.fillStyle = sand;
     cgContext.fillRect(0,groundGraphicRect.y, canvas.width, canvas.height);

     canvasContainer.insertBefore(cityGraphicCanvas, canvasContainer.firstChild);
 }

     //========================================================================
     //========================:: GROUND ::==================================
     //========================================================================

     var groundX = 0;
     function renderGroundPattern(){
         context.drawImage(groundPatternCanvas, groundX, groundGraphicRect.y);
         groundX -= scrollSpeed;
         groundX %= 16;
     }

     //colors
     var groundLightGreen = "#97e556";
     var groundDarkGreen = "#73be29";
     var groundDarkerGreen = "#4b7e19";
     var groundShadow = "#d1a649";
     var groundBorder = "#4c3f48";
     var sand = "#dcd795";
     var groundGraphicRect = new Sakri.Geom.Rectangle();
     var groundPatternCanvas;

     function createGroundPattern(){
         groundGraphicRect.y = canvas.height*.85;
         if(!groundPatternCanvas){
             groundPatternCanvas = document.createElement("canvas");
         }
         groundPatternCanvas.width = 16;
         groundPatternCanvas.height = 16;
         var groundContext = groundPatternCanvas.getContext("2d");
         groundContext.fillStyle = groundLightGreen;
         groundContext.fillRect(0,0,16,16);

         //diagonal graphic
         groundContext.fillStyle = groundDarkGreen;
         groundContext.beginPath();
         groundContext.moveTo(8,3);
         groundContext.lineTo(16,3);
         groundContext.lineTo(8,13);
         groundContext.lineTo(0,13);
         groundContext.closePath();
         groundContext.fill();

         //top border
         groundContext.fillStyle = groundBorder;
         groundContext.globalAlpha = .2;
         groundContext.fillRect(0,0,16,1);
         groundContext.globalAlpha = 1;
         groundContext.fillRect(0,1,16,1);
         groundContext.globalAlpha = .6;
         groundContext.fillRect(0,2,16,1);

         //hilite
         groundContext.fillStyle = "#FFFFFF";
         groundContext.globalAlpha = .3;
         groundContext.fillRect(0,3,16,2);

         //bottom border
         groundContext.fillStyle = groundDarkerGreen;
         groundContext.globalAlpha = .3;
         groundContext.fillRect(0,10,16,3);
         groundContext.globalAlpha = 1;
         groundContext.fillRect(0,11,16,1);

         //shadow
         groundContext.fillStyle = groundShadow;
         groundContext.fillRect(0,13,16,3);

         var groundPattern = context.createPattern(groundPatternCanvas, "repeat-x");

         groundPatternCanvas.width = canvas.width + 16;
         groundPatternCanvas.height = 16;

         groundContext.fillStyle = groundPattern;
         groundContext.fillRect(0, 0, groundPatternCanvas.width, 16);

     }

     function clearTimeoutsAndIntervals(){
         gameState = -1;
     }

     var maxCharacters = 8;

     function changeText(){
         var textInput = document.getElementById("textInput");
         if(textInput.value && textInput.text!=""){
             if(textInput.value.length > maxCharacters){
                 alert("Sorry, there is only room for "+maxCharacters+" characters. Try a shorter name.");
                 return;
             }
             if(textInput.value.indexOf(" ")>-1){
                 alert("Sorry, no support for spaces right now :(");
                 return;
             }
             word = textInput.value;
             clearTimeoutsAndIntervals();
             animating = false;
             setTimeout(commitResize, 100);
         }
     }

CSS页面样式文件(style.css)如下:

 html, body{
     margin : 0px;
     width : 100%;
     height : 100%;
     overflow: hidden;
     background-color: #FFFFFF;
 }

 #canvasContainer{
     margin : 0px;
     width : 100%;
     height : 100%;
 }

 #textInputSpan{
     position: absolute;
     color: #000000;
     font-family: sans-serif;
 }

  如果需要源码 复制不了代码的,留言邮箱我给大家打包发过去。

  当然还有,不要忘了点赞哦~谢谢大家的支持。谢谢大家了,哈哈。

  (*^_^*)

原程序来自:HTML5资源教程