较早前LGame示例下载地址:http://loon-simple.googlecode.com/files/LGame-Simple-0.2.5.7z
最新版LGame(0.2.6)下载地址:http://loon-simple.googlecode.com/files/LGame-0.2.6.rar
1、如何启动LGame
目前的LGame提供有J2SE以及Android两个开发版本,两版的主要类及函数虽然相同,但由于Android版对应于手机环境,而J2SE版对应于PC环境,所以依旧有少许的差别。
J2SE版:
在J2SE环境下,只需要在Main函数中构造如下内容即可。
public static void main(String[] args) { // 获得一个游戏窗体 GameScene frame = new GameScene("窗体名", 480, 320); // 得到此窗体所对应的游戏部署器 Deploy deploy = frame.getDeploy(); // 设定此游戏屏幕(在任何时候都可以通过Screen中的setScreen函数切换游戏屏幕) deploy.setScreen(new Game()); // 是否显示FPS deploy.setShowFPS(true); // 是否显示框架logo deploy.setLogo(false); // 允许的最大刷新率 deploy.setFPS(100); // 开始游戏主循环 deploy.mainLoop(); // 显示游戏画面 frame.showFrame(); }
Android版:
而在Android版中,我们则需要分两步走,一是需要配置相关的AndroidManifest.xml 文档。
如下所示:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.loon.test" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".Main" android:configChanges="orientation|keyboardHidden" <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="3" /> <uses-permission android:name="android.permission.INTERNET"/> </manifest>
而调用的方法如下:
package org.loon.test; import org.loon.framework.android.game.LAD; import org.loon.framework.android.game.LGameAndroid2DActivity; import org.loon.framework.android.game.core.LSystem; import android.os.Bundle; public class Main extends LGameAndroid2DActivity { public void onCreate(Bundle icicle) { // 有Admob广告,纵屏显示,广告居于屏幕下方,广告ID为“XXXXXXXX”,广告刷新速度为60秒 this.initialization(icicle,false,LAD.BOTTOM, "XXXXXXXX",60); // 无Admob广告,纵屏显示 // this.initialization(icicle,false); // 使用游戏窗体Game this.setScreen(new Game()); // 设定FPS为60 this.setFPS(60); // 不显示游戏Logo(设定Logo为setLogo) this.setShowLogo(false); // 显示FPS this.setShowFPS(true); // 显示游戏画面 this.showScreen(); } }
这时LGame框架就会根据我们所实现的不同Screen,来展示我们的游戏了(很简单吧)。
2、如何构建Screen类
Screen是一个抽象类,也是LGame框架所提供的游戏界面展示器,其中封装了基本的图形接口与相关的操作设备交互函数,在LGame框架中,可以直接作为游戏界面进行展示的Screen共有三种。
一、Screen
即最基本的Screen,包含了最基本的Screen函数,默认自动刷新游戏画面(根据FPS所设定的速度),不提供repaint以及getLGraphics方法,是提供LGame框架调用的最基本Screen形态。
J2SE版使用方式如下:
import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import org.loon.framework.game.simple.core.graphics.Screen; import org.loon.framework.game.simple.core.graphics.device.LGraphics; public class ScreenExample extends Screen { // draw中LGraphics会根据设定的FPS自动刷新,使用上与标准的J2SE Graphics以及J2ME Graphics接口没有区别(API为二者的综合) public void draw(LGraphics g) { } // 鼠标左键 public void leftClick(MouseEvent e) { } // 鼠标中间键 public void middleClick(MouseEvent e) { } // 鼠标右键 public void rightClick(MouseEvent e) { } // 键盘按下 public void onKey(KeyEvent e) { } // 键盘放开 public void onKeyUp(KeyEvent e) { } }
另外,在 Screen 中还有一个重要的 alter 函数,我们可以通过重载 alter 函数实现最简单的定时操作,譬如 :
// 设定计时器,每隔 1 秒允许执行一次
LTimer timer = new LTimer(LSystem. SECOND );
// 重载 alter 函数
public void alter(LTimerContext context){
if ( timer .action(context.getTimeSinceLastUpdate())){
}
}
Android版使用方式如下:
Android 版 Screen API 与使用方法基本等价于 J2SE 版,但由于手机与 PC 间功能有所差别,所以具体的 API 名及函数有所不同。
import org.loon.framework.android.game.core.graphics.Screen; import android.view.KeyEvent; import android.view.MotionEvent; public class ScreenExample extends Screen{ // 与J2SE版相同,draw中LGraphics会根据设定的FPS自动刷新,使用上与标准的J2SE Graphics以及J2MEGraphics接口没有区别(API为二者的综合) public void draw(LGraphics g) { } //键盘按下 public boolean onKeyDown(int keyCode, KeyEvent e) { return true; } //键盘放开 public boolean onKeyUp(int keyCode, KeyEvent e) { return true; } //触摸屏按下 public boolean onTouchDown(MotionEvent e) { return true; } //手指在触摸屏上移动 public boolean onTouchMove(MotionEvent e) { return true; } //触摸屏放开 public boolean onTouchUp(MotionEvent e) { return true; } }
关于 alter 函数部分完全一致。
二、ThreadScreen
J2SE版:
ThreadScreen 是一个实现了 Runnable 接口的 Screen ,它采用 double buffer 方式将绘图与业务线程分离, gameLoop 函数中即是一个独立的线程。
import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import org.loon.framework.game.simple.core.graphics.ThreadScreen; import org.loon.framework.game.simple.core.graphics.device.LGraphics; public class ThreadScreenExample extends ThreadScreen { public ThreadScreenExample () { // ThreadScreen及CanvasScreen都允许变更游戏图形界面大小,下例重载参数为最初(实际)的界面大小。 super(300, 450); // 设定显示时图像大小,此时游戏将以320x480的大小运行(视原有界面不同,会有不同程度的失真) resizeScreen(320, 480); } // ThreadScreen绘图器,为标准Screen中draw函数的封装,区别在于ThreadScreen的修改仅在repaint时生效,而且ThreadScreen不会自动清除原有的图像内容。 public void drawScreen(LGraphics g) { } // gameLoop的刷新速度可以通过setSynchroFPS函数调整。 public void gameLoop() { } // 鼠标左键 public void leftClick(MouseEvent e) { } // 鼠标中间键 public void middleClick(MouseEvent e) { } // 鼠标右键 public void rightClick(MouseEvent e) { } // 键盘按下 public void onKey(KeyEvent e) { } // 键盘放开 public void onKeyUp(KeyEvent e) { } }
与标准 Screen 的其它区别在于, ThreadScreen 可以通过 getLGraphics 或 getDraw ( Draw 类为 LGraphics 的简化封装)函数直接获得对 LGraphics 的操作权,并非一定要通过 drawScreen 函数绘图。
Android版:
J2SE 与 Android 版的差别仅仅在于鼠标、键盘等设备函数上,其它细节相同。
import org.loon.framework.android.game.core.graphics.ThreadScreen; import android.view.KeyEvent; import android.view.MotionEvent; public class ThreadScreenExample extends ThreadScreen { public ThreadScreenExample () { // ThreadScreen及CanvasScreen都允许变更游戏图形界面大小,下例重载参数为最初(实际)的界面大小。 super(300, 450); // 设定显示时图像大小,此时游戏将以320x480的大小运行(视原有界面不同,会有不同程度的失真) resizeScreen(320, 480); } // ThreadScreen绘图器,为标准Screen中draw函数的封装,区别在于drawScreen的修改仅在repaint时生效,而且drawScreen不会自动清除原有的图像内容。 public void drawScreen(LGraphics g) { } // gameLoop的刷新速度可以通过setSynchroFPS函数调整。 public void gameLoop() { } //键盘按下 public boolean onKeyDown(int keyCode, KeyEvent e) { return true; } //键盘放开 public boolean onKeyUp(int keyCode, KeyEvent e) { return true; } //触摸屏按下 public boolean onTouchDown(MotionEvent e) { return true; } //手指在触摸屏上移动 public boolean onTouchMove(MotionEvent e) { return true; } //触摸屏放开 public boolean onTouchUp(MotionEvent e) { return true; } }
三、CanvasScreen
CanvasScreen 是 0.2.6 版中最新提供的 Screen 实现,模拟 J2ME 中 Canvas 而成(也混合了 GameCanvas 的 API ),相关函数在 J2SE 及 Android 版中完全一致。
import org.loon.framework.game.simple.core.graphics.CanvasScreen; import org.loon.framework.game.simple.core.graphics.device.LGraphics; public class CanvasScreenExample extends CanvasScreen { public CanvasScreenExample(){ //与ThreadScreen相同,CanvaScreen允许改变游戏图像大小。 //以下参数分为别原始的图像宽与高(300x450),要求显示的宽与高(320x480) super(300,450,320,480); } // CanvasScreen绘图器,与标准Screen中draw函数的区别在于paint的修改仅在repaint时生效,而且paint不会自动清除原有的图像内容。 public void paint(LGraphics g) { } // 键盘按下 public void keyPressed(int keyCode) { } // 键盘放开 public void keyReleased(int keyCode) { } // 触摸屏或鼠标移动 public void pointerMove(double x, double y) { } // 触摸屏或鼠标按下 public void pointerPressed(double x, double y) { } // 触摸屏或鼠标放开 public void pointerReleased(double x, double y) { } }
与标准 Screen 的其它区别在于, CanvasScreen 可以通过 getLGraphics 函数直接获得对 LGraphics 的操作权,并非一定要通过 paint 函数绘图。另外,由于 CanvasScreen 的 Paint 函数并不直接关联父类的 draw 函数,所以 LGame 中提供的精灵或组件无法直接通过 add 函数加载显示,而是只能在 paint 中手动调用相应组件的绘图器进行绘制(关于这点,用惯 J2ME 的朋友应该没什么不习惯的。另外 LGame 提供有配套的 j2me 精灵类包可供使用,为 1 : 1 仿 J2ME 原有 API 实现)。
以下是一个CanvasScreen的使用示例:
//初始化时的精灵动画
//移动时的精灵动画
//背景图片
请注意,为了演示图像扩大机制,示例所用的精灵以及游戏背景图像都非常之小,而实际开发中并非一定要使用图像扩充,更不是只能使用此比例的图像。
下面我制作一个 Sword.java ,这是一个自定义的精灵类,用以显示上图所示的“骷髅剑士”。(在不重新实现 ISprite 的基础上,我们也可以直接使用现成的 Sprite 类来完成此例。但是,关于动作细节部分就只能在精类外部设定或者重载 Sprite 的 update 函数来实现(和实现 ISprite 没什么区别了 ||| ))。
import org.loon.framework.game.simple.action.map.RectBox; import org.loon.framework.game.simple.action.sprite.Animation; import org.loon.framework.game.simple.action.sprite.ISprite; import org.loon.framework.game.simple.action.sprite.SpriteImage; import org.loon.framework.game.simple.core.LObject; import org.loon.framework.game.simple.core.LSystem; import org.loon.framework.game.simple.core.graphics.device.LGraphics; import org.loon.framework.game.simple.core.timer.LTimer; public class Sword extends LObject implements ISprite { /** * */ private static final long serialVersionUID = 1L; // 精灵移动范围的最大宽度(即背景图实际宽,为240) private static final int WIDTH = 240; private boolean init, right, flag, visible; private int randX; private Animation animation; private LTimer time; private static final String kName1 = "res/s1.png", kName2 = "res/s2.png"; public Sword() { // 加载怪物剑士的“出土”动画(以下参数为图像所在地址、图像宽、图像高、播放间隔) this.animation = Animation.getDefaultAnimation(kName1, 18, 18, 150); // 设定计时器间隔为10豪秒 this.time = new LTimer(10); // 设定精灵初始位置(x轴随机,y轴48(立于相对于背景视觉的“地面”上)) this.setLocation(LSystem.random.nextInt(WIDTH), 48); // 随机决定精灵剑士向左或向右冲锋 this.right = LSystem.random.nextInt(2) == 0 ? true : false; // 随机决定精灵剑士以匀速或两倍速前进 this.flag = LSystem.random.nextInt(2) == 0 ? true : false; // 随机决定精灵剑士的“冲锋”停止点 this.randX = LSystem.random.nextInt(70); // 当前精灵可见 this.visible = true; } // 设定精灵绘图器内容 public void createUI(LGraphics g) { if (animation != null) { // PS:Android版中没有提供序列化保存SpriteImage的方法,直接getImage即可,而没有serializablelImage。 // 反转图像 if (right) { g.drawMirrorImage(animation.getSpriteImage().serializablelImage .getImage(), x(), y()); // 正向 } else { g.drawImage(animation.getSpriteImage().serializablelImage .getImage(), x(), y()); } } } // 当前精灵宽 public int getWidth() { SpriteImage si = animation.getSpriteImage(); if (si == null) { return -1; } return si.getWidth(); } // 当前精灵高 public int getHeight() { SpriteImage si = animation.getSpriteImage(); if (si == null) { return -1; } return si.getHeight(); } // 精灵计时器,用以在timer满足条件时变更精灵样式 public void update(long timer) { if (time.action(timer)) { animation.update(timer); // 当动画没有播放时 if (!animation.isRunning()) { // 初始化动画精灵(以下参数为图像所在地址、图像宽、图像高、播放间隔) animation = Animation.getDefaultAnimation(kName2, 26, 18, 50); } else if (animation.isRunning() && init) { // 向左 if (!right && (x() + randX) > 0) { if (flag) { // 精灵向左移动 move_left(); } else { // 精灵向左移动(速度x2) move_left(2); } if ((x() - randX) <= 0) { right = true; } // 向右 } else if (right && (x() + animation.getSpriteImage().getWidth() - randX) <= WIDTH) { if (flag) { // 精灵向右移动(速度x2) move_right(2); } else { // 精灵向右移动 move_right(); } // 当达到屏幕边缘时,改变移动方向 if ((x() + animation.getSpriteImage().getWidth() + randX) >= WIDTH) { right = false; } } } // 当精灵动画结束时,设定init=true(精灵动画播放完毕) if (!init && animation.getTotalFrames() - 1 == animation .getCurrentFrameIndex()) { animation.setRunning(false); init = true; } } } // 透明度 public float getAlpha() { return 0; } // 碰撞盒 public RectBox getCollisionBox() { return new RectBox(Math.round(x()), Math.round(y()), getWidth(), getHeight()); } // 显示状态 public boolean isVisible() { return visible; } // 是否显示精灵 public void setVisible(boolean visible) { this.visible = visible; } }
设定一个 CanvasScreenExample.java ,用以继承 CanvasScreen 。
import org.loon.framework.game.simple.GameScene; import org.loon.framework.game.simple.action.sprite.Sprites; import org.loon.framework.game.simple.core.graphics.CanvasScreen; import org.loon.framework.game.simple.core.graphics.Deploy; import org.loon.framework.game.simple.core.graphics.LImage; import org.loon.framework.game.simple.core.graphics.device.LGraphics; public class CanvasScreenExample extends CanvasScreen implements Runnable { // 设定精灵组,显示范围为宽240,高80(此为实际背景图大小) private Sprites sprs = new Sprites(240, 80); // 设定背景图像 private LImage background = LImage.createImage("res/background.png"); // 是否允许线程运行 private boolean running; // 刷新间隔 private long speed = 30; public CanvasScreenExample() { // 重载游戏画面大小,将240x80的实际游戏图像大小,扩大为480x160的显示大小 super(240, 80, 480, 160); // 创建五个骷髅剑士的精灵 Sword[] sw = new Sword[5]; //循环载入 for (int i = 0; i < sw.length; i++) { // 将精灵载入精灵管理器 sprs.add(sw[i] = new Sword()); } // 允许线程运行 this.running = true; // 启动线程 this.callEvent(new Thread(this)); } // 当切换不同的Screen,或者游戏结束时,会触发此函数 public void dispose() { this.running = false; } // 在绘图器中绘制背景图以及相关精灵 public void paint(LGraphics g) { // 绘制背景图像到位置(0,0) g.drawImage(background, 0, 0); // 绘图精灵组中所有精灵(默认位置(0,0),也允许通过setLocation或setViewWindow变更显示位置及显示范围) sprs.createUI(g); } public void run() { while (running) { // 刷新游戏画面 this.repaint(); // 间隔30豪秒 this.pause(speed); // 刷新精灵组 sprs.update(speed); } } public void keyPressed(int keyCode) { } public void keyReleased(int keyCode) { } public void pointerMove(double x, double y) { } public void pointerPressed(double x, double y) { } public void pointerReleased(double x, double y) { } }
此时,我们只需要根据需要实例化相关的Screen(也就是setScreen),就会得到如下效果:
实际运行效果如下( Android 版效果与此相同, PC 版中窗体实际大小被设定为 480x320 )
PS: 在 CanvasScreen 中也允许完全照搬 J2ME 中 Canvas(GameCanvas) 与相关精灵(内置有 API 1:1 的精灵类相关实现)的构建方式,可以将任何 J2ME 游戏代码平移其中。简单的讲,您在只掌握 J2ME 技术的情况下也可以使用 LGame ,而无需单独学习任何 LGame 框架本身的构建方式。
较早前LGame示例(仅PC版)下载地址:http://loon-simple.googlecode.com/files/LGame-Simple-0.2.5.7z
最新版LGame(0.2.6)下载地址:http://loon-simple.googlecode.com/files/LGame-0.2.6.rar