2019独角兽企业重金招聘Python工程师标准>>>
之前用过Android,Python的pygame,c#编程语言开发过游戏,一般来说,Java开发的游戏通常是AVG(英文adwenture game的简称)冒险游戏。
就技术角度而言,使用Java 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 plain copy to clipboard print ?
- 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
- *
- * [url]http://www.apache.org/licenses/LICENSE-2.0[/url]
- *
- * 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:ceponline@yahoo.com.cn
- * @version 0.1
- */
- public interface IControl extends MouseListener, MouseMotionListener,
- KeyListener {
- public abstract void draw(final Graphics g);
- public abstract IControl invoke();
- }
而后,再构造一个接口,命名为IAVG,同样继承鼠标及键盘监听,并在其中设定三个抽象方法,用以操作IControl接口:
view plain copy to clipboard print ?
- 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
- *
- * [url]http://www.apache.org/licenses/LICENSE-2.0[/url]
- *
- * 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:ceponline@yahoo.com.cn
- * @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 plain copy to clipboard print ?
- 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
- *
- * [url]http://www.apache.org/licenses/LICENSE-2.0[/url]
- *
- * 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:ceponline@yahoo.com.cn
- * @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 plain copy to clipboard print ?
- 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
- *
- * [url]http://www.apache.org/licenses/LICENSE-2.0[/url]
- *
- * 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:ceponline@yahoo.com.cn
- * @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 的基本原理。
例子 图下:
end,游戏编程语言之间的开发可以融会贯通