Java版AVG游戏开发入门[0]——游戏模式转换中的事件交互 推荐
2009-02-08 10:06
791 查看
AVG,即Adventure Game,可以直译为[冒险游戏]。但是通常情况下我们说AVG是指[文字冒险游戏],也有人更直白的解释成自己选择路线和结局的电子小说,与硬砍硬杀的RPG或者揉破键盘的ACT不同,AVG多以解谜或文字游戏等脑力攻关推动剧情发展。现在日本流行的ADV,可以看作是AVG英文全称的不同缩写方式,大体上讲,AVG == ADV。
由于商业化需要,现代主流的AVG往往是GalGame,也就是少女游戏,或称少女恋爱游戏,但GalGame != AVG,只是下属分支中的一环罢了,AVG包含GalGame,但GalGame并不能完全代表AVG/ADV。另外关于GalGame的详细介绍,在若木民喜《只有神才知道的世界》中演绎的相当生动,有兴趣的可以自己去看看~
就技术角度而言,AVG开发可以算得所有游戏类型中最容易的。一款简单AVG游戏的制作难度甚至在贪食蛇、俄罗斯方块之下。由于实现的简易性,导致AVG的开发重心往往着重于策划及美工,程序员的作用则微乎其微。同时也正因AVG开发的门坎约等于0,所以此类型的同人游戏之多即可堪称世界之冠。另外,AVG开发工具普及的也促进了AVG的量产化。利用工具,即始是小说作者、漫画家等非软件专业出身的人士,往往也能轻易制作出顶级的AVG大作。(顺便一提,目前我所见过最好的AVG制作工具是鬼子的livemaker,采用类似思维导图的方式构造整个游戏,很多轻小说作者乃至网络漫画家用它制作自己作品的宣传游戏。但就技术角度上说,livemaker的开发依旧没什么难度......)
由于AVG的大泛滥,通常仅有文字、图片及语音的AVG往往无法满足用户需求(H除外-_-)。我们每每可在AVG游戏类型后发现个+号,比如《樱花大战》是AVG+SLG,《生化危机》是AVG+ACT。所以客观上说,AVG开发仅仅能进行字图的交互是不够的,还要解决多模块组件的协调问题。
在Java桌面应用开发中,我们都知道绘图是极为简单的,有Image、Graphics两个对象就可以Paint一个图形,即使图形对象再多,最后它们也必须统一在一个Paint中,所以Java中不存在图像的交互问题。
但问题在于,图像的显示可以统一,但是触发图像变化的事件却是很难统一的。比如现在有需求如下,在AVG模式中,触发键盘事件上、下、左、右时为控制画面的前进、后退,切换模式到SLG模
式后,设定上、下、左、右是光标移动,那么如果我要在程序中实现,就必须记录当前模式,而后根据不同模式调用事件,再反馈到图形上。如果只有几个事件的区
别,我们当然可以很容易用分支来实现;问题是,随着游戏规模的加大,这些分支将成几何倍数增多,单纯的分支判定到最后只能忙于应付,落个费力不讨好。
其实在这时,我们大可以使用一些技巧来轻松解决问题。
示例如下:
首先,我们构造一个接口,命名为IControl,继承鼠标及键盘监听,并在其中设定两个抽象方法:
view plaincopy to clipboardprint?package org.loon.simple.avg;
import java.awt.Graphics;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
/**
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email:[email]ceponline@yahoo.com.cn[/email]
* @version 0.1
*/
public interface IControl extends MouseListener, MouseMotionListener,
KeyListener {
public abstract void draw(final Graphics g);
public abstract IControl invoke();
}
而后,再构造一个接口,命名为IAVG,同样继承鼠标及键盘监听,并在其中设定三个抽象方法,用以操作IControl接口:
view plaincopy to clipboardprint?package org.loon.simple.avg;
import java.awt.Graphics;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
/**
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email:[email]ceponline@yahoo.com.cn[/email]
* @version 0.1
*/
public interface IAVG extends MouseListener, MouseMotionListener,
KeyListener {
public abstract void draw(final Graphics g);
public abstract IControl getControl();
public abstract void setControl(final IControl control);
}
再后,制作一个显示图像用组件,命名为AVGCanva,继承自Canvas。
view plaincopy to clipboardprint?package org.loon.simple.avg;
import java.awt.Canvas;
import java.awt.Graphics;
/**
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email:[email]ceponline@yahoo.com.cn[/email]
* @version 0.1
*/
public class AVGCanvas extends Canvas {
/**
*
*/
private static final long serialVersionUID = 1982278682597393958L;
private boolean start;
private IAVG avg;
public AVGCanvas(IAVG handler) {
this.avg = handler;
this.start = false;
this.addKeyListener(handler);
this.addMouseListener(handler);
this.addMouseMotionListener(handler);
}
public void update(Graphics g) {
paint(g);
}
public void paint(Graphics g) {
if (this.start) {
this.avg.draw(g);
}
}
public void startPaint() {
this.start = true;
}
public void endPaint() {
this.start = false;
}
}
这段代码中的paint方法中并没有现成的方法,而是调用了IAVG接口的draw。紧接着,我们再设定一个AVGFrame用以加载AVGCanvas。
view plaincopy to clipboardprint?package org.loon.simple.avg;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/**
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email:[email]ceponline@yahoo.com.cn[/email]
* @version 0.1
*/
public class AVGFrame extends Frame implements Runnable {
/**
*
*/
private static final long serialVersionUID = 198284399945549558L;
private IAVG avg;
private AVGCanvas canvas;
private boolean fps;
private String titleName;
private Thread mainLoop;
public AVGFrame(String titleName, int width, int height) {
this(new AVG(), titleName, width, height);
}
public AVGFrame(IAVG avg, String titleName, int width, int height) {
super(titleName);
Lib.WIDTH = width;
Lib.HEIGHT = height;
this.avg = avg;
this.titleName = titleName;
this.addKeyListener(avg);
this.setPreferredSize(new Dimension(width + 5, height + 25));
this.initCanvas(Lib.WIDTH, Lib.HEIGHT);
this.pack();
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
this.setResizable(false);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public void run() {
gameLoop();
}
/**
* 开始循环窗体图像
*
*/
private synchronized void gameLoop() {
canvas.startPaint();
long second = 0L;
int moveCount = 0;
// 循环绘制
for (;;) {
long start = System.currentTimeMillis();
this.paintScreen();
long end = System.currentTimeMillis();
long time = end - start;
long sleepTime = 20L - time;
if (sleepTime < 0L)
sleepTime = 0L;
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (this.fps) {
moveCount++;
second += System.currentTimeMillis() - start;
if (second >= 1000L) {
this.setTitle(new StringBuilder(titleName).append(" FPS:")
.append(moveCount).toString());
moveCount = 0;
second = 0L;
}
}
}
}
/**
* 启动游戏循环
*
*/
public void mainLoop() {
this.mainLoop = new Thread(this);
this.mainLoop.start();
}
/**
* 初始化背景帆布
*
* @param width
* @param height
*/
private void initCanvas(final int width, final int height) {
canvas = new AVGCanvas(avg);
canvas.setBackground(Color.black);
canvas.setPreferredSize(new Dimension(width, height));
this.add(canvas);
}
public IAVG getAVG() {
return this.avg;
}
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
}
public synchronized void paintScreen() {
canvas.repaint();
}
public boolean isShowFPS() {
return fps;
}
public void setShowFPS(boolean fps) {
this.fps = fps;
}
public Thread getMainLoop() {
return mainLoop;
}
public String getTitleName() {
return titleName;
}
}
我们可以看到,在本例鼠标键盘事件及图像绘制完全通过接口方式实现。此时,只要让不同组件统一实现IControl接口,便可以轻松转换事件及图像的绘制。也正是我们都再熟悉不过的MVC模式中,通过Event导致Controller改变Model及View的基本原理。
下一回,我们将具体讲解一个AVG游戏实现的基本流程。
示例代码界面如下图:
、
示例程序下载地址:http://download.csdn.net/source/999273(源码在jar内)
由于商业化需要,现代主流的AVG往往是GalGame,也就是少女游戏,或称少女恋爱游戏,但GalGame != AVG,只是下属分支中的一环罢了,AVG包含GalGame,但GalGame并不能完全代表AVG/ADV。另外关于GalGame的详细介绍,在若木民喜《只有神才知道的世界》中演绎的相当生动,有兴趣的可以自己去看看~
就技术角度而言,AVG开发可以算得所有游戏类型中最容易的。一款简单AVG游戏的制作难度甚至在贪食蛇、俄罗斯方块之下。由于实现的简易性,导致AVG的开发重心往往着重于策划及美工,程序员的作用则微乎其微。同时也正因AVG开发的门坎约等于0,所以此类型的同人游戏之多即可堪称世界之冠。另外,AVG开发工具普及的也促进了AVG的量产化。利用工具,即始是小说作者、漫画家等非软件专业出身的人士,往往也能轻易制作出顶级的AVG大作。(顺便一提,目前我所见过最好的AVG制作工具是鬼子的livemaker,采用类似思维导图的方式构造整个游戏,很多轻小说作者乃至网络漫画家用它制作自己作品的宣传游戏。但就技术角度上说,livemaker的开发依旧没什么难度......)
由于AVG的大泛滥,通常仅有文字、图片及语音的AVG往往无法满足用户需求(H除外-_-)。我们每每可在AVG游戏类型后发现个+号,比如《樱花大战》是AVG+SLG,《生化危机》是AVG+ACT。所以客观上说,AVG开发仅仅能进行字图的交互是不够的,还要解决多模块组件的协调问题。
在Java桌面应用开发中,我们都知道绘图是极为简单的,有Image、Graphics两个对象就可以Paint一个图形,即使图形对象再多,最后它们也必须统一在一个Paint中,所以Java中不存在图像的交互问题。
但问题在于,图像的显示可以统一,但是触发图像变化的事件却是很难统一的。比如现在有需求如下,在AVG模式中,触发键盘事件上、下、左、右时为控制画面的前进、后退,切换模式到SLG模
式后,设定上、下、左、右是光标移动,那么如果我要在程序中实现,就必须记录当前模式,而后根据不同模式调用事件,再反馈到图形上。如果只有几个事件的区
别,我们当然可以很容易用分支来实现;问题是,随着游戏规模的加大,这些分支将成几何倍数增多,单纯的分支判定到最后只能忙于应付,落个费力不讨好。
其实在这时,我们大可以使用一些技巧来轻松解决问题。
示例如下:
首先,我们构造一个接口,命名为IControl,继承鼠标及键盘监听,并在其中设定两个抽象方法:
view plaincopy to clipboardprint?package org.loon.simple.avg;
import java.awt.Graphics;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
/**
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email:[email]ceponline@yahoo.com.cn[/email]
* @version 0.1
*/
public interface IControl extends MouseListener, MouseMotionListener,
KeyListener {
public abstract void draw(final Graphics g);
public abstract IControl invoke();
}
package org.loon.simple.avg; import java.awt.Graphics; import java.awt.event.KeyListener; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; /** * Copyright 2008 - 2009 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed . an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loonframework * @author chenpeng * @email:[email]ceponline@yahoo.com.cn[/email] * @version 0.1 */ public interface IControl extends MouseListener, MouseMotionListener, KeyListener { public abstract void draw(final Graphics g); public abstract IControl invoke(); }
而后,再构造一个接口,命名为IAVG,同样继承鼠标及键盘监听,并在其中设定三个抽象方法,用以操作IControl接口:
view plaincopy to clipboardprint?package org.loon.simple.avg;
import java.awt.Graphics;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
/**
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email:[email]ceponline@yahoo.com.cn[/email]
* @version 0.1
*/
public interface IAVG extends MouseListener, MouseMotionListener,
KeyListener {
public abstract void draw(final Graphics g);
public abstract IControl getControl();
public abstract void setControl(final IControl control);
}
package org.loon.simple.avg; import java.awt.Graphics; import java.awt.event.KeyListener; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; /** * Copyright 2008 - 2009 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed . an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loonframework * @author chenpeng * @email:[email]ceponline@yahoo.com.cn[/email] * @version 0.1 */ public interface IAVG extends MouseListener, MouseMotionListener, KeyListener { public abstract void draw(final Graphics g); public abstract IControl getControl(); public abstract void setControl(final IControl control); }
再后,制作一个显示图像用组件,命名为AVGCanva,继承自Canvas。
view plaincopy to clipboardprint?package org.loon.simple.avg;
import java.awt.Canvas;
import java.awt.Graphics;
/**
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email:[email]ceponline@yahoo.com.cn[/email]
* @version 0.1
*/
public class AVGCanvas extends Canvas {
/**
*
*/
private static final long serialVersionUID = 1982278682597393958L;
private boolean start;
private IAVG avg;
public AVGCanvas(IAVG handler) {
this.avg = handler;
this.start = false;
this.addKeyListener(handler);
this.addMouseListener(handler);
this.addMouseMotionListener(handler);
}
public void update(Graphics g) {
paint(g);
}
public void paint(Graphics g) {
if (this.start) {
this.avg.draw(g);
}
}
public void startPaint() {
this.start = true;
}
public void endPaint() {
this.start = false;
}
}
package org.loon.simple.avg; import java.awt.Canvas; import java.awt.Graphics; /** * Copyright 2008 - 2009 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed . an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loonframework * @author chenpeng * @email:[email]ceponline@yahoo.com.cn[/email] * @version 0.1 */ public class AVGCanvas extends Canvas { /** * */ private static final long serialVersionUID = 1982278682597393958L; private boolean start; private IAVG avg; public AVGCanvas(IAVG handler) { this.avg = handler; this.start = false; this.addKeyListener(handler); this.addMouseListener(handler); this.addMouseMotionListener(handler); } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { if (this.start) { this.avg.draw(g); } } public void startPaint() { this.start = true; } public void endPaint() { this.start = false; } }
这段代码中的paint方法中并没有现成的方法,而是调用了IAVG接口的draw。紧接着,我们再设定一个AVGFrame用以加载AVGCanvas。
view plaincopy to clipboardprint?package org.loon.simple.avg;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/**
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email:[email]ceponline@yahoo.com.cn[/email]
* @version 0.1
*/
public class AVGFrame extends Frame implements Runnable {
/**
*
*/
private static final long serialVersionUID = 198284399945549558L;
private IAVG avg;
private AVGCanvas canvas;
private boolean fps;
private String titleName;
private Thread mainLoop;
public AVGFrame(String titleName, int width, int height) {
this(new AVG(), titleName, width, height);
}
public AVGFrame(IAVG avg, String titleName, int width, int height) {
super(titleName);
Lib.WIDTH = width;
Lib.HEIGHT = height;
this.avg = avg;
this.titleName = titleName;
this.addKeyListener(avg);
this.setPreferredSize(new Dimension(width + 5, height + 25));
this.initCanvas(Lib.WIDTH, Lib.HEIGHT);
this.pack();
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
this.setResizable(false);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public void run() {
gameLoop();
}
/**
* 开始循环窗体图像
*
*/
private synchronized void gameLoop() {
canvas.startPaint();
long second = 0L;
int moveCount = 0;
// 循环绘制
for (;;) {
long start = System.currentTimeMillis();
this.paintScreen();
long end = System.currentTimeMillis();
long time = end - start;
long sleepTime = 20L - time;
if (sleepTime < 0L)
sleepTime = 0L;
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (this.fps) {
moveCount++;
second += System.currentTimeMillis() - start;
if (second >= 1000L) {
this.setTitle(new StringBuilder(titleName).append(" FPS:")
.append(moveCount).toString());
moveCount = 0;
second = 0L;
}
}
}
}
/**
* 启动游戏循环
*
*/
public void mainLoop() {
this.mainLoop = new Thread(this);
this.mainLoop.start();
}
/**
* 初始化背景帆布
*
* @param width
* @param height
*/
private void initCanvas(final int width, final int height) {
canvas = new AVGCanvas(avg);
canvas.setBackground(Color.black);
canvas.setPreferredSize(new Dimension(width, height));
this.add(canvas);
}
public IAVG getAVG() {
return this.avg;
}
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
}
public synchronized void paintScreen() {
canvas.repaint();
}
public boolean isShowFPS() {
return fps;
}
public void setShowFPS(boolean fps) {
this.fps = fps;
}
public Thread getMainLoop() {
return mainLoop;
}
public String getTitleName() {
return titleName;
}
}
package org.loon.simple.avg; import java.awt.Color; import java.awt.Dimension; import java.awt.Frame; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; /** * Copyright 2008 - 2009 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed . an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loonframework * @author chenpeng * @email:[email]ceponline@yahoo.com.cn[/email] * @version 0.1 */ public class AVGFrame extends Frame implements Runnable { /** * */ private static final long serialVersionUID = 198284399945549558L; private IAVG avg; private AVGCanvas canvas; private boolean fps; private String titleName; private Thread mainLoop; public AVGFrame(String titleName, int width, int height) { this(new AVG(), titleName, width, height); } public AVGFrame(IAVG avg, String titleName, int width, int height) { super(titleName); Lib.WIDTH = width; Lib.HEIGHT = height; this.avg = avg; this.titleName = titleName; this.addKeyListener(avg); this.setPreferredSize(new Dimension(width + 5, height + 25)); this.initCanvas(Lib.WIDTH, Lib.HEIGHT); this.pack(); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); this.setResizable(false); this.setLocationRelativeTo(null); this.setVisible(true); } public void run() { gameLoop(); } /** * 开始循环窗体图像 * */ private synchronized void gameLoop() { canvas.startPaint(); long second = 0L; int moveCount = 0; // 循环绘制 for (;;) { long start = System.currentTimeMillis(); this.paintScreen(); long end = System.currentTimeMillis(); long time = end - start; long sleepTime = 20L - time; if (sleepTime < 0L) sleepTime = 0L; try { Thread.sleep(sleepTime); } catch (InterruptedException e) { e.printStackTrace(); } if (this.fps) { moveCount++; second += System.currentTimeMillis() - start; if (second >= 1000L) { this.setTitle(new StringBuilder(titleName).append(" FPS:") .append(moveCount).toString()); moveCount = 0; second = 0L; } } } } /** * 启动游戏循环 * */ public void mainLoop() { this.mainLoop = new Thread(this); this.mainLoop.start(); } /** * 初始化背景帆布 * * @param width * @param height */ private void initCanvas(final int width, final int height) { canvas = new AVGCanvas(avg); canvas.setBackground(Color.black); canvas.setPreferredSize(new Dimension(width, height)); this.add(canvas); } public IAVG getAVG() { return this.avg; } protected void processWindowEvent(WindowEvent e) { super.processWindowEvent(e); } public synchronized void paintScreen() { canvas.repaint(); } public boolean isShowFPS() { return fps; } public void setShowFPS(boolean fps) { this.fps = fps; } public Thread getMainLoop() { return mainLoop; } public String getTitleName() { return titleName; } }
我们可以看到,在本例鼠标键盘事件及图像绘制完全通过接口方式实现。此时,只要让不同组件统一实现IControl接口,便可以轻松转换事件及图像的绘制。也正是我们都再熟悉不过的MVC模式中,通过Event导致Controller改变Model及View的基本原理。
下一回,我们将具体讲解一个AVG游戏实现的基本流程。
示例代码界面如下图:
、
示例程序下载地址:http://download.csdn.net/source/999273(源码在jar内)
相关文章推荐
- Java版AVG游戏开发入门[0]——游戏模式转换中的事件交互
- Java版AVG游戏开发入门[0]——游戏模式转换中的事件交互
- Java版AVG游戏开发入门示例[3]——脚本引擎的制作及应用 推荐
- Java版SLG游戏开发入门[0]--让绘制的窗口响应鼠标事件 推荐
- Java版AVG游戏开发入门[1] —— CG的绘制 推荐
- Win8应用开发 入门篇(三) UX交互导航模式
- JAVA游戏入门开发DAY 4 添加主角
- 【UNITY3D 游戏开发之八】Unity编译到iPhone运行 Collider 无法正常触发事件解决方案 推荐
- Android开发之Java设计模式入门篇
- Java版SLG游戏开发入门[0]--让绘制的窗口响应鼠标事件
- H5游戏开发:游戏引擎入门推荐
- 人生如梦游戏间,RPG游戏开源开发讲座(JAVA篇)[1]——风云初现 推荐
- Java开发中的23种设计模式详解(推荐)
- Java版AVG游戏开发入门示例[3]——脚本引擎的制作及应用
- JAVA游戏编程之三----j2se 手机游戏入门开发--俄罗斯方块_1
- 基于HTML5+WebSocket+JAVA的棋牌游戏开发,从入门到放弃(三)
- JAVA游戏入门开发DAY 1
- JAVA游戏入门开发DAY 3 接收用户输入
- 用swing开发 震撼的CSDN用户关系图(转)和基于JMF的java rpg入门游戏
- 基于Java的移动游戏开发入门-Java基础-Java-编程开发