本文介绍了如何利用HTML5技术来打造一款非常酷的斯诺克桌球游戏,文章中详细地列出了开发的全过程,并解说了实现这个游戏的几个关键点。在文章末尾我向大家提供了游戏的在线实例页面和源码下载链接,如果你只是想玩玩(需要使用支持HTML5的浏览器,建议使用Chrome 12, Internet Explorer 9 或者 Fire Fox 5及其以上版本),那你可以跳过正文拉到页面最底端去玩玩那个游戏或者下载源码,但我建议你好好看看实现过程,对我们学习HTML5非常有帮助。

毫无疑问,我们已经目睹了HTML5背后的那场伟大的Web开发革命。经过那么多年HTML4的统治,一场全新的运动即将完全改变现在的Web世界。正是他释放出来的现代化气息和丰富的用户体验,让它很快地成为了一个独特的插件运行在类似Flash和Silverlight的框架之上。

如果你是一个非常年轻的开发者,也许你是刚刚在开始学习HTML5,所以可能你并没有注意到他有太大的变化。在任何时候,我希望这篇文章能够帮助到你,当然,也希望像我一样的老手能从中学到一些新的花样。

你的点评对我来说非常重要,所以我很期待你的来信。当然能让我更兴奋的是当你在那个游戏画面上右击时暗暗地说一句“Hey,这居然不是Flash!也不是Silverlight!”

系统要求

想要使用本文提供的HTML5桌球应用,你必须安装下面的这些浏览器:Chrome 12, Internet Explorer 9 or Fire Fox 5

游戏规则

也许你已经知道这是一个什么样的游戏了,是的,这是“英式斯诺克”,实际上更确切的说是“简易版英式斯诺克”,因为没有实现所有的斯诺克游戏规则。你的目标是按顺序将目标球灌入袋中,从而比其他选手得到更多的分数。轮到你的时候,你就要出杆了:根据提示,你必须先打进一个红色球得到1分,如果打进了,你就可以继续打其他的球 - 但是这次你只能打彩色球了(也就是除红色球以外的球)。如果成功打进,你将会得到各自彩球对应的分数。然后被打进的彩球会回到球桌上,你可以继续击打其他的红球。这样周而复始,直到你失败为止。当你把所有的红球都打完以后,球桌上就只剩下6个彩球了,你的目标是将这6个彩球按以下顺序依次打入袋中:黄(2分)、绿(3分)、棕(4分)、蓝(5分)、粉(6分)、黑(7分)。如果一个球不是按上面顺序打进的,那它将会回到球桌上,否则,它最终会留在袋里。当所有球都打完后,游戏结束,得分最多的人胜出。

犯规处理

为了处罚你的犯规,其他选手将会得到你的罚分:

◆ 白球掉入袋中罚4分

◆ 白球第一次击中的球是错误的话罚第一个球的分值

◆ 第一个错误的球掉入袋中罚第一个球的分值

◆ 处罚的分数至少是4

下面的这段代码展示了我是如何来计算犯规的:

varstrokenBallsCount=0;

console.log('strokenBalls.length: ' + strokenBalls.length);

for (vari=0; i

varball=strokenBalls[i];

//causing the cue ball to first hit a ball other than the ball on

if (strokenBallsCount== 0) {

if (ball.Points != teams[playingTeamID - 1].BallOn.Points) {

if (ball.Points== 1 || teams[playingTeamID - 1].BallOn.Points== 1 ||

fallenRedCount== redCount) {

if (teams[playingTeamID - 1].BallOn.Points<4) {

teams[playingTeamID - 1].FoulList[teams[playingTeamID - 1]

.FoulList.length] = 4;

$('#gameEvents').append('

Foul 4 points :  Expected ' +

teams[playingTeamID - 1].BallOn.Points + ', but hit ' + ball.Points);

}

else {

teams[playingTeamID - 1].FoulList[teams[playingTeamID - 1]

.FoulList.length] = teams[playingTeamID - 1].BallOn.Points;

$('#gameEvents').append('

Foul ' + teams[playingTeamID - 1]

.BallOn.Points + ' points :  Expected ' + teams[playingTeamID - 1]

.BallOn.Points + ', but hit ' + ball.Points);

}

break;

}

}

}

strokenBallsCount++;

}

//Foul: causing the cue ball to miss all object balls

if (strokenBallsCount== 0) {

teams[playingTeamID - 1].FoulList[teams[playingTeamID - 1].FoulList.length] = 4;

$('#gameEvents').append('

Foul 4 points :  causing the cue ball

to miss all object balls');

}

for (vari=0; i

varball=pottedBalls[i];

//causing the cue ball to enter a pocket

if (ball.Points== 0) {

teams[playingTeamID - 1].FoulList[teams[playingTeamID - 1].FoulList.length] = 4;

$('#gameEvents').append('

Foul 4 points :  causing the cue ball

to enter a pocket');

}

else {

//causing a ball different than the target ball to enter a pocket

if (ball.Points != teams[playingTeamID - 1].BallOn.Points) {

if (ball.Points== 1 || teams[playingTeamID - 1].BallOn.Points== 1

||fallenRedCount== redCount) {

if (teams[playingTeamID - 1].BallOn.Points<4) {

teams[playingTeamID - 1].FoulList[teams[playingTeamID - 1]

.FoulList.length] = 4;

$('#gameEvents').append('

Foul 4 points : '

+ ball.Points + ' was potted, while ' + teams[playingTeamID - 1]

.BallOn.Points + ' was expected');

$('#gameEvents').append('

ball.Points: ' + ball.Points);

$('#gameEvents').append('

teams[playingTeamID - 1]

.BallOn.Points: ' + teams[playingTeamID - 1].BallOn.Points);

$('#gameEvents').append('

fallenRedCount: ' + fallenRedCount);

$('#gameEvents').append('

redCount: ' + redCount);

}

else {

teams[playingTeamID - 1].FoulList[teams[playingTeamID - 1]

.FoulList.length] = teams[playingTeamID - 1].BallOn.Points;

$('#gameEvents').append('

Foul ' + teams[playingTeamID - 1]

.BallOn.Points + ' points : ' + ball.Points + ' was potted, while '

+ teams[playingTeamID - 1].BallOn.Points + ' was expected');

}

}

}

}

}

得分

我们根据下面的规则来计算得分:红(1分)、黄(2分)、绿(3分)、棕(4分)、蓝(5分)、粉(6分)、黑(7分)。代码如下:

if (teams[playingTeamID - 1].FoulList.length== 0) {

for (vari=0; i

varball=pottedBalls[i];

//legally potting reds or colors

wonPoints += ball.Points;

$('#gameEvents').append('

Potted +' + ball.Points + ' points.');

}

}

else {

teams[playingTeamID - 1].FoulList.sort();

lostPoints=teams[playingTeamID - 1].FoulList[teams[playingTeamID - 1].FoulList.length - 1];

$('#gameEvents').append('

Lost ' + lostPoints + ' points.');

}

teams[playingTeamID - 1].Points += wonPoints;

teams[awaitingTeamID - 1].Points += lostPoints;

选手的闪动动画头像

游戏是有两位选手参与的,每一位选手都有自己的昵称和头像,选手的昵称我们就简单地以“player 1”和“player 2”来命名了(也许让用户自己输入会更漂亮)。每位选手的头像是一只正在打桌球的可爱小狗。当轮到其中一位选手时,他的头像就会有一闪一闪的动画效果,同时对手的头像会停止闪动。

这个效果我们是通过改变img元素的CSS3属性opacity的值来实现的:我们使用jquery的animatio函数让opacity的值在0-1.0之间变化。

function animateCurrentPlayerImage() {

varotherPlayerImageId=0;

if (playingTeamID== 1)

otherPlayerImageId='player2Image';

else

otherPlayerImageId='player1Image';

varplayerImageId='player'+ playingTeamID + 'Image';

$('#' + playerImageId).animate({

opacity: 1.0

}, 500, function () {

$('#' + playerImageId).animate({

opacity: 0.0

}, 500, function () {

$('#' + playerImageId).animate({

opacity: 1.0

}, 500, function () {

});

});

});

$('#' + otherPlayerImageId).animate({

opacity: 0.25

}, 1500, function () {

});

}

力量控制条

一个优秀的斯诺克选手都能很好地把握住每一杆的力度.不同的技巧需要不同的击球方式:直接的,间接的,或者利用边角的等等。不同方向和不同力度的组合可以构造成千上万种可能的路径。幸运的是,这个游戏提供了一个非常漂亮的力度控制条,可以帮助选手在击球前调整他们的球杆。

为了达到这一点,我们使用了HTML5的meter元素标签,它可以完成测量距离的工作。meter标签最好在知道这次测量的最小值和最大值的情况下使用。在我们的这个例子中,这个值在0到100之间,因为IE9不支持meter,所以我用了一张背景图来替代,这样效果也是一样的。

#strengthBar { position: absolute; margin:375px 0 0 139px;

width: 150px; color: lime; background-color: orange;

z-index: 5;}

当你点击了力度条后,你实际上是选择了一个新的力度。一开始你可能不是很熟练,但在真实世界中,这是需要时间来训练自己的能力的。点击力度条的代码如下:

$('#strengthBar').click(function (e) {

varleft= $('#strengthBar').css('margin-left').replace('px', '');

varx=e.pageX - left;

strength= (x / 150.0);

$('#strengthBar').val(strength * 100);

});

在当前选手的头像框里面,你会注意到有一个小球,我叫他“ball on”,就是当前选手在规定时间内应该要击打的那个球。如果这个球消失了,那选手将失去4分。同样如果选手第一次击中的球不是框内显示的球,那他也将失去4分。

这个“ball on”是直接将canvas元素覆盖在用户头像上的,所以你在头像上看到的那个球,他看起来像是在标准的div上盖了一个img元素,但是这个球并不是img实现的。当然我们也不能直接在div上画圆弧和直线,这就是为什么我要将canvas覆盖到头像上的原因了。看看代码吧:

varplayer1BallOnContext=player1BallOnCanvas.getContext('2d');

varplayer2BallOnContext=player2BallOnCanvas.getContext('2d');

.

.

.

function renderBallOn() {

player1BallOnContext.clearRect(0, 0, 500, 500);

player2BallOnContext.clearRect(0, 0, 500, 500);

if (playingTeamID== 1) {

if (teams[0].BallOn != null)

drawBall(player1BallOnContext, teams[0].BallOn, new Vector2D(30, 120), 20);

}

else {

if (teams[1].BallOn != null)

drawBall(player2BallOnContext, teams[1].BallOn, new Vector2D(30, 120), 20);

player1BallOnContext.clearRect(0, 0, 133, 70);

}

}

旋转屋顶上的电风扇

在这个游戏中这把电风扇纯属拿来玩玩有趣一把的。那为什么这里要放一把电风扇?是这样的,这个游戏的名字叫HTML5斯诺克俱乐部,放一把电风扇就有俱乐部的气氛了,当然,我也是为了说明如何实现CSS3的旋转。

实现这个非常简单:首先我们需要一张PNG格式的电扇图片。只是我们并没有用电扇本身的图片,我们用他的投影。通过显示风扇在球桌上的投影,让我们觉得它在屋顶上旋转,这样就达到了我们目的:

#roofFan { position:absolute; left: 600px; top: -100px; width: 500px; height: 500px;

border: 2px solid transparent; background-image: url('/Content/Images/roofFan.png');

background-size: 100%; opacity: 0.3; z-index: 2;}

.

.

.

在线斯诺克html5,用HTML 5打造斯诺克桌球俱乐部相关推荐

  1. HTML5斯诺克桌球俱乐部【译】

    不久前,我翻译了一些技术文章,放在我的博客上,没看过的且有兴趣的朋友可以去看看:Javascript中的陷阱大集合[译].轻松学习正则表达式[译].jQuery调用Google翻译实例[译].这次这篇 ...

  2. 【转】HTML5斯诺克桌球俱乐部【译】

    [http://www.cnblogs.com/sxwgf/archive/2011/11/20/2256359.html] 不久前,我翻译了一些技术文章,放在我的博客上,没看过的且有兴趣的朋友可以去 ...

  3. 有7克、2克砝码各一个,天平一只,如何只用这些物品三次将140克的盐分成50、90克各一份?

    微软面试题:有7克.2克砝码各一个,天平一只,如何只用这些物品三次将140克的盐分成50.90克各一份?(4种解法) 解法很多,仁者见仁智者见智: 1 ): 把2g和7g砝码放在同一边称量出9g盐 把 ...

  4. C语言给出点坐标进行克里金插值,Arcgis笔记之克里金插值——求助surfer8.0

    arcgis的插值方法比较丰富,但是有一点,那就是克里金插值.arcgis中克里金插值的结果不平滑,看起来非常难看.如下图,是对图中点数据某个属性值的插值结果. arcgis克里金插值结果 使用su ...

  5. mad和php的区别,独家揭秘评测恩雅eutx1尤克里里和卡卡mad尤克里里有啥区别?哪个好?深度剖析曝光...

    这两个恩雅eutx1尤克里里和卡卡mad尤克里里都还可以的哈,老牌子的,质量不错的,但是恩雅EUTX1整体要精致点儿,性价比也蛮高的,看个人吧,我自己用的是恩雅EUTX1,款式是我喜欢的,整体看着大气 ...

  6. 面试题:有7克、2克砝码各一个,天平一只,如何只用这些物品称三次,将140克的盐分成50、90克各一份?...

    问题:面试题:有7克.2克砝码各一个,天平一只,如何只用这些物品称三次,将140克的盐分成50.90克各一份? 解法一: ①用天平将盐分成70g两份,即140 ->70 + 70; ②用天平将其 ...

  7. 用计算机做一克拉等于多少克的单位换算,克和克拉怎么换算(克拉和克的换算单位是多少)...

    克拉(Ct)是宝石的质量(重量)单位,现定1克拉等于0.2克或200毫克.一克拉又分为100分,如50分即0.5克拉,以用作计算较为细小的宝石.因为宝石的密度基本上相. 1克拉=0.0002千克 克拉 ...

  8. 【面试智力题】有7克、2克砝码各一个,天平一只,如何只用这些物品三次将140克的盐分成50、90克各一份?

    问题描述 有7克.2克砝码各一个,天平一只,如何只用这些物品三次将140克的盐分成50.90克各一份? 解法一 第一次:2+7->称9g盐 第二次:9+7->称16g盐 第三次:16+7- ...

  9. 克里金插值的定义----普通克里金插值算法

    点击打开链接https://xg1990.com/blog/archives/222 点击打开链接: 百度文库克里金算法详解及实例计算过程 https://wenku.baidu.com/view/2 ...

最新文章

  1. 运维企业专题(7)LVS高可用与负载均衡中篇——VS/NAT模式配置详解
  2. Windows Server 2016 简介和安装
  3. Linux 技巧:让进程在后台可靠运行的几种方法
  4. STM32H743+Keil-将变量定义到指定内存
  5. opencv打开的图片应用于nn.Conv2d()(二)
  6. 离婚前一晚是什么心情呢?
  7. python输出输入的字符串_python笔记3-输出输入、字符串格式化
  8. 查询oracle数据库错误修改了,【案例】Oracle报错ora-00600[2662] 修改控制文件scn推进数据库scn...
  9. MATLAB 语言基础知识 矩阵和数组 从矩阵中删除行或列
  10. paper的经验和会议排名
  11. 第六讲 复数和复指数
  12. 安装win10 ltsc应用商店
  13. 异步4月新书,送出一本你爱的!
  14. 【小家Spring】注意BeanPostProcessor启动时对依赖Bean的“误伤”陷阱(is not eligible for getting processed by all...)
  15. 创建本地的https证书
  16. python中“羊车门问题”的简单分析与代码实现
  17. CAS和hotspot源码
  18. 瞬时频率函数matlab,Hilbert 变换与瞬时频率
  19. maven的下载安装,setting.xml配置教程,Idea 配置maven
  20. CSS--实现照片墙

热门文章

  1. 飞畅科技-工业级POE交换机解决方案专家
  2. 【渝粤教育】电大中专电子商务网站建设与维护 (27)作业 题库
  3. java hessian rmi_RMI,socket,rpc,hessian,http比较
  4. bitmap的java原理_布隆算法的原理及JAVA实现
  5. 【卷积码系列2】(n,k,m)卷积码的生成多项式矩阵系数转网格图描述(不使用MATLAB库函数)
  6. 2020-08-21 光纤通信第四章知识点整理
  7. 安卓手机背景变黑色怎么改_别着急扔掉旧手机 你的电脑可能需要它
  8. flask-mail异步发送邮件_SpringBoot 2.0 集成 JavaMail ,实现异步发送邮件
  9. 如何搭建socks5和ss节点_redis cluster搭建实践(非常详细,值得收藏)
  10. 第一单元总结:基于基础语言、继承和接口的简单OOP