?? 示例程序下載地址:http://download.csdn.net/source/999273(源碼在jar內)
?
?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,繼承鼠標及鍵盤監聽,并在其中設定兩個抽象方法:
?
??? 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: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接口:
??? 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: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。
?
???? 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: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。
?
??? 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: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的基本原理。
?
?? 下一回,我們將具體講解一個AVG游戲實現的基本流程。
?
? 示例代碼界面如下圖:
?
?
?
?
?
?
?
?
?
?
? 、
?
?? 示例程序下載地址:http://download.csdn.net/source/999273(源碼在jar內)
?