Java版AVG游戏开发入门[0]——游戏模式转换中的事件交互

简介:
 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,继承鼠标及键盘监听,并在其中设定两个抽象方法:
 
   
  1. package org.loon.simple.avg;  
  2. import java.awt.Graphics;  
  3. import java.awt.event.KeyListener;  
  4. import java.awt.event.MouseListener;  
  5. import java.awt.event.MouseMotionListener;  
  6. /** 
  7.  * Copyright 2008 - 2009 
  8.  *  
  9.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
  10.  * use this file except in compliance with the License. You may obtain a copy of 
  11.  * the License at 
  12.  *  
  13.  * [url]http://www.apache.org/licenses/LICENSE-2.0[/url] 
  14.  *  
  15.  * Unless required by applicable law or agreed to in writing, software 
  16.  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
  17.  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
  18.  * License for the specific language governing permissions and limitations under 
  19.  * the License. 
  20.  *  
  21.  * @project loonframework 
  22.  * @author chenpeng 
  23.  * @email:[email]ceponline@yahoo.com.cn[/email] 
  24.  * @version 0.1 
  25.  */  
  26. public interface IControl extends MouseListener, MouseMotionListener,  
  27.         KeyListener {  
  28.     public abstract void draw(final Graphics g);  
  29.     public abstract IControl invoke();  
  30. }  
 
 
  而后,再构造一个接口,命名为IAVG,同样继承鼠标及键盘监听,并在其中设定三个抽象方法,用以操作IControl接口:

   
  1. package org.loon.simple.avg;  
  2. import java.awt.Graphics;  
  3. import java.awt.event.KeyListener;  
  4. import java.awt.event.MouseListener;  
  5. import java.awt.event.MouseMotionListener;  
  6. /** 
  7.  * Copyright 2008 - 2009 
  8.  *  
  9.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
  10.  * use this file except in compliance with the License. You may obtain a copy of 
  11.  * the License at 
  12.  *  
  13.  * [url]http://www.apache.org/licenses/LICENSE-2.0[/url] 
  14.  *  
  15.  * Unless required by applicable law or agreed to in writing, software 
  16.  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
  17.  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
  18.  * License for the specific language governing permissions and limitations under 
  19.  * the License. 
  20.  *  
  21.  * @project loonframework 
  22.  * @author chenpeng 
  23.  * @email:[email]ceponline@yahoo.com.cn[/email] 
  24.  * @version 0.1 
  25.  */  
  26. public interface IAVG extends MouseListener, MouseMotionListener,  
  27.         KeyListener {  
  28.     public abstract void draw(final Graphics g);  
  29.     public abstract IControl getControl();  
  30.     public abstract void setControl(final IControl control);  
  31. }   


     再后,制作一个显示图像用组件,命名为AVGCanva,继承自Canvas。
 
    
  1. package org.loon.simple.avg;  
  2. import java.awt.Canvas;  
  3. import java.awt.Graphics;  
  4. /** 
  5.  * Copyright 2008 - 2009 
  6.  *  
  7.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
  8.  * use this file except in compliance with the License. You may obtain a copy of 
  9.  * the License at 
  10.  *  
  11.  * [url]http://www.apache.org/licenses/LICENSE-2.0[/url] 
  12.  *  
  13.  * Unless required by applicable law or agreed to in writing, software 
  14.  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
  15.  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
  16.  * License for the specific language governing permissions and limitations under 
  17.  * the License. 
  18.  *  
  19.  * @project loonframework 
  20.  * @author chenpeng 
  21.  * @email:[email]ceponline@yahoo.com.cn[/email] 
  22.  * @version 0.1 
  23.  */  
  24. public class AVGCanvas extends Canvas {  
  25.     /** 
  26.      *  
  27.      */  
  28.     private static final long serialVersionUID = 1982278682597393958L;  
  29.     private boolean start;  
  30.     private IAVG avg;  
  31.     public AVGCanvas(IAVG handler) {  
  32.         this.avg = handler;  
  33.         this.start = false;  
  34.         this.addKeyListener(handler);  
  35.         this.addMouseListener(handler);  
  36.         this.addMouseMotionListener(handler);  
  37.     }  
  38.       
  39.     public void update(Graphics g) {  
  40.         paint(g);  
  41.     }  
  42.     public void paint(Graphics g) {  
  43.         if (this.start) {  
  44.             this.avg.draw(g);  
  45.         }  
  46.     }  
  47.     public void startPaint() {  
  48.         this.start = true;  
  49.     }  
  50.     public void endPaint() {  
  51.         this.start = false;  
  52.     }  
  53. }  
 
     这段代码中的paint方法中并没有现成的方法,而是调用了IAVG接口的draw。紧接着,我们再设定一个AVGFrame用以加载AVGCanvas。
 
   
  1. package org.loon.simple.avg;  
  2. import java.awt.Color;  
  3. import java.awt.Dimension;  
  4. import java.awt.Frame;  
  5. import java.awt.event.WindowAdapter;  
  6. import java.awt.event.WindowEvent;  
  7.   
  8. /** 
  9.  * Copyright 2008 - 2009 
  10.  *  
  11.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
  12.  * use this file except in compliance with the License. You may obtain a copy of 
  13.  * the License at 
  14.  *  
  15.  * [url]http://www.apache.org/licenses/LICENSE-2.0[/url] 
  16.  *  
  17.  * Unless required by applicable law or agreed to in writing, software 
  18.  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 
  19.  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
  20.  * License for the specific language governing permissions and limitations under 
  21.  * the License. 
  22.  *  
  23.  * @project loonframework 
  24.  * @author chenpeng 
  25.  * @email:[email]ceponline@yahoo.com.cn[/email] 
  26.  * @version 0.1 
  27.  */  
  28. public class AVGFrame extends Frame implements Runnable {  
  29.     /** 
  30.      *  
  31.      */  
  32.     private static final long serialVersionUID = 198284399945549558L;  
  33.     private IAVG avg;  
  34.     private AVGCanvas canvas;  
  35.     private boolean fps;  
  36.     private String titleName;  
  37.     private Thread mainLoop;  
  38.     public AVGFrame(String titleName, int width, int height) {  
  39.         this(new AVG(), titleName, width, height);  
  40.     }  
  41.     public AVGFrame(IAVG avg, String titleName, int width, int height) {  
  42.         super(titleName);  
  43.         Lib.WIDTH = width;  
  44.         Lib.HEIGHT = height;  
  45.         this.avg = avg;  
  46.         this.titleName = titleName;  
  47.         this.addKeyListener(avg);  
  48.         this.setPreferredSize(new Dimension(width + 5, height + 25));  
  49.         this.initCanvas(Lib.WIDTH, Lib.HEIGHT);  
  50.         this.pack();  
  51.         this.addWindowListener(new WindowAdapter() {  
  52.             public void windowClosing(WindowEvent e) {  
  53.                 System.exit(0);  
  54.             }  
  55.         });  
  56.         this.setResizable(false);  
  57.         this.setLocationRelativeTo(null);  
  58.         this.setVisible(true);  
  59.     }  
  60.     public void run() {  
  61.         gameLoop();  
  62.     }  
  63.     /** 
  64.      * 开始循环窗体图像 
  65.      *  
  66.      */  
  67.     private synchronized void gameLoop() {  
  68.         canvas.startPaint();  
  69.         long second = 0L;  
  70.         int moveCount = 0;  
  71.         // 循环绘制  
  72.         for (;;) {  
  73.             long start = System.currentTimeMillis();  
  74.             this.paintScreen();  
  75.             long end = System.currentTimeMillis();  
  76.             long time = end - start;  
  77.             long sleepTime = 20L - time;  
  78.             if (sleepTime < 0L)  
  79.                 sleepTime = 0L;  
  80.             try {  
  81.                 Thread.sleep(sleepTime);  
  82.             } catch (InterruptedException e) {  
  83.                 e.printStackTrace();  
  84.             }  
  85.             if (this.fps) {  
  86.                 moveCount++;  
  87.                 second += System.currentTimeMillis() - start;  
  88.                 if (second >= 1000L) {  
  89.                     this.setTitle(new StringBuilder(titleName).append(" FPS:")  
  90.                             .append(moveCount).toString());  
  91.                     moveCount = 0;  
  92.                     second = 0L;  
  93.                 }  
  94.             }  
  95.         }  
  96.     }  
  97.     /** 
  98.      * 启动游戏循环 
  99.      *  
  100.      */  
  101.     public void mainLoop() {  
  102.         this.mainLoop = new Thread(this);  
  103.         this.mainLoop.start();  
  104.     }  
  105.     /** 
  106.      * 初始化背景帆布 
  107.      *  
  108.      * @param width 
  109.      * @param height 
  110.      */  
  111.     private void initCanvas(final int width, final int height) {  
  112.         canvas = new AVGCanvas(avg);  
  113.         canvas.setBackground(Color.black);  
  114.         canvas.setPreferredSize(new Dimension(width, height));  
  115.         this.add(canvas);  
  116.     }  
  117.     public IAVG getAVG() {  
  118.         return this.avg;  
  119.     }  
  120.     protected void processWindowEvent(WindowEvent e) {  
  121.         super.processWindowEvent(e);  
  122.     }  
  123.     public synchronized void paintScreen() {  
  124.         canvas.repaint();  
  125.     }  
  126.     public boolean isShowFPS() {  
  127.         return fps;  
  128.     }  
  129.     public void setShowFPS(boolean fps) {  
  130.         this.fps = fps;  
  131.     }  
  132.     public Thread getMainLoop() {  
  133.         return mainLoop;  
  134.     }  
  135.     public String getTitleName() {  
  136.         return titleName;  
  137.     }  
  138. }  
 
  我们可以看到,在本例鼠标键盘事件及图像绘制完全通过接口方式实现。 此时,只要让不同组件统一实现IControl接口,便可以轻松转换事件及图像的绘制。也正是我们都再熟悉不过的 MVC 模式中,通过 Event 导致 Controller 改变 Model View 的基本原理。
 
   下一回,我们将具体讲解一个AVG游戏实现的基本流程。
 
  示例代码界面如下图:
 
  
 
 
 
 
  
 
  
 
  


示例程序下载地址:[url]http://download.csdn.net/source/999273[/url](源码在jar内)


本文转自 cping 51CTO博客,原文链接:http://blog.51cto.com/cping1982/129556
相关文章
|
17天前
|
Java
Java猜数字游戏
Java猜数字游戏
16 2
|
29天前
|
Java Android开发
基于Java的坦克大战游戏的设计与实现
基于Java的坦克大战游戏的设计与实现
13 0
|
6天前
|
存储 Java
模式匹配魔法:Java 21中switch语句的巨大进化
模式匹配魔法:Java 21中switch语句的巨大进化
10 0
|
6天前
|
JSON 前端开发 Java
JWT解密:探秘令牌魔法与Java的完美交互
JWT解密:探秘令牌魔法与Java的完美交互
20 0
JWT解密:探秘令牌魔法与Java的完美交互
|
20天前
|
关系型数据库 Java 开发工具
Java入门高频考查基础知识9(15问万字参考答案)
本文探讨了Spring Cloud的工作原理,包括注册中心的心跳机制、服务发现机制,以及Eureka默认的负载均衡策略。同时,概述了Spring Boot中常用的注解及其实现方式,并深入讨论了Spring事务的注解、回滚条件、传播性和隔离级别。文章还介绍了MySQL的存储引擎及其区别,特别关注了InnoDB如何实现MySQL的事务处理。此外,本文还详细探讨了MySQL索引,包括B+树的原理和设计索引的方法。最后,比较了Git和SVN的区别,并介绍了Git命令的底层原理及流程。
29 0
Java入门高频考查基础知识9(15问万字参考答案)
|
20天前
|
存储 缓存 算法
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
最重要的是保持自信和冷静。提前准备,并对自己的知识和经验有自信,这样您就能在面试中展现出最佳的表现。祝您面试顺利!Java 是一种广泛使用的面向对象编程语言,在软件开发领域有着重要的地位。Java 提供了丰富的库和强大的特性,适用于多种应用场景,包括企业应用、移动应用、嵌入式系统等。下是几个面试技巧:复习核心概念、熟悉常见问题、编码实践、项目经验准备、注意优缺点、积极参与互动、准备好问题问对方和知其所以然等,多准备最好轻松能举一反三。
46 0
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
|
20天前
|
存储 算法 JavaScript
Java入门高频考查算法逻辑基础知识3-编程篇(超详细18题1.8万字参考编程实现)
解决这类问题时,建议采取下面的步骤: 理解数学原理:确保你懂得基本的数学公式和法则,这对于制定解决方案至关重要。 优化算法:了解时间复杂度和空间复杂度,并寻找优化的机会。特别注意避免不必要的重复计算。 代码实践:多编写实践代码,并确保你的代码是高效、清晰且稳健的。 错误检查和测试:要为你的代码编写测试案例,测试标准的、边缘情况以及异常输入。 进行复杂问题简化:面对复杂的问题时,先尝试简化问题,然后逐步分析和解决。 沟通和解释:在编写代码的时候清晰地沟通你的思路,不仅要写出正确的代码,还要能向面试官解释你的
32 0
|
20天前
|
存储 Java 编译器
Java入门高频考查基础知识2(超详细28题2.5万字答案)
多态是面向对象编程中的一个重要概念,它允许不同类的对象对同一消息作出不同的响应。在具体实现上,多态允许一个父类的引用指向其子类的对象,并根据实际指向的对象的类型来调用相应的方法。在 Java 中,多态可以通过以下几种方式实现:在同一个类中,方法名相同,但形参列表不同,实现了多态。子类可以重写(覆盖)其父类的方法,实现多态。在父类引用中调用该方法时,根据实际指向的子类对象的类型来调用相应的方法实现。
38 0
|
20天前
|
编解码 算法 安全
【Java技术专题】「入门到精通系列」深入探索Java技术中常用到的六种加密技术和实现
【Java技术专题】「入门到精通系列」深入探索Java技术中常用到的六种加密技术和实现
44 0
|
29天前
|
传感器 人工智能 数据可视化
Java智慧工地监管一体化云平台APP源码 SaaS模式
高支模监测:高支模立杆及倾斜角度,高支模立杆的荷载,架体的水平位移以及模板沉降情况,当检测数据超过预警值时,实时报警。
30 2