蓝牙连接 对战五子棋
技术与开发
上期我们为五子棋游戏添加了触摸屏支持功能。本期我们将完成五子棋游戏的最后一个功能——蓝牙对战。我们需要给五子棋游戏添加蓝牙接口,使其可以支持双机对战。蓝牙是当前手机设备间的主流通信方式之一,目前主流手机均支持蓝牙通信,开发程序时考虑蓝牙支持功能,是非常有必要的。
蓝牙对战设计思路
摆脱传统连线的束缚,彻底地享受无拘无束的乐趣,蓝牙给予我们的便利足以让人精神振奋。随着技术的进步,现在,一部蓝牙手机已不再需要上千元的高价,很多四五百元的低端手机也具备了蓝牙功能,可以说蓝牙已经走进了千家万户,未来的手机程序应该考虑到这一点,具备蓝牙连接功能的手机程序才更具有市场竞争力。
为五子棋游戏添加蓝牙功能先要进入游戏开启蓝牙功能,将两部手机分别作为主机和客户机,然后建立蓝牙连接,一切就绪后主机和客户机各开启一个蓝牙线程,在游戏的同时通过蓝牙接口进行数据交换。在玩游戏结束后交换两个玩家的角色,进行下一盘游戏(见图)。

蓝牙连接的细节
蓝牙连接分为下面几个阶段:设备管理、设备发现、服务发现、通信。
设备管理:设备管理主要是用于管理当前的蓝牙设备(如用户的手机),获取当前设备的相关信息。我们可以利用javax.bluetooth.DeviceClass类来获得设备类型和它所提供的服务类型。
设备发现:蓝牙设备需要一种机制来允许它们发现其他的蓝牙设备并访问它们。通俗地讲就是一部手机需要有一定机制来发现另一部具备蓝牙功能的手机,这样它们才有建立连接的可能。
服务发现:服务发现允许你发现附近的服务,而不管是哪一台设备提供的服务。
通信:两部蓝牙设备必须共享通用的通信协议才能通信。为了能够访问更多的蓝牙手机,蓝牙java API提供了这样一个机制,它允许连接使用RFCOMM,L2CAP或OBEX协议的任何手机。
要实现上述4个步骤,需要编写蓝牙类,在游戏中调用它即可。我们编写的这个类具有较强的通用性,读者在编写完成后可以将它保存,以后遇到需要蓝牙通信的项目时只需将它添加进去调用即可,非常方便。
蓝牙对战设计步骤
第一步:编写蓝牙类
在NetBeans中打开五子棋项目,新建一个WirelessDevice.java文件,并在该文件中创建一个WirelessDevice类作为蓝牙通信的基础类。我们将在这个类中添加一些蓝牙通信所必需的函数,在使用蓝牙进行游戏交互对战时,涉及到通信和数据传输的时候只需简单调用这些函数即可。关键代码如下所示(完整代码下载地址:http://www.shudoo.com/bzsoft):
public byte readData(){ //从蓝牙流中读取数据
try{
return (byte)inputStream.read();
}catch(Exception e){
return (byte)0;
//[1]做主机
public void doServer(){
try{
//将蓝牙设备设置成可发现设备
localDevice = LocalDevice.getLocalDevice();
localDevice.setDiscoverable(DiscoveryAgent.GIAC);
//建立连接字符串
String connectionURL =“btspp://localhost:”+uuid+“;authenticate=false;encrypt=false;name=RFCOMM Server”;
//打开蓝牙通道
server = (StreamConnectionNotifier)Connector.open(connectionURL);
//取得主机的连接字符串
connURL = servRecord[0].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT,false);
//这里可以获取主机参数
//servRecord[0].getAttributeValue(0x101);
try{
//蓝牙连接建立,返回连接对象
conn = (StreamConnection)Connector.open(connURL);
if(conn!=null){
isConnected=true;
//建立客户读写通道
outputStream=conn.openOutputStream();
inputStream=conn.openInputStream();
第二步:编写蓝牙通信服务线程
线程是蓝牙通信所必需的。我们需要新建一个线程为蓝牙通信服务。蓝牙类的各种方法必须在新的线程中执行,否则会造成程序死锁。此外线程也作同步和接收数据之用。关键代码如下所示(完整代码下载地址:http://www.shudoo.com/bzsoft):
//开始游戏
state=2;
while(true){
if(remoteDevice.getDataNumber()>0){ //当消息数量大于0时
int x=remoteDevice.readData(); //从数据流中读取x坐标
int y=remoteDevice.readData(); //从数据流中读取y坐标
System.out.println(x);
System.out.println(y);
if(turn!=side && x<15 && y<15)gameFinished=setChess(x,y);
else if(x==20 && y==20){
gameFinished=3;
第三步:读写数据
接下来我们要在游戏的按键逻辑处理部分加入蓝牙读写流。蓝牙读写流和读写文件类似,只不过读写文件是针对文件进行读写,而蓝牙读写流则是对其他机器进行读写,以数据流的方式进行数据传输。
也许有读者会产生疑问,只对按键进行处理的话,我们上期所添加的触摸屏支持功能是否在蓝牙游戏中就不能用了呢?不是的,因为我们上期添加触摸屏支持功能时采用了一个小技巧,即在点击相应位置时调用相应的按键处理函数进行处理,因此不存在冲突。
找到GameCanvas.java文件中的keyPressed()函数,并对它进行改写,以使其支持蓝牙对战。关键代码如下所示(完整代码下载地址:http://www.shudoo.com/bzsoft):
//按键移动光标
if(keyCode==KEY_NUM2 && cursorY>0)cursorY——;
else if(keyCode==KEY_NUM8 && cursorY<14)cursorY++;
else if(keyCode==KEY_NUM4 && cursorX>0)cursorX——;
else if(keyCode==KEY_NUM6 && cursorX<14)cursorX++;
else if(keyCode==KEY_NUM5){
if(turn==side){ 如果轮到当前玩家走棋
gameFinished=setChess(cursorX,cursorY); //若游戏结束,则使gameFinished>0
//将走棋的信息(落子位置的x,y坐标)写入蓝牙流
remoteDevice.writeData((byte)cursorX);
remoteDevice.writeData((byte)cursorY);
第四步:在模拟器中测试
完成以上三步后我们的程序应该已经可以支持蓝牙对战了,参照我们上期提供的方法重新生成JAD和JAR文件。由于Symbian SDK自带的模拟器不能双开,因此我们仍然使用WTK中自带的模拟器来运行该程序。
在NetBeans中点击两次工具栏中的“开始”按钮,即可运行该程序。我们可以看到两个手机界面,我们可以分别对两个模拟器进行操作,以实现联机对战。有条件的读者可以找两部支持蓝牙和Java的手机进行调试。
读者反馈
开发QQ群:怎么够判断两个按键一起按下的事件?我想利用组合键对程序进行控制。
小编:很遗憾,在Canvas类中不可以,我们目前只能做到每次检测一个按键。手机的按键操作应该很简洁,请尽量避免在程序中设计多键并按的功能,这也不符合用户的使用习惯。可以采用有先后顺序的组合键,来激活程序的功能,不过要优先考虑一键实现某个功能。
开发QQ群:看了上期文章,我想问一下能否同时响应两个以上的触摸屏点击?
小编:事实上你说的是“多点触摸”技术了,目前仅有iPhone等极少数手机具备该功能。多点触摸是需要硬件支持的,一般手机上使用的普通触摸屏是无法响应多点同时按下的,只有支持多点触摸的手机才可以。需要注意的是,iPhone等手机虽然支持多点触摸,但不支持Java程序。
开发QQ群:对于只有触摸屏的手机,如果要玩魂斗罗等格斗类游戏的话可以在屏幕上虚拟出一个键盘,我想问具体该怎么设计?
小编:其实这并不复杂。做虚拟键盘,实际上主要是虚拟出方向键和射击键等按键,我们可以使用绘图函数在屏幕上某个位置绘制朝向四个方向的箭头和一两个圆圈,当用户点击屏幕时判断一下点击的坐标,如果是点在哪个箭头或者圆圈的身上,则执行相应的操作即可。
开发QQ群:为什么我按照上期的例子添加了游戏音效后仍然听不到任何声音?
小编:程序是为手机服务的,因此它在很多方面也要听命于手机。你说的情况很可能是将手机情景模式设置为无声了。这里特别提醒大家注意,在设计程序时不应该强制给用户播放声音,而应该尊重用户自己的设置。
开发QQ群:我使用手机QQ时发现如果用户不方便开启声音,可以选择振动模式,请问我该如何在游戏中添加振动功能?
小编:调用com.nokia.mid.ui.*; DeviceControl.startVibra(x, y); 即可添加振动功能,第一个参数x是振动的频率,第二个y参数是振动持续时间,用毫秒表示,编程时可自行设置。但是在这里要提醒大家一下,我们强烈建议不要在游戏中频繁使用振动,因为振动是非常耗电的,而且容易引起用户反感。另外一般的手机都可以通过设置关闭程序的振动特性,我们可以使用public boolean vibrate(int duration)进行检测,如果用户关闭了振动功能则返回false,反之返回true。
总结
做到这一步,五子棋游戏程序就开发完成了。通过五子棋游戏程序的开发,大家了解了手机程序开发的基本流程。从下期开始,我们将为大家奉献更有实战性质的程序开发,欢迎大家跟我们同步学习,一起成长。由于申请加入开发QQ群的人太多,我们决定启用第二个QQ群,群号是84524010,验证码:手机开发。