较早前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函数中构造如下内容即可。
[java] view plain
copy
print ?
- public static void main(String[] args) {
-
- GameScene frame = new GameScene("窗体名",
- 480, 320);
-
- Deploy deploy = frame.getDeploy();
-
- deploy.setScreen(new Game());
-
- deploy.setShowFPS(true);
-
- deploy.setLogo(false);
-
- deploy.setFPS(100);
-
- deploy.mainLoop();
-
- frame.showFrame();
- }
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文档。
如下所示:
[xhtml] view plain
copy
print ?
- 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>
而调用的方法如下:
[java] view plain
copy
print ?
- 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) {
-
- this.initialization(icicle,false,LAD.BOTTOM, "XXXXXXXX",60);
-
-
-
- this.setScreen(new Game());
-
- this.setFPS(60);
-
- this.setShowLogo(false);
-
- this.setShowFPS(true);
-
- this.showScreen();
- }
- }
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版使用方式如下:
[java] view plain
copy
print ?
- 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 {
-
-
- 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) {
- }
- }
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名及函数有所不同。
[java] view plain
copy
print ?
- import org.loon.framework.android.game.core.graphics.Screen;
- import android.view.KeyEvent;
- import android.view.MotionEvent;
- public class ScreenExample extends Screen{
-
-
- 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;
- }
- }
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函数中即是一个独立的线程。
[java] view plain
copy
print ?
- 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 () {
-
- super(300, 450);
-
- resizeScreen(320, 480);
- }
-
- public void drawScreen(LGraphics g) {
- }
-
- 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) {
- }
- }
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版的差别仅仅在于鼠标、键盘等设备函数上,其它细节相同。
[java] view plain
copy
print ?
- import org.loon.framework.android.game.core.graphics.ThreadScreen;
- import android.view.KeyEvent;
- import android.view.MotionEvent;
- public class ThreadScreenExample extends ThreadScreen {
- public ThreadScreenExample () {
-
- super(300, 450);
-
- resizeScreen(320, 480);
- }
-
- public void drawScreen(LGraphics g) {
- }
-
- 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;
- }
- }
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版中完全一致。
[java] view plain
copy
print ?
- 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(){
-
-
- super(300,450,320,480);
- }
-
- 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) {
- }
- }
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没什么区别了|||))。
[java] view plain
copy
print ?
- 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;
-
- 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);
-
- this.time = new LTimer(10);
-
- 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) {
-
-
- 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();
- }
-
- 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 {
-
- move_left(2);
- }
- if ((x() - randX) <= 0) {
- right = true;
- }
-
- } else if (right
- && (x() + animation.getSpriteImage().getWidth() - randX) <= WIDTH) {
- if (flag) {
-
- move_right(2);
- } else {
-
- move_right();
- }
-
- if ((x() + animation.getSpriteImage().getWidth() + randX) >= WIDTH) {
- right = false;
- }
- }
- }
-
- 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;
- }
- }
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。
[java] view plain
copy
print ?
- 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 {
-
- private Sprites sprs = new Sprites(240, 80);
-
- private LImage background = LImage.createImage("res/background.png");
-
- private boolean running;
-
- private long speed = 30;
- public CanvasScreenExample() {
-
- 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));
- &nbs
给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow