/** * 画布重画事件,替代Canvas中的paint()事件, 根据不同的游戏状态(gameState)画出游戏画面 * 本方法由thread每次重新启动, 最后执行flushGraphics()重画缓冲区 */ public synchronized void paintCanvas(Graphics g){ if(gameState == GAME_INIT){ //游戏第一次启动 //设置为全屏模式并清屏 this.setFullScreenMode(true); g.setColor(255, 255, 255); g.fillRect(0, 0, mainWidth, mainHeight); if(!COMMAND_ADD_FLAG){ //添加响应命令及监听器 this.addCommand(pauseCommand); this.addCommand(exitCommand); this.setCommandListener(this); COMMAND_ADD_FLAG = true; } if(fishCollectionVector != null){ fishCollectionVector = null; fishCollectionVector = new Vector(); } if(this.layerManager != null){ this.layerManager = null; this.layerManager = new LayerManager(); if(userViewWindow){ this.layerManager.setViewWindow(xViewWindow, yViewWindow, wViewWindow, hViewWindow); } } if(mySub != null){ mySub = null; mySub = new Sub(this, SubMIDlet.createImage("/res/sub.png"), getWidth() / 3, getHeight() / 3, layerManager); } //创建背景图层 this.createSandBackground(); this.createSunkenBoat(); this.createFishCollection(0, FishCollection.NUM_FISH_TYPES); this.createMysub(); this.createSeaBackground(); mySub.setPosition(getWidth() / 3, getHeight() / 3); gameState = GAME_RUN; }else if(gameState == GAME_RUN){ //游戏处于运行状态 //提供游戏运行标识Flag,保证对用户操作的响应和"敌人"的运行动作只有在运行的时候生效 //在性能过耗(可用内存不到当前内存总量的4/5时),进行垃圾回收GC if(rt.freeMemory() < (rt.totalMemory() * 4 / 5)){ rt.gc(); } }else if(gameState == GAME_SUSPEND){ //下一轮游戏 //更新数据 mySub.setHpLife(15); mySub.setPosition(mainWidth / 3, mainHeight / 3); if(PLAYER_LEVEL >= 4){ gameState = GAME_OVER; }else{ PLAYER_LEVEL ++; controller.EventHandler(Controller.EVENT_NEXTROUND); //目前游戏只设计了四级关卡 ENEMY_MAX = PLAYER_LEVEL * 10; ENEMY_CURRENT = 0; TRIGGER_COUNT = 0; TICK_COUNT = 0; ENEMY_CURRENT_LIMIT = PLAYER_LEVEL * 2; Layer layer = null; //暂时删除layerManager中所有文件,清空鱼雷与敌人潜艇数据 //为更新图层做准备 this.tinfishCollectionVector.removeAllElements(); this.enemyCollectionVector.removeAllElements(); this.fishCollectionVector.removeAllElements(); // for(int i = 0; i < layerManager.getSize(); i++){ // layer = layerManager.getLayerAt(i); // layerManager.remove(layer); // } layer = null; //更新海底图层数据 this.SEABACK_DENSITY = (SEABACK_DENSITY + 1) % 4; gameState = GAME_INIT; this.unActive(); } }else if(gameState == GAME_OVER){ //游戏结束 threadAlive = false; controller.EventHandler(Controller.EVENT_MENU_GAMEOVER); gameState = this.GAME_INIT; } //在缓冲区重画 this.layerManager.paint(g, 0, (getHeight() - WORLD_HEIGHT) / 2); this.flushGraphics(); } public void commandAction(Command command, Displayable display) { if(command == startCommand){ if(this.gameState == GAME_OVER){ gameState = GAME_INIT; }else{ gameState = GAME_RUN; } this.removeCommand(this.startCommand); this.addCommand(pauseCommand); }else if(command == pauseCommand){ gameState = GAME_PAUSE; this.removeCommand(this.pauseCommand); this.addCommand(startCommand); }else if(command == exitCommand){ gameState = GAME_OVER; } } /** * 创建海底沙地背景图层 */ protected void createSandBackground(){ Image bottomTitles = SubMIDlet.createImage("/res/bottom.png"); //将图片bottomTitles切成指定大小(TILE_WIDTH, TILE_HEIGHT) //创建一个指定维数(1, WIDTH_IN_TILES)的背景数组 TiledLayer layer = new TiledLayer(WIDTH_IN_TILES, 1, bottomTitles, TILE_WIDTH, TILE_HEIGHT); for(int column = 0; column < WIDTH_IN_TILES; column++){ //将海底图层数组中的每个小格用原始图片的第i块来填充 int i = SubMIDlet.createRandom(NUM_DENSITY_LAYER_TILES) + 1; layer.setCell(column, 0, i); } layer.setPosition(0, WORLD_HEIGHT - bottomTitles.getHeight()); layerManager.append(layer); bottomTitles = null; } /** * 创建海底水层背景图片 */ protected void createSeaBackground(){ if(this.SEABACK_DENSITY >= 4){ SEABACK_DENSITY = 0; } Image image = SubMIDlet.createImage("/res/densityLayer" + this.SEABACK_DENSITY + ".png"); layerSeaback = new TiledLayer(WIDTH_IN_TILES, HEIGHT_IN_TILES, image, TILE_WIDTH, TILE_HEIGHT); for(int row = 0; row < HEIGHT_IN_TILES; row++){ for(int column = 0; column < WIDTH_IN_TILES; column++){ layerSeaback.setCell(column, row, SubMIDlet.createRandom(NUM_DENSITY_LAYER_TILES) + 1); } } layerSeaback.setPosition(0, 0); layerManager.append(layerSeaback); image = null; } /** * 创建沉船图层 */ protected void createSunkenBoat(){ Image imageSunkenBoat = SubMIDlet.createImage("/res/sunkenBoat.png"); //出现的沉船数量 int numSunkenBoats = 1 + (WORLD_WIDTH / (3 * imageSunkenBoat.getWidth())); Sprite sunkenBoat; int bx = 0; for(int i = 0; i < numSunkenBoats; i++){ sunkenBoat = new Sprite(imageSunkenBoat, imageSunkenBoat.getWidth(), imageSunkenBoat.getHeight()); sunkenBoat.setTransform(this.rotations[SubMIDlet.createRandom(this.rotations.length)]); //随机定义沉船位置 bx = (WORLD_WIDTH - imageSunkenBoat.getWidth()) / numSunkenBoats; bx = (i * bx) + SubMIDlet.createRandom(bx); sunkenBoat.setPosition(bx, WORLD_HEIGHT - imageSunkenBoat.getHeight()); //添加图层 this.layerManager.append(sunkenBoat); //mySub.addCollideable(sunkenBoat); } imageSunkenBoat = null; } /** * 创建玩家潜艇 */ protected void createMysub(){ this.layerManager.append(mySub); } /**创建鱼群背景 * @param startId * @param endId */ protected void createFishCollection(int startId, int endId){ for(int id = startId; id < endId; id++){ int w = WORLD_WIDTH / 4; int h = WORLD_HEIGHT / 4; int x = SubMIDlet.createRandom(WORLD_WIDTH - w); int y = SubMIDlet.createRandom(WORLD_HEIGHT - h); int vx = FishCollection.randomVelocity(TILE_WIDTH / 4); int vy = FishCollection.randomVelocity(TILE_HEIGHT / 4); //初始化鱼类图层, 同时把图层添加到图层管理器上 FishCollection fishCollection = new FishCollection(layerManager, id, x, y, w, h, vx, vy, 0, 0, WORLD_WIDTH, WORLD_HEIGHT); this.fishCollectionVector.addElement(fishCollection); } } /**重新设置图层显示区域 * @param x 玩家潜艇位置x * @param y 玩家潜艇位置y * @param width 玩家潜艇宽 * @param height 玩家潜艇高 */ public void adjustViewWindow(int xSub, int ySub, int width, int height) { if (this.userViewWindow) { xViewWindow = xSub + (width / 2) - (wViewWindow / 2); if (xViewWindow < 0) { xViewWindow = 0; } if (xViewWindow > (WORLD_WIDTH - wViewWindow)) { xViewWindow = WORLD_WIDTH - wViewWindow; } yViewWindow = ySub + (height / 2) - (hViewWindow / 2); if (yViewWindow < 0) { yViewWindow = 0; } if (yViewWindow > (WORLD_HEIGHT - hViewWindow)) { yViewWindow = WORLD_HEIGHT - hViewWindow; } layerManager.setViewWindow(xViewWindow, yViewWindow, wViewWindow, hViewWindow); } } /** 获取玩家潜艇 * @return 返回 mySub。 */ public Sub getMySub() { return mySub; } /** * @return 返回 threadAlive。 */ public boolean isThreadAlive() { return threadAlive; } /** * @param threadAlive 要设置的 threadAlive。 */ public void setThreadAlive(boolean threadAlive) { this.threadAlive = threadAlive; } public void active(){ this.showNotify(); } public void unActive(){ this.hideNotify(); } } 6.6 小结 MIDP 2.0添加的游戏API大大简化了MIDP游戏的开发,使得开发者能够更关注游戏的逻辑和底层架构,同时还提高了游戏性能。遗憾的是,目前支持MIDP 2.0的手机还不多,使用MIDP 2.0 Game API编写的游戏无法在MIDP 1.0平台上运行。 本章节关注了基本的GAME API的使用,作为一名游戏开发人员熟练掌握这些系统提供的API是一个基本功,但仅仅有这些是不够的。游戏开发中还有很多话题,大大超出了基本API的使用。读者们应该大量的阅读和实践才能一窥游戏开发的全貌。如果需要更多的资料请参阅www.j2medev.com文章区之游戏开发专题的文章,会给你更大的收获。

评论