📄 enginethread.java
字号:
package engine.kernel;
import javax.microedition.lcdui.*;
import java.lang.*;
/**
* 引擎主线程与低级屏幕主体。<br>
* 这里控制整个引擎的运行期间的逻辑方法调用和绘图请求的调用。由于目前J2ME实现各个厂商有不同的API,比如Nokia公司有自己的FullCanvas,Motorola等公司用的是Canvas,所以这个类在最后发布的时候,需要有两个版本,即支持FullCanvas的版本和支持Canvas的版本。<br>
* 本引擎会根据是否是MIDP2.0的简表环境,然后自动设置全屏幕。所以,由于MIDP版本不同的修改,不用再修改引擎本身的代码。
* @author 贾永明
* @version 2.8.0
* @since HuoHouStudioEngine1.0
*/
final class EngineThread extends Canvas implements Runnable{
//final class EngineThread extends com.nokia.mid.ui.FullCanvas implements Runnable{
/**
* 屏幕宽度。<br>该参数在{@link engine.kernel.EngineThread#EngineThread(int, int, boolean, boolean, boolean) EngineThread(int scrWidthAdjust, int scrHeightAdjust, boolean continueAfterException, boolean applyDoubleBuffered, boolean appendCommandSoftX)}中会通过Canvas.getWidth()自动获取,如果程序开发人员认为自动获取的数据不能够反映真实的屏幕宽度或者不是程序员希望的数据,可以通过{@link engine.kernel.EngineMIDlet#EngineMIDlet(boolean, int, int, boolean, int, int, int, String, int, int, boolean) EngineMIDlet(boolean continueAfterException, int scrWidthAdjust, int scrHeightAdjust, boolean isDoubleBuffered, int fps, int reservedScreenNormalCapacity, int backgroundCapacity, String keyMapURL, int maxCombineKey, int tbkh, boolean appendCommandSoftX)}的参数screenWidthAdjust,传给引擎方法Canvas.getWidth()获取的数据与真实屏幕宽度或者希望宽度的偏差。
*/
int scrWidth;
/**
* 屏幕高度。<br>该参数在{@link engine.kernel.EngineThread#EngineThread(int, int, boolean, boolean, boolean) EngineThread(int scrWidthAdjust, int scrHeightAdjust, boolean continueAfterException, boolean applyDoubleBuffered, boolean appendCommandSoftX)}中会通过Canvas.getHeight()自动获取,如果程序开发人员认为自动获取的数据不能够反映真实的屏幕高度或者不是程序员希望的数据,可以通过{@link engine.kernel.EngineMIDlet#EngineMIDlet(boolean, int, int, boolean, int, int, int, String, int, int, boolean) EngineMIDlet(boolean continueAfterException, int scrWidthAdjust, int scrHeightAdjust, boolean isDoubleBuffered, int fps, int reservedScreenNormalCapacity, int backgroundCapacity, String keyMapURL, int maxCombineKey, int tbkh, boolean appendCommandSoftX)}的参数screenHeightAdjust,传给引擎方法Canvas.getHeight()获取的数据与真实屏幕高度或者希望高度的偏差。
*/
int scrHeight;
/**
* 发生严重异常的情况下的处理方式,true:继续运行,false:关闭程序。
*/
private boolean isContinueAnyway;
/**
* 是否需要启动后台缓冲,true:启动,false:不启动。
*/
private boolean isBuffered;
/**
* 后台缓冲屏幕的画笔。
*/
Graphics bufferedGraphics;
/**
* 后台缓冲屏幕的画面。
*/
Image bufferedImage;
/**
* 游戏每帧的毫秒数。<br>比如:1000(1000毫秒)/12(每秒12帧),就是mspf = 1000/12 ·=83。默认是0x7fffffffffffffffL,即最大的毫秒数。
*/
long mspf = 0x7fffffffffffffffL;
/**
* 按键保持状态的时延。
*/
long timeoutHoldKey;
/**
* 当前逻辑处理时间。
*/
long currentTime;
/**
* constructor。<br>在这里做出了一些具体的数据的初始化。比如屏幕的宽度、高度,全屏幕的设置,缓冲屏幕的创建等等。
* @param <b>scrWidthAdjust</b> 屏幕宽度调整,本引擎所获取的屏幕的宽度是通过Canvas自带的getWidth()方法获取的。但是,出于某些不可预料的原因,本引擎所获取的屏幕的宽度不能够准确的表现屏幕的真实的宽度的时候,需要程序员在这里给出宽度的修正数据。<br>
* @param <b>scrHeightAdjust</b> 屏幕高度调整,本引擎所获取的屏幕的宽度是通过Canvas自带的getWidth()方法获取的。但是,出于某些不可预料的原因,本引擎所获取的屏幕的高度不能够准确的表现屏幕的真实的高度的时候,需要程序员在这里给出高度的修正数据。<br>
* @param <b>continueAfterException</b> 发生严重异常的情况下的处理方式,true:发生严重异常之后仍然继续运行,false:发生严重异常之后关闭应用程序。<br>
* @param <b>applyDoubleBuffered</b> 是否启用双缓冲绘制,true:启用,false:不启用。<br>
* @param <b>appendCommandSoftX</b> 是否需要添加高级命令按钮作为左右软键,true:需要添加,false:不需要添加。由于有些硬件的左右软键在Canvas里面捕捉不到,这里需要用高级命令按钮Command代替。
*/
EngineThread(int scrWidthAdjust, int scrHeightAdjust, boolean continueAfterException, boolean applyDoubleBuffered, boolean appendCommandSoftX){
//检测当前简表的版本,判断是否可以全屏幕
if(!EngineManager.checkProperty("microedition.profiles", "MIDP-1.0") && !appendCommandSoftX){
setFullScreenMode(true);
}
//获得屏幕宽度
scrWidth = getWidth() + scrWidthAdjust;
//获得屏幕高度
scrHeight = getHeight() + scrHeightAdjust;
//获得异常处理方案
isContinueAnyway = continueAfterException;
//判断是否需要缓冲绘图以及是否硬件已经支持缓冲绘图,来创建双缓冲机制
if((isBuffered = (applyDoubleBuffered && !isDoubleBuffered()))){
bufferedGraphics = (bufferedImage = Image.createImage(scrWidth, scrHeight)).getGraphics();
}
if(appendCommandSoftX){
addCommand(new Command("确定", Command.OK, 1));
addCommand(new Command("取消", Command.CANCEL, 1));
setCommandListener(new CommandListener(){
public void commandAction(Command command, Displayable displayable){
if(command.getCommandType() == Command.OK){
keyPressed(EngineKey.keyMap[6]);
keyReleased(EngineKey.keyMap[6]);
}else if(command.getCommandType() == Command.CANCEL){
keyPressed(EngineKey.keyMap[7]);
keyReleased(EngineKey.keyMap[7]);
}
}
});
}
//标记程序运行启动标志量
EngineManager.hasStarted = true;
}
/**
* 引擎主线程的run方法。
*/
public void run(){
long remainTime= 0;
while(EngineManager.hasStarted){
try{
while(EngineManager.isPause && EngineManager.hasStarted){
//暂停
Thread.sleep(5);
}
//取得当前时间
currentTime = System.currentTimeMillis();
synchronized(this){
//绘制当前
if(isShown()){
repaint();
serviceRepaints();
}
//逻辑处理
handle();
}
//取得刷新剩余时间
remainTime = mspf - (System.currentTimeMillis() - currentTime);
if(remainTime > 0){
//剩下点时间,继续等待
Thread.sleep(remainTime);
}
}catch(Throwable t){
EngineManager.hasStarted = isContinueAnyway;
EngineManager.debugEngine(t, null);
}
}
//退出
try{
EngineManager.engineMidlet.destroyApp(true);
}catch(Throwable t){
EngineManager.debugEngine(t, null);
}finally{
//最后的关闭
EngineManager.engineMidlet.notifyDestroyed();
EngineManager.engineMidlet = null;
System.gc();
}
}
/**
* 引擎主逻辑入口。
* @throws Exception 一切可能产生的异常。
*/
private void handle() throws Exception{
//后台ScreenListener实例运行
if(EngineManager.backgroundID != null && EngineManager.scrList != null){
for(int i = EngineManager.backgroundID.length() - 1; i >= 0; i--){
((EventListener)(EngineManager.scrList.elementAt((int)(EngineManager.backgroundID.charAt(i))))).handle(false, scrWidth, scrHeight, currentTime, null, null);
}
}
//前台ScreenListener实例运行
if(EngineManager.scrListener instanceof EventListener){
EngineKey.holdFlag = (currentTime - curPressTime) > timeoutHoldKey;
((EventListener)EngineManager.scrListener).handle(true, scrWidth, scrHeight, currentTime, keyInfo, EngineManager.debugInfo);
}
}
/**
* 引擎主绘制入口。
* @param <b>graphics</b> 画笔设备的引用,由硬件系统传给引擎使用。
*/
protected void paint(Graphics graphics){
if(EngineManager.scrListener instanceof DrawListener){
try{
//绘制
//3D应用可能会有异常需要捕捉
((DrawListener)EngineManager.scrListener).paint((isBuffered ? bufferedGraphics : graphics), scrWidth, scrHeight, currentTime, keyInfo, EngineManager.debugInfo);
if(isBuffered){
//首先恢复缓冲屏幕的画笔
bufferedGraphics.translate(-bufferedGraphics.getTranslateX(), -bufferedGraphics.getTranslateY());
//绘制缓冲屏幕
graphics.setClip(0, 0, scrWidth, scrHeight);
graphics.drawImage(bufferedImage, 0, 0, Graphics.LEFT|Graphics.TOP);
}
}catch(Throwable t){
EngineManager.debugEngine(t, null);
}
}
}
/**
* 继承于Canvas的方法。<br>属于MIDlet运行机制的一个接口,当前低级屏幕隐藏的时候调用。
*/
protected final void hideNotify(){
if(EngineManager.scrListener != null){
if(EngineManager.hasStarted && !EngineManager.isPause){
EngineManager.engineMidlet.save(EngineManager.HIDENOTIFY_CALLER);
EngineManager.isPause = true;
}
}
}
/**
* 继承于Canvas的方法。<br>属于MIDlet运行机制的一个接口,当前低级屏幕显现的时候调用。
*/
protected final void showNotify(){
if(EngineManager.scrListener != null){
if(EngineManager.hasStarted && EngineManager.isPause){
EngineManager.engineMidlet.load(EngineManager.SHOWNOTIFY_CALLER);
EngineManager.isPause = false;
}
}
}
//以下是按键接口
/**
* 当前按键信息。
*/
String keyInfo;
/**
* 当前按键操作按下的时刻。
*/
private long curPressTime;
/**
* 继承于Canvas的方法。<br>属于MIDlet运行机制的一个接口,当前低级屏幕被显现,并且有按键按下的时候调用。
* @param <b>keyCode</b> 由系统传给引擎的按键的机器码。
*/
protected void keyPressed(int keyCode){
long prePressTime = curPressTime;
if(EngineKey.combineState != null){
if(((curPressTime = System.currentTimeMillis()) - prePressTime) > timeoutHoldKey){
EngineKey.combineState.delete(0, EngineKey.combineState.length());
}
}
char action = (char)getGameAction(keyCode), key = (char)keyCode;
if(EngineKey.pressState != null){
EngineKey.pressState.delete(0, 2);
}
if(EngineKey.keyMap != null){
for(int i = EngineKey.keyMap.length - 1; i > 5; i--){
if(EngineKey.keyMap[i] == keyCode){
if(EngineKey.holdState != null){
int currentholdKeyAmount = EngineKey.holdState.length();
if((currentholdKeyAmount & 0x1) != 0){
EngineKey.holdState.delete(0, currentholdKeyAmount);
}else if(currentholdKeyAmount > 1 && EngineKey.holdState.charAt(1) == (char)EngineKey.keyMap[0]){
EngineKey.holdState.delete(0, 2);
}
EngineKey.holdState.insert(0, key);
EngineKey.holdState.insert(0, action);
}
if(EngineKey.pressState != null){
EngineKey.pressState.delete(0, 2);
EngineKey.pressState.append(action);
EngineKey.pressState.append(key);
keyInfo = "keyPressed keyCode(" + keyCode + ") is " + getKeyName(keyCode) + ", action is " + getGameAction(keyCode);
}
break;
}
}
}
}
/**
* 继承于Canvas的方法。<br>属于MIDlet运行机制的一个接口,当前低级屏幕被显现,并且有按键释放的时候调用。
* @param <b>keyCode</b> 由系统传给引擎的按键的机器码。
*/
protected void keyReleased(int keyCode){
if(EngineKey.keyMap != null){
char action = (char)getGameAction(keyCode), key = (char)keyCode;
for(int i = EngineKey.keyMap.length - 1; i > 5; i--){
if(EngineKey.keyMap[i] == keyCode){
if(EngineKey.holdState != null){
int currentholdKeyAmount = EngineKey.holdState.length();
if(currentholdKeyAmount > 1 && (currentholdKeyAmount & 0x1) == 0){
if(EngineKey.holdState.charAt(1) == key && currentholdKeyAmount > 2){
EngineKey.holdState.setCharAt(0, (char)EngineKey.keyMap[0]);
EngineKey.holdState.setCharAt(1, (char)EngineKey.keyMap[0]);
}else{
EngineKey.holdState.delete(currentholdKeyAmount - 2, currentholdKeyAmount);
}
}
}
if(EngineKey.combineState != null){
int currentCombineKeyAmount = EngineKey.combineState.length();
if(currentCombineKeyAmount == EngineKey.combineState.capacity()){
EngineKey.combineState.delete(0, currentCombineKeyAmount);
}
EngineKey.combineState.append(action);
EngineKey.combineState.append(key);
keyInfo = "keyReleased keyCode(" + keyCode + ") is " + getKeyName(keyCode) + ", action is " + getGameAction(keyCode);
}
break;
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -