/**
* 画布重画事件,替代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文章区之游戏开发专题的文章,会给你更大的收获。
评论