主机控制键:
- 移动: W: 上, D: 前, A: 后, S:下
- 攻击: J: 轻拳, K: 重拳, U: 轻腿, I: 重腿
- 特殊技能: 下→前→拳: 波动拳, 下→后→腿:旋风腿, 前→下→前→拳:升龙拳
副机(小键盘):
- 移动: ↑: 上, ←: 前, →: 后, ↓:下
- 攻击: 1: 轻拳, 2: 重拳, 4: 轻腿, 5: 重腿
- 特殊技能: 下→前→拳: 波动拳, 下→后→腿:旋风腿, 前→下→前→拳:升龙拳
其他:
- 按 F2 暂停游戏, 1 键大战电脑 ai, 2 键双人对打.
- 如果控制不了, 注意切换下输入法哈.
图片素材来自互联网, 原作者 Random. 游戏版权归 CAPCOM 公司所有. 欧洲杯之前加上 websocket 和 3D 音效.
开发过程介绍
大概是 1个月前开始学习HTML5, 就写了这样一个东东练手. 不过说来惭愧, 至今也只学会了canvas的drawImage. 每天的业余时间不太固定, 有时候一天能写三小时, 有时候一天能写三分钟. 代码也写的相当潦草. 总的来说有点虎头蛇尾. 本来准备找个时间再重构一下, 突然发现失去了兴致, 欧洲杯又马上开始了. 对我来说, 已经差不多达到练手的目的, 所以还是罢了.
非常简单的记录一些实现思路. 暂且不讨论api. 一是因为api到处可以查阅, 二是因为我确实只认识drawImag. 本人技术也十分有限, 请轻砸.
代码里只有几个 js文件, 每个文件的功能如下:
- Class.js 创建类和对象.
- Game.js 游戏入口文件.
- Map.js 绘制地图.
- Config.js 各种游戏人物动作打架挨打等等配置.
- Interface.js 各种接口
- Main.js 负责游戏逻辑
- Ai.js Ai
- Timer.js 全局定时器
- Class.js.
为毛要搞这样一个东西呢. 保护原型, 继承的时候修正 constructor 什么的, 反正现在不搞个 Class.create都有点不太好意思.
这里也借鉴了 prototype框架里的一些思路. 相对于prototype里的换汤不换药. 这儿的class.create选择返回一个普通的object对象, 有点像jquery里$的搞法.
这样可以自由的扩展 Class的各种方法,而不用再搭理Function的原型. 举个例子, Class.empty()可以秒杀这个类生成的所有对象. 比如现在正在设计一个飞机游戏. 有个大招可以清除屏幕上的所有子弹和敌机. 那么, 哼哼..
因为 Class.create返回的是一个普通的object. 所以不能用new Function的方式生成对象. 具体使用方法如下例.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
var Hero = Class.create( function( name ){ this.name = name; } , { addSkill: function( skill ){ ....... } }) var hero1 = Hero.getInstance( "半人马酋长" ); hero1.addSkill( "六级跳大" ); var hero2 = Hero.getInstance( "山岭巨人" ) hero2.addSkill( "六级跳大" ) var hero3 = Hero.getInstance( "黑暗游侠" ); hero3.addSkill( "六级跳大">" ); |
Timer.js
用 js做动画, 无非就是用setInterval或者setTimeout让图片的top和left, 或者图片本身的src在很短的时间内间隔变换. 达到视觉的动画效果. 跟动画片一样.
虽然屏幕上有很多精灵在同时运动. 但在一个游戏中, 只有也应该只有一个全局的定时器.
- 是从性能出发. setInterval的开销相当不小.
- 是为了统一管理, 比如方便的实现暂停功能.
北京时间 X点X分X秒X毫秒, 东经X度北纬X度在发生什么. 整个世界就是这样组成.
定时器从游戏开始一直在不停执行, 像地铁环线. 每隔1小时回到起点. 也像我们自己, 每隔24小时回到原点, 周而复始.
1 2 3 4 5 6 7 8 9 10 11 |
var timer = Timer.add( function(){ alert (1) }) timer.start(); //上车 timer.stop(); //下车 timer.slow( 1000 ) 地铁减速 |
Interface.js
我之前写过几个小游戏, 每个都搞了很多类在里面. 比如坦克大战, 子弹是一个类, 移动是一个类. 碰撞是一个类. 坦克先继承碰撞类, 再继承移动类. 这样一来坦克既能碰撞也能移动. 非常酷.
可是真的需要那么多类么. 有种方式或许更轻巧敏捷, 那就是接口.
让精灵可以移动只需要 Spirit.interface( 'Animate', Interfaces.Animate );
上帝创造生命的时候, 没有让腔肠动物和环节动物实现眼睛的接口.
人类当然实现了眼睛的接口, 但人类不是从眼睛继承来的.
接口在未被声明之前, 只是一个普通的函数, 没有构造器, 没有prototype. 基本不占内存开销.
对于每个宿主 ( 实现者 )来说, 比如精灵1的animate和精灵2的animate. 它们像两个平行的宇宙. 每个都有各自的scope. 局部变量.
接口之间不赞成互相通信. 但可以通过宿主来通信. 就像人类实现了耳朵接口和嘴巴接口.
耳朵听到声音先把信息报告给大脑. 大脑再控制嘴巴说话. 但耳朵和嘴巴是不应该长到一起的. 这样不至于耳朵坏了的时候要修理嘴巴. 其实就是三个字, 要解耦!
Intanfances 里面的主要接口有这些:
Event: 一个简单的自定义事件机制, 以便在Animate,Frame和碰撞检测的时候实现有限状态机.
- Lock: 动作锁.
- Queue: 一个简单队列机制.
- StatusManage: 管理精灵的各种状态.
- Shadow: 精灵的阴影.
- Animate: 移动.
- SpiritFrames: 精灵的动画帧.
- KeyManage: 键盘管理器, 收集玩家输入.
- Collision: 检测碰撞.
- AttackEffect: 攻击效果.
- Audio: 音效.
Main.js
游戏的具体逻辑都在里面, 这个模块里一共实现了三个类. 精灵类, 战斗类, 还有一个类有点别扭, 它是波动拳类. - -!.
整个游戏里也只有这 3个类. 不过因为逻辑较多. 时间消耗基本都花在了这里. 毕竟它不像贪食蛇, 只要判断食物, 墙壁和尾巴.
Ai.js
这个模块负责 Ai所有逻辑, 也是写的最轻松的一个模块. 写好之后基本没改过.
对于电脑 ai来讲, 它明白对方的每一个动作. 所以对每一组动作, 都给ai设计了一组反应动作. 比如你出旋风腿, 电脑就出升龙拳.
但这样的话就没人打的过电脑了, 所以电脑的每次反应都有一组对的和一组错的, 可以调节ai的难度, 当ai越难的时候, 随到正确那组动作的可能性越大.
写游戏和写普通的应用有点不一样的地方是, 游戏需要更好的抽象出每个场景之间的共同点, 或者找出他们的不同点. 要尽量尽量少写if else. 除非是逼不得已. 当你写了一个if, 就意味着可能要写N个else if. 当逻辑越来越多的时候, 维护这些if会异常痛苦.
街头霸王里面的动作有很多种, 比如跳跃的时候不能移动, 攻击的时候既不能跳跃也不能移动, 跌倒的时候既不能跳跃也不能攻击也不能移动. 死亡之后啥也干不了. 那么怎么处理这些逻辑呢. 想想如果是写这样的代码.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
If ( isJump ){ If ( move ) return false; }else if( isAttack ){ If ( move || jump ) return false; }else if ( fall_down ){ If ( move || jump || attack ) return false; }... |
游戏里的具体逻辑比这复杂的多, 我也想不到得写多少个if else, if else. 闭上眼睛就是if else.
现在我是这样实现的. 给每种动作在配置文件里加一个锁. 精灵在动的时候, 总是被它锁住的. 移动的锁是0级, 跳跃是1级, 攻击是2级. 摔倒是3级.
当要执行一个新的动作的时候, 比如攻击的时候突然被踢倒. 会先比较2个动作的锁的级别. 如果后面动作的级别大于之前动作的级别. 就会打破之前的锁, 执行新的动作. 反之会无视新的动作. 比如攻击的时候移动和跳跃都是没用的.
转载请注明原地址:http://www.alloyteam.com/2012/05/html5-streetfighter-demo/
你的大爷 2014 年 8 月 26 日
厉害挺好玩的。www.ckhub.com
土豆 2013 年 10 月 28 日
曾哥,你再详细地解释一下你的代码么?
比如里的那几个 easing: {
linear: function( t, b, c, d ){
return c*t/d + b;
},
easeIn: function( t, b, c, d ){
return c*(t/=d)*t + b;
},
strongEaseIn: function(t, b, c, d){
return c * (t /= d) * t * t * t * t + b;
},
strongEaseOut: function(t, b, c, d){
return c * ((t = t / d – 1) * t * t * t * t + 1) + b;
},
sineaseIn: function( t, b, c, d ){
return c*(t/=d)*t*t + b;
},
sineaseOut: function(t,b,c,d){
return c*((t=t/d-1)*t*t + 1) + b;
},
sineaseInOut: function(t,b,c,d){
if ((t/=d/2) < 1) return c/2*t*t + b;
return -c/2 * ((–t)*(t-2) – 1) + b;
}
它们有什么区别?各个函数是什么意思?谢谢!
yong 2012 年 10 月 10 日
firefox 下音频文件解析失败,程序加载不完
svenzeng 2012 年 10 月 10 日
可以用 chrome 试一下。firefox 可能版本不太合适。
浩子 2012 年 10 月 6 日
请问游戏的图片素材哪里找的,一直没找到好的游戏图片资源,烦请大侠们指点下。感激不尽啊!!!!
svenzeng 2012 年 10 月 10 日
我也是网上找到, 街机模拟器里可以扒,不过是苦力活。
浩子 2012 年 10 月 13 日
呵呵,楼主写这游戏也是苦力活啊!很强
Freetao 2014 年 6 月 13 日
呵呵呵,很强+1 哦。
匿名 2012 年 9 月 17 日
能把游戏人物图像改了把代码发给我吗
匿名 2012 年 9 月 17 日
邮箱 1378605125@qq.com. 谢谢楼主了
deleted 2012 年 9 月 18 日
没听明白。
FG 2012 年 8 月 28 日
不错,有意思,可惜就是 HTML5 兼容性是个问题,还好我一直用 chrome
perlt 2012 年 8 月 5 日
怎么只有两个人玩而已。
ark 2012 年 8 月 5 日
不知是我游戏白痴了,还是 NPC 太强了
svenzeng 2012 年 8 月 7 日
我找到好几个必杀方式了
herbertd 2012 年 6 月 14 日
CHROM 可以正常运行。
做得很好!就是电脑太强了吧?搞不定他。
Pel 2012 年 6 月 5 日
@svenzeng 曾哥有没有作弊码啊, 电脑太强了!
匿名 2012 年 6 月 4 日
下载下来。可以玩。需要使用新版 谷歌浏览器,其他的一概不行。
avindeng 2012 年 6 月 4 日
很好,很强大。
就是操作起来比较费劲,老是被打败。
avindeng 2012 年 6 月 4 日
没有声音,下载的源码文件中的 mp3 文件无法播放,估计是不是音频文件出了问题啊?
白菜 2012 年 6 月 2 日
基本没法玩,IF/FF 无法加载,chrome 下页面崩溃。
TAT.Kinvix 2012 年 6 月 3 日
目前只测试过 chrome,请升级到 chrome 最新版本
argentwolf 2012 年 6 月 2 日
好奇怪,我这里 ff12 和 ie9 都卡在 loading 了,ff 是 11/11,ie9 是 1/11,下载到本地也一样。有人有同样的状况吗?
HTML5游戏 – 街头霸王 – html5Street 2012 年 5 月 31 日
[…] 因为 Class.create 返回的是一个普通的 object. 所以不能用 new Function 的方式生成对象. 具体使用方法如下例. view plainprint? […]
Trista Wang 2012 年 5 月 31 日
可以跑~
Fish 2012 年 5 月 31 日
safiri 可以跑,不过玩得过程有点卡,chrome 的确没有运行起来,一直在 loading 和 11/11,也许是我不够耐心,呵呵。
TAT.Kinvix 2012 年 5 月 31 日
因为这几天访问量太大,再加上是国外服务器,会出现不稳定情况,我也遇到过,不过 Chrome 刷新一下就好了
Freetao 2014 年 6 月 13 日
呵呵呵。
jackqqxu 2012 年 5 月 30 日
我在 FF,谷歌,QQ 浏览器上面都测试过了,无法启动游戏,再加载 mp3 的时候,返回 206,资源下载不全,你们那边可以玩起来吗?
匿名 2012 年 5 月 30 日
chrome,firefox 应该都可以.. 刷几次还是玩不了么?
TAT.Kinvix 2012 年 5 月 31 日
因为放在国外服务器可能会不够稳定,请刷新几次试试!
svenzeng 2012 年 5 月 29 日
看看头像
jesse 2012 年 5 月 29 日
lz 头像亮了