代码改变世界

javascript异步编程系列【十】—Jscex+Easeljs制作坦克大战

2011-09-15 08:01  【当耐特】  阅读(5534)  评论(13编辑  收藏  举报

一.简介

为了利用当今和未来的硬件,您可以对代码进行并行化,以将工作分摊在多个处理器上。 往往,并行化需要线程和锁的低级操作,但是Jscex不用,因为javascript这种解释型语言,仅仅需要一个线程来解释它,已其他线程无关,且不冲突!

 

二.回顾

上面介绍了一下Easeljs以及其优势,并且利用Easeljs+Jscex实现了坦克的右移以及开炮,但是还存在许多问题,比如移动不能开炮,开炮不能移动。

这篇主要利用Jscex并行编程模型搭起游戏的基本框架,并且解决坦克的转弯和开火。

 

三.架构设计

昨天我仔细想了想,不管是任何东西,拆得越细就越好控制。如果使用Easeljs的tick(也就相当于Jscex的while(true)),任何东西都往里面丢,函数冗长,不能灵活控制。Jscex有个很明显的优势,它可以轻松挂起一个while(true),用于监听,然后根据监听的结果做出相应的操作。所以,我把坦克大战拆成以下七个异步任务,游戏的所有元素都在下面七个异步任务当中:

a.坦克的移动

b.子弹的生产

c.子弹的飞行

d.碰撞检测,比如击中墙壁,击中敌方坦克

e.宝物的生成,比如增加火力的宝物,增加生命的宝物

f.统计任务,比如消灭敌军坦克获取积分

g. GameOver监听,比如老巢被灭,比如自己牺牲并且剩余生命条数为0

 

这七个任务同时执行,看似相互独立,其实是相互影响,比如

碰撞检测到击中敌方坦克,就会触发统计任务,

击中掉宝坦克,触发宝物的生成

被敌方坦克消灭老巢,触发GameOver

 

四.转弯和开火

 

开始打算用rotation属性来旋转图片,实现转弯,并且带有转弯动画,这也算超越了以前的坦克大战。然后rotation旋转图片不会以图片的中心旋转,而会以图片左上角为基准点旋转,这叫我情何以堪!旋转效果如下:

 

好吧,我还是用四张图片吧,反正素材就提供了4张图片。

fiveTank

 

我们把转弯与开火拆成三个异步任务:

a.坦克的移动

b.子弹的生产

c.子弹的飞行

坦克的移动:

var moveAsync = eval(Jscex.compile("async", function () {
var i = 0;
while (true) {
if (goRight == true) {
bmpR.visible = true;
bmpL.visible = false;
bmpD.visible = false;
bmpU.visible = false;
bmpL.x += 1;
bmpR.x += 1;
bmpD.x += 1;
bmpU.x += 1;
}
if (goLeft == true) {
bmpR.visible = false;
bmpL.visible = true;
bmpD.visible = false;
bmpU.visible = false;
bmpR.x -= 1;
bmpL.x -= 1;
bmpD.x -= 1;
bmpU.x -= 1;
}
if (goUp == true) {
bmpR.visible = false;
bmpL.visible = false;
bmpD.visible = false;
bmpU.visible = true;
bmpR.y -= 1;
bmpL.y -= 1;
bmpD.y -= 1;
bmpU.y -= 1;
}
if (goDown == true) {
bmpR.visible = false;
bmpL.visible = false;
bmpD.visible = true;
bmpU.visible = false;
bmpR.y += 1;
bmpL.y += 1;
bmpD.y += 1;
bmpU.y += 1;
}
stage.update();
$await(Jscex.Async.sleep(10));
}
}))

 

生成子弹:

var bulletStream = new Array();
var createBulletAsync = eval(Jscex.compile("async", function () {
var i = 0;
while (true) {
if (shootHeld == true) {
bulletStream[i] = new Bitmap("image/tankmissile.gif");
if (bmpD.visible == true) {
bulletStream[i].direction = "down";
bulletStream[i].x = bmpR.x + 21;
bulletStream[i].y = bmpR.y + 60;
}
if (bmpL.visible == true) {
bulletStream[i].direction = "left";
bulletStream[i].x = bmpR.x ;
bulletStream[i].y = bmpR.y + 21;
}
if (bmpR.visible == true) {
bulletStream[i].direction = "right";
bulletStream[i].x = bmpR.x + 60;
bulletStream[i].y = bmpR.y + 21;
}
if (bmpU.visible == true) {
bulletStream[i].direction = "up";
bulletStream[i].x = bmpR.x + 21;
bulletStream[i].y = bmpR.y ;
}
stage.addChild(bulletStream[i]);
i++;
}
stage.update();
$await(Jscex.Async.sleep(200));
}
}))

我们要在生成子弹的时候,告诉子弹的方向,也许以后会扩展一个子弹的速度。

 

子弹的飞行:

var fireAsync = eval(Jscex.compile("async", function () {
while (true) {
for (bullet in bulletStream) {
if (bulletStream[bullet].direction == "up") {
bulletStream[bullet].y -= 10;
}
if (bulletStream[bullet].direction == "down") {
bulletStream[bullet].y += 10;
}
if (bulletStream[bullet].direction == "right") {
bulletStream[bullet].x += 10;
}
if (bulletStream[bullet].direction == "left") {
bulletStream[bullet].x -= 10;
}
}
stage.update();
$await(Jscex.Async.sleep(50));
}
}))

 

元素初始化,并行任务开始:

function init() {
canvas = document.getElementById("testCanvas");
stage = new Stage(canvas);
bmpR = new Bitmap("image/p1tankR.gif");
bmpL = new Bitmap("image/p1tankL.gif");
bmpD = new Bitmap("image/p1tankD.gif");
bmpU = new Bitmap("image/p1tankU.gif");
bmpL.visible = false;
bmpD.visible = false;
bmpU.visible = false;
stage.addChild(bmpR);
stage.addChild(bmpL);
stage.addChild(bmpD);
stage.addChild(bmpU);
Ticker.addListener(stage);
createBulletAsync().start();
fireAsync().start();
moveAsync().start();
}

 

五.在线演示

操作指南:WSAD+J

 

未完待续,下篇加入敌方坦克,ohoh··········

 

最新的Jscex 库,请上https://github.com/JeffreyZhao/jscex或者http://www.sndacode.com/projects/jscex/wiki下载吧····

六.同步

本文已同步更新至:

HTML5实验室【目录】:   http://www.cnblogs.com/iamzhanglei/archive/2011/11/06/2237870.html