您的位置:首页 > 其它

libgdx游戏引擎教程(十三)演员类的用户交互功能详解(附源码)

2013-03-12 09:26 686 查看
转自:http://www.apkbus.com/android-60457-1-1.html

本讲源码:


edu.nju.wsj.libgdx.rar(3.8
MB, 下载次数: 126)

2012-7-23 17:52 上传
点击文件名下载附件

下载积分: 下载豆 -2

今天是该系列教程的第十三讲,也是系列教程的第二十二篇。这两天有巴友经常问我一些问题,其中很多问到了我今天要讲的内容,我就在这里一起分析一下好了。

这一讲我们来具体分析一下一个我们早就接触到的东西,演员类Actor,不过似乎我们都是一直只会简单的使用演员类,我们对Actor的主要工作都集中在draw()函数中,即我们大部分修改都是基于Actor怎么绘制,其实Actor的绘制功能只是其中的一部分,游戏最重要的部分是和用户的交互,即让用户在玩游戏的时候全身心投入,或者说增加用户的粘度。我们如果只在游戏的绘制方面下功夫,这个游戏就好比是动画片,用户只要按下一个按钮就开始看我们辛辛苦苦制作的动画片?以上也是说笑的,但无疑游戏开发中,提高游戏和用户之间的交互应该放在第一位。

[align=left]Actor类中其实提供了很多对用户交互请求做出响应的函数,还是老样子,我们先来看看文档好了。我们主要关注以下几个方法:[/align]



2012-7-23 17:38 上传
下载附件 (2.32 KB)



2012-7-23 17:38 上传
下载附件 (27.45 KB)

[align=left]其中最主要的是hit()方法,我们来看看这个是怎么使用的。接下来的代码在十二讲的基础做修改,我们先新建一个Actor类,ExampleActor:[/align]

public class ExampleActor extends Actor {

@Override

public void draw(SpriteBatch arg0, float arg1) {

// TODO Auto-generated method stub

}

@Override

public Actor hit(float arg0, float arg1) {

// TODO Auto-generated method stub

return null;

}

}

复制代码

[align=left][/align]
[align=left]我们修改一下构造函数,可以在ExampleActor类初始化的时候就对其位置进行设定,并且在Actor的draw()中绘制一张图片,方便我们确认Actor的位置。顺便把另外几个我们提到的交互函数也实现一下,其实也就是打印一句话,便于我们追踪Actor的响应,从而了解其中的机制。另外为了我们马上加入多个Actor而用于标识每一个Actor,我们再设置一个字符串变量,在创建时传入。Actor的资源是Testin的logo,大小我已经做过处理变成了128*64:[/align]



2012-7-23 17:39 上传
下载附件 (7.69 KB)

[align=left]修改后的代码如下:[/align]

public class ExampleActor extends Actor {

Texture tx;

String Id;

@Override

public void draw(SpriteBatch arg0, float arg1) {

// TODO Auto-generated method stub

//根据这个Actor的位置来绘制

arg0.draw(tx, this.x, this.y);

}

@Override

public Actor hit(float arg0, float arg1) {

// TODO Auto-generated method stub

Log.i("Testin","hit"+Id);

return null;

}

@Override

public boolean touchDown(float x, float y, int pointer) {

// TODO Auto-generated method stub

Log.i("Testin","touchDown"+Id);

return super.touchDown(x, y, pointer);

}

@Override

public void touchDragged(float x, float y, int pointer) {

// TODO Auto-generated method stub

Log.i("Testin","touchDragged"+Id);

super.touchDragged(x, y, pointer);

}

@Override

public boolean touchMoved(float x, float y) {

// TODO Auto-generated method stub

Log.i("Testin","touchMoved"+Id);

return super.touchMoved(x, y);

}

@Override

public void touchUp(float x, float y, int pointer) {

// TODO Auto-generated method stub

Log.i("Testin","touchUp"+Id);

super.touchUp(x, y, pointer);

}

public ExampleActor(int x,int y,String Id) {

super();

//对坐标进行初始化

this.x=x;

this.y=y;

this.Id=Id;

//对纹理对象进行初始化,资源文件放在assets文件下

tx=new Texture(Gdx.files.internal("actor.png"));

}

}

复制代码
我们接下来在MyGame.java中加入一个Actor,并加入stage,让这个Actor能够正常显示。

ExampleActor example;

复制代码
show()函数中初始化,并加入舞台:

example=new ExampleActor(100, 100,"1");

stage.addActor(example);

复制代码

看一下运行效果:



2012-7-23 17:38 上传
下载附件 (29.03 KB)

[align=left]没错,Actor确实显示出来了,那我们触摸一下,看看Logcat中的输出:[/align]



2012-7-23 17:38 上传
下载附件 (98.57 KB)

[align=left]确实有输出,但是这里有两点需要注意:[/align]

[align=left]第一点:[/align]

[align=left]我们在stage上触摸的任一点都会有hit+ID的输出,即系统不经任何判断,只要stage捕捉到触摸事件,就会通知其内的所有Actor,调用所有子Actor的hit()方法,为了证明这一点,我们再在MyGame.java的stage中再加入一个ExampleActor的实例,设置其ID为2,我们再来看看输出。[/align]
[align=left][/align]

<span lang="EN-US" style="font-size:10.0pt;font-family:

"Courier New";mso-fareast-font-family:宋体;mso-fareast-theme-font:minor-fareast;

color:black;mso-font-kerning:0pt;mso-ansi-language:EN-US;mso-fareast-language:

ZH-CN;mso-bidi-language:AR-SA">ExampleActor </span><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New";mso-fareast-font-family:宋体;

mso-fareast-theme-font:minor-fareast;color:#0000C0;mso-font-kerning:0pt;

mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA">example2</span><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New";mso-fareast-font-family:

宋体;mso-fareast-theme-font:minor-fareast;color:black;mso-font-kerning:0pt;

mso-ansi-language:EN-US;mso-fareast-language:ZH-CN;mso-bidi-language:AR-SA">;</span>

复制代码

[align=left]同样的:[/align]
[align=left][/align]

Example2=new ExampleActor(200, 200,"2");

stage.addActor(example2);

复制代码
[align=left]看看效果:[/align]



2012-7-23 17:38 上传
下载附件 (32.95 KB)

[align=left]随意触摸屏幕上的任何一个位置,看看Logcat的输出:[/align]



2012-7-23 17:38 上传
下载附件 (111.08 KB)

[align=left]我们看到,这两个ExampleActor的hit()方法都确实触发了,而且我们可以看到,是stage中的Actor队列的末尾的Actor最先响应,然后逐步是队列前部的Actor(我们先加入example再加入的example)。[/align]
[align=left][/align]

[align=left]第二点:[/align]

[align=left]很多同学也许看到这里已经有疑惑了,首先,既然触摸事件会由stage通知在其内的每一个Actor并调用这些Actor各自的hit()方法,那我们怎么判断触摸的是哪一个Actor呢?其次,细心的同学已经注意到了,为什么只有hit()方法被触发了但另外四个方法都没有输出?[/align]

[align=left]其实这里的重点在于hit()中的处理,我们再做一个处理,在hit()方法中打印传入的两个参数,按照文档的说法:[/align]

[align=left]传入的应该是一个x,一个y,应该指的是一个坐标,可是具体的含义我们还是不清楚,因此在ExampleActor的hit()方法中添加以下语句:[/align]

Log.i("Testin","x:"+arg0+" y:"+arg1);

复制代码

[align=left]我们再运行一下,并且随意触摸屏幕的一个位置,输出如下:[/align]



2012-7-23 17:38 上传
下载附件 (145.61 KB)

[align=left]我们可以看到,还是同样的有输出。但是我们可以发现一个很奇怪的现象,如果传入的参数x,y是指触摸点在屏幕上的位置,为什么两个Actor的输出x,y结果不一样呢?细心的同学可以注意到,这两个x和两个y之间都相差100,正是我们初始化时这两个ExampleActor坐标(100,100)和(200,200)之间的差。[/align]

[align=left]事实正是这样,libgdx文档中中并没有对这两个参数做任何的介绍,一开始大家很容易就任何传入的是触摸点的坐标,我们经过实践以后发现并不是这样。事实上,传入的这个参数是触摸点相对于Actor的坐标。除了hit()方法,touchDragged(),touchMoved(),touchDown(),touchUp()这四个方法中传入的x,y参数也是触摸点相对于Actor的x,y值,而不是触摸点的绝对坐标。[/align]

[align=left][/align]
[align=left][/align]
[align=left]现在我们又面临一个问题,怎么触发touchDragged(),touchMoved(),touchDown(),touchUp()这四个方法呢?[/align]

[align=left]我直接揭晓答案好了。事实上,这四个方法的触发需要hit()方法的配合,我们可以看到默认的hit()方法返回的是null,而当经过相应的判定之后,我们在hit()方法中返回这个Actor实例,即:[/align]

return this;

复制代码
的时候,这四个事件就会被触发。那我们对hit()方法进行相应的修改:

@Override

public Actor hit(float arg0, float arg1) {

// TODO Auto-generated method stub

Log.i("Testin","hit"+Id);

Log.i("Testin","x:"+arg0+" y:"+arg1);

if(arg0>0&&arg1>0&&arg0<tx.getWidth()&&arg1<tx.getHeight())

return this;

return null;

}

复制代码
这里我们将这个Actor看作是一个和图片资源actor.png一样大的矩形。运行一下,看看效果,我触摸了其中一个ExampleActor,输出如下:



2012-7-23 17:38 上传
下载附件 (125.9 KB)

[align=left]实际上我是触摸了第二个ExampleActor,即example2,因此我们可以看见example2的touchDown的输出,而看不见第一个的,这就实现了一个简单的触摸检测。[/align]

[align=left][/align]
[align=left]那我们怎么能让Actor的touchUp()和touchDragged()也接收事件呢?我也直接揭晓答案好了:我们看到现在能够触发touchDown()了,若touchDown()返回true,则该Actor成为group(即这里的Stage)的焦点,这意味着该Actor可以接收到touchDragged()和touchUp()事件并做出相应的响应。我们修改touchDown()函数:[/align]

@Override

public boolean touchDown(float x, float y, int pointer) {

// TODO Auto-generated method stub

Log.i("Testin","touchDown"+Id);

// return super.touchDown(x, y, pointer);

return true;

}

复制代码
[align=left]再运行一下,并触摸第二个ExampleActor,观察输出:[/align]



2012-7-23 17:38 上传
下载附件 (159.01 KB)

[align=left]我们可以看到,touchUp()和touchDragged()也做出了响应。但是我们为什么没有看到”hit1”这个输出?原因在于,一旦系统找到一个匹配的Actor,就不会继续搜寻。这里我们触摸的是第二个ExampleActor,且前面我们说过,系统是从Actor队列的尾部开始搜寻,因此找到example2后就不再继续搜寻。[/align]

[align=left][/align]
[align=left]相反如果我们触摸的是第一个ExampleActor的话,我们可以看到“hit2”这个输出,因为系统发现第二个ExampleActor不匹配,它会自动向前继续搜索:[/align]



2012-7-23 17:38 上传
下载附件 (169.82 KB)

这些都验证了我们之前的猜测。

抱歉,这里忘了和大家说了,touchMoved是libgdx在PC上运行的时候才响应的,因为Libgdx是一个跨平台的引擎,在Android里是不起作用的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐