分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.youkuaiyun.com/jiangjunshow
也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!
较早前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));
- &nbs
给我老师的人工智能教程打call!http://blog.youkuaiyun.com/jiangjunshow