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

原创 2011年01月14日 16:47:00

第十一章 演员(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

《Python核心编程》第11章 习题

11-2 函数。结合你对练习5-2的解,以便你创建一个带一对相同数字并同时返回它们之和以及产物的结合函数。 fun=lambda x,y:x+y print fun(1,3) 11-3 函数...
  • birdzb
  • birdzb
  • 2016年01月22日 16:15
  • 2867

思科CCNA第二学期第十一章答案

1.请参见图示。“O*E2 0.0.0.0/0 [110/1] via 192.168.1.1, 00:05:34, Serial0/0”一行中的“O*E2”代表什么含义? ...
  • u014253173
  • u014253173
  • 2015年01月24日 21:05
  • 2362

Python核心编程(第十三章)--面向对象编程

面向对象编程主要是类和类的实例 创建类: class MyNewObjectType(bases): 'define MyNewObjectType class' class_suit...
  • u014380159
  • u014380159
  • 2016年06月02日 15:43
  • 421

《Python核心编程》第14章 习题

14-3.执行环境。创建运行其他Python脚本的脚本。 filename = r'D:\test.py' execfile(filename)14-4. os.system()。调用os.sy...
  • birdzb
  • birdzb
  • 2017年04月01日 20:28
  • 482

《C++ Primer Plus(第六版)》(20)(第十一章 使用类 编程题答案1)

这章主要讲重载运算符,友元函数和类型转换。 1. 第一题就困了我好久,怎么都访问不了私有成员,一开始以为是哪里写错了,对着书敲代码都不行。 后来又觉得会不会友元的重载运算符太复杂,就自己写个简单的友元...
  • u012175089
  • u012175089
  • 2016年12月22日 10:12
  • 2329

C++Primer第五版 第十一章习题答案(1~10)

1:知识点1:关联容器与顺序容器有着根本的不同 知识点2:关联容器的元素是按关键词来保存和访问的,顺序容器是按他们在容器中的位置来顺序访问 知识点3:关键词在关联容器中起到重要的作用,map中的元素是...
  • misayaaaaa
  • misayaaaaa
  • 2017年03月01日 09:31
  • 1810

java语言程序设计基础篇第十一章编程练习题

1package yongheng; import java.util.Scanner;public class Main { public static void main(String a...
  • gyhguoge01234
  • gyhguoge01234
  • 2016年09月08日 22:19
  • 2225

python核心编程-第12章课后练习答案

第一题: 路径搜索和搜索路径。路径搜索和搜索路径之间有什么不同? 解答:前者是指查找某个文件的操作,后者是去查找一组目录。 第二题: 导入属性。假设你的模块mymodule里有一个foo()函...
  • qq_34171520
  • qq_34171520
  • 2016年10月31日 12:04
  • 674

C++ Primer Plus第六版 第十一章 编程练习答案

//第一题 //windows下\r\n在txt中是换行...被坑了= = //vector.h #ifndef VECTOR_H_ #define VECTOR_H_ #include name...
  • zhaoshu01234
  • zhaoshu01234
  • 2015年09月26日 10:54
  • 1760

python 核心编程2 第十三章练习

'''对类进行定制。写一个类,用来将浮点数值转换为金额。在本练习里,我们使用美国 货币,但读者也可以自选任意货币。 基本任务: 编写一个dollarize()函数,它以一个浮点数值作为输入,返回一个字...
  • mingyuezhao01
  • mingyuezhao01
  • 2017年06月11日 18:33
  • 233
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:从零开始Android游戏编程(第二版) 第十一章 演员(Actor)、视口(ViewWindow),演出开始
举报原因:
原因补充:

(最多只允许输入30个字)