点赞链接 👈
游戏链接 👉 愤怒的小鸟微恐版
本文对这个游戏进行批评与自我批评
游戏框架
MONKEY PATCH
可以看出这是一个非常不规范的游戏,完全不是按照Y总的教程来的....
我以为的:
acwing要求的:
所以…做了一个hack,把index的内容写进了js。
至于我为什么会这么以为,因为在github上搜到了一个类似的项目,在那基础上改的。而且直接打开index.html配置很方便…
游戏组成
游戏内容主要有几个类:
- Game: 定义游戏流程
- Level: 定义关卡
- Entity: 定义游戏中的物体特性
另外还有一些辅助类,帮助完成资源加载、绑定和计算。其中计算碰撞和反弹用到的是:
- box2d: 用于计算碰撞
Game
定义了游戏的整个流程, 这点遵从原项目的设计,我没有做改动:
- Preclude: 加载背景图和字幕
- Intro: 关卡刚刚载入,游戏将在整个关卡范围内平移游戏画面,向玩家展现关卡中的所有东西
- Load-next-hero: 检查是否有下一个英雄可以装填到弹弓上去,如果有,装填该英雄。如果我们的英雄耗尽了而坏蛋却没有被全部消灭,关卡就结束了
- Wait-for-firing: 将视野移回到弹弓,等待玩家发射“英雄”。此时,游戏正在等待玩家单击英雄。在这个阶段,玩家可以也很有可能用鼠标拖拽画面,查看整个关卡
- Firing: 在这个阶段,玩家已经单击了英雄,但还没有释放鼠标按键。此时,游戏正在等待玩家拖拽英雄,调整角度和位置释放英雄
- Fired: 玩家释放了鼠标按键并发射英雄之后进入这个阶段。此时,游戏将所有的事情交给物理引擎来处理,用户仅仅在观看。游戏画面会随着发射出的英雄平移
Levels
Levels开始,可以发挥个人想象力了。
每个Levels定义的内容有:
- 每关的前景图和背景图
- 开始时候的提示语
- 关卡内容(地图角色,英雄角色,坏蛋角色)
Entities
无论是障碍物,敌人,还是子弹,都可以被视为一个Entities。
每个entity会有属性,以及对应的图像;shape分两种,circle和rectangle;圆形的需要设定半径radius,矩形的需要设定width和height;isStatic表示是否要参与运动的计算(自由落体,滚动..),如果设置为false,可以设置出浮空的木板等;
对vilian障碍物还需要有health参数表示何时会消失,score表示这次能获得多少分数;另外还有一组物理参数(density密度, friction摩擦系数, restitution反弹系数),用来计算每次碰撞后的路径。
对hero,即填充发射的子弹,增加了额外的power参数,用来调整伤害值;同时删掉了score属性。
伤害计算
玩家发射时拉扯弹弓,给定初始impulse,其大小和距弹弓中心距离成正比。然后直接调用box2d的ApplyImpulse功能
var impulse = new b2Vec2((slignshotCenterX-mouse.x-game.offsetLeft)*impulseScaleFactor, (slingshotCenterY-mouse.y)*impulseScaleFactor);
hero.ApplyImpulse(impulse, WorldCenter);
碰撞事件通过注册box2d的callback来处理:
var listener = new Box2D.Dynamics.b2ContactListener();
listener.PostSolve = function(contact, impulse) {
var body1 = contact.GetFixtureA().GetBody();
var body2 = contact.GetFixtureB().GetBody();
var entity1 = body1.GetUserData();
var entity2 = body2.GetUserData();
var impulseAlongNormal = Math.abs(impulse.normalImpulses[0]); // 法向冲撞力
// 监听器被调用得有些太频繁了,滤去非常小的冲击
// 尝试不同的值后,5 似乎比较好
if (impulseAlongNormal > 5) {
// 如果对象有生命值,用冲击值削弱生命值
var harm = impulseAlongNormal;
if (entity1.power) {
harm = harm * entity1.power;
} else if (entity2.power) {
harm = harm * entity2.power;
}
if (entity1.health) {
entity1.health -= harm;
}
if (entity2.health) {
entity2.health -= harm;
}
...
// 处理其他的状态,播放音乐等
};
box2d.world.SetContactListener(listener);
过关条件及奖励
当vilian全部消失,而hero还在的话,游戏获胜;否则游戏失败。
分数比较随意。
超过特定关卡后可以解锁一些新的操作。
关卡解析
白色字体,请反选
Level 1
$\color\white{热身}$
Level 2
$\color\white{眼睛基本碰到就能消灭,一种方案是对着地板反弹过障碍物, 也可以等第四关后再来}$
Level 3
$\color\white{为第四关铺垫,瞄准最下面一排的障碍物打就行}$
Level 4
$\color\white{钢铁打不破,但是文字提示空白格。在等待发射时按空格,钢铁会变成玻璃,结构和第三关相同,这个能力可以带到之后的游戏}$
$\color\white{这时候回到第二关,可以用这个功能键把钢铁的障碍物换成玻璃的}$
Level 5
$\color\white{可以用快捷键把上方钢铁换成玻璃,然后击碎玻璃,让上面的障碍物自由落体。落体完可能还剩一些villian,需要留好子弹清场;}$
$\color\white{也可以利用上方的反弹清除一部分viliian,再使用自由落体}$
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%