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;
}
HTML5与Javascript 实现网页弹球游戏的更多相关文章
- HTML5 CSS JavaScript在网页中扮演的角色
HTML (content layer) CSS (presentation layer) JavaScript (Interactive layer) 参考链接: [1] https://www.y ...
- HTML5、javascript写的craps游戏
1. [代码][HTML]代码 <!DOCTYPE HTML><html><head><meta charset="utf-8"> ...
- HTML5游戏开发进阶指南(亚马逊5星畅销书,教你用HTML5和JavaScript构建游戏!)
HTML5游戏开发进阶指南(亚马逊星畅销书,教你用HTML5和JavaScript构建游戏!) [印]香卡(Shankar,A.R.)著 谢光磊译 ISBN 978-7-121-21226-0 201 ...
- 基于html5实现的愤怒的小鸟网页游戏
之前给大家分享一款基于html5 canvas和js实现的水果忍者网页版,今天给大家分享一款基于html5实现的愤怒的小鸟网页游戏.这款游戏适用浏览器:360.FireFox.Chrome.Safar ...
- [转]25个HTML5和JavaScript游戏引擎库
本文转自:http://www.open-open.com/news/view/27c6ed 1. The GMP JavaScript Game Engine GMP是一个基于精灵2-D游戏,它可以 ...
- 18个HTML5和JavaScript游戏引擎库
1) Best HTML5 and javascript game engine Library- Impactjs 2) Best HTML5 and javascript game en ...
- [译]终极塔防——运用HTML5从头创建一个塔防游戏
翻译共享一篇CodeProject的高星力作,原文地址:http://www.codeproject.com/Articles/737238/Ultimate-Tower-Defense 下载演示项目 ...
- 怎样用HTML5 Canvas制作一个简单的游戏
原文连接: How To Make A Simple HTML5 Canvas Game 自从我制作了一些HTML5游戏(例如Crypt Run)后,我收到了很多建议,要求我写一篇关于怎样利用HTML ...
- 好程序员技术分享html5和JavaScript的区别
好程序员技术分享html5和JavaScript的区别,HTML5广义上讲是前端开发学科的代名词,包含HTML5.CSS3及JavaScript三个重要的部分,是运行在浏览器上应用的统称.如PC端网站 ...
随机推荐
- Developing
To work with the Android code, you will need to use both Git and Repo. In most situations, you can u ...
- mysql slow 分析工具
慢查询有什么用? 它能记录下所有执行超过long_query_time时间的SQL语句,帮你找到执行慢的SQL,方便我们对这些SQL进行优化. 测试用 MySQL 版本. Serv ...
- 关于Linux下的环境变量
一.交互式shell和非交互式shell 要搞清bashrc与profile的区别,首先要弄明白什么是交互式shell和非交互式shell,什么是login shell 和non-login shel ...
- Python常用操作符
Python常用操作符 1.成员关系操作符in 显示的数字前面填充'0'代替空格 6.转义字符 符号 含义 \' 单引号\" 双引号\a 发出系统响铃声\b 退格符\n 换行符\t 横向制表 ...
- .NET重构(一):抽象工厂模式实现登录
导读:一路艰辛,我也走到了重构.在重构之前,师傅让用经典三层(UI.BLL.DAL)敲了登录.用户的增删改查,共五条线.从开始对三层的朦胧,到五条线结束,终于对三层有了逻辑上清晰的理解.然后就画了几天 ...
- BZOJ 2820 YY的GCD ——莫比乌斯反演
我们可以枚举每一个质数,那么答案就是 $\sum_{p}\sum_{d<=n}\mu(d)*\lfloor n / pd \rfloor *\lfloor m / pd \rfloor$ 直接做 ...
- VMware虚拟机 NAT模式 配置静态ip
前言:Ubuntu 16.04 VMware虚拟机 NAT模式 配置静态ip,这个问题困扰我好长时间,桥接的静态ip我会了,然而用NAT 的方式配置集群会更好.(NAT 方式客户机之间的通讯不经过路由 ...
- VMware---之网卡设置
闲来无事,扯点皮,详细说下NAT配置过程 NAT全称Network Address Translation网络地址转换,顾名思义,配置的重点也是地址转换. 步骤1.配置局域网段及网关 打开vmware ...
- 小Z的袜子(bzoj 2038)
Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……具体来说,小Z把这N只袜 ...
- PatentTips - GPU Support for Blending
Graphics processing units (GPUs) are specialized hardware units used to render 2-dimensional (2-D) a ...