• HTML5与Javascript 实现网页弹球游戏


    终于效果图:



    1. 使用html 5 的canvas 技术和javascript实现弹球游戏

             总体流程图:

             1.1 html5 canvas技术的使用

             首先在html页面中定义画布。

            


        <canvas bgcolor = "#FFF" id="gamePane" width="1000" height="500" tabindex="0">
    Sorry, your browser doesn't support the HTML5 game.
    </canvas>


             定义完画布之后就能够在javascript代码中对画布进行操作。


    canvas = document.getElementById('gamePane');
    ctx = canvas.getContext("2d");


             在画布中构绘图形。        

             ballImg = new Image();
             ballImg.src = "/site_media/images/kkball.ico";
             ctx.drawImage(ballImg, ballX- radius, ballY-radius, 2*radius, 2*radius);


           1.2 javascript弹球游戏实现

             使用canvas技术我们实现了弹球游戏的GUI界面,接下来是游戏功能逻辑。

             1.2.1首先明白游戏功能:

    A.      游戏元素: 弹球,砖块。挡板,道具。

    B.      游戏開始, 球从挡板出发。碰撞到砖块或者游戏边界时会反弹,碰撞到砖块时砖块消失,假设砖块隐藏了道具,道具显示并下落,碰到挡板时会发挥道具效果。弹球碰到挡板时也会反弹,可是假设碰到下边界则会损失游戏生命。

    C.      当砖块全然消失时进入下一关,随着关卡数添加。板的长度会减小。球的速度回加快。

    D.      道具: 1. 使弹球速度乘以1.3;2. 使弹球速度除以1.3;3. 使板的长度乘以2。4. 使板的长度除以2;

    1.2.2 画布的刷新

    画布的刷新使用html中的定时器实现。每0.003秒调用一次draw。更新画面。

     interval = setInterval(draw, 3);
    


    1.2.3用户交互 

    用户通过鼠标进行交互,游戏还未開始时, 球和板的x坐标都会随鼠标x坐标变化。这时点击鼠标左键,球和板的x坐标不再变化。这时能够设置球执行方向。方向为鼠标所在位置。

    游戏開始后,板x坐标随鼠标x坐标变化。

    为鼠标点击和移动设置响应函数。


    canvas.addEventListener('mousedown',onMouseDown, false);
    canvas.addEventListener('mousemove', padMove, false);
    canvas.addEventListener('mouseup', start, false);


    鼠标事件响应函数。

    //鼠标落下点击事件
    function onMouseDown(e){
            if(isStart==0){
               isPressed = 1;
     }
    }
        //鼠标移动点击事件
    function padMove(e){
    var x;
    x = e.layerX;
    x = x<padWidth/2?padWidth/2:x;
    x = x>(worldWidth-padWidth/2)?

    (worldWidth-padWidth/2):x; padX = x; if(isStart==0){ //假设游戏还未開始,则须要又一次绘制板。假设游戏開始了,板的绘制在draw中完毕。 if(isPressed == 0){ ballX = padX; ctx.clearRect(0, worldHeight-padHeight-2*radius, worldWidth, 2*radius); //clear the pad drawBall(); drawPad(); } } } //鼠标抬起事件函数,设置弹球角度,设置定时器定时刷新页面。

    function start(e){ if(isStart==0){ ballAngle = Math.atan((worldHeight- e.layerY)/(e.layerX - ballX)); if(ballAngle > 0){ ballAngle = - ballAngle; } else{ ballAngle = Math.PI - ballAngle; } isStart =1; isPressed = 0; interval = setInterval(draw, 3); } }


     

             1.2.4 弹球运动与碰撞检測

           弹球位置更新。

            

    ballX = ballX + ballSpeed * Math.cos(ballAngle);
             ballY = ballY + ballSpeed * Math.sin(ballAngle);



           球游戏边界碰撞检測。 

    //球碰撞到左右两边边界
    if(ballX < radius || ballX > worldWidth - radius){
               ballAngle = Math.PI - ballAngle;
    }
    //球碰到上边界
    if(ballY < radius){
               ballAngle = Math.PI*2 - ballAngle;
    }
    //球碰到下边界
    if(ballY > worldHeight-radius){
    //假设球未碰到板上。则游戏停止,推断生命是否用完,用完游戏结束
               if(ballX< padX-padWidth/2 || ballX > padX + padWidth/2){
                        ctx.clearRect(0,0,worldWidth,worldHeight-padHeight);
                        self.clearInterval(interval);
                        if(life>0){
                                 drawInfo(1);
                                 life = life -1;
                                 reset();
     
    }
                        else if(life ==0){
                                 drawInfo(2);
                                 getData();
     
                        }
                        return;
               }
    //球碰到板上
               else{
                        ballAngle = Math.PI*2 - ballAngle;
               }
    }
    //推断砖块是否打完,假设打完进入下一关
    if(count>= col*row){
               ctx.clearRect(0,0,worldWidth,worldHeight-padHeight);
     
               self.clearInterval(interval);
               newLevel();
               return;
             }


             1.2.5 弹球与砖块碰撞检測。      

        每次弹球到达可能有砖块的那一层的时候。推断弹球位置所在砖块是否还在。假设还在。则消去它。同一时候推断其是否有道具。假设有。则创建道具。

          

    function testCollision(){
    //球的位置不可能有砖块
    if(ballY > brickHeight * row){
               return;
    }
    //循环推断弹球在那一层
    for(var i = row;i>0;i--){
               if((ballY-radius)<=(brickHeight*i)){
                       
              
                        if((ballY-radius)>(brickHeight*(i-1))){
                                 var x = Math.floor(ballX/brickWidth);
     
                                 if(bricks[i-1][x].isdisplay==0){
                                           continue;
                                 }
                                 else{
                                           bricks[i-1][x].isdisplay=0;
                                           ballAngle= Math.PI*2-ballAngle;
                                           score= score+100;
                                           count = count +1;
                    //推断是否有道具
                                           if(bricks[i-1][x].tool!=0){
                                                    var brickX = bricks[i-1][x].col * brickWidth;
                                                    var brickY = bricks[i-1][x].row * brickHeight;
                                                    var temp = new tool(brickX, brickY, bricks[i-1][x].tool);
                                                    toolArray.push(temp);                                            }
                                           return;
                                 }
     
                        }
                        else{
                                 continue;
                        }
     
               }
               else
                        break;
    }
    }

     1.2.6 道具的实现


             初始化时创建一个存放道具的Array。

      toolArray = new Array();

            



          

    if(bricks[i-1][x].tool!=0){
               var brickX = bricks[i-1][x].col * brickWidth;
               var brickY = bricks[i-1][x].row * brickHeight;
               var temp = new tool(brickX, brickY, bricks[i-1][x].tool);
        toolArray.push(temp);                                           
    }


           每次碰到砖块时,推断砖块是否有道具,假设有道具就创建道具。将其放入数组。

    砖块是否有道具及道具类型由随机数产生。

           每次刷新画面时调用testTool函数。推断道具是否落究竟部。

    假设落到板上则发挥效果。

            



    function testTool(){
    //循环遍历整张道具数组
    for(var i = 0;i<toolArray.length;i++){
               console.log("tesetool", toolArray[i].type);
               var temp = toolArray[i];
    //道具还未落究竟部
               if(temp.y<worldHeight-padHeight){
                        continue;
               }
               else{
        //道具落到板上,推断道具类型。发挥效果。
                        if(temp.x>=padX-padWidth/2 && temp.x<=padX+padWidth/2){
                                 switch(temp.type){
                                           case 1:{
                                                    if(ballSpeed<2.6)
                                                             ballSpeed=ballSpeed*1.3;
                                                    console.log("tool", temp.type);
                                                    break;
                                           }
                                           case 2:{
                                                    if(ballSpeed>1.5)
                                                    ballSpeed=ballSpeed/1.3;
                                                    console.log("tool", temp.type);
                                                    break;
                                           }
                                           case 3:{
                                                    if(padWidth<200){
                                                             padWidth = padWidth *2;
                                                    }
                                                    console.log("tool", temp.type);
                                                    break;
                                           }
                                           case 4:{
                                                    if(padWidth>50)
                                                             padWidth=padWidth /2;
                                                    console.log("tool", temp.type);
                                                    break;
                                           }
                                 }
     
     
                        }
     
                        toolArray.splice(i, 1);
     
     
               }
    }
    }

     完整代码:

    var canvas;
    var ctx;
    var ballX = 500;
    var ballY = 470;
    var ballAngle = -Math.PI/2;
    var radius = 20;
    var ballSpeed = 2;
    var padX = 500;  //挡板位置
    var padWidth = 100;
    var padHeight = 10;
    var worldWidth;
    var worldHeight;
    var interval;
    var score = 0;
    var brickWidth = 100;
    var brickHeight = 25;
    var bricks;
    var color;
    var col = 10;
    var row = 5;
    var isStart = 0;
    var time = 0;
    var life = 3;
    var isPressed = 0;
    var level = 1;
    var count = 0;
    var ballImg;
    var brickImg;
    var padImg;
    var tool1Img;
    var tool2Img;
    var tool3Img;
    var tool4Img;
    var toolArray;
    
    var toolLength = 30;
    var toolHeight = 30;
    
    var isLoad = [0,0,0,0,0,0,0];
    
    var loadInterval;
    
    
    function brick(){
    	this.col = 0;
    	this.row = 0;
    	this.isdisplay = 1;  //是否显示
    	this.tool = 0;  //道具类型,0 表示无道具。

    this.color = "#000000" } //tool: //type: //1: make the ball speed x1.3 //2: make the ball speed /1.3 //3: make the pad length twice //4: make the pad length 1/2 function tool(x , y ,type){ this.x = x; this.y = y; this.type = type; } function loadImage(){ tool1Img = new Image(); tool1Img.src = "/site_media/images/tool1.png";1 tool1Img.addEventListener('load', function(){isLoad[0]=1}, false); tool2Img = new Image(); tool2Img.src = "/site_media/images/tool2.png"; tool2Img.addEventListener('load', function(){isLoad[1]=1}, false); tool3Img = new Image(); tool3Img.src = "/site_media/images/tool3.png"; tool3Img.addEventListener('load', function(){isLoad[2]=1}, false); tool4Img = new Image(); tool4Img.src = "/site_media/images/tool4.png"; tool4Img.addEventListener('load', function(){isLoad[3]=1}, false); padImg = new Image(); padImg.src = "/site_media/images/pad.png"; padImg.addEventListener('load', function(){isLoad[4]=1}, false); ballImg = new Image(); ballImg.src = "/site_media/images/kkball.ico"; ballImg.addEventListener('load', function(){isLoad[5]=1}, false); brickImg = new Image(); brickImg.src = "/site_media/images/brick.ico"; brickImg.addEventListener('load', function(){isLoad[6]=1}, false); //brickImg.addEventListener('load', init, false); loadInterval = setInterval(loadTest, 3); } //to test if all of the image is loaded function loadTest(){ var i; for(i=0;i<isLoad.length;i++){ if(isLoad[i]==0){ break; } } if(i>=isLoad.length){ self.clearInterval(loadInterval); init(); } } function GetRandomNum(Min,Max) { var Rand = Math.random(); console.log("Rand", Rand); if(Rand>0 && Rand<0.6){ return 0; } else if(Rand<=0.7){ return 1; } else if(Rand<=0.8){ return 2; } else if(Rand<=0.9){ return 3; } else if(Rand <=1){ return 4; } } function init(){ //init the game pane padWidth = 100; ballSpeed = 2; count = 0; isStart = 0; ballX = 500; ballY = 470; padX = 500; canvas = document.getElementById('gamePane'); worldWidth = canvas.width; worldHeight = canvas.height; ctx = canvas.getContext("2d"); toolArray = new Array(); //create the array of the bricks //canvas.addEventListener('keydown', onKeyDown, true); drawInfo(3); color = new Array("#FF0000", "#00FF00", "#0000FF", "#ff00ff") bricks = new Array(); for(var i = 0; i< row; i++){ bricks[i] = new Array(); for(var j = 0;j<col;j++){ var temp = new brick(); temp.col = j; temp.row = i; temp.isdisplay=1; temp.tool = GetRandomNum(1, 4); console.log("temp.tool", temp.tool); temp.color = color[(i*col+j)%4]; bricks[i][j]= temp; } } canvas.focus(); drawBall(); drawPad(); drawText(); drawBricks(); canvas.addEventListener('mousedown',onMouseDown, false); canvas.addEventListener('mousemove', padMove, false); canvas.addEventListener('mouseup', start, false); } function reset(){ padWidth = 100; ballSpeed =2; toolArray = new Array(); isStart=0; ballX = 500; ballY = 470; padX = 500; drawBricks(); drawBall(); drawPad(); drawText(); } function newLevel(){ padWidth = padWidth - 5; ballSpeed = ballSpeed + 0.1; if(padWidth<= 40){ drawInfo(4); getData(); return; } else{ row = row +1; level =level + 1; init(); } } function onMouseDown(e){ if(isStart==0){ isPressed = 1; } } function padMove(e){ var x; x = e.layerX; x = x<padWidth/2?padWidth/2:x; x = x>(worldWidth-padWidth/2)?(worldWidth-padWidth/2):x; padX = x; if(isStart==0){ if(isPressed == 0){ ballX = padX; ctx.clearRect(0, worldHeight-padHeight-2*radius, worldWidth, 2*radius); //clear the pad drawBall(); drawPad(); } } } function start(e){ if(isStart==0){ ballAngle = Math.atan((worldHeight- e.layerY)/(e.layerX - ballX)); if(ballAngle > 0){ ballAngle = - ballAngle; } else{ ballAngle = Math.PI - ballAngle; } isStart =1; isPressed = 0; interval = setInterval(draw, 3); } } function testCollision(){ if(ballY > brickHeight * row){ return; } for(var i = row;i>0;i--){ if((ballY-radius)<=(brickHeight*i)){ if((ballY-radius)>(brickHeight*(i-1))){ var x = Math.floor(ballX/brickWidth); if(bricks[i-1][x].isdisplay==0){ continue; } else{ bricks[i-1][x].isdisplay=0; ballAngle= Math.PI*2-ballAngle; score= score+100; count = count +1; if(bricks[i-1][x].tool!=0){ var brickX = bricks[i-1][x].col * brickWidth; var brickY = bricks[i-1][x].row * brickHeight; var temp = new tool(brickX, brickY, bricks[i-1][x].tool); toolArray.push(temp); } return; } } else{ continue; } } else break; } } function testTool(){ for(var i = 0;i<toolArray.length;i++){ console.log("tesetool", toolArray[i].type); var temp = toolArray[i]; if(temp.y<worldHeight-padHeight){ continue; } else{ if(temp.x>=padX-padWidth/2 && temp.x<=padX+padWidth/2){ switch(temp.type){ case 1:{ if(ballSpeed<2.6) ballSpeed=ballSpeed*1.3; console.log("tool", temp.type); break; } case 2:{ if(ballSpeed>1.5) ballSpeed=ballSpeed/1.3; console.log("tool", temp.type); break; } case 3:{ if(padWidth<200){ padWidth = padWidth *2; } console.log("tool", temp.type); break; } case 4:{ if(padWidth>50) padWidth=padWidth /2; console.log("tool", temp.type); break; } } } toolArray.splice(i, 1); } } } function postData(){ var xmlhttp = new XMLHttpRequest(); xmlhttp.open("POST","../storeScore/",true); xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); var text = "score="+score; xmlhttp.send(text) } function getData(){ var url = "../storeScore/"+score+"/"; window.location = url; } function drawInfo(num){ ctx.font = '50pt Calibri'; ctx.fillStyle = "#E67E22"; var text="One life lost!" if (num ==2){ text = "Game over!" } else if(num ==3){ text = "Level "+ level; } else if(num ==4){ text = "Congratulations!" } ctx.fillText(text, 350, 250); } function drawBall(){ ctx.drawImage(ballImg, ballX- radius, ballY-radius, 2*radius, 2*radius); } function drawBricks(){ for(var i =0;i<row;i++){ for(var j=0;j<col;j++){ if(bricks[i][j].isdisplay ==1){ ctx.fillStyle = bricks[i][j].color; var x = bricks[i][j].col * brickWidth; var y = bricks[i][j].row * brickHeight; //ctx.fillRect(x, y, brickWidth, brickHeight); ctx.drawImage(brickImg, x, y, brickWidth, brickHeight); } } } } function drawPad(){ //ctx.fillStyle = "#0000FF"; ctx.clearRect(0, worldHeight-padHeight, worldWidth, padHeight); //clear the pad //ctx.fillRect(padX-padWidth/2, worldHeight-padHeight, padWidth, padHeight); ctx.drawImage(padImg, padX-padWidth/2, worldHeight-padHeight, padWidth, padHeight); } function drawText(){ ctx.font = '15pt Calibri'; ctx.fillStyle = "black"; var text= "level:"+level; ctx.fillText(text, 900, 370) text = "life: " + life; ctx.fillText(text, 900, 430); text = 'point:'+score; ctx.fillText(text, 900, 390); var min; if(time > 60){ min =Math.floor(time/60); } else{ min =0; } var sec = Math.floor(time % 60); if(min <10){ tMin = '0'+ min; } else tMin = ''+min; if(sec<10){ tSec = '0'+sec; } else tSec=''+ sec; text = 'time: '+ tMin +":"+tSec; ctx.fillText(text, 900, 410); } function drawTool(){ for(var i =0;i<toolArray.length;i++){ switch(toolArray[i].type){ case 1:{ ctx.drawImage(tool1Img, toolArray[i].x, toolArray[i].y, 30, 30); break; } case 2:{ ctx.drawImage(tool2Img, toolArray[i].x, toolArray[i].y, 30, 30); break; } case 3:{ ctx.drawImage(tool3Img, toolArray[i].x, toolArray[i].y, 30, 30); break; } case 4:{ ctx.drawImage(tool4Img, toolArray[i].x, toolArray[i].y, 30, 30); break; } } toolArray[i].y = toolArray[i].y+1; } } function draw(){ //first clear the canvas ctx.clearRect(0,0,worldWidth,worldHeight-padHeight); //ball drawBall(); drawPad(); drawBricks(); drawTool(); drawText(); //flush the position of the ball ballX = ballX + ballSpeed * Math.cos(ballAngle); ballY = ballY + ballSpeed * Math.sin(ballAngle); //test the collision of the brick and the ball testCollision(); testTool(); if(ballX < radius || ballX > worldWidth - radius){ ballAngle = Math.PI - ballAngle; } if(ballY < radius){ ballAngle = Math.PI*2 - ballAngle; } if(ballY > worldHeight-radius){ if(ballX< padX-padWidth/2 || ballX > padX + padWidth/2){ ctx.clearRect(0,0,worldWidth,worldHeight-padHeight); self.clearInterval(interval); if(life>0){ drawInfo(1); life = life -1; reset(); } else if(life ==0){ drawInfo(2); getData(); } return; } else{ ballAngle = Math.PI*2 - ballAngle; } } if(count>= col*row){ ctx.clearRect(0,0,worldWidth,worldHeight-padHeight); self.clearInterval(interval); newLevel(); return; } time = time +0.003; }



  • 相关阅读:
    4个Python推导式相关的开发技巧
    解决Maven的repository配置不生效的问题
    jeecgboot新建module模块
    java.lang.IllegalArgumentException: Required executor memory (1024), overhead (384 MB), and PySpark
    sparkStreaming 消费kafka0_10版本 demo
    Linux_磁盘分区、挂载、查看
    Java 最常见 200+ 面试题全解析
    Java代码打成jar后 classgetClassLoadergetResource("")返回为null
    scala的maven项目打包后没有内容
    flume 到 kafka整合
  • 原文地址:https://www.cnblogs.com/lytwajue/p/6859642.html
Copyright © 2020-2023  润新知