- 浏览: 13570 次
最新评论
【贪吃蛇―Java程序员写Android游戏】系列 3. 用J2ME实现Android的Snake Sample详解
2011年04月10日
本次会详细讲解将Android的Snake Sample移植到J2ME上,从而比较二者的区别和联系。
在《1.Android SDK Sample-Snake详解 》中,我们已经详细介绍了Android实现的Snake项目结构,现在我们要将这个项目用J2ME实现。
一、 J2ME vs. Android
Android的UI实用、方便,而且很美观,基本无需改动且定制方便。而J2ME的高级用户界面比较鸡肋,在现在大多数的应用里都看不到,多数稍微复杂点的界面都是手工画,或是用一些开源的高级UI库。接下来我们简单比较下二者的区别,为Snake项目从Android到J2ME的移植做准备。
1. 平台
J2ME:
开发平台
Android:
操作系统
2. 工程结构
J2ME:
res:资源文件
src:源代码
Android:
src:源代码
res\drawable:图片
res\raw:声音
res\values:字符串
assets:数据文件
3. 安装包
J2ME:
jad,jar
Android:
apk
4. 代码结构
J2ME:
MIDlet,Canvas,采用继承的方式,只有一个MIDlet,一般只有一个Canvas
Android:
Activity,View,采用继承的方式,只有一个Activity,一般只有一个View
5. 入口程序
J2ME:
MIDlet类
Android:
Activity类
6. 主程序结构
J2ME: package com.deaboway.j2me; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeExcepti on; public class MyMidlet extends MIDlet { protected void destroyApp(boolean arg0) throws MIDletStateChangeException { // TODO Auto-generated method stub } protected void pauseApp() { // TODO Auto-generated method stub } protected void startApp() throws MIDletStateChangeException { // TODO Auto-generated method stub } } Android: package com.deaboway.android; import android.app.Activity; import android.os.Bundle; public class myActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); } } 7. 生命周期-开始
J2ME:
startApp(),活动状态,启动时调用,初始化。
Android:
onCreate(),返回时也会调用此方法。
onCreate()后调用onStart(),onStart()后调用onResume(),此时Activity进入运行状态。
8. 生命周期-暂停
J2ME:
pauseApp(),暂停状态,如来电时,调用该接口。
Android:
onPause()。
9. 生命周期-销毁
J2ME:
destroyApp(),销毁状态,退出时调用。
Android:
onStop(),程序不可见时调用onDestroy(),程序销毁时调用。
10. 刷新
J2ME:
高级UI组件由内部刷新实现。低级UI,canvas中通过调用线程结合repaint()来刷新,让线程不断循环。低级UI架构可以用MVC方式来实现,建议使用二级缓存。
Android:
高级UIHandler类通过消息的机制刷新。onDraw()刷新接口,低级UI开发者用线程控制更新,在lockCanvas()和unlockCanvasAndPost()方法之间绘制。
如果去读API,我们可以发现J2ME中Canvas的repaint()与Android中View的invalidate()/postInvalidate()方法实现了相同的功能(连说明文字几乎都一样…),但是invalidate()/postInvalidate()两者却有着区别:invalidate() 只能在UI这个线程里通过调用onDraw(Canvas canvas)来update屏幕显示,而postInvalidate()是要在non-UI线程里做同样的事情的。这就要求我们做判断,哪个调用是本 线程的,哪个不是,这在做多线程callback的时候尤为重要。而在J2ME中,不管怎样直接调用repaint()就好了。
11. 绘画
J2ME:
Displayable类。J2me中所有可显示的组件都是直接或间接的继承了Displayable,直接的是Canvas和Screen。不同的继承导致了低级 UI和高级UI的区别。J2me中现成的UI组件都是直接或者间接继承了Screen。只要调用Display.getDisplay(MIDLet instan).setCurrrent(Displayable disp),就可以把组件显示到手机界面上。切换界面的时候也可以使用该接口。
Android:
View类。可见的组件直接或者间接继承了android.view.View。通过 Activity.setContentView(View view)就可以显示在android手机界面上,切换界面的时候也可以使用该接口。如果是直接继承了View而不是Android自带的UI组件,那么 还要自己去实现它的刷新,类似J2me的低级UI组件。
12. 画笔
J2ME:
高级UI组件由内部刷新实现。低级UI,canvas中通过调用线程结合repaint()来刷新,让线程不断循环。低级UI架构可以用MVC方式来实现,建议使用二级缓存。
Android:
Canvas类,Android绘 制的时候会传入一个参数Paint。该对象表示绘制的风格,比如颜色,字体大小,字体格式等。Android的Canvas不同于J2ME的Canvas,它更像于J2ME的Graphics,用来绘制。
13. 全屏
J2ME:
Canvas中SetFullScreenMode()。
Android:
getWindow().setFlags(WindowManager.LayoutParams.FL AG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLS CREEN);requestWindowFeature(Window.FEATURE_NO_TITLE );
14. 获得屏幕尺寸
J2ME:
Canvas类的getHeight()和getWidth()
Android:
Display d = getWindowManager().getDefaultDisplay();
screenWidth = d.getWidth();
screenHeight = d.getHeight();
15. 可绘区域
J2ME:
int clipX = g.getClipX();
int clipY = g.getClipY();
int clipWidth = g.getClipWidth();
int clipHeight = g.getClipHeight();
g.clipRect(x, y, width, height);
g.setClip(clipX, clipY, clipWidth, clipHeight);//释放当前状态
Android:
canvas.save();//保存当前状态
canvas.clipRect(x,y, x+width, y+height)
cavnas.resave();//释放当前状态
16. 清屏操作
J2ME:
g.setColor(Color.WHITE);
g.fillRect(0,0,getWidth(),getHeight());
Android: // 首先定义paint
Paint paint = new Paint();
// 绘制矩形区域-实心矩形
// 设置颜色
paint.setColor(Color.WHITE);
// 设置样式-填充
paint.setStyle(Style.FILL);
// 绘制一个矩形
canvas.drawRect(new Rect(0, 0, getWidth(), getHeight()), paint);
17. 双缓冲
J2ME:
Image bufImage=Image.createImage(bufWidth, bufHeight);
Graphics bufGraphics=bufImage.getGraphics();
Android:
Bitmap carBuffer = Bitmap.createBitmap(bufWidth, bufHeight, Bitmap.Config.ARGB_4444);
Canvas carGp = new Canvas(carBuffer);
18. 图片类
J2ME:
Image类,Image.createImage(path);
Android:
BitMap类,BitmapFactory.decodeResource(getResources(),R.draw able.map0);
19. 绘制矩形
J2ME:
drawRect的后两个参数为宽度和高度
Android:
drawRect的后两个参数为结束点的坐标
20. 按键
J2ME:
keyPressed()
keyRepeated()
keyReleased()
Android:
onKeyDown()
onKeyUp()
onTracKballEvent()
21. 键值
J2ME:
Canvas.LEFT…
Android:
KeyEvent.KEYCODE_DPAD_LEFT…
22. 触笔
J2ME:
pointerPressed(),pointerReleased(),pointerDragged( )
Android:
onTouchEvent()
23. 数据存储
J2ME:
Record Management System (RMS)
Android:
SQLite数据库,SharedPreferences类
24. 连接
J2ME:
从Connector打开,可以直接在Connector.Open时设置连接是否可读写,以及超时设置
Android:
从URL对象打开,必须使用setDoInput(boolean)和setDoOutput(boolean)方法设置,使用setConnectTimeout(int)不仅可以对连接超时进行设置,还能设置超时时间,参数为0时忽略连接超时
25. 游戏开发包
J2ME:
javax.microedition.lcdui.game.*;
GameCanvas/Layer/LayerManager/ Sprite/TiledLayer
Android:
无专门针对游戏的开发包。 26. 音效 J2ME: Player s=Manager.createPlayer(InputStream); s.prepare();//创建 s.start();//播放 s.stop();//暂停 s.stop();//关闭 s.release();//释放 Android: MediaPlayer类处理背景音乐
SoundPool类处理一些简单的音效
27. 显示文本
J2ME:
String
Android:
TextView类
28. 打印信息
J2ME:
System.out.println()
Android:
Log类
二、 迁移关键点
1. 基础类和结构
J2ME程序的主体从Activity改变为MIDlet,TileView从View改变为Canvas,相关的方法也需要进行调整,但是主体结构和逻辑还是一致的。此外,有些J2ME不支持的类,需要做对应处理。
资源获取,从xml改为自行获取: private void initSnakeView() { // 获取图片资源 try { imageRED_STAR = Image.createImage("/redstar.png"); imageRED_STAR = Utils.zoomImage(imageRED_STAR,mTileSize,mTileSize) ; imageYELLOW_STAR = Image.createImage("/yellowstar.png"); imageYELLOW_STAR = Utils.zoomImage(imageYELLOW_STAR,mTileSize,mTileSi ze); imageGREEN_STAR = Image.createImage("/greenstar.png"); imageGREEN_STAR = Utils.zoomImage(imageGREEN_STAR,mTileSize,mTileSiz e); } catch(Exception e) { Log.info("Create Images: "+e); } // 设置贴片图片数组 resetTiles(4); // 把三种图片存到Bitmap对象数组 loadTile(RED_STAR, imageRED_STAR); loadTile(YELLOW_STAR, imageYELLOW_STAR); loadTile(GREEN_STAR, imageGREEN_STAR); } ArrayList,用Vector替换掉: // 坐标数组转整数数组,把Coordinate对象的x y放到一个int数组中--用来保存状态 private String coordVectorToString(Vector cvec) { int count = cvec.size(); StringBuffer rawArray = new StringBuffer(); for (int index = 0; index Title: Snake * Copyright: (C) 2011 Gavin's Snake project. Licensed under the Apache License, Version 2.0 (the "License") * @author Gavin */ package com.deaboway.snake.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import javax.microedition.rms.RecordStore; public class Bundle extends BaseRMS { private static String[] SECTION = { "\"AL\":","\"DT\":", "\"ND\":","\"MD\":", "\"SC\":","\"ST\":"}; private static int LEN = SECTION.length; private static boolean inited = false; private static Bundle INSTANCE; public static void INIT(){ if(inited)return; inited = true; INSTANCE = new Bundle(); INSTANCE.loadBundles(); } public static Bundle getInstance(){ return INSTANCE; } private String[] CONTENT = new String[LEN]; private Bundle() { super("snake-view"); } public void loadBundles() { try { this.open(); this.close(); } catch (Exception e) { try { this.close(); RecordStore.deleteRecordStore(this.getRMSName()); this.open(); this.close(); } catch (Exception ex) { } } } public void resetBundles() { try { this.close(); RecordStore.deleteRecordStore(this.getRMSName()); this.open(); this.close(); } catch (Exception ex) { } } public void updateBundles() throws Exception { try { this.openonly(); updateData(); if (this.getRecordStore() != null) this.close(); } catch (Exception e) { throw new Exception(this.getRMSName() + "::updateBundles::" + e); } } protected void loadData() throws Exception { try { byte[] record = this.getRecordStore().getRecord(1); DataInputStream istream = new DataInputStream( new ByteArrayInputStream(record, 0, record.length)); String content = istream.readUTF(); int[] start = new int[LEN+1]; for(int i =0;iTitle: Snake * Copyright: (C) 2011 Gavin's Snake project. Licensed under the Apache License, Version 2.0 (the "License") * @author Gavin */ package com.deaboway.snake.util; public class Log{ private static final int FATAL = 0; private static final int ERROR = 1; private static final int WARN = 2; private static final int INFO = 3; private static final int DEBUG = 4; private static int LOG_LEVEL = INFO; public static void info(String string){ if(LOG_LEVEL >= INFO){ System.out.println("[Deaboway][ INFO] " + string); } } public static void debug(String string){ if(LOG_LEVEL >= DEBUG){ System.out.println("[Deaboway][DEBUG] " + string); } } public static void warn(String string){ if(LOG_LEVEL >= WARN){ System.out.println("[Deaboway][ WARN] " + string); } } public static void error(String string){ if(LOG_LEVEL >= ERROR){ System.out.println("[Deaboway][ERROR] " + string); } } public static void fatal(String string){ if(LOG_LEVEL >= FATAL){ System.out.println("[Deaboway][FATAL] " + string); } } } 2. TileView类 (1)用Image替换BitMap,"private Image[] mTileArray;"
(2)private final Paint mPaint = new Paint();不再需要了。直接在Graphics中drawImage即可
(3)onSizeChanged() 不会被自动调用,需要在构造函数中主动调用,以实现对应功能。onSizeChanged(this.getWidth(),this.getHeight());
(4)最重要的,用paint替换onDraw,呵呵,Canvas的核心啊!失去它你伤不起!!!咱也试试咆哮体!!!!!!
3. SnakeView类
(1)J2ME 没有Handler,直接用Thread定期repaint()就OK。这里要
发表评论
-
编译Boost 1.38
2012-01-20 10:18 834编译Boost 1.38 2010年10月28日 首先, ... -
Collection接口和Map接口的主要实现类
2012-01-20 10:18 753Collection接口和Map接口的 ... -
Microsoft PE/COFF文件格式
2012-01-20 10:18 935Microsoft PE/COFF文件格式 ... -
开始-java之路(1)
2012-01-20 10:17 862开始-java之路(1) 2011年02月17日 今天开 ... -
ARM经典100问
2012-01-19 15:19 723ARM经典100问 2011年03月13日 第1章 体系 ... -
电脑管理破解
2012-01-19 15:18 586电脑管理破解 2011年03月10日 1、单击“开始―― ... -
电脑知识
2012-01-19 15:18 578电脑知识 2010年06月23日 ... -
2010-11-17
2012-01-19 15:18 6132010-11-17 2010年11月17日 PC:个人 ... -
2003 系统常用的设置
2012-01-17 05:05 6692003 系统常用的设置 201 ... -
站点主机安全档案
2012-01-17 05:05 679站点主机安全档案 2011 ... -
计算机常用词汇(F)
2012-01-17 05:05 653计算机常用词汇(F) 2011年09月29日 Failu ... -
WINDOWS XP 桌面主题的安装制作
2012-01-17 05:05 975WINDOWS XP 桌面主题的安装制作 2011年04月1 ... -
Java体系结构对信息安全的支持
2012-01-17 05:05 667Java体系结构对信息安全的支持 2010年06月09日 ... -
组件介绍
2012-01-16 03:56 803组件介绍 2009年11月22日 ... -
简历3
2012-01-16 03:56 692简历3 2009年11月09日 简[/b][b]历[/b ... -
JAVA基础加强(一)
2012-01-16 03:56 636JAVA基础加强(一) 2011年04月04日 2011 ... -
有关SVN的一些麻烦
2012-01-16 03:56 1200有关SVN的一些麻烦 2011年02月28日 前段时间整 ...
相关推荐
### 贪吃蛇——Java程序员开发Android游戏详解 #### 一、项目背景与目标 贪吃蛇是一款经典的休闲游戏,曾经风靡于诺基亚蓝色屏幕手机时代,成为其标志性游戏之一。随着移动设备的发展,贪吃蛇也登陆了Android平台...
java 贪吃蛇游戏.zipjava 贪吃蛇游戏.zipjava 贪吃蛇游戏.zipjava 贪吃蛇游戏.zip java 贪吃蛇游戏.zipjava 贪吃蛇游戏.zipjava 贪吃蛇游戏.zipjava 贪吃蛇游戏.zip java 贪吃蛇游戏.zipjava 贪吃蛇游戏.zipjava ...
java贪吃蛇游戏.zipjava贪吃蛇游戏.zipjava贪吃蛇游戏.zipjava贪吃蛇游戏.zip java贪吃蛇游戏.zipjava贪吃蛇游戏.zipjava贪吃蛇游戏.zipjava贪吃蛇游戏.zip java贪吃蛇游戏.zipjava贪吃蛇游戏.zipjava贪吃蛇游戏.zip...
Java实现贪吃蛇小游戏.zipJava实现贪吃蛇小游戏.zipJava实现贪吃蛇小游戏.zip Java实现贪吃蛇小游戏.zipJava实现贪吃蛇小游戏.zipJava实现贪吃蛇小游戏.zip Java实现贪吃蛇小游戏.zipJava实现贪吃蛇小游戏.zipJava...
"Snake(j2me).rar"这个压缩包中包含了使用J2ME编写的贪吃蛇游戏源码,对于想要了解或深入学习J2ME游戏开发的程序员来说,这是一个非常宝贵的资源。 J2ME是Java平台的一个子集,专为资源有限的嵌入式设备设计,如...
Java版贪吃蛇游戏.zipJava版贪吃蛇游戏.zipJava版贪吃蛇游戏.zip Java版贪吃蛇游戏.zipJava版贪吃蛇游戏.zipJava版贪吃蛇游戏.zip Java版贪吃蛇游戏.zipJava版贪吃蛇游戏.zipJava版贪吃蛇游戏.zip Java版贪吃蛇游戏....
java实现的贪吃蛇小游戏.zipjava实现的贪吃蛇小游戏.zipjava实现的贪吃蛇小游戏.zip java实现的贪吃蛇小游戏.zipjava实现的贪吃蛇小游戏.zipjava实现的贪吃蛇小游戏.zip java实现的贪吃蛇小游戏.zipjava实现的贪吃蛇...
java swing 贪吃蛇游戏.zipjava swing 贪吃蛇游戏.zipjava swing 贪吃蛇游戏.zip java swing 贪吃蛇游戏.zipjava swing 贪吃蛇游戏.zipjava swing 贪吃蛇游戏.zip java swing 贪吃蛇游戏.zipjava swing 贪吃蛇游戏....
在Android平台上,我们可以找到许多实现贪吃蛇的游戏源码,这为我们理解和学习移动游戏开发提供了宝贵的学习资源。这里我们将深入分析一款名为"简单的贪吃蛇源码"的Android游戏源码,探讨其设计思路、主要技术和实现...
java图形界面,贪吃蛇游戏练习.zipjava图形界面,贪吃蛇游戏练习.zip java图形界面,贪吃蛇游戏练习.zipjava图形界面,贪吃蛇游戏练习.zip java图形界面,贪吃蛇游戏练习.zipjava图形界面,贪吃蛇游戏练习.zip java图形...
java-小游戏贪吃蛇实验报告.zipjava-小游戏贪吃蛇实验报告.zip java-小游戏贪吃蛇实验报告.zipjava-小游戏贪吃蛇实验报告.zip java-小游戏贪吃蛇实验报告.zipjava-小游戏贪吃蛇实验报告.zip java-小游戏贪吃蛇实验...
《J2ME贪吃蛇游戏源代码解析及学习指南》 贪吃蛇是一款经典的游戏,深受全球玩家喜爱。在移动设备领域,J2ME(Java Micro Edition)平台曾是开发移动应用的重要选择,其中就包括了贪吃蛇这个游戏。本文将深入解析...