从零开始Android游戏编程(第二版) 第十一章 演员(Actor)、视口(ViewWindow),演出开始

第十一章 演员(Actor)、视口(ViewWindow),演出开始

本章内容与第七章、第八章关系非常密切,如果对这两章的内容不熟悉请大家先浏览一下七、八章,再回来看本章。

Actor是一个接口,他的作用是统一类的行为(读者可以阅读一下Facede模式相关文章)。我们用一个比喻来说明:演员们有了各自的剧本,导演对所有演员说:做下一个动作!演员们就会各自行动。而不用导演分别告诉每个人,你要这样做,他要那样做。具体到程序中,帧动画、动态图块两种操作会调用完全不同的函数,这样不利于在游戏循环中做出一致的处理。所以我们让他们都实现Actor接口,只要调用接口定义的函数,他们就会做出各自的动作。Actor接口的定义很简单:

public interface Actor {

public void tick();

}

对于实现了Actor接口的任何类型,发出的指令就只有一个:tick。

下面请看实例演示:

我们将创建两个类Tank和Map,分别继承自Sprite和TiledLayer,都实现Actor接口。为tank创建帧动画,为Map创建动态图块,然后将他们显示在SceneMain中。

首先,我们可以复制第十章的例子创建一个新项目,并将第八章中用到的org.yexing.android.games.common包拷贝到项目中。

clip_image002

创建一个Tank类,继承自Sprite,实现Actor接口。

在tick函数中播放帧动画

public void tick() {

// TODO Auto-generated method stub

nextFrame();

}

然后创建一个Map类继承自TiledLayer,实现Actor接口。

在tick函数中播放动态图块

public void tick() {

// TODO Auto-generated method stub

if (getAnimatedTile(-1) == 4) {

setAnimatedTile(-1, 5);

} else {

setAnimatedTile(-1, 4);

}

}

最后在SceneMain中创建这两个类的实例并显示他们

Layer layers[] = new Layer[2];

int mapdate[][] = { { 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0 },

{ 0, 1, 0, 2, 0, 0, 0, 1, 0, 1, 0, 1, 0 },

{ 0, 1, -1, -1, -1, 0, 1, 1, 0, 1, 2, 1, 0 },

{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0 },

{ 3, 0, 0, 1, 0, 0, 2, 0, 0, 1, 3, 1, 2 },

{ 3, 3, 0, 0, 0, 1, 0, 0, 2, 0, 3, 0, 0 },

{ 0, 1, 1, 1, 3, 3, 3, 2, 0, 0, 3, 1, 0 },

{ 0, 0, 0, 2, 3, 1, 0, 1, 0, 1, 0, 1, 0 },

{ 2, 1, 0, 2, 0, 1, 0, 1, 0, 0, 0, 1, 0 },

{ 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 2, 1, 0 },

{ 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },

{ 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0 },

{ 0, 1, 0, 1, 0, 1, 6, 1, 0, 1, 1, 1, 0 }, };

public SceneMain() {

paint = new Paint();

paint.setColor(Color.WHITE);

paint.setTextAlign(Align.CENTER);

Bitmap bmpTank = BitmapFactory.decodeFile("/sdcard/player1.png");

Bitmap bmpTile = BitmapFactory.decodeFile("/sdcard/tile.png");

Tank tank = new Tank(bmpTank, 32, 32);

tank.setFrameSequence(new int[]{0, 1});

Map map = new Map(13, 13, bmpTile, 32, 32);

map.createAnimatedTile(4);

for(int y=0; y<13; y++) {

for(int x=0; x<13; x++) {

map.setCell(y, x, mapdate[x][y]);

}

}

layers[0] = map;

layers[1] = tank;

}

@Override

public void update(Canvas c) {

// TODO Auto-generated method stub

c.drawARGB(255, 0, 0, 0);

c.drawText("SceneMain", GameView.width/2, GameView.height/2, paint);

for(int i=0; i<2; i++) {

((Actor)layers[i]).tick();

layers[i].paint(c);

}

}

需要读者关注的就是update方法中对tick的调用。运行程序,我们可以看到动画的效果。

还需要注意一点,我们将位图文件放置在了sdcard的根目录。读者可以在项目的res/drawable下找到这两个文件,自行push到sdcard中。

下面再来看ViewWindow。我们可以将它理解成舞台的前台,或者相机的取景器。演员只有走到前台,观众才能看得见。而演员走下台,就从观众视线消失。通常,屏幕就是一个视口,因为无论如何我们也看不到屏幕之外的东西。而有时候,我们需要更小的视口,局部的变化,就需要自行定义视口了。其实,视口的功能我们已经实现了,他就在LayerManager中,只是我们前面没有用到也就没有做介绍。

下面就先让我们来了解一下LayerManager的功能。我们知道Sprite、TiledLayer都是继承自Layer,那么LayerManager,顾名思义,就是用来管理Layer的。具体说是管理Layer的显示的。要使用LayerManager,我们首先调用函数append()或insert()将Layer加入到LayerManager中,就如我们将纸张放入文件夹一样,然后调用paint就可以将所有Layer一次显示出来。Layer有一个属性:z,表示Layer的Z坐标,如图:

clip_image003

Z坐标从屏幕内指向屏幕外,也就是说Z坐标越大离用户越近,前面的Layer会遮住后面的Layer。

我们改写前面的程序,用LayerManager代替Layer数组

public SceneMain() {

super();

……

layerManager.append(map);

layerManager.insert(tank, 100);

……

public void update(Canvas c) {

……

for(int i=0; i

((Actor)layerManager.getLayerAt(i)).tick();

}

layerManager.paint(c, 0, 0);

}

熟悉了LayerManager之后就让我们来学习视口。我们可以将Layer想像成一张张非常大的画布,他们被放在LayerManager这个容器中,视口就是在容器上开一个小窗户,使用户只能看到窗口那一部分,其余的区域都不可见。

让我们看一下LayerManager的构造函数

public LayerManager() {

setViewWindow(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);

}

我们可以看到在这里,已经定义了一个视口。这个视口非常大,可以想象他与Layer一般大,所以我们看不到他的效果。但是如果我们把视口缩小呢?

public void update(Canvas c) {

……

layerManager.setViewWindow(0, 0, 100, 100);

layerManager.paint(c, 0, 0);

}

运行程序,可以看到只有视口内的部分被显示了出来。

clip_image005

ViewWindow的难点在坐标。让我们回头看

layerManager.setViewWindow(x, y, width, height);

layerManager.paint(c, x, y);

这两个函数都用到了坐标,他们有着完全不同的含义。首先看paint,其中的x,y表示视口的左上角相对于屏幕的坐标。我们前面说过,视口可以理解为LayerManager上的窗口,改变这个坐标,整个LayerManager就会跟着一起移动。让我们修改程序,将视口显示在(100,100)的位置

layerManager.paint(c, 100, 100);

clip_image007

可以看到,所有Layer的左上角都移动到了(100,100)的位置。

再来看setViewWindow,其中的x,y表示视口相对于Layer左上角的坐标,让我们修改他们的数值,看看效果。

layerManager.setViewWindow(50, 50, 100, 100);

clip_image009

可以看到,左上角的坦克不见了。

合理的运用setViewWindow可以很方便的实现滚屏效果。

本章示例程序http://u.115.com/file/f198eeda92

阅读更多
想对作者说点什么? 我来说一句

从零开始Android游戏编程

2011年08月12日 850KB 下载

从零开始Android游戏编程(第二版)

2013年05月02日 1.17MB 下载

从零开始学Storm 第2版

2017年11月21日 170.02MB 下载

从零开始开始学Python 第二版

2016年07月28日 6.14MB 下载

没有更多推荐了,返回首页

不良信息举报

从零开始Android游戏编程(第二版) 第十一章 演员(Actor)、视口(ViewWindow),演出开始

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭