随笔 - 1, 文章 - 7, 评论 - 3, 引用 - 0
数据加载中……

蓝牙联网五子棋对战游戏分析

蓝牙联网五子棋对战游戏分析

 

五子棋是一款比较经典的短、平、快的益智类游戏。蓝牙联网五子棋是蓝牙应用开发里采用轮回制运用的一个典型样式。这里详细分析下它的构架和联网应用。

 

首先介绍下主要用到的八个类:

BTGame   midlet 类,控制所有 midlet 的运行和销毁;

MyCanvas  :调用 GameWorld.keyPressed() 方法处理键盘输入并实例化和绘制 GameWorld

Chess      :抽象了棋盘上是否为服务器下子;

GameWorld :抽象了游戏的棋盘和棋子以及通过调用 Control 类来收发信息;

Control    :主要在 GameWorld 类和 Connetion 类之间传递坐标值和服务器判断值;

Connetion  :根据服务器判断值类启动服务器和客户端并把其棋子坐标传递给 Control 类;

Server     :主要是创建蓝牙服务和连接并等候服务,并负责服务器的信息收发;

Client     :主要负责搜索设备和服务,并负责客户端的信息收发。

 

基本概念介绍

五子棋首先是由 BTGame 类运行 midlet ,启动画布 MyCanvas 类,再根据启动服务器 / 客户端的选择再逐次启动 GameWorld 类、 Control 类、 Connection 类和其选择模式的线程,来完成蓝牙通信的初始化以及创建连接和收发信息。 MyCanvas 类再通过调用 GameWorld 类的 draw( ) 来绘制背景、棋盘和棋子。

 

――――――――――――――――――――――――――――――――――

 

下面我们来一一分析各个类,从 BTGame 类开始。

第一个类: BTGame

import javax.microedition.midlet.*;

import javax.microedition.lcdui.*;

public class BTGame extends MIDlet implements CommandListener{

  private static         BTGame instance;

  private MyCanvas     mycanvas ;

  private ChoiceGroup   choices;

  private Form         initForm;

  /** 构造函数 */

  public BTGame() {

    instance = this;

  }

  /** 主方法 */

  public void startApp() {

   initForm = new Form("Exce4");

   String[] peerNames = { "Server", "Client"};

   choices = new ChoiceGroup("Please select type:", Choice.EXCLUSIVE, peerNames, null);

   initForm.append(choices);              // 加上选择列表

   Command exitCommand = new Command("Exit", Command.EXIT, 0);      

   initForm.addCommand(exitCommand);   // 加上退出命令

   Command playCommand = new Command("Play", Command.OK, 0);

   initForm.addCommand(playCommand);   // 加上进入命令

   initForm.setCommandListener(this);

   // 设置当前窗体为屏幕显示对象

   Display.getDisplay(this).setCurrent(initForm);

  }

  public void pauseApp() {  }

  public void destroyApp(boolean unconditional) {  }

  /** 退出――销毁 midlet */

  public static void quitApp() {

    instance.destroyApp(true);

    instance.notifyDestroyed();

    instance = null;

  }

  public void commandAction(Command c, Displayable s) {

    if (c.getCommandType() == Command.EXIT) {

      destroyApp(true);

      notifyDestroyed();

    }

    else if (c.getCommandType() == Command.OK) {

      // 确定选择使用的连接

      String name = choices.getString(choices.getSelectedIndex());

      // 创建游戏画布

      if (mycanvas == null) {

        mycanvas = new MyCanvas(Display.getDisplay(this), name);

        Command exitCommand = new Command("Exit", Command.EXIT, 0);

        mycanvas.addCommand(exitCommand);

        mycanvas.setCommandListener(this);

        // 启动画布

        mycanvas.start();

      }

    }

  }

}

――――――――――――――――――――――――――――――――――

然后咱们再接着分析 MyCanvas 类:

第二个类: MyCanvas

import javax.microedition.lcdui.*;

import java.io.*;

import javax.microedition.media.*;

import javax.microedition.io.*;

import java.util.Vector;

public class MyCanvas extends Canvas implements Runnable, CommandListener {

  public static String name;

  private long frameDelay ;

  boolean slepping;            // 是否

  boolean newGame;           // 是否是新的游戏

  Display display;

  private GameWorld gameworld;// 引用 GameWorld

  public void start() {          // 启动画布

     display.setCurrent(this);    // 设置画布为当前屏幕显示对象

     System.out.println(" 画布启动 " );

     gameworld = new GameWorld();

     gameworld.start() ;            // 启动 GameWorld

     System.out.println("gameworld 启动 " );

     Thread t = new Thread(this);    

     t.start();                      // 启动一个新线程

  }

  public MyCanvas(Display display,String name) {  // 构造函数

    System.out.println(name);

    this.name = name;

    slepping = false;                           // 动画循环准备释放

    frameDelay = 33;                          // 设置帧频率为 3 帧每秒, 1/3=330ms

    this.display = display;                       // 传递显示对象

    try {

      jbInit();                                // 引用 jbInit() 方法,初始化组件

    }catch (Exception e) {

      e.printStackTrace();

    }

  }

  /** 组件初始化 */

  private void jbInit() throws Exception {

    // 在画布上设置命令监听器

    setCommandListener(this);

    // 加上命令

    addCommand(new Command("Exit", Command.EXIT, 1));

    addCommand(new Command("Pause", Command.SCREEN, 1));

  }

  /** 处理命令事件 */

  public void commandAction(Command command, Displayable displayable) {

    if (command.getLabel().equals("Exit")) {

      BTGame.quitApp();// 退出,销毁 midlet

    }

    if (command.getLabel().equals("Pause ")) {

    }

  }

  protected void keyPressed(int keycode){      // 按键响应处理

     gameworld.keyPressed(getGameAction(keycode));   // 引用 GameWorld 类的按键响应

   }

  public void run() {                   // 游戏主循环

       while (!slepping) {              // 判断动画循环是否停止

        repaint();                     // 绘制画布

         try {

           Thread.sleep(frameDelay);     // 线程停顿 330ms 即每秒 3 帧。

         }

         catch (InterruptedException ie) {}

       }

    }

     public void paint(Graphics g){               

     g.setColor(0x00000000);                    // 设置背景颜色为黑色

     g.fillRect(0, 0, getWidth(), getHeight());        // 清除显示屏

     gameworld.draw(g) ;                        // 引用 GameWorld 类的 draw ()方法

    }

}

――――――――――――――――――――――――――――――――――

这个类主要是判断该点是否为服务器下

第三个类: class

public class Chess { 

  public boolean isServer;            // 判断是否为服务器     

  public Chess() {     }

  public Chess(boolean isServer) {

    this.isServer = isServer;           // 外部应用函数传递是非值给该类的服务器判断值

  }

}

――――――――――――――――――――――――――――――――――

这个类主要整合了棋盘、棋子以及接收棋子位置信息的构架和按键响应事件的方法:

第四个类: GameWorld

import javax.microedition.lcdui.*;

public class GameWorld {

  private Control control;  

  private Chess[][] chess;              // 棋子数组

  private MyCanvas mycanvas;        

  private int chessMapGrid, chessGridLength; // 棋盘一边格子数,每格宽度

  private int chessLength;              // 棋子的直径

  private int chessMapX, chessMapY;     // 棋盘左上角 x,y 坐标

  public static boolean myMove;

  public boolean isServer;

  private int selectedX, selectedY;         // 选择框在棋盘格局上的 x,y 位置

  public GameWorld() {

    try {

      init();                         // 调用初始化 init() 方法

    }

    catch (Exception e) {}

  }

  public void start() {                //GameWorld 类启动

    System.out.println("GameWorld 启动 " );

    control = new Control(this);      

    control.start();                  // 控制类启动

  }

  public void init() {                  // 初始化方法           

    chessMapGrid = 15;              // 一边棋盘格数

    chessMapX = 7;                  // 棋盘的 x 轴初始位置

    chessMapY = 32;                 // 棋盘的 y 轴初始位置   

    chessGridLength = 15;               // 棋盘格子宽度

    chessLength = chessGridLength - 1;             // 棋子直径

    selectedX = selectedY = chessMapGrid / 2;        // 天元点的定位

    chess = new Chess[chessMapGrid + 1][chessMapGrid + 1];   // 棋盘上的棋子数组

    isServer = MyCanvas.name.equals("Server");       // 从画布中获取服务器判断值

    myMove = !isServer;                         // 客户端总是先下

  }

  public void keyPressed(int keycode) {              // 按键响应

    if (myMove) {                               // 是否轮到下

      switch (keycode) {

        case Canvas.UP:                          // 向上, y 值变小

          selectedY = (--selectedY + chessMapGrid + 1) % (chessMapGrid + 1);

          break;

        case Canvas.DOWN:                      // 向下, y 值变大

          selectedY = (++selectedY) % (chessMapGrid + 1);

          break;

        case Canvas.LEFT:                         // 向左, x 值变小

          selectedX = (--selectedX + chessMapGrid + 1) % (chessMapGrid + 1);

          break;

        case Canvas.RIGHT:                         // 向右, x 值变大

          selectedX = (++selectedX) % (chessMapGrid + 1);

          break;

        case Canvas.FIRE:                            // 确定,通告绘制棋子颜色

          if (chess[selectedY][selectedX] == null) {       // 判断棋盘该点是否未下子   

            chess[selectedY][selectedX] = new Chess(this.isServer); // 该点位置确定

            myMove = false;                           // 设置为未轮到

            control.sendMessage(selectedX, selectedY);     // 把按键确认的坐标发送出去

          }

          break;

      }

    }

  }

  public void receiveMessage() {                  // 接收信息        

    System.out.println("gamewold is receivemessage");

    System.out.println(control.getSelectedX());

    if (!myMove) {                                  // 是否未轮到下

      selectedX = control.getSelectedX();                 // 控制类把 x 坐标传过来

      selectedY = control.getSelectedY();                // 控制类把 y 坐标传过来  

      chess[selectedY][selectedX] = new Chess(!isServer);  // 设置棋子的判断值

      myMove = true;                              // 设置为轮到下

    }

  }

   public void draw(Graphics g) {

    paintMap(g);                 // 绘制棋盘

    paintSelected(g);              // 绘制选择框  

    paintChesses(g);              // 绘制棋子

  }

  protected void paintMap(Graphics g) {               // 棋盘

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

      for (int j = 0; j < chessMapGrid; j++) {

        g.setColor(128, 128, 128);              // 棋盘为灰色

        g.drawRect(chessMapX + j * chessGridLength,

                   chessMapY + i * chessGridLength,

                   chessGridLength, chessGridLength);

      }

    }

  }

  protected void paintSelected(Graphics g) {          // 选择框  

    g.setColor(0, 0, 255);                         // 选择框为蓝色   

    g.drawRect(chessMapX + selectedX * chessGridLength - chessGridLength / 2,

               chessMapY + selectedY * chessGridLength - chessGridLength / 2,

               chessGridLength, chessGridLength);

  }

  protected void paintChesses(Graphics g) {           // 棋子

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

      for (int j = 0; j <= chessMapGrid; j++) {

        if (chess[i][j] != null) {

          if (chess[i][j].isServer) {

            g.setColor(255, 255, 255);               // 服务器为白色

          }

          else {

            g.setColor(255, 0, 0);                   // 客户端为红色

          }

          g.fillArc(chessMapX + j * chessGridLength - chessLength / 2,

                    chessMapY + i * chessGridLength - chessLength / 2,

                    chessLength, chessLength, 0, 360);

        }

      }

    }

  }

}

―――――――――――――――――――――――――――――――

这个控制类主要在 GameWorld 类和连接类之间传递坐标值和服务器判断值

第五个类: Control

public class Control {

  Connection connection;

  GameWorld gameworld;

  int selectedX,selectedY;                              // 传递棋子坐标

  public boolean isServer;                              // 传递服务器判断值

  public Control(GameWorld gameworld) {                // 构造函数       

    this.gameworld = gameworld;         

    isServer = gameworld.isServer ;        

  }

  public void start(){

   System.out.println("Control 启动 " );

     connection = new Connection(this);

     connection.start() ;                           // 启动连接

   }

   public void sendMessage(int selected_X,int selected_Y){   // 发送坐标信息

    connection.sendMessage(selected_X,selected_Y);  // 引用连接类的 sendMessage ()方法

   }

 public void receiveMessage(){           // 接收信息

      gameworld.receiveMessage() ;      // 引用 GameWorld 类的 receiveMessage() 方法

      System.out.println("control is receivemessage");

 }

  public int getSelectedX(){          // 获取 x 坐标

    selectedX = connection.getSelectedX() ;   // 引用连接类的 getSelectedX() 方法

    return selectedX;

  }

  public int getSelectedY(){         // 获取 y 坐标

    selectedY = connection.getSelectedY() ;  // 引用连接类的 getSelectedY() 方法

    return selectedY;

  }

}

―――――――――――――――――――――――――――――――――――

连接类根据服务器判断值分别启动服务器和客户端并把其棋子坐标传递给控制类

第六个类: Connetion

public class Connection {

  Server server;

  Client client;

  int selectedX,selectedY;              // 传递棋子坐标    

  boolean isServer;                    // 传递服务器判断值

  Control control;

  public Connection(Control control) {   // 构造函数

    this.control = control;              // 外部调用函数传递控制对象

    isServer = control.isServer;         // 控制对象的服务器判断值传递过来

  }

  public void start(){

  System.out.println("Connection 启动 " );

  if (isServer) {                          // 是否为服务器

  server = new Server(this);  

  server.start();                           // 启动服务器

  }

  else {

      client = new Client(this);

      client.start();                       // 否则启动客户端

  }

  }

  public void sendMessage(int selected_X,int selected_Y){       // 发送坐标值

           if (isServer)   // 发送服务器的坐标

           server.sendMessage(Integer.toString(selected_X),Integer.toString(selected_Y));

         else {          // 发送客户端的坐标

           System.out.println("connection is sendmessage") ;

           System.out.println(Integer.toString(selected_Y)) ;

           client.sendMessage(Integer.toString(selected_X), Integer.toString(selected_Y));

         }

  }

   public void receiveMessage(String messagex,String messagey){    // 接收坐标值

   selectedX = Integer.parseInt(messagex);    // 接收到的字符串 x 转换为 x 坐标值

   selectedY = Integer.parseInt(messagey);    // 接收到的字符串 y 转换为 y 坐标值

   System.out.println("connection is receivemessage");

   control.receiveMessage() ;     // 引用控制类的 receiveMessage() 方法

  }

  public int getSelectedX(){       // 发送 x 坐标值

    return selectedX;

  }

  public int getSelectedY(){        // 发送 y 坐标值

    return selectedY;

  }

}

――――――――――――――――――――――――――――――

这个服务器类主要是创建蓝牙服务和连接并等候连接,负责服务器的信息收发

第七个类: Server

 

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.*;

import java.io.IOException;

import java.util.Vector;

import javax.bluetooth.DiscoveryAgent;

import javax.bluetooth.LocalDevice;

import javax.bluetooth.ServiceRecord;

import javax.bluetooth.UUID;

import javax.microedition.io.Connector;

import javax.microedition.io.StreamConnection;

import javax.microedition.io.StreamConnectionNotifier;

import javax.microedition.lcdui.*;

public class Server implements Runnable{

  Connection connection;

  StreamConnection conn1 = null;         // 流连接

  LocalDevice local = null;               // 本地蓝牙管理器

  ClientProcessor processor;              // 客户处理

  DataOutputStream dos;                 // 输出流

  boolean isClosed = false;                // 连接判断值

  boolean isOut = false;                   // 发送判断值

  StreamConnectionNotifier notifier;        // 流连接通告   

  String messagex = null,messagey=null;     // 信息

  String connectionURL =

      "btspp://localhost:F0E0D0C0B0A000908070605040302010;"

      + "authenticate=false;encrypt=false;name=RFCOMM Server";

    // 定义服务连接 URL 其中UUID为393a84ee7cd111d89527000bdb544cb1

  Vector queue = new Vector();                // 连接队列

  public Server(Connection connection) {        // 构造函数

    this.connection = connection;               // 外部引用的连接传递给该类的连接        

  }

  public void start(){

   System.out.println("Server 启动 " );

    Thread t = new Thread(this);

    t.start() ;                                // 启动线程

  }

  public void run(){                           

     try {                                   // 服务器的初始化

        local = LocalDevice.getLocalDevice();// 回收本地设备获得蓝牙管理器

         local.setDiscoverable(DiscoveryAgent.GIAC);// 被发现的模式为 GIAC

         } catch (Exception e) {}

      try {

        notifier = (StreamConnectionNotifier)Connector.open(connectionURL);// 创建连接通告

        System.out.println("server is opening") ;

      } catch (IOException e1) {}

       processor = new ClientProcessor();    // 引用客户处理方法

       while (!isClosed) {                 // 连接是否关闭

          StreamConnection conn = null;

          try {

             conn = notifier.acceptAndOpen();// 开始接受连接

           } catch (IOException e) {

               continue; // 无论是客户端错误或连接中断 ――都将继续

          }

          processor.addConnection(conn);// 添加连接和唤醒处理线程

     }

  }

  private class ClientProcessor implements Runnable {       // 客户处理线程

           private Thread processorThread;

           private Vector queue = new Vector();           // 连接队列

           private boolean isOk = true;

           ClientProcessor() {

               processorThread = new Thread(this);

               processorThread.start();                  // 线程启动

           }

           public void run() {

               while (!isClosed) {                    // 连接是否关闭

                   synchronized (this) {               // 同步

                       if (queue.size() == 0) { 

                           try {

                               wait();// 阻塞,直到有新客户连接

                           } catch (InterruptedException e) {  }

                       }

                   }

                   // 处理连接队列

                   StreamConnection conn;

                   synchronized (this) {               // 同步

                       if (isClosed) {                 // 连接是否关闭了

                           return;

                       }

                       conn = (StreamConnection) queue.firstElement();// 获取连接

                       queue.removeElementAt(0);   // 移除连接队列的等候连接

                       processConnection(conn);     // 引用处理连接方法

                   }

               }

           }

           void addConnection(StreamConnection conn) {

             synchronized (this) {

                   queue.addElement(conn);// 往连接队列添加新连接,

                   notify();              // 同时唤醒处理线程

               }

           }

   }

   public void sendMessage(String message1,String message2){     // 发送信息

    messagex = message1;

    messagey = message2;

    try {

            dos.writeUTF(messagex);              // 传送发送信息 x 到数据输出流里

            System.out.println("chance");       

            dos.writeUTF(messagey) ;             // 传送发送信息 y 到数据输出流里

            dos.flush();                         // 刷新数据输出流        

            dos.close();                        // 输出关闭    

    } catch (IOException e) {   }

  }

   private void readInputString(StreamConnection conn) {         // 接收信息

       String message1,message2 = null;

       try {

           DataInputStream dis = conn.openDataInputStream();  // 输入

           message1 = dis.readUTF();                     

           message2 = dis.readUTF() ;                     

           dis.close();                                   // 输入关闭

           connection.receiveMessage(message1,message2) ;   // 传递给连接类接收       

        } catch (Exception e) {

           e.printStackTrace();

           System.out.println("exce4") ;

       }

   }

   private void processConnection(StreamConnection conn) {     // 连接处理

    try{

     dos = conn.openDataOutputStream();        // 发送信息

     }

    catch(Exception e){}

    readInputString(conn);                    // 接收信息

   }

}

 

――――――――――――――――――――――――――――――――――――――

这是客户端类,主要负责搜索设备和服务,并负责客户端的信息收发。

第八个类: Client

 

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.IOException;

import java.util.Vector;

import javax.microedition.io.Connector;

import javax.microedition.io.StreamConnection;

import javax.microedition.lcdui.*;

  //jsr082 API

import javax.bluetooth.BluetoothStateException;

import javax.bluetooth.DeviceClass;

import javax.bluetooth.DiscoveryAgent;

import javax.bluetooth.DiscoveryListener;

import javax.bluetooth.LocalDevice;

import javax.bluetooth.RemoteDevice;

import javax.bluetooth.ServiceRecord;

import javax.bluetooth.UUID;

public class Client implements Runnable,DiscoveryListener{

  private Connection connection;

  private DiscoveryAgent discoveryAgent;

   // 响应服务的 UUID

   private static final UUID ECHO_SERVER_UUID = new UUID(

           "F0E0D0C0B0A000908070605040302010", false);

   Vector devices = new Vector();   // 设备集合

   Vector records = new Vector();   // 服务集合

   String messagex,messagey;        //

   String message_1,message_2;     //

   StreamConnection   conn ;       // 流连接   

   int i=1;

   int[] transIDs;                  // 服务搜索的事务 id 集合

   public Client(Connection connection){           // 构造函数

    this.connection = connection;                 // 外部引用的连接传递该类连接

  }

  public void start(){

   System.out.println("Client 启动 " );

    Thread t = new Thread(this);

    t.start() ;                                  // 启动线程    

  }

  public synchronized void run(){      

    try  {                                                // 客户端初始化

           LocalDevice local = LocalDevice.getLocalDevice();   // 回收蓝牙管理器

           discoveryAgent = local.getDiscoveryAgent() ;        // 回收发现代理

        }catch (BluetoothStateException bse) {}

          try {

            discoveryAgent.startInquiry(DiscoveryAgent.GIAC,this); // GIAC 找普通的设备

         }catch (BluetoothStateException bse) {}

         try{

            wait();  // 阻塞 , inquiryCompleted() 回调方法在请求完成的情况下唤醒

         }catch(Exception e){}

         UUID[] uuids = new UUID[1];                        

         uuids[0] = ECHO_SERVER_UUID;                   // 响应服务的 UUID

         transIDs = new int[devices.size()];        // 服务搜索的事务 id 数等于发现设备数

        for (int i = 0; i < devices.size(); i++) {

          RemoteDevice rd = (RemoteDevice) devices.elementAt(i);   //  

         try {

          System.out.println("begin searchservices") ;

          transIDs[i] = discoveryAgent.searchServices(null, uuids,rd, this); // 记录服务搜索 id

             } catch (BluetoothStateException e) {

                continue;

            }

        }

      try {

          wait();// 阻塞 , serviceSearchCompleted() 回调方法在设备搜索完的情况下唤醒

      } catch (InterruptedException e1) {

          e1.printStackTrace();

      }

      System.out.println("Client run end") ;

  }

  public void deviceDiscovered(RemoteDevice remoteDevice,DeviceClass deviceClass) {

         devices.addElement(remoteDevice);//remoteDevice 就是被发现的设备本身

         System.out.println("discovered a device ") ;

          System.out.println(remoteDevice.getBluetoothAddress()) ;

 }    // agent.startinquiry 发出的去发现设备

   public void inquiryCompleted(int param) {           // 请求完成

   System.out.println("start inquiry completed") ;

   switch (param) {

              case DiscoveryListener.INQUIRY_COMPLETED:

              break;

              case DiscoveryListener.INQUIRY_ERROR:

              break;

              case DiscoveryListener.INQUIRY_TERMINATED:

              break;

         }

         System.out.println("complete inquary ") ;

         synchronized (this) {

             notify();  // 设备搜索完的情况下唤醒等待

      }

 }

 public void serviceSearchCompleted(int transID, int respCode) {       // 搜索完成

       System.out.println("complete service Search") ;

       switch(respCode){

           case DiscoveryListener.SERVICE_SEARCH_COMPLETED:

                   break;

           case DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE:

                   break;

           case DiscoveryListener.SERVICE_SEARCH_ERROR:

                   break;

           case DiscoveryListener.SERVICE_SEARCH_NO_RECORDS:

                   break;

           case DiscoveryListener.SERVICE_SEARCH_TERMINATED:

                   break;

       }

       synchronized (this) {

       notify();

       }

   }

    public void servicesDiscovered(int transID,ServiceRecord[] serviceRecord) {

       System.out.println("get server") ;

       for (int i = 0; i < serviceRecord.length; i++) {

         records.addElement(serviceRecord[i]); // 返回 transID;ID 是辨别 service 的唯一识别;

       }

   }

  public void sendMessage(String message1,String message2){       // 收发信息

   message_1 = message1;

   message_2 = message2;

   Thread fetchThread=new Thread(){

   public void run(){                               // 定义线程

    try {

       ServiceRecord sr=(ServiceRecord)records.elementAt(0); // 获取服务记录

       String url = sr.getConnectionURL( ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);                                         // 获取服务的连接地址

       conn = (StreamConnection) Connector.open(url);         // 获取流连接

       // 发送信息

       DataOutputStream dos=conn.openDataOutputStream();

        dos.writeUTF(message_1);             // 传送发送信息 1 到数据输出流里

       System.out.println("writex"+i+message_1);

       dos.writeUTF(message_2);             // 传送发送信息 2 到数据输出流里  

       System.out.println("writey"+i+message_2) ;

       dos.flush() ;                           // 刷新数据输出流

       dos.close();                           // 关闭数据输出流

        // 接收信息

       DataInputStream dis = conn.openDataInputStream();

       messagex = dis.readUTF();            // 传送接收信息到 messagex

       System.out.println("messagex is"+ i + messagex);

       messagey = dis.readUTF();            // 传送接收信息到 messagey 

       System.out.println("messagey is"+i + messagey);

       dis.close();                           // 关闭数据输入流

       System.out.println(i) ;

       i++;

       connection.receiveMessage(messagex,messagey) ; // 引用连接类的接收信息方法

    }catch(Exception e){

      System.out.println("exce4");

      e.printStackTrace() ;

    }

    }

   };

    fetchThread.start();                              // 启动 fetch 线程

  }

}

 

――――――――――――――――――――――――――――――――――――――

看了上面的注解,相信你应该已经很清楚蓝牙五子棋是如何构架和联网应用的。

 

 

 

 

首先从 BTGame 类运行 midlet ,按启动按钮进入画布 MyCanvas 类,再根据启动服务器 / 客户端的选择按钮再逐次启动 GameWorld 类、 Control 类、 Connection 类和其选择模式的线程,来完成蓝牙通信的初始化。再由客户端先下子,发送信息出去,建立连接。由于游戏的主循环在 MyCanvas 类中,根据每秒的帧数通过调用 GameWorld 类的 draw( ) 一直不停地绘制在绘制背景、棋盘、选择框和棋子。用户通过 GameWorld 类的按键响应来发送坐标信息给 Control 类, Control 类再通过 Connection 类传递给用户所选择的模式端口,通过空中接口传输给对方。对方接收下来后,处理流程就是一个对应的逆过程。

 

至此,你可以体会到蓝牙联网五子棋是蓝牙应用开发里采用轮回制运用的一个典型样式。如果你要开发基于事件的游戏的话,可以借此参照。但基于事件的游戏要比回合驱动的游戏复杂得多。

 

普遍面对的问题就是保持同步。如果是状态同步的话,需要建立一个类似于 update() 方法来向其他实例通告其当前状态,而且还要考虑到发送失败的可能。在服务器与客户端之间要建立一个容错机制。如果是输入同步的话,要充分考虑到随机效果(如对象的放置错位等),因为它们不会被输入影响到。

 

同时,在设计开发时,也要特别注意通信的带宽问题。一个字符串 String 已足够聊天应用程序,而如果你想开发数据量大点的游戏或是多媒体应用程序将可能使用字符和二进制数据混用组合。由于带宽是基于事件的游戏中得一个比较大的考量因素,对于在手机上开发基于事件的游戏,带宽通常是非常具有挑战性的。随着技术的提升,这种挑战将会减小,但是,开发高效率的网络代码被普遍认为是游戏开发中最具挑战性的方面之一,并且对于手机游戏来说有过之而无不及。

 

 

 

 

【移动开发小亮点】出品

编者exce4

转贴请注明出处

posted on 2006-03-17 12:02 Java ME---------F6ME 阅读(721) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航: