LGame Android及J2SE游戏引擎 入门示例——如何构建一个游戏

               

较早前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版使用方式如下:

AndroidScreen 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可以通过getLGraphicsgetDrawDraw类为LGraphics的简化封装)函数直接获得对LGraphics的操作权,并非一定要通过drawScreen函数绘图。

Android版:

J2SEAndroid版的差别仅仅在于鼠标、键盘等设备函数上,其它细节相同。

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

CanvasScreen0.2.6版中最新提供的Screen实现,模拟J2MECanvas而成(也混合了GameCanvasAPI),相关函数在J2SEAndroid版中完全一致。

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函数绘图。另外,由于CanvasScreenPaint函数并不直接关联父类的draw函数,所以LGame中提供的精灵或组件无法直接通过add函数加载显示,而是只能在paint中手动调用相应组件的绘图器进行绘制(关于这点,用惯J2ME的朋友应该没什么不习惯的。另外LGame提供有配套的j2me精灵类包可供使用,为11仿J2ME原有API实现)。

 

以下是一个CanvasScreen的使用示例:

 

//初始化时的精灵动画

01

//移动时的精灵动画

02

//背景图片

03

请注意,为了演示图像扩大机制,示例所用的精灵以及游戏背景图像都非常之小,而实际开发中并非一定要使用图像扩充,更不是只能使用此比例的图像。


下面我制作一个Sword.java,这是一个自定义的精灵类,用以显示上图所示的“骷髅剑士”。(在不重新实现ISprite的基础上,我们也可以直接使用现成的Sprite类来完成此例。但是,关于动作细节部分就只能在精类外部设定或者重载Spriteupdate函数来实现(和实现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

 

03

PS:CanvasScreen中也允许完全照搬J2MECanvas(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

           

猜你喜欢

转载自blog.csdn.net/qq_44934536/article/details/89437005