Bluetooth版本俄罗斯方块,文件结构及游戏截图如下:
package game.tetris;/*** * @author Administrator*/ public class bug {/** Creates a new instance of bug */public static void println(String s) {System.out.println(s);}public static void print(String s) {System.out.print(s);}public static void printState(String role, int gameState) {switch (gameState) {case TetrisCanvas.GAME_WAIT:println(" gameState = GAME_WAIT ");break;case TetrisCanvas.GAME_WAIT_REMOTE:println(" gameState = GAME_WAIT_REMOTE ");break;case TetrisCanvas.GAME_INIT:println(" gameState = GAME_WAIT ");break;case TetrisCanvas.GAME_RUN:println(" gameState = GAME_WAIT ");break;case TetrisCanvas.GAME_OVER:println(" gameState = GAME_WAIT ");break;case TetrisCanvas.GAME_START_DEMO:println(" gameState = GAME_WAIT ");break;case TetrisCanvas.GAME_SUSPEND:println(" gameState = GAME_WAIT ");break;case TetrisCanvas.GAME_EXIT:println(" gameState = GAME_WAIT ");break;default:println(" undefined gamestate");}}}
package game.tetris;import game.bluetooth.*; import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import javax.bluetooth.*;public class MainMIDlet extends MIDlet implements CommandListener {private Display display;private BluetoothDiscovery disc;private TetrisCanvas canvas;private MasterSlaveSelect select;public MainMIDlet() {// System.out.println(System.getProperty("microedition.m3g.version"));display = Display.getDisplay(this);ErrorScreen.init(null, display);disc = new BluetoothDiscovery(display);// ketrisCanvas的构造函数放到M/SThread中,将conn数组传入ketrisCanvas中// ketrisCanvas = new KetrisCanvas(this);}public void startApp() {String name;try {name = LocalDevice.getLocalDevice().getFriendlyName();// System.out.println("LocalDevice.getLocalDevice().getFriendlyName() = "// + name);} catch (BluetoothStateException e) {showAlertAndExit("", "Please switch Bluetooth on!", AlertType.ERROR);return;}disc.setServiceUUID("20000000000010008000006057028C19");disc.setName(name);startUI();}/*** 通过UserNameInterface选择做Master还是Slave*/public void startUI() {select = new MasterSlaveSelect(this);display.setCurrent(select);}public void pauseApp() {}public void destroyApp(boolean unconditional) {}public void showAlertAndExit(String t, String s, AlertType type) {Alert a = new Alert(t, s, null, type);a.addCommand(new Command("Exit", Command.EXIT, 1));a.setCommandListener(this);display.setCurrent(a);}public void Exit() {destroyApp(false);notifyDestroyed();}public void commandAction(Command c, Displayable s) {switch (c.getCommandType()) {case Command.EXIT:Exit();break;}}public Display getDisplay() {return display;}public BluetoothDiscovery getDisc() {return disc;}public void setCanvas(TetrisCanvas _canvas) {canvas = _canvas;}public TetrisCanvas getCanvas() {return canvas;} }
package game.tetris;import java.io.*;public interface Serialization {public byte[] serialize() throws IOException;public void deserialize(byte[] data) throws IOException;}
package game.tetris;import javax.microedition.lcdui.*;import java.util.Random;public class TetrisBlock {// 各种砖块,1-7为活动砖块颜色,8为墙砖颜色public static final int[] BRICK_COLORS = { 0x00FF0000, 0x0000FF00,0x00FFFF00, 0x000000FF, 0x00FF00FF, 0x0000FFFF, 0x00C0DCC0,0x00808080 };/*** blockpattern的编码规则:blockpattern表示一个下坠物体的形状,一种下坠物的颜色是固定的。* 对于一个下坠物,用一个三维数组表示,第一维用rot表示(旋转值),第二维用x(也就是行),第三维用y表示(也就是列)。 所以* blockpattern1:田字及四种旋转形状 blockpattern2:反L字及四种旋转形状 blockpattern3:L字及四种旋转形状* blockpattern4:1字及四种旋转形状 ........................ 第一维最重要:rot,旋转值*/protected int blockpattern1[][][] = {{ { 0, 0, 0, 0 },{ 0, 1, 1, 0 },{ 0, 1, 1, 0 },{ 0, 0, 0, 0 } }// 1,0,0,{ { 0, 0, 0, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 } },{ { 0, 0, 0, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 } },{ { 0, 0, 0, 0 }, { 0, 1, 1, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 } } };protected int blockpattern2[][][] = {{ { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 } },{ { 0, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 1, 1 }, { 0, 0, 0, 0 } },{ { 0, 0, 0, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 1, 0, 0 } },{ { 0, 0, 0, 0 }, { 1, 1, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 0 } } };protected int blockpattern3[][][] = {{ { 0, 1, 0, 0 }, { 0, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 } },{ { 0, 0, 0, 0 }, { 0, 1, 1, 1 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 } },{ { 0, 0, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } },{ { 0, 0, 0, 0 }, { 0, 0, 1, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 } } };protected int blockpattern4[][][] = {{ { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } },{ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 1, 1, 1, 1 }, { 0, 0, 0, 0 } },{ { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } },{ { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 1, 1, 1, 1 }, { 0, 0, 0, 0 } } };protected int blockpattern5[][][] = {{ { 0, 0, 0, 0 }, { 1, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 } },{ { 0, 0, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 } },{ { 0, 0, 0, 0 }, { 1, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 } },{ { 0, 0, 1, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 } } };protected int blockpattern6[][][] = {{ { 0, 0, 0, 0 }, { 0, 1, 1, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 } },{ { 0, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 0 } },{ { 0, 0, 0, 0 }, { 0, 1, 1, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 } },{ { 0, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 0 } } };protected int blockpattern7[][][] = {{ { 0, 0, 0, 0 }, { 1, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 } },{ { 0, 1, 0, 0 }, { 1, 1, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 } },{ { 0, 1, 0, 0 }, { 1, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },{ { 0, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 } } };private int blockpattern[][][]; /* 当前坠物形状,为以上定义的七个下坠物之一 */private int blockNextpattern[][]; /* 下一个坠物形状,显示在游戏容器的右边 */private int x; // blockpattern左上角x坐标,x=i表示左上角距离游戏容器左上角x轴上i个小砖块单位private int y; // blockpattern左上角y坐标,y=i表示左上角距离游戏容器左上角y轴上i个小砖块单位private int oldx; // x的旧值private int oldy; // y的旧值private int rot; // 旋转值,0-3private int oldrot; // 旋转旧值private int pattern; /* 组成当前坠物所用小砖块id(1-7),同时也表示一种下坠物形状 */private int next; /* 组成下一个坠物所用小砖块id(1-7),同时也表示一种下坠物形状 */private final int UNDEFINED = 99;private TetrisMap map;protected Random rand;public int gamearea_x;public int gamearea_y;public int brick_Width;/* 构造,保存map,初始化blockimage,rand,next */// 把ketrisBlock中pattern,next的随机数生成放到构造方法中,(便于编程)public TetrisBlock(TetrisMap map, boolean isMaster) {this.map = map;if (isMaster) {rand = new Random();// 随机生成的pattern和next在1~7之间,8为墙next = Math.abs(rand.nextInt()) % 7 + 1;pattern = next;next = Math.abs(rand.nextInt()) % 7 + 1;} else {// 如果本TetrisBlock代表的是附屏,// 则当前下坠方块和下一个下坠方块由远端设备决定pattern = UNDEFINED;next = UNDEFINED;}setParameter();}public void setPN(int pattern_2, int next_2) {// bug.println(" KetrisBlock_2.setPN()");// bug.println("pattern_2 = "+ pattern_2 );// bug.println("next_2 = " + next_2);// pattern = pattern_2;next = next_2;}public void setParameter() {gamearea_x = map.gamearea_x;gamearea_y = map.gamearea_y;brick_Width = map.brick_Width;}/* 初始化 */protected void init() {// pattern = next;// next = Math.abs(rand.nextInt()) % 7 + 1;/* 得到当前下坠物 */switch (pattern) {case 1:readPattern(blockpattern1);break;case 2:readPattern(blockpattern2);break;case 3:readPattern(blockpattern3);break;case 4:readPattern(blockpattern4);break;case 5:readPattern(blockpattern5);break;case 6:readPattern(blockpattern6);break;case 7:readPattern(blockpattern7);break;}/* 得到下一个下坠物 */switch (next) {case 1:readNextPattern(blockpattern1);break;case 2:readNextPattern(blockpattern2);break;case 3:readNextPattern(blockpattern3);break;case 4:readNextPattern(blockpattern4);break;case 5:readNextPattern(blockpattern5);break;case 6:readNextPattern(blockpattern6);break;case 7:readNextPattern(blockpattern7);break;}x = 5; /* 游戏容器内径的一半 */y = 0; /* y坐标 */rot = 0;// 判断map数据,决定y的真正值,之所以这么处理,是因为当game over的时候,最后一个下坠物,可能只能画出一部分// 为了达到这个效果,必须让y成为一个恰当的负值while (isCrashAtBegin()) {y--;if (y < -4) {break;}}oldx = x;oldy = y;oldrot = rot;}/*** 设置当前下坠物变量的内容* * @param nowblock* int[][][] 7种下坠物常量之一*/private void readPattern(int[][][] nowblock) {blockpattern = new int[4][4][4];for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {for (int k = 0; k < 4; k++) {blockpattern[i][j][k] = nowblock[i][j][k];}}}}/*** 设置下一个下坠物变量的内容。只需要包存4中旋转变化中的第一种即可,所以roto为值=0* * @param nowblock* int[][][] 7种下坠物常量之一 很容易理解*/private void readNextPattern(int[][][] nowblock) {blockNextpattern = new int[4][4];for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {blockNextpattern[i][j] = nowblock[0][i][j];}}}/* 旋转下坠物 */protected void rotBlock() {rot++;if (rot == 4) {rot = 0;}}/*** 绘制下坠物,包括清除下坠物的旧图像,调用绘制下坠物新图像的函数 本地方法* * @param g* Graphics*/public void paint(Graphics g) {// 如果3维都没有变化,则无需重画if ((oldrot != rot) || (oldx != x) || (oldy != y)) {// 清除旧图形g.setColor(TetrisCanvas.BACKGROUND);for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (blockpattern[oldrot][i][j] == 1) {g.fillRect(gamearea_x + (oldx + j) * brick_Width,gamearea_y + (oldy + i) * brick_Width,brick_Width, brick_Width);}}}drawBlock(g);oldrot = rot;oldx = x;oldy = y;}}/*** 绘制下坠物* * @param g* Graphics 本地,远端均可使用*/public void drawBlock(Graphics g) {for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (blockpattern[rot][i][j] == 1) {drawBrick(gamearea_x + (x + j) * brick_Width, gamearea_y+ (y + i) * brick_Width, g, pattern - 1);}}}}/** 远端用户使用,清除当前下坠的方块*/public void eraseBlock(Graphics g) {// 清除旧图形g.setColor(TetrisCanvas.BACKGROUND);int px = gamearea_x + 5 * brick_Width;int py = gamearea_y;int width = brick_Width * 4;g.fillRect(px, py, width, width);// 绘制重新接收的当前方块drawBlock(g);}/*** 判断下坠物是不是和map中已有的砖块重叠,为了处理gameover的时候,只需画出部分下坠物的情况* * @return true:有重叠,false:无重叠*/public boolean isCrashAtBegin() {// 行for (int i = 3; i >= 0; i--) {// 列for (int j = 0; j < 4; j++) {int mx = x + j;int my = y + i;if (my < 0) {my = 0;}if (blockpattern[rot][i][j] == 1 && map.get(mx, my) != 8&& map.get(mx, my) != 0) {return true;}}}return false;}/*** 画小砖块* * @param px* x坐标* @param py* y坐标* @param g* Graphics* @param colorIndex* 颜色索引值*/public void drawBrick(int px, int py, Graphics g, int colorIndex) {// 画白边g.setColor(255, 255, 255);g.fillRect(px, py, 1, brick_Width);g.fillRect(px, py, brick_Width, 1);// 画中心int color = BRICK_COLORS[colorIndex];g.setColor(color);g.fillRect(px + 1, py + 1, brick_Width - 1, brick_Width - 1);// 画灰边g.setColor(0x00c0c0c0);g.fillRect(px + brick_Width - 1, py + 1, 1, brick_Width - 1);g.fillRect(px + 1, py + brick_Width - 1, brick_Width - 2, 1);}/*** 在游戏容器的右边绘出下一个下坠物* * @param g* Graphics*/public void drawNextBlock(Graphics g) {// 清除绘制区域g.setColor(TetrisCanvas.BACKGROUND);int px = gamearea_x + 12 * brick_Width;int py = gamearea_y + 2 * brick_Width;int width = brick_Width * 4;g.fillRect(px, py, width, width);for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (blockNextpattern[i][j] == 1) {drawBrick(px + j * brick_Width, py + i * brick_Width, g,next - 1);}}}}/*** 判断下坠物是否能下移* * @param kyouseiflag* boolean true:自动下移 false:人工按键下移* @return boolean*/public boolean checkDown() {boolean check = true;/* 分别扫描下坠物的4行,从最下面的那行开始 */for (int i = 0; i < 4; i++) {int row = 3;while (row >= 0) {if (blockpattern[rot][row][i] == 1) {if (map.get(x + i, y + row + 1) != 0) {check = false;}row = -1; /* 终止循环 */} else {row--;}}}return check;}/* 下坠物下移1行 */public void down() {y = y + 1;}/* 判断是否能旋转 */public boolean checkRot() {boolean check = true;int tmpRot = rot + 1;if (tmpRot == 4) {tmpRot = 0;}for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (blockpattern[tmpRot][i][j] == 1) {if (map.get(x + j, y + i) != 0) {check = false;}}}}return check;}/* 判断下坠物是否可以移动 */public boolean checkMove(int direct) {boolean check = true;/* 分别扫描下坠物的4行 */for (int i = 0; i < 4; i++) {if (direct == 1) { /* 左移 */int row = 0;while (row <= 3) {if (blockpattern[rot][i][row] == 1) {if (map.get(x + row - 1, y + i) != 0) {check = false;}row = 4; /* 终止循环 */} else {row++;}}} else { /* 右移 */int row = 3;while (row >= 0) {if (blockpattern[rot][i][row] == 1) {if (map.get(x + row + 1, y + i) != 0) {check = false;}row = -1; /* 终止循环 */} else {row--;}}}}return check;}/* 左右移动 */public void move(int direct) {if (direct == 1) {x = x - 1;} else {x = x + 1;}}public int getY() {return y;}/* 根据下坠物的当前位置设置地图数据 */public void fixBlock() {for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (blockpattern[rot][i][j] == 1) {map.set(x + j, y + i, pattern);}}}}public int getPattern() {return pattern;}public int getNext() {return next;}public void generatePN() {pattern = next;next = Math.abs(rand.nextInt()) % 7 + 1;} }
package game.tetris;//Work Canvas import game.bluetooth.*; import game.tetris.*;import java.io.IOException; import java.io.InputStream; import java.io.OutputStream;import javax.microedition.lcdui.*;/*** * Title:* * * Description: 该类为游戏画布* * * Copyright: Copyright (c) 2004* * * Company: www.jagie.com* * * @author: an unknown Japanese,Jagie* @version 1.0*/public class TetrisCanvas extends Canvas implements CommandListener, Runnable {// Midletprotected MainMIDlet midlet;protected Command exitCmd;protected Command startCmd;protected int gameState; /* 游戏运行状态 */protected TetrisBlock block; /* 当前下坠物 */protected TetrisMap map; /* 游戏地图 */protected TetrisBlock blockOther;protected TetrisMap mapOther;protected Thread thread; /* 重画线程,该线程实现游戏画布重画机制 *//* counter,maxCount这2个变量是用来控制游戏速度 */protected int counter;protected int maxCount;boolean GAME_CLEAR_SCREEN = false;protected boolean startDemoFlag; /* 是否已经显示过开始画面 */public static int mainWidth; /* 屏幕宽度,在sun gray emulator上=180 */public static int mainHeight; /* 屏幕高度,在sun gray emulator上=177 */public static int GAMEAREA_X; // 游戏区域左上角x坐标,游戏区域为左边的游戏容器区域和右边的下一个下坠物显示区域组成public static int GAMEAREA_Y; // 游戏区域左上角y坐标public static int BRICK_WIDTH; // 小砖块的边长public static final int BACKGROUND = 0x00000000; // 背景颜色// edit wts 20060910private BluetoothConnection[] btConnections;private String role;// protected static final int PRESSED_KEY = 99;// protected static final int PRESSED_STARTCOMMAND = 100; /* 传输给远端玩家,自己按了开始键// */// protected static final int PRESSED_EXITCOMMAND = 101; /* 传输给远端玩家,自己按了退出键// */// protected static final int REMOTE_GAME_EXIT = 102;protected static final int SEND_PN = 103;/* 传送和接收ketrisBlock的pattern和next值 */protected static final int GAME_WAIT = 104; /* 自身先按了,等待远程用户,主屏显示等待 */protected static final int GAME_WAIT_REMOTE = 105;/* 远程用户先按了,等待本桤用户,附屏显示等待 */protected static final int GAME_INIT = 106; /* 游戏初始状态 */protected static final int GAME_RUN = 107; /* 游戏运行状态 */protected static final int GAME_OVER = 108; /* 游戏结束状态 */protected static final int GAME_START_DEMO = 109; /* demo状态,显示demo的画面 */protected static final int GAME_SUSPEND = 110; /* 挂起状态,值与demo状态同 */protected static final int GAME_EXIT = 111;protected static final int GAME_WIN = 112;protected static final int GAME_DISCONNECTED = 113; protected static final int SEND_MAPDATA = 114;// edit wts 20060911public static int GAMEAREA_X_REMOTE;// 附屏的X坐标public static int GAMEAREA_Y_REMOTE;// 附屏的Y坐标public static int BRICK_WIDTH_REMOTE;public static int mainWidth_Remote;public static int mainHeight_Remote;protected int gameState_Remote; /* 游戏运行状态 */protected TetrisBlock block_Remote; /* 当前下坠物 */protected TetrisMap map_Remote; /* 游戏地图 */protected boolean startDemoFlag_Remote;/* counter_2,maxCount_2这2个变量是用来控制远端用户的游戏速度 */protected int counter_Remote;// protected int maxCount_Remote; masCount_Remote不需要它public static int offSet; // 计算主屏位置的偏移值protected byte[] data;protected int pattern_Remote;protected int next_Remote;// 联机版public TetrisCanvas(MainMIDlet _midlet, BluetoothConnection[] btConns,String _role) {midlet = _midlet;btConnections = btConns;role = _role;bug.println(role);if (!(Role.ROLE_SINGLE == role)) {setCanvas();setReceiveThread();} else {setSingleCanvas();}}// public TetrisCanvas( MainMIDlet _midlet, String _role)// {// midlet = _midlet;// role = _role;// setSingleCanvas();// }public void setSingleCanvas() {mainHeight = getHeight();mainWidth = getWidth();offSet = 0;// 计算小砖块宽度int min = mainWidth;// 比较,使用高和宽中最小一个来计算if (mainHeight < min) {min = mainHeight;}// 游戏区域应该能被16整除for (; min >= 0; min--) {if (min % 16 == 0) {break;}}// 游戏区域为min的方形,且min为16的倍数BRICK_WIDTH = min / 16; // 砖块厚度GAMEAREA_X = (mainWidth - min) / 2;GAMEAREA_Y = (mainHeight - min) / 2;startDemoFlag = false; // 还没有显示开始画面gameState = GAME_START_DEMO; // 游戏处于demo画面状态map = new TetrisMap(this, true);block = new TetrisBlock(map, true);map.setTetrisBlock(block);addCommand();thread = new Thread(this);thread.start();}public void setCanvas() {init();// true设置的是主屏,false设置的是附屏map = new TetrisMap(this, true);block = new TetrisBlock(map, true);map.setTetrisBlock(block);// edit wts 20060911map_Remote = new TetrisMap(this, false);block_Remote = new TetrisBlock(map_Remote, false);map_Remote.setTetrisBlock(block_Remote);addCommand();// startCmd = new Command("开始", Command.OK, 0);// exitCmd = new Command("退出", Command.EXIT, 0);// addCommand(startCmd);// addCommand(exitCmd);// setCommandListener(this);thread = new Thread(this);thread.start();bug.println(role);}private void addCommand() {startCmd = new Command("开始", Command.OK, 0);exitCmd = new Command("退出", Command.EXIT, 0);addCommand(startCmd);addCommand(exitCmd);setCommandListener(this);}/* 初始化,显示demo画面所需的设置 */protected void init() {// 假设主屏所占用的是屏幕的2/3(下部),则宽度不变,高度取2/3,再加一个高度1/3的偏移值即可!!mainHeight = getHeight() * 2 / 3;offSet = mainHeight / 3 + mainHeight * 2 / 15;mainWidth = getWidth();// 计算小砖块宽度int min = mainWidth;// 比较,使用高和宽中最小一个来计算if (mainHeight < min) {min = mainHeight;}// 游戏区域应该能被16整除for (; min >= 0; min--) {if (min % 16 == 0) {break;}}// 游戏区域为min的方形,且min为16的倍数BRICK_WIDTH = min / 16; // 砖块厚度GAMEAREA_X = (mainWidth - min) / 2;GAMEAREA_Y = (mainHeight - min) / 2 + offSet;startDemoFlag = false; // 还没有显示开始画面gameState = GAME_START_DEMO; // 游戏处于demo画面状态initRemote();}public void initRemote() {// 附屏占用的是屏幕的1/5(上部),则宽度不变,高度取1/5mainHeight_Remote = getHeight() * 1 / 5;mainWidth_Remote = getWidth();// 计算小砖块宽度int min_2 = mainWidth_Remote;if (mainHeight_Remote < min_2) {min_2 = mainHeight_Remote;}// 游戏区域应该能被16整除for (; min_2 >= 0; min_2--) {if (min_2 % 16 == 0) {break;}}// 游戏区域为min的方形,且min为16的倍数BRICK_WIDTH_REMOTE = min_2 / 16; // 砖块厚度GAMEAREA_X_REMOTE = (mainWidth_Remote - min_2) / 2;GAMEAREA_Y_REMOTE = (mainHeight_Remote - min_2) / 2;startDemoFlag_Remote = false;gameState_Remote = GAME_START_DEMO;outputParameters();}public void outputParameters() {bug.println("mainWidth = " + mainWidth);bug.println("mainHeight = " + mainHeight);bug.println("BRICK_WIDTH = " + BRICK_WIDTH);bug.println("GAMEAREA_X = " + GAMEAREA_X);bug.println("GAMEAREA_Y = " + GAMEAREA_Y);bug.println("mainWidth_2 = " + mainWidth_Remote);bug.println("mainHeight_2 = " + mainHeight_Remote);bug.println("BRICK_WIDTH_2 = " + BRICK_WIDTH_REMOTE);bug.println("GAMEAREA_X_2 = " + GAMEAREA_X_REMOTE);bug.println("GAMEAREA_Y_2 = " + GAMEAREA_Y_REMOTE);}public void setReceiveThread() {for (int i = 0; i < btConnections.length; i++) { // loop through allReceiveThread rt = new ReceiveThread(i);rt.start();}}public void run() {while (true) {try {thread.sleep(50);} catch (InterruptedException e) {break;}repaint();}}public synchronized void commandAction(Command c, Displayable d) {if (c == exitCmd) {midlet.destroyApp(false);midlet.notifyDestroyed();transmitMsg(GAME_EXIT);bug.println("send GAME_EXIT state!");// add by wts 20060912// transmitMsg( PRESSED_EXITCOMMAND );} else if (c == startCmd) {// 还没有开始游戏或者游戏已结束if (startDemoFlag == false || gameState == GAME_OVER|| gameState == GAME_WIN) {startDemoFlag = true;// game = GAME_INIT;gameState = GAME_WAIT;// 如果远端主机己经在等待,则不必显示等待画面,直接进入游戏if (gameState_Remote == GAME_WAIT_REMOTE|| Role.ROLE_SINGLE == role) {gameState = GAME_INIT;gameState_Remote = GAME_INIT;transmitMsg(GAME_INIT);} else {transmitMsg(GAME_WAIT);}sendPN();} else if (gameState == GAME_WAIT) {if (gameState_Remote == GAME_WAIT_REMOTE) {gameState = GAME_INIT;gameState_Remote = GAME_INIT;transmitMsg(GAME_INIT);}} else {// 处于游戏中if (gameState == GAME_SUSPEND) {// 如果处于挂起状态,则进入运行状态gameState = GAME_RUN;transmitMsg(GAME_RUN);} else if (gameState == GAME_RUN) {gameState = GAME_SUSPEND;transmitMsg(GAME_SUSPEND);}}}// end else if : 按下的是startCmd}protected synchronized void keyPressed(int keyCode) {int action = getGameAction(keyCode);bug.println(" key action code = " + action);if (action == Canvas.LEFT && gameState == GAME_RUN) { /* 左移 */if (block.checkMove(1)) {block.move(1);}} else if (action == Canvas.RIGHT && gameState == GAME_RUN) { /* 右移 */if (block.checkMove(2)) {block.move(2);}} else if (action == Canvas.UP && gameState == GAME_RUN) { /* 下坠块变化 */if (block.checkRot()) {block.rotBlock();}} else if (action == Canvas.DOWN && gameState == GAME_RUN) { /* 下移 */if (block.checkDown()) {block.down();}} else if (action == Canvas.FIRE && gameState == GAME_RUN) { /* 下坠块变化 */if (block.checkRot()) {block.rotBlock();}}// 将信息传给远端用户transmitMsg(action);}// 绘制主屏的任务全部放这里public void paint(Graphics g) {if (!GAME_CLEAR_SCREEN) {GAME_CLEAR_SCREEN = true;g.setColor(BACKGROUND);g.fillRect(0, offSet, getWidth(), getHeight());return;}if (gameState == GAME_START_DEMO) { /* 游戏处于demo画面状态 */if (!startDemoFlag) {// 游戏还没开始,显示demo画面g.setColor(BACKGROUND);g.fillRect(0, 0, this.mainWidth, this.mainHeight);g.setColor(0, 255, 0);g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD,Font.SIZE_LARGE));g.drawString("m俄罗斯方块", mainWidth / 2, this.mainHeight / 4+ offSet, g.BASELINE | g.HCENTER);Font f2 = Font.getFont(Font.FACE_PROPORTIONAL,Font.STYLE_PLAIN, Font.SIZE_MEDIUM);}/* 游戏第一次启动 */// 第一次启动显示开始画面,// 之后都是直接显示(直接开始),} else if (gameState == GAME_WAIT) {if (gameState_Remote == GAME_WAIT_REMOTE) {gameState = GAME_INIT;gameState_Remote = GAME_INIT;} else {g.setColor(BACKGROUND);g.fillRect(0, 0, this.mainWidth, this.mainHeight + offSet);g.setColor(0, 255, 0);g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD,Font.SIZE_LARGE));g.drawString("m等待", mainWidth / 2, mainHeight / 4 + offSet,g.BASELINE | g.HCENTER);Font f2 = Font.getFont(Font.FACE_PROPORTIONAL,Font.STYLE_PLAIN, Font.SIZE_MEDIUM);}} else if (gameState == GAME_INIT) {g.setColor(BACKGROUND);g.fillRect(0, 0, getWidth(), getHeight());// 画出游戏地图(容器部分)map.init();map.paint(g);block.init();block.drawBlock(g);block.drawNextBlock(g);counter = 0;maxCount = 8;gameState = GAME_RUN;} else if (gameState == GAME_RUN) {counter++;if (counter >= maxCount) {if (block.checkDown()) {block.down();block.paint(g);} else {int y = block.getY();block.paint(g);block.fixBlock();if (map.check(g, y)) {map.repaintMap(g);}// 无论是否有行被消,均要传送// 将map数据传递给远程用户,在远程用户的附屏上显示它.// 实现serialize接口sendMapdata();block.generatePN();sendPN();block.init();y = block.getY();if (y < 0) {gameState = GAME_OVER;transmitMsg(GAME_OVER);}block.drawBlock(g);block.drawNextBlock(g);}counter = 0;} else {block.paint(g);}} else if (gameState == GAME_OVER) {g.setColor(BACKGROUND);g.fillRect(0, 0, getWidth(), getHeight());g.setColor(255, 0, 0);g.setFont(Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD,Font.SIZE_LARGE));g.drawString("mGame Over", TetrisCanvas.GAMEAREA_X + 8* TetrisCanvas.BRICK_WIDTH, TetrisCanvas.GAMEAREA_Y + 4* TetrisCanvas.BRICK_WIDTH, g.BASELINE | g.HCENTER);transmitMsg(GAME_OVER);} else if (gameState == GAME_WIN) {g.setColor(BACKGROUND);g.fillRect(0, 0, getWidth(), getHeight());g.setColor(255, 0, 0);g.setFont(Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD,Font.SIZE_LARGE));g.drawString("mYOU WIN", TetrisCanvas.GAMEAREA_X + 8* TetrisCanvas.BRICK_WIDTH, TetrisCanvas.GAMEAREA_Y + 4* TetrisCanvas.BRICK_WIDTH, g.BASELINE | g.HCENTER);}if (gameState_Remote == GAME_OVER) {gameState = GAME_WIN;}// 绘制远端用户的界面if (!(Role.ROLE_SINGLE == role))paint_Remote(g);}// end paintpublic void paint_Remote(Graphics g) {if (gameState == GAME_OVER) {gameState_Remote = GAME_WIN;}if (gameState_Remote == GAME_START_DEMO) { /* 游戏处于demo画面状态 */if (!startDemoFlag_Remote) {// 游戏还没开始,显示demo画面g.setColor(BACKGROUND);g.fillRect(0, 0, mainWidth_Remote, mainHeight_Remote);g.setColor(0, 255, 0);g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD,Font.SIZE_LARGE));g.drawString("s俄罗斯方块(远端)", mainWidth_Remote / 2,mainHeight_Remote / 4, g.BASELINE | g.HCENTER);}/* 游戏第一次启动 */} else if (gameState_Remote == GAME_WAIT_REMOTE) {g.setColor(BACKGROUND);g.fillRect(0, 0, mainWidth_Remote, mainHeight_Remote);g.setColor(0, 255, 0);g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD,Font.SIZE_LARGE));g.drawString("s等待(远端)", mainWidth_Remote / 2,mainHeight_Remote / 4, g.BASELINE | g.HCENTER);} else if (gameState_Remote == GAME_INIT) {map_Remote.init();map_Remote.paint(g);block_Remote.init();block_Remote.drawBlock(g);block_Remote.drawNextBlock(g);gameState_Remote = GAME_RUN;} else if (gameState_Remote == GAME_RUN) {if (b_receviedMapdata) {map_Remote.repaintMap_Remote(g);b_receviedMapdata = false;}if (b_receviedPN) {block_Remote.eraseBlock(g);block_Remote.drawNextBlock(g);b_receviedPN = false;}}// end if( game == GAME_RUN)else if (gameState_Remote == GAME_OVER) {g.setColor(BACKGROUND);g.fillRect(0, 0, mainWidth_Remote, mainHeight_Remote);g.setColor(255, 0, 0);g.setFont(Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD,Font.SIZE_LARGE));g.drawString("sGame Over", GAMEAREA_X_REMOTE + 8* BRICK_WIDTH_REMOTE, GAMEAREA_Y_REMOTE + 4* BRICK_WIDTH_REMOTE, g.BASELINE | g.HCENTER);} else if (gameState_Remote == GAME_DISCONNECTED) {g.setColor(BACKGROUND);g.fillRect(0, 0, mainWidth_Remote, mainHeight_Remote);g.setColor(255, 0, 0);g.setFont(Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD,Font.SIZE_LARGE));g.drawString("sOTHER DISCONNECTED!", GAMEAREA_X_REMOTE + 8* BRICK_WIDTH_REMOTE, GAMEAREA_Y_REMOTE + 4* BRICK_WIDTH_REMOTE, g.BASELINE | g.HCENTER);} else if (gameState_Remote == GAME_EXIT) {g.setColor(BACKGROUND);g.fillRect(0, 0, mainWidth_Remote, mainHeight_Remote);g.setColor(255, 0, 0);g.setFont(Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD,Font.SIZE_LARGE));g.drawString("sOTHER EXIT", GAMEAREA_X_REMOTE + 8* BRICK_WIDTH_REMOTE, GAMEAREA_Y_REMOTE + 4* BRICK_WIDTH_REMOTE, g.BASELINE | g.HCENTER);} else if (gameState_Remote == GAME_WIN) {g.setColor(BACKGROUND);g.fillRect(0, 0, mainWidth_Remote, mainHeight_Remote);g.setColor(255, 0, 0);g.setFont(Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD,Font.SIZE_LARGE));g.drawString("sOTHER WIN", GAMEAREA_X_REMOTE + 8* BRICK_WIDTH_REMOTE, GAMEAREA_Y_REMOTE + 4* BRICK_WIDTH_REMOTE, g.BASELINE | g.HCENTER);}System.gc();}public static void clear(Graphics g) {// 绘制整个背景g.setColor(0x00000000);g.fillRect(0, offSet, mainWidth, mainHeight);// 绘制面板背景g.setColor(BACKGROUND);g.fillRect(TetrisCanvas.GAMEAREA_X, TetrisCanvas.GAMEAREA_Y,16 * TetrisCanvas.BRICK_WIDTH, 16 * TetrisCanvas.BRICK_WIDTH);}public static void clear_Remote(Graphics g) {// 绘制整个背景g.setColor(0x00000000);g.fillRect(0, 0, mainWidth_Remote, mainHeight_Remote);// 绘制面板背景g.setColor(BACKGROUND);g.fillRect(TetrisCanvas.GAMEAREA_X_REMOTE, GAMEAREA_Y_REMOTE,16 * TetrisCanvas.BRICK_WIDTH_REMOTE,16 * TetrisCanvas.BRICK_WIDTH_REMOTE);}public void sendPN() {transmitMsg(SEND_PN);transmitMsg(block.getPattern());transmitMsg(block.getNext());}public synchronized void transmitMsg(int action) {if (Role.ROLE_SINGLE == role)return;/** 如果远端退出或断开,则不必再传送数据*/if (GAME_EXIT == gameState_Remote|| GAME_DISCONNECTED == gameState_Remote)return;for (int i = 0; i < btConnections.length; i++) {try {OutputStream os = btConnections[i].getOutputStream();os.write(action);os.flush();} catch (IOException e) {btConnections[i].close();if (checkIfAllClosed()) {return;}}}}public void sendMapdata() {if (Role.ROLE_SINGLE == role)return;if (GAME_EXIT == gameState_Remote|| GAME_DISCONNECTED == gameState_Remote)return;transmitMsg(SEND_MAPDATA);for (int i = 0; i < btConnections.length; i++) {serialize(map, btConnections[i]);}}public boolean checkIfAllClosed() {boolean allclosed = true;for (int l = 0; l < btConnections.length; l++) {if (btConnections[l].isClosed() != true) {allclosed = false;}}if (allclosed) {}return allclosed;}/*** The ReceiveThread is used to receive the remote keypresses. * For each remote device there exists an own RecieveThread.*/private class ReceiveThread extends Thread {int index;int receviedNum;InputStream inputStream;/*** Constructor.* * @param i* Index, that corresponds to the number of the* BluetoothConnection.*/public ReceiveThread(int i) {// Storeindex = i;inputStream = btConnections[index].getInputStream();}/*** Reads from stream until end of stream reached (disconnect).* The read character (which is the key the remote user pressed) is* displayed to the local user.*/public void run() {// Read input stream (data from remote device)int inp_Action;while (true) {// Read (blocking)try {// inp_Action =// btConnections[index].getInputStream().read();inp_Action = inputStream.read();} catch (IOException e) {btConnections[index].close();checkIfAllClosed();gameState_Remote = GAME_DISCONNECTED;return;}if (inp_Action == -1) {btConnections[index].close();checkIfAllClosed();bug.println("inp_action = -1, Remote user is disconnectioned!");gameState_Remote = GAME_DISCONNECTED;return;}// end if// add by wts 20060912// 这里应该分成四部分:// 一个是对传入命令的解析(响应commandAction),// 一个是对按键的响应(action)// 一个是接收patter,next;// 一个是通知游戏结束状态switch (inp_Action) {case GAME_START_DEMO:case GAME_WAIT:case GAME_INIT:case GAME_RUN:case GAME_SUSPEND:case GAME_OVER:case GAME_EXIT:updateRemoteGameState(inp_Action);break;case SEND_PN:receivePN(inputStream, inp_Action);break;case Canvas.UP:case Canvas.DOWN:case Canvas.LEFT:case Canvas.RIGHT:case Canvas.FIRE:// 什么都不做break;case SEND_MAPDATA:recevieMapdata();default:}if (GAME_EXIT == gameState_Remote) {bug.println("Remote have exited!, ReceiveThread won't recevie data!");break;}}// end while}// end run}// end ReceiveThread// 接收到的是远端用户的新的状态public synchronized void updateRemoteGameState(int _gameState) {// 如果对方发送来GAME_WAIT状态信息,则证明自己还没有点击"开始"键// (仅建立连接)if (_gameState == GAME_WAIT) {gameState_Remote = GAME_WAIT_REMOTE;return;} else if (_gameState == GAME_INIT) {gameState = GAME_INIT;gameState_Remote = GAME_INIT;sendPN();return;}gameState_Remote = _gameState;}// end updateRemoteCommand// 判断是否接收到新的当前方块和下一个方块boolean b_receviedPN;public synchronized boolean receivePN(InputStream inputStream,int inp_Action) {if (inp_Action == this.SEND_PN) {try {pattern_Remote = inputStream.read();next_Remote = inputStream.read();} catch (IOException e) {try {throw new Exception("ERROR In read Remote pattern and next");} catch (Exception e1) {e1.printStackTrace();}}block_Remote.setPN(pattern_Remote, next_Remote);block_Remote.init();bug.println(" receivePN.recevied PN");b_receviedPN = true;return true;}return false;}boolean b_receviedMapdata;public void recevieMapdata() {// 能设置一个变量进行检测最好,bug.println("begin receviedMapdata");deserialize(map_Remote, btConnections[0]);b_receviedMapdata = true;bug.println("end receviedMapdata");}public void serialize(Serialization serialization,BluetoothConnection bluetoothConnection) {bug.println("beging serialize mapdata");OutputStream os = bluetoothConnection.getOutputStream();try {data = serialization.serialize();// 数据传输:// 1、把数据序列化后的长度传过去// 2、byte数组传过去。bluetoothConnection.writeInt(data.length);bug.println("send mapdata length = " + data.length);os.write(data);os.flush();data = null;} catch (IOException e) {System.out.println("Error coming from serialize");}}public void deserialize(Serialization serialization,BluetoothConnection bluetoothConnection) {InputStream is = bluetoothConnection.getInputStream();try {int length = bluetoothConnection.readInt();bug.println("recevied data length = " + length);data = new byte[length];is.read(data);serialization.deserialize(data);data = null;System.gc();} catch (IOException e) {System.out.println("Error:Coming from deserizlize");}} }
* Title:*
* Description: 该类为游戏画布*
* Copyright: Copyright (c) 2004*
* Company: www.jagie.com*
package game.tetris;import javax.microedition.lcdui.*;import java.io.*; import javax.microedition.media.*;/*** 游戏地图,地图高16个小砖块,宽16小砖块,但是游戏容器高16,宽12(包括左右2堵墙) 所以容器的内直径为10* * Title:* * * Description:* * * Copyright: Copyright (c) 2004* * * Company:* * * @author: an unknown Japanese,Jagie* @version 1.0*/public class TetrisMap implements Serialization {// 地图数据protected int mapdata[][];protected boolean mapBlockExist[]; // 长度为16的boolean数组,如果mapBlockExist[i]=true,则第i+1行有砖块public int score; // 分数public static final Font SCOREFONT = Font.getFont(Font.FACE_SYSTEM,Font.STYLE_PLAIN, Font.SIZE_LARGE);public TetrisCanvas canvas;public int gamearea_x;public int gamearea_y;public int brick_Width;public boolean isMaster;public TetrisBlock block;public static Player player;static {try {InputStream is = TetrisMap.class.getResourceAsStream("/chimes.wav");player = Manager.createPlayer(is, "audio/x-wav");} catch (IOException ioe) {ioe.printStackTrace();} catch (MediaException me) {me.printStackTrace();}}public TetrisMap(TetrisCanvas canvas, boolean _isMaster) {this.canvas = canvas;mapdata = new int[16][12];mapBlockExist = new boolean[16];setParameters(_isMaster);}public void setParameters(boolean _isMaster) {isMaster = _isMaster;if (isMaster) {gamearea_x = canvas.GAMEAREA_X;gamearea_y = canvas.GAMEAREA_Y;brick_Width = canvas.BRICK_WIDTH;} else {gamearea_x = canvas.GAMEAREA_X_REMOTE;gamearea_y = canvas.GAMEAREA_Y_REMOTE;brick_Width = canvas.BRICK_WIDTH_REMOTE;// outputParameters();}}public void outputParameters() {bug.println("map_2 parameters:");bug.println("gamearea_x = " + gamearea_x);bug.println("gamearea_y = " + gamearea_y);bug.println("brick_Width = " + brick_Width);}public void setTetrisBlock(TetrisBlock block) {this.block = block;}public void init() {// 清除计分score = 0;// 先把全部元素清0for (int i = 0; i < 16; i++) {for (int j = 0; j < 12; j++) {mapdata[i][j] = 0;}mapBlockExist[i] = false;}// 设置2堵墙for (int i = 0; i < 16; i++) {mapdata[i][0] = 8;mapdata[i][11] = 8;}// 设置容器底for (int i = 0; i < 12; i++) {mapdata[15][i] = 8;}mapBlockExist[15] = true;}/*** 获取地图某行某列的数据* * @param x* int 行号* @param y* int 列号* @return int 地图数据,非0表示有砖块*/public int get(int x, int y) {int data = mapdata[y][x];return data;}/* 设置地图数据 */public void set(int x, int y, int val) {if (x >= 0 && y >= 0) {mapdata[y][x] = val;mapBlockExist[y] = true;}}/*** 该方法其实只负责非运动砖块* * @param g* Graphics 本地、远端用户均需调用, 绘制的是墙*/public void paint(Graphics g) {// 清屏if (isMaster) {TetrisCanvas.clear(g);} else {TetrisCanvas.clear_Remote(g);}for (int i = 0; i < 16; i++) {for (int j = 0; j < 12; j++) {if (mapdata[i][j] == 8) {block.drawBrick(gamearea_x + j * brick_Width, gamearea_y+ i * brick_Width, g, 7);}}}}/** 本地用户方法*/int deleteRowNum;/** 检测是否需要消行, 需要返回true, 否则返回假*//** 本地方法*/public boolean check(Graphics g, int row) {boolean deleteFlag = false;deleteRowNum = 0;// 最多可以连消4行int tmpRowNo;if (row + 4 >= 15) {tmpRowNo = 15;} else {tmpRowNo = row + 4;}for (int y = row; y < tmpRowNo; y++) {boolean flag = true;for (int x = 1; x < 11; x++) {if (mapdata[y][x] == 0) { /* 空白区 */flag = false;}}// 这个循环的是一行,/* 需要消行 */if (flag) {mapBlockExist[y] = false;for (int x = 1; x < 11; x++) {mapdata[y][x] = 0;}// 这一行的mapdata全部置为0deleteRow(g, y);deleteFlag = true;deleteRowNum++;// 加分score += 10;paintScore(g);// 发声try {if (player != null) {player.start();}} catch (MediaException me) {}}}// end forreturn deleteFlag;}// 删除行,只是简单的把该行置黑/** 本地用户方法*/protected void deleteRow(Graphics g, int y) {g.setColor(TetrisCanvas.BACKGROUND);g.fillRect(gamearea_x + brick_Width, gamearea_y + y * brick_Width,10 * brick_Width, brick_Width);}/* 该方法在有消去行为后调用 *//** 本地用户方法*/public void repaintMap(Graphics g) {// 从容启底开始for (int i = 14; i > 0; i--) {int tmp;// 有砖块的行才移动if (mapBlockExist[i]) {// 只有下一行为空白行才进行移动if (!mapBlockExist[i + 1]) {tmp = i + 1;if (!mapBlockExist[i + 2]) {tmp = i + 2;if (!mapBlockExist[i + 3]) {tmp = i + 3;}// end if(!mapBlockExist[i+3])}// end if(!mapBlockExist[i+2])deleteRow(g, i);// 行复制for (int j = 1; j < 11; j++) {mapdata[tmp][j] = mapdata[i][j];mapdata[i][j] = 0;}mapBlockExist[i] = false;mapBlockExist[tmp] = true;drawBlock(g, tmp);}// end if(!mapBlockExist[i+1])}// end if(mapBlockExist[i])}// end foroutputMapdata();}/** 远端用户方法*/public void repaintMap_Remote(Graphics g) {for (int i = 15; i > 0; i--) {drawBlockAll(g, i);}paintScore(g);}/** 远端用户方法*/public void drawBlockAll(Graphics g, int y) {// outputParameters();for (int x = 1; x < 11; x++) {if (mapdata[y][x] != 0) {block.drawBrick(gamearea_x + x * brick_Width, gamearea_y + y* brick_Width, g, mapdata[y][x] - 1);} else {g.setColor(TetrisCanvas.BACKGROUND);g.fillRect(gamearea_x + x * brick_Width, gamearea_y + y* brick_Width, brick_Width, brick_Width);}}}/** 本地方法, 远端用户不会调用它*/public void drawBlock(Graphics g, int y) {for (int x = 1; x < 11; x++) {if (mapdata[y][x] != 0) {block.drawBrick(gamearea_x + x * brick_Width, gamearea_y + y* brick_Width, g, mapdata[y][x] - 1);}}}/** 应该本地和远端用户都可以调用*/private void paintScore(Graphics g) {if (0 == score) {return;}// 清除记分牌g.setColor(TetrisCanvas.BACKGROUND);g.fillRect(gamearea_x + 12 * brick_Width, gamearea_y + 6 * brick_Width,brick_Width * 7, brick_Width * 7);// 计分g.setColor(0, 255, 0);g.setFont(SCOREFONT);g.drawString("" + score, gamearea_x + 14 * brick_Width, gamearea_y + 8* brick_Width, g.TOP | g.HCENTER);}public void outputMapdata() {for (int i = 0; i < 16; i++) {System.out.println("line " + i + ":");for (int j = 0; j < 12; j++) {System.out.print(mapdata[i][j] + ", ");}System.out.println();}}public void outputdeleteRowNum() {bug.println("deleteRowNum = " + deleteRowNum);}public void caculateScore() {score += deleteRowNum * 10;}public void deserialize(byte[] data) throws IOException {ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);for (int i = 0; i < 16; i++) {for (int j = 0; j < 12; j++) {mapdata[i][j] = dataInputStream.readInt();}}deleteRowNum = dataInputStream.readInt();caculateScore();outputMapdata();outputdeleteRowNum();}public byte[] serialize() throws IOException {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);for (int i = 0; i < 16; i++) {for (int j = 0; j < 12; j++) {dataOutputStream.writeInt(mapdata[i][j]);}}dataOutputStream.writeInt(deleteRowNum);outputMapdata();outputdeleteRowNum();return byteArrayOutputStream.toByteArray();}}
* Description:*
* Company:*
package game.bluetooth;import javax.microedition.io.*; import java.io.*;public class BluetoothConnection {private StreamConnection streamConnection;private InputStream inputStream;private OutputStream outputStream;private String localName; // 此连接的本地设备名private String remoteName; // 此连接的远端设备名private String url; // url字符串,用来建立连接用public BluetoothConnection(StreamConnection con, String ln, String rn)throws IOException {localName = ln;remoteName = rn;url = "";streamConnection = con;openStreams();}public BluetoothConnection(String urlStrings, String ln, String rn)throws IOException {localName = ln;remoteName = rn;url = urlStrings;connect();}private void connect() throws IOException {streamConnection = (StreamConnection) Connector.open(url);openStreams();}private void openStreams() throws IOException {inputStream = streamConnection.openInputStream();outputStream = streamConnection.openOutputStream();}public synchronized void close() {try {outputStream.close();} catch (IOException e) {}try {inputStream.close();} catch (IOException e) {}try {if (streamConnection != null) {streamConnection.close();streamConnection = null;}} catch (IOException e) {}}public InputStream getInputStream() {return inputStream;}public OutputStream getOutputStream() {return outputStream;}public String getLocalName() {return localName;}public String getRemoteName() {return remoteName;}protected void setRemoteName(String rn) {// 设置远端连接的名称remoteName = rn;}protected void setLocalName(String ln) {localName = ln;}/** * 传送一个字符串到远端设备 必须首先传送字符串长度 */public void writeString(String s) throws IOException {byte[] bytes = s.getBytes();outputStream.write(bytes.length);outputStream.write(bytes);outputStream.flush();}/** * 读取远端设备发送来的字符串 必须首先读入字符串长度 */public String readString() throws IOException {int length = inputStream.read();byte[] bytes = new byte[length];read(bytes, length);return new String(bytes);}/** * 写一个整数 */public void writeInt(int v) throws IOException {outputStream.write((v & 0xFF));outputStream.write(((v >> 8) & 0xFF));outputStream.write(((v >> 16) & 0xFF));outputStream.write(((v >> 24) & 0xFF));}/** * 读一个整数 */public int readInt() throws IOException {int res;res = inputStream.read();res += inputStream.read() << 8;res += inputStream.read() << 16;res += inputStream.read() << 24;return res;}public boolean isClosed() {if (streamConnection == null) {// 己断开return true;} else {// 仍然连接return false;}}/*** 读取bytes到数组中,直到读入len个byte。*/public void read(byte[] arr, int len) throws IOException {int offs, count;offs = 0;while (len > 0) {// 仍有需要读入的bytecount = inputStream.read(arr, offs, len);len -= count;offs += count;}} }
package game.bluetooth;import javax.microedition.lcdui.*; import javax.microedition.io.*; import java.io.*; import java.util.Vector; import javax.bluetooth.*; import java.util.Timer; import java.util.TimerTask;/*** BluetoothDiscoery类提供了易用的API用来搜索设备与服务 主要的方法是searchService和waitOnConnection* searchService方法用来搜索邻近的蓝牙设备并且与提供对应服务的设备建立连接* waitOnConnection方法则是用来提供服务并且等待其它设备与本地设备建立连接* 在这两个方法使用前,读者应该提供备用户名和服务,这里有两个方法:setName和setServiceUUID方法来设置* 这里使用LIAC(有限查询)服务模式,*/public class BluetoothDiscovery extends Alert implements CommandListener {static int dev_num = 0;// 用来判断设备发现只调用一次,可发现多个,结果为真// Attribute ID for service name for base languagestatic private final int SERVICE_NAME_BASE_LANGUAGE = 0x0100;// 指定查找设备为手机,0x0200是手机在蓝牙通讯中指定的特征码static private final int MAJOR_DEVICE_CLASS_PHONE = 0x0200;// 四种服务发现类型,本例程中只使用了一种:SEARCH_ALL_DEVICES_SELECT_ONEstatic public final int SEARCH_CONNECT_FIRST_FOUND = 1;static public final int SEARCH_CONNECT_ALL_FOUND = 2;static public final int SEARCH_ALL_DEVICES_SELECT_ONE = 3;static public final int SEARCH_ALL_DEVICES_SELECT_SEVERAL = 4;// 一台Master能够连接的最大蓝牙设备数static private final int BLUETOOTH_MAX_DEVICES = 7;// MainMIDlet传入的display对象private Display display;// 本地设备的引用private LocalDevice localDevice = null;// 用来保存发现模式的变量private int previousDiscoverabilityMode = -1;private String serviceUUID = null;private String localName = null;// 服务代理和Discovery监听器,用来发现设备与服务用private DiscoveryAgent discoveryAgent;private Listener listener;// 发现模式private int searchType;// trans action id for current service search, if there is no serv search// this is -1private int serviceSearchTransId;// 返回服务的url字符串向量,可用来建立连接private Vector urlStrings;// 所有发现的服务记录向量private Vector foundServiceRecords;private int maxDevices;// 一个显示所有己连接设备的列表private DeviceList deviceList;// 警告字符串,如没有设备或服务被发现时通知玩家private String warning;// notifier建立服务时使用private StreamConnectionNotifier notifier;// 建立连接的对象数组private BluetoothConnection[] btConnections;// 代表BluetoothDiscovery本身,方便内部类访问private BluetoothDiscovery root;// 进度条对象的引用private InqProgressBar progressBar;private Object block_m; // Master端的线程同步对象private Object block_s; // Slave端的线程同步对象private Object block_ss; // 服务查找时的阻塞线程private Object block_notifier; // /** * BluetoothDiscovery类的构造方法, disp是Display类的实例,* 因为玩家需要通过BluetoothDiscovery的内部类与Display的交互了解服务发现状态 */public BluetoothDiscovery(Display disp) {super("");root = this;display = disp;// InitializeprogressBar = null;deviceList = null;// 构造block_m、block_s、block_ss、block_notifier对象来进行本地设备与远端设备的同步block_m = new Object();block_s = new Object();block_ss = new Object();block_notifier = new Object();try {// 获得本地设备localDevice = LocalDevice.getLocalDevice();// 得到本地设备最大可连接远端设备数maxDevices = Integer.parseInt(localDevice.getProperty("bluetooth.connected.devices.max"));if (maxDevices > BLUETOOTH_MAX_DEVICES) { // 最多可连接数为7// BLUETOOTH_MAX_DEVICES=7maxDevices = BLUETOOTH_MAX_DEVICES;}} catch (Exception e) {localDevice = null;}}private void closeNotifier() {synchronized (block_notifier) {if (notifier != null) {try {notifier.close();} catch (Exception e) {String message = "Error trying to close notifier"+ e.getMessage();ErrorScreen.showError(message, display.getCurrent());}notifier = null;}}}public void commandAction(Command c, Displayable s) {switch (c.getCommandType()) {case Command.CANCEL:try {if (listener != null) {// 通知用户取消搜索Alert a = new Alert("", "Search cancelled", null,AlertType.INFO);a.setTimeout(10000);display.setCurrent(a);// 取消搜索discoveryAgent.cancelInquiry(listener);// 取消服务搜索// 取消服务搜索需要使用一个新的线程来结束// 不然的话上面的Alert画面就不会显示出来waitOnServSearchTermination w = new waitOnServSearchTermination();w.start();}listener = null;closeNotifier();// 停止progressBarif (progressBar != null) {progressBar.stop();progressBar = null;}} catch (Exception e) {String message = "Error trying to cancel: " + e.getMessage();ErrorScreen.showError(message, display.getCurrent());}break;}// end switch}/*** 保存发现模式,用来以后的模式恢复*/private void saveDiscoverability() {try {previousDiscoverabilityMode = LocalDevice.getLocalDevice().getDiscoverable();} catch (Exception e) {}}/*** 重新设置发现模式,把以前保存的模式设置为当前发现模式*/private void restoreDiscoverability() {try {if (previousDiscoverabilityMode != -1) {localDevice.setDiscoverable(previousDiscoverabilityMode);}} catch (Exception e) {}}/*** 设置代表本地玩家的用户名*/public void setName(String ln) {localName = ln;}/*** 设置UUID值*/public void setServiceUUID(String UUID) {serviceUUID = UUID;}public BluetoothConnection[] searchService(int st)throws BluetoothStateException, InterruptedException, IOException {StreamConnection con;DataElement de;String rname;// serviceSearchTransId为服务搜索号(transID)serviceSearchTransId = -1;searchType = st;foundServiceRecords = new Vector();urlStrings = new Vector();// 得到服务代理类对象,进行设备与服务的发现discoveryAgent = localDevice.getDiscoveryAgent();// 构造Discovery监听器对象listener = new Listener();// 显示搜索进度条progressBar = new InqProgressBar("Search Devices...", 105);warning = "";// 异步调用设备发现(startInquiry)方法,这里使用block_m对象进行线程阻塞synchronized (block_m) {discoveryAgent.startInquiry(DiscoveryAgent.LIAC, listener);block_m.wait();}deviceList = null;if (progressBar != null) {progressBar.stop();}if (!warning.equals("")) {Alert al = new Alert(null, warning, null, AlertType.INFO);al.setTimeout(2000);display.setCurrent(al);synchronized (al) {try {al.wait(2000);} catch (InterruptedException e) {}}}// 构造一个列表btConnections = new BluetoothConnection[urlStrings.size()];// 判断是否有设备被发现,如发现,进行下一步操作if (urlStrings.size() > 0) {progressBar = new PageProgressBar("Connecting...", urlStrings.size());// 连接查询到的设备(这里只有一个设备会被返回)for (int i = 0; i < urlStrings.size(); i++) {de = ((ServiceRecord) foundServiceRecords.elementAt(i)).getAttributeValue(SERVICE_NAME_BASE_LANGUAGE);rname = (String) de.getValue();((PageProgressBar) progressBar).nextDevice();btConnections[i] = new BluetoothConnection((String) urlStrings.elementAt(i), localName, rname);// 向远端玩家发送设置的代表自己的名称字符串btConnections[i].writeString(localName);}progressBar.stop();}// 释放progressBarprogressBar = null;// 释放listenerlistener = null;return btConnections;}/**使本地设备向外发布自身的服务,并且等待连接 返回一个BluetoothConnection数组 */public BluetoothConnection[] waitOnConnection()throws BluetoothStateException, IOException, InterruptedException {acceptAndOpenThread t;String ServiceName;// 保存当前发现状态saveDiscoverability();// 设置为有限查询状态localDevice.setDiscoverable(DiscoveryAgent.LIAC);// 调用Connector的open方法返回一个StreamCOnnectionNotifier对象notifier = (StreamConnectionNotifier) Connector.open("btspp://localhost:" + serviceUUID + ";name=" + localName+ ";authorize=false;authenticate=false;encrypt=false");// 调用Alert的方法setTitle("Waiting");setString("Waiting for someone to connect...");setTimeout(FOREVER);addCommand(new Command("Cancel", Command.CANCEL, 1));setCommandListener(this);display.setCurrent(this);// 设立一个新的acceptAndOpenThread线程来等待Master端的连接t = new acceptAndOpenThread();// 阻塞,直到被唤醒synchronized (block_s) {// 运行acceptAndOpenThread线程t.start();// 这里使用block_s对象进行阻塞block_s.wait();}notifier = null;restoreDiscoverability();return btConnections;}// 内部类,封装了一个gauge进度条控件private class InqProgressBar extends TimerTask {protected Gauge gauge;protected Timer tm;private InqProgressBar(String title, int max) {gauge = new Gauge(title, false, max, 0);Command cmStop = new Command("Cancel", Command.CANCEL, 1);// 创建一个Form对象,将gauge、stop commmand加在其上Form f = new Form("");f.append(gauge);f.addCommand(cmStop);f.setCommandListener(root);display.setCurrent(f);tm = new Timer();tm.scheduleAtFixedRate(this, 0, 100);}public void run() {int time;time = gauge.getValue() + 1;if (time > gauge.getMaxValue()) {time = 0;}gauge.setValue(time);}protected void stop() {cancel();tm.cancel();}}// 内部类// 继承自InqProgressBarprivate class PageProgressBar extends InqProgressBar {static final int PAGE_TIME = 30; // in 1/10 secs, 3 secsprivate int timer_max;private PageProgressBar(String str, int countDev) {super(str, countDev * PAGE_TIME);timer_max = 0;}public final void run() {int time;// add one secondtime = gauge.getValue() + 1;// Is current value of gauge less than the max?if (time > timer_max) { // Stoptime = timer_max;}// Store new valuegauge.setValue(time);}/**Start progress bar for next device. */public void nextDevice() {// Set current valuegauge.setValue(timer_max);// Stop the timertimer_max += PAGE_TIME;}}// 内部类,实现了DiscoveryListener接口,实现了该接口定义的方法// deviceDiscovered,inquiryCompleted,servicesDiscovered,serviceSearchCompletedprivate class Listener implements DiscoveryListener {private Vector cached_devices;ServiceRecord currServRec;/*** 构造方法*/public Listener() {cached_devices = new Vector();}/*** devoceDiscovered方法在设备被发现时调用,由DiscoveryAgent的startInquiry方法* 需要注意的是一个设备可能被发现多次, 因此需要进行检验,不能重复记录 discoveryAgent.startInquiry(* DiscoveryAgent.LIAC, listener ); btDevice :设备搜索中被发现的设备 cod* :设备类,通过调用getMajorDeviceClass()方法判断所发现的设备是否是手机*/public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {if (cod.getMajorDeviceClass() != MAJOR_DEVICE_CLASS_PHONE) {return;}dev_num++;// 需要进行判断,看是否是新发现的设备,如果,则加入cached_devices向量中if (!cached_devices.contains(btDevice)) {cached_devices.addElement(btDevice);}}/**inquiryCompleted方法在搜索邻近设备结束后调用 discType属以下中的一个:* 1:INQUIRY_COMPLETED:搜索正常结束时返回* 2:INQUIRY_TERMINATED:搜索被DiscoveryAgent.cancelInquiry()方法取消* 3:INQUIRY_ERROR:搜索过程中发生错误 */public void inquiryCompleted(int discType) {// 搜索设备正常结束if (discType == INQUIRY_COMPLETED) {if (cached_devices.size() == 0) {warning = "No devices found!";} else {// 结束设备搜索进度条progressBar.stop();// 开始服务搜索进度条progressBar = new PageProgressBar("Search Service...",cached_devices.size());// 开始搜索服务nextDeviceServiceSearch();// 返回return;}}// 如果搜索被中断或没有设备被发现,则直接唤醒线程,searchService继续向下运行synchronized (block_m) {block_m.notifyAll();}}/**NextDeviceServiceSearch. 该方法用来从一个设备中查找是否有相关服务*/private void nextDeviceServiceSearch() {UUID[] u = new UUID[1];u[0] = new UUID(serviceUUID, false);int attrbs[] = { SERVICE_NAME_BASE_LANGUAGE };RemoteDevice dev;((PageProgressBar) progressBar).nextDevice();// 获得下一设备try {dev = (RemoteDevice) cached_devices.firstElement();cached_devices.removeElementAt(0);} catch (Exception e) {// 所有设备都已经搜索if (foundServiceRecords.size() == 0) {// 没有感兴趣的服务被发现warning = "No service found!";}if ((foundServiceRecords.size() == 0)| (searchType == SEARCH_CONNECT_ALL_FOUND)) {synchronized (block_m) {block_m.notifyAll();}}if (deviceList != null) {deviceList.ready();}return;}// end catch// 搜索服务try {currServRec = null;// 这里,使用DiscoveryAgent的searchServices方法,在指定的设备上搜索服务,// 服务被发现的话,则listener类的相应监听方法被回调// static private final int SERVICE_NAME_BASE_LANGUAGE = 0x0100;// int attrbs[] = { SERVICE_NAME_BASE_LANGUAGE };serviceSearchTransId = discoveryAgent.searchServices(attrbs, u,dev, listener);} catch (BluetoothStateException e) {// 发生错误,// 搜索下一设备nextDeviceServiceSearch();}}/*** 如指定的服务被发现,则该方法被调用* * @param transID* : the transaction ID of the service search that is posting* the result.* @param servRecord* : 指的是所要搜索的服务*/public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {// 在指定设备上发现的服务currServRec = servRecord[0];}/*** searchServices transID:代表服务搜索号 respCode:代表了服务搜索如何结束的信息量*/public void serviceSearchCompleted(int transID, int respCode) {synchronized (block_ss) {// 重置服务搜索号serviceSearchTransId = -1;if (currServRec != null) {// 在foundSericeRecords向量中增加一个元素:currServRecfoundServiceRecords.addElement(currServRec);urlStrings.addElement(currServRec.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false));// System.out.println("urlString:"+currServRec.getConnectionURL(// ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false ));}switch (searchType) {case SEARCH_CONNECT_FIRST_FOUND:// 因是只发现一个,所以可以返回了if (currServRec != null) {synchronized (block_m) {block_m.notifyAll();}return;}break;case SEARCH_CONNECT_ALL_FOUND:break;case SEARCH_ALL_DEVICES_SELECT_ONE:case SEARCH_ALL_DEVICES_SELECT_SEVERAL:if (currServRec != null) {// 更新显示搜索到设备的列表displayFoundServices();}break;}// 如果是意外中断的if (respCode == SERVICE_SEARCH_TERMINATED) {synchronized (block_ss) {block_ss.notifyAll();}} else {// 搜索下一设备nextDeviceServiceSearch();}}}/*** 显示搜索到相关服务的设备*/private void displayFoundServices() {if (deviceList == null) {// 如deviceList为空,则创建一个int lt;if (searchType == SEARCH_ALL_DEVICES_SELECT_SEVERAL) {lt = List.MULTIPLE;} else {lt = List.IMPLICIT;}deviceList = new DeviceList(lt);}// 增加新的服务/设备项// 得到远端设备的名称DataElement de = ((ServiceRecord) foundServiceRecords.lastElement()).getAttributeValue(SERVICE_NAME_BASE_LANGUAGE);System.out.println("de.getDataType()= " + de.getDataType());String rname = (String) de.getValue();deviceList.append(rname, null);}}// end listener/*** 内部类waitOnServSearchTermination 当服务搜索被中止时就需要用到该类了,* */private class waitOnServSearchTermination extends Thread {/*** Terminates service search. Waits until serviceSearchCompleted is* called and then notifies the searchServices method.*/public void run() {synchronized (block_ss) {if (serviceSearchTransId != -1) { // only if there is a service// search active// 如果正在进行服务搜索,// 则调用DiscoveryAgent的cancelServiceSearch()方法取消该服务搜索// serviceSearchTransId为服务搜索号(transID)discoveryAgent.cancelServiceSearch(serviceSearchTransId);// wait until service search has terminated// 等待,直到服务搜索中止try {block_ss.wait();} catch (InterruptedException e) {}// 唤醒block_m阻塞的线程,返回到searchService()方法继续运行synchronized (block_m) {block_m.notifyAll();}}}}}/*** DeviceList : 一个列表类,来显示发现的服务/设备表*/private class DeviceList extends List implements CommandListener {private Command ok;private Command stop;private Command cancel;/*** list_type:定义List的选择类型, MULTIPLE(多选)或IMPLICIT(唯一)*/public DeviceList(int list_type) {super("Select:", list_type);ok = new Command("OK", Command.OK, 1);stop = new Command("Stop", Command.STOP, 1);cancel = new Command("Cancel", Command.CANCEL, 1);addCommand(ok);addCommand(stop);setCommandListener(this);display.setCurrent(this);}/*** 取消当前的服务搜索*/private void cancelServSearch() {synchronized (block_ss) {if (serviceSearchTransId != -1) { // only if there is a service// search active// 如果正在进行服务搜索,// 则调用DiscoveryAgent的cancelServiceSearch()方法取消该服务搜索// serviceSearchTransId为服务搜索号(transID)discoveryAgent.cancelServiceSearch(serviceSearchTransId);// wait until service search has terminated// 等待,直到服务搜索中止try {block_ss.wait();} catch (InterruptedException e) {}}}}/*** 当没有服务/设备元素需要加入时,则调用ready()方法, "Stop"按钮变为"Cancal"按钮*/public void ready() {removeCommand(stop);addCommand(cancel);}public void commandAction(Command c, Displayable s) {int com = c.getCommandType();if ((c == SELECT_COMMAND)&& (searchType == SEARCH_ALL_DEVICES_SELECT_ONE)) {// 行为和按了OK按键相同com = Command.OK;}switch (com) {case Command.OK:// 玩家按下了OK按钮,// 首先取消当前服务搜索cancelServSearch();// 删除所有没有选择的服务/设备元素for (int i = size() - 1; i >= 0; i--) {if (!isSelected(i)) {urlStrings.removeElementAt(i);}}// 返回到searchService()方法,// 这时urlStrings向量在已经存在建立连接的url值字符串synchronized (block_m) {block_m.notifyAll();}break;case Command.STOP:// 玩家按下了STOP按钮// 首先取消当前服务搜索cancelServSearch();ready();break;case Command.CANCEL:// 玩家按下了CANCEL按钮// 删除urlStrings中的所有元素urlStrings.removeAllElements();// // 返回到主程序中synchronized (block_m) {block_m.notifyAll();}break;}}}/*** acceptAndOpenThread. 把等待Master端的连接定义为一个线程是为了使玩家可以进行取消操作 和IE浏览器的工作机制一样* 在waitOnConnection()方法中为BluetoothDiscovery加入一个Cancel类型的命令按钮* 如果查一下MIDP2.0规范,会看到静态值Cancel的定义: CANCEL public static final int CANCELA* command that is a standard negative answer to a dialog implemented by* current screen. Nothing is cancelled automatically by the implementation;* cancellation is implemented by the commandAction provided by the* application. With this command type, the application hints to the* implementation that the user wants to dismiss the current screen without* taking any action on anything that has been entered into the current* screen, and usually that the user wants to return to the prior screen. In* many cases CANCEL is interchangeable with BACK, but BACK is mainly used* for navigation as in a browser-oriented applications. Value 3 is assigned* to CANCEL.* */private class acceptAndOpenThread extends Thread {/*** 等待连接或抛出异常*/public void run() {StreamConnection con;// 声明一个长度为一的BluetoothConnection对象数组,btConnections = new BluetoothConnection[1];// 广播服务,等待Master端的连接try {con = (StreamConnection) notifier.acceptAndOpen();btConnections[0] = new BluetoothConnection(con, localName,"Host");// 读取代表远端设备的名称,在远端设备上是localName,在本地设备就成为了remoteNameString remoteName = btConnections[0].readString();btConnections[0].setRemoteName(remoteName);} catch (Exception e) {btConnections[0] = null;}closeNotifier();// 重新唤醒被block_s对象阻塞的线程// 在waitOnConnection方法中被阻塞了,// 所以,继续运行waitOnConnection中的代码synchronized (block_s) {block_s.notifyAll();}}} }
package game.bluetooth;// Copyright 2004 Nokia Corporation. // // THIS SOURCE CODE IS PROVIDED 'AS IS', WITH NO WARRANTIES WHATSOEVER, // EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF MERCHANTABILITY, FITNESS // FOR ANY PARTICULAR PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE // OR TRADE PRACTICE, RELATING TO THE SOURCE CODE OR ANY WARRANTY OTHERWISE // ARISING OUT OF ANY PROPOSAL, SPECIFICATION, OR SAMPLE AND WITH NO // OBLIGATION OF NOKIA TO PROVIDE THE LICENSEE WITH ANY MAINTENANCE OR // SUPPORT. FURTHERMORE, NOKIA MAKES NO WARRANTY THAT EXERCISE OF THE // RIGHTS GRANTED HEREUNDER DOES NOT INFRINGE OR MAY NOT CAUSE INFRINGEMENT // OF ANY PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OWNED OR CONTROLLED // BY THIRD PARTIES // // Furthermore, information provided in this source code is preliminary, // and may be changed substantially prior to final release. Nokia Corporation // retains the right to make changes to this source code at // any time, without notice. This source code is provided for informational // purposes only. // // Nokia and Nokia Connecting People are registered trademarks of Nokia // Corporation. // Java and all Java-based marks are trademarks or registered trademarks of // Sun Microsystems, Inc. // Other product and company names mentioned herein may be trademarks or // trade names of their respective owners. // // A non-exclusive, non-transferable, worldwide, limited license is hereby // granted to the Licensee to download, print, reproduce and modify the // source code. The licensee has the right to market, sell, distribute and // make available the source code in original or modified form only when // incorporated into the programs developed by the Licensee. No other // license, express or implied, by estoppel or otherwise, to any other // intellectual property rights is granted herein.import javax.microedition.lcdui.*; import java.util.Timer; import java.util.TimerTask;public class ErrorScreen extends Alert {private static Display display;private static Image image;private static ErrorScreen instance = null;private ErrorScreen() {super("Error");setType(AlertType.ERROR);setTimeout(3000); // three secondssetImage(image);}public static void init(Image img, Display disp) {image = img;display = disp;}public static void showError(String message) {if (instance == null) {instance = new ErrorScreen();}instance.setString(message);display.setCurrent(instance);}public static void showError(String message, Displayable next) {if (instance == null) {instance = new ErrorScreen();}instance.setString(message);display.setCurrent(instance, next);} }
package game.bluetooth;import game.tetris.*; import javax.microedition.lcdui.*;public class MasterSlaveSelect extends List implements CommandListener {private MainMIDlet midlet;public MasterSlaveSelect(MainMIDlet _midlet) {super("Select Role:", List.IMPLICIT);midlet = _midlet;setFitPolicy(Choice.TEXT_WRAP_ON);append(Role.ROLE_SLAVE, null);append(Role.ROLE_MASTER, null);append(Role.ROLE_SINGLE, null);addCommand(new Command("选择", Command.OK, 1));addCommand(new Command("退出", Command.EXIT, 1));setCommandListener(this);}public void commandAction(Command c, Displayable d) {if (c.equals(List.SELECT_COMMAND) || (c.getCommandType() == Command.OK)) {int i = getSelectedIndex();String s = getString(i);if (s.equals(Role.ROLE_SLAVE)) {SlaveThread slaveThread = new SlaveThread(midlet);slaveThread.start();}if (s.equals(Role.ROLE_MASTER)) {MasterThread masterThread = new MasterThread(midlet, midlet.getDisc().SEARCH_ALL_DEVICES_SELECT_ONE);masterThread.start();}if (s.equals(Role.ROLE_SINGLE)) {SingleThread singleThread = new SingleThread(midlet);singleThread.start();}} else if (c.getCommandType() == Command.EXIT) {midlet.Exit();}} }
package game.bluetooth;import game.tetris.*;import javax.microedition.lcdui.AlertType;public class MasterThread extends Thread {private MainMIDlet midlet;private int searchType;protected MasterThread(MainMIDlet _midlet, int st) {midlet = _midlet;searchType = st;}public void run() {try {BluetoothConnection conn[] = midlet.getDisc().searchService(searchType);if (conn.length != 0) {midlet.setCanvas(new TetrisCanvas(midlet, conn,Role.ROLE_MASTER));midlet.getDisplay().setCurrent(midlet.getCanvas());} else {midlet.startUI();}} catch (Exception e) {midlet.showAlertAndExit("Error:", e.getMessage(), AlertType.ERROR);return;}bug.println("run master thread");}// end run }
package game.bluetooth;public class Role {public static final String ROLE_MASTER = "Master";public static final String ROLE_SLAVE = "Slave";public static final String ROLE_SINGLE = "Single"; }
package game.bluetooth;import game.tetris.*;import javax.microedition.lcdui.*;public class SingleThread extends Thread {private MainMIDlet midlet;protected SingleThread(MainMIDlet _midlet) {midlet = _midlet;}/*** This method runs the client.*/public void run() {midlet.setCanvas(new TetrisCanvas(midlet, null, Role.ROLE_SINGLE));midlet.getDisplay().setCurrent(midlet.getCanvas());bug.println("run Single player");}// end run }
package game.bluetooth;import game.tetris.*;import javax.microedition.lcdui.AlertType;public class SlaveThread extends Thread {private MainMIDlet midlet;SlaveThread(MainMIDlet _midlet) {midlet = _midlet;}public void run() {try {// 等待Master端的连接BluetoothConnection[] conn = midlet.getDisc().waitOnConnection();if (conn[0] == null) {midlet.startUI();return;}midlet.setCanvas(new TetrisCanvas(midlet, conn, Role.ROLE_SLAVE));midlet.getDisplay().setCurrent(midlet.getCanvas());} catch (Exception e) {midlet.showAlertAndExit("Error:", e.getMessage(), AlertType.ERROR);return;}} }
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
Duilib中list控件支持ctrl和shif多行选中的实现
[ICML2015]Batch Normalization:Accelerating Deep Network Training by Reducing Internal Covariate Shif
win10系统 微软输入法 于eclipse ctrl+shif+f冲突间接处理办法
Codeforces Round #259 (Div. 2) B. Little Pony and Sort by Shif
读LDD3,内存映射与DMA--PAGE_SHIF…
VMware虚拟机安装XP【要先分区,再设置BOOT 启动CD,shif+上移】
更换iBus五笔的左与右Shif
sublime ctrl+shif+f 没用解决办法
idea 对 ctrl + z 的撤销 是 ctrl + shif + z
计算机最早的设计师应用于,计算机应用基础选择题doc.doc
win10自带截图神器:Win+Shift+S
Python基础之文件目录操作
python简述目录_Python基础之文件目录操作(示例代码)
tp5 如何做数据采集
任务2-7(服务器字体+阿里巴巴矢量库)
html标签(1):h1~h6,p,br,pre,hr
TI 电量计介绍与芯片选型指南
几款TI电源芯片简介
TI DSP芯片C2000系列读取FLASH数据
德州仪器(Ti)平台嵌入式开发基础
TI三相电机智能栅极驱动芯片特点分类
省选模拟(12.08) T3 圈圈圈圈圈圈圈圈
Hadoop生态圈技术栈(上)
大数据开发基础入门与项目实战(三)Hadoop核心及生态圈技术栈之6.Impala交互式查询
小猿圈之Linux下Mysql 操作命令
大数据Hadoop生态圈常用面试题
大数据开发基础入门与项目实战(三)Hadoop核心及生态圈技术栈之4.Hive DDL、DQL和数据操作
备战Noip2018模拟赛11(B组)T3 Monogatari 物语
【智能优化算法-圆圈搜索算法】基于圆圈搜索算法Circle Search Algorithm求解单目标优化问题附matlab代码
NYOJ 78 圈水池
递归问题 跑道 汽车 绕圈问题 Python实现
Hadoop生态圈(三):MapReduce
微信公众账号
微信扫一扫加关注