什么是SLG呢?也就是Simulation Game的缩写,即模拟策略游戏。
以我这种准骨灰级玩家的视点来看(鄙人88年开始玩FC,时年6岁),早期的SLG游戏,大体只是《三国志》(I由1985年开始发售)这类发布指令扩充军备并战斗的“命令下达式游戏”,并没有什么分类上的难度。但自从《火焰纹章》(1990年开始发售)出现伊始,即策略游戏与传统RPG的分野变得模糊起来,这种具有故事情节的战棋策略游戏,同时兼具了SLG及RPG的双特性,以后的岁月中人们习惯分类其为——SRPG,火焰系列也据此被后人视作SRPG的鼻祖游戏之一。但事实上讲,此类游戏仍旧具备着传统SLG那样如同下棋般战斗并采用回合制的特点,RPG的情节部分仅仅是作为游戏内容的补充罢了,始终摆脱不掉传统策略游戏地图-〉指令-〉战斗的大框架,故此客观上依然应被划入了SLG范围。再后来,随着电脑的普及,如大众软件这些媒体杂志又把文明和模拟城市乃至美少女梦工厂这样的游戏也划分进SLG里,但按照现在的说法,足球经理、模拟人生应该是“SIM”,即单纯的Simulation,而美少女梦工厂则是TCG——不过在日式游戏划分中,这些依然都属于SLG。
就鄙人看来,强分策略类游戏类型是没有什么意义的,作为最初源泉的SLG是能够包含SRPG、RTS种种分支的。就好比有的人是博士、有的人是硕士,但我们依旧可以将其统称为“知识分子”,划到一个大圈子里面去。又比如我们平时可能常说“上海人怎样”、“北京人如何”,但当我说“中国人”时,自然能够将这些都包罗其中,无论好坏,谁都脱身不得。 而在此类游戏中,包含策略因素的这个大圈子的统一称谓,便是SLG无疑。
实际上,绝大多数英文站点也是将此类游戏统一丢到Simulation Game下的(包括模拟城市之类的纯SIM),并没有进行SRPG(Strategies Role Play Games)或RTS(Real-Time Strategy Game)乃至其余种种的细分。归根究底,因为这些游戏近似的因素太多,在大多数时候已经难以区分其本来面貌,“名无实,实无名”,只能一概而论了。而今有不少新生代玩家喜欢硬分游戏种类,窃以为愚了。
——————————————————————————————————————————————————————————
闲话说了不少,现在开始进入正题。在本系列中,我将结合实例尝试以Java实现典型战棋类SLG的主要功能,本文为第0节,也就是准备章节。
看过我以前写的RPG及ACT系列的朋友们,应该已对Java中2D图形绘制功能有了初步的认识,在本文中,我将阐述如何令绘制的窗体而非组件响应鼠标事件,及如何在窗体中自定义非标准大小的鼠标指针,作为本系列的预备知识。
首先,我们都知道,在Java中可以通过Cursor组件自定义游标样式,比如下图有一组取材自Langrisser2的光标图片。
在Java桌面开发中,我们可以通过分解这组图片来得到小图,以此来自定义鼠标光标。
但是有一个问题,这时无论图片原始大小如何,至多也只能是32x32大小,如果超出这个范围,则无法作为游标在窗体中完整显示。
也就是说,如上图这样46x46的大图,要么缩小显示,要么局部显示,总之46x46的状态下是无法完整的显示在窗体中的。
可我们明明见到很多游戏中的光标是不规则不成比例的,究竟如何做到呢?其实很简单,自己绘制就好了。
绝大多数不合规矩的东西,我们都可以自己把它“画出来”,只要能确定它的坐标。
如下代码记录了键盘及鼠标状态下的图标移动:
-
-
publicvoidsetKeyset(){
-
addKeyListener(newKeyAdapter(){
-
publicvoidkeyTyped(KeyEvente){
- }
-
publicvoidkeyReleased(KeyEvente){
- }
-
publicvoidkeyPressed(KeyEvente){
-
if(e.getKeyCode()==KeyEvent.VK_RIGHT){
- currentX=currentX+move;
- }
-
if(e.getKeyCode()==KeyEvent.VK_LEFT){
- currentX=currentX-move;
- }
-
if(e.getKeyCode()==KeyEvent.VK_UP){
- currentY=currentY-move;
- }
-
if(e.getKeyCode()==KeyEvent.VK_DOWN){
- currentY=currentY+move;
- }
- repaint();
- }
- });
- }
-
-
-
publicvoidsetMouse(){
-
addMouseListener(newMouseAdapter(){
-
publicvoidmousePressed(MouseEvente){
- }
-
publicvoidmouseReleased(MouseEvente){
- }
- });
-
addMouseMotionListener(newMouseMotionAdapter(){
-
publicvoidmouseMoved(MouseEventex){
- currentX=ex.getX();
- currentY=ex.getY();
- repaint();
- }
-
publicvoidmouseDragged(MouseEventex){
- currentX=ex.getX();
- currentY=ex.getY();
- repaint();
- }
- });
- }
此时,我们只需将光标在指定位置drawImage一下,自然就会得到想要的结果。但是有一点需要注意,那就是系统的Cursor此时还存在,如果我们不进行处理,画面上会出现两个游标的尴尬局面。但是Java并没有提供给我们直接取消光标的方法,这时该怎么办呢?很简单,我们将其“隐形”即可。
比如这样:
-
CursorFramef=newCursorFrame();
-
int[]pixels=newint[256];
- Imageimage=Toolkit.getDefaultToolkit().createImage(
-
newMemoryImageSource(16,16,pixels,0,16));
- CursortransparentCursor= Toolkit.getDefaultToolkit()
-
.createCustomCursor(image,newPoint(0,0),"hidden");
- f.setCursor(transparentCursor);
我们绘制一张16x16的透明图作为游标,在使用者看来,就只能见到我们drawImage出的“伪游标”罢了。
现在我们据此制作一个假单的仿Langrisser2开始界面,代码如下:
-
packageorg.slg.simple;
-
importjava.awt.Color;
-
importjava.awt.Cursor;
-
importjava.awt.Graphics;
-
importjava.awt.Graphics2D;
-
importjava.awt.Image;
-
importjava.awt.Panel;
-
importjava.awt.Point;
-
importjava.awt.Toolkit;
-
importjava.awt.event.KeyAdapter;
-
importjava.awt.event.KeyEvent;
-
importjava.awt.event.MouseAdapter;
-
importjava.awt.event.MouseEvent;
-
importjava.awt.event.MouseMotionAdapter;
-
importjava.awt.image.BufferedImage;
-
importjava.awt.image.MemoryImageSource;
-
-
-
publicclassExemplePanelextendsPanel{
-
-
-
privatestaticfinallongserialVersionUID=1L;
-
finalstaticintcurrentWidth=480;
-
finalstaticintcurrentHeight=360;
-
-
finalImage_background;
-
-
finalImage[]_mouses;
-
-
finalImage_backgroundImage;
- Graphics_backgroundGraphics;
- Image_mouse;
- Image_arrow;
-
-
int_select=1;
-
-
int_currentX=0;
-
-
int_currentY=0;
-
int_move=5;
-
publicExemplePanel(){
-
-
_background=newBufferedImage(currentWidth,currentHeight,
- BufferedImage.TYPE_INT_ARGB);
-
-
_backgroundImage=Utility.loadImage("image/start.gif");
-
- _mouses=Utility.getImageColumns(
-
Utility.loadImage("image/cursor.png"),46);
-
-
setBackground(newColor(0,0,0));
-
_arrow=Utility.loadImage("image/arrow.png");
- _backgroundGraphics=_background.getGraphics();
-
- setKeyset();
-
- setMouse();
-
-
ThreadmouseAnimation=newThread(){
-
publicvoidrun(){
-
intcursorMax=_mouses.length;
-
intcursorIndex=0;
-
do{
-
if(cursorIndex<cursorMax){
- _mouse=_mouses[cursorIndex];
-
try{
-
Thread.sleep(500);
-
}catch(InterruptedExceptione){
- e.printStackTrace();
- }
- repaint();
-
}else{
-
cursorIndex=0;
- }
- cursorIndex++;
-
}while(true);
- }
- };
-
- mouseAnimation.start();
- }
-
publicvoidpaint(Graphicsg){
-
-
_backgroundGraphics.drawImage(_backgroundImage,0,0,this);
-
-
_backgroundGraphics.drawImage(_mouse,_currentX,_currentY,this);
- drawTitle((Graphics2D)_backgroundGraphics);
-
-
g.drawImage(_background,0,0,this);
- }
-
publicvoidupdate(Graphicsg){
- paint(g);
- }
-
-
-
publicvoidsetKeyset(){
-
addKeyListener(newKeyAdapter(){
-
publicvoidkeyTyped(KeyEvente){
- }
-
publicvoidkeyReleased(KeyEvente){
- }
-
publicvoidkeyPressed(KeyEvente){
-
if(e.getKeyCode()==KeyEvent.VK_RIGHT){
- _currentX=_currentX+_move;
- }
-
if(e.getKeyCode()==KeyEvent.VK_LEFT){
- _currentX=_currentX-_move;
- }
-
if(e.getKeyCode()==KeyEvent.VK_UP){
- _currentY=_currentY-_move;
- }
-
if(e.getKeyCode()==KeyEvent.VK_DOWN){
- _currentY=_currentY+_move;
- }
- repaint();
- }
- });
- }
-
-
-
publicvoidsetMouse(){
-
int[]pixels=newint[256];
- Imageimage=Toolkit.getDefaultToolkit().createImage(
-
newMemoryImageSource(16,16,pixels,0,16));
-
- CursortransparentCursor=Toolkit.getDefaultToolkit()
-
.createCustomCursor(image,newPoint(0,0),"hidden");
-
- setCursor(transparentCursor);
-
addMouseListener(newMouseAdapter(){
-
publicvoidmousePressed(MouseEvente){
-
if(e.getButton()==1){
-
State.l_clk=true;
- }
-
if(e.getButton()==3){
-
State.r_clk=true;
- }
- }
-
publicvoidmouseReleased(MouseEvente){
-
if(e.getButton()==1){
-
State.l_clk=false;
- }
-
if(e.getButton()==3){
-
State.r_clk=false;
- }
- }
- });
-
addMouseMotionListener(newMouseMotionAdapter(){
-
publicvoidmouseMoved(MouseEventex){
- _currentX=ex.getX();
- _currentY=ex.getY();
- repaint();
- }
-
publicvoidmouseDragged(MouseEventex){
- _currentX=ex.getX();
- _currentY=ex.getY();
- repaint();
- }
- });
- }
-
-
-
voiddrawTitle(Graphics2Dg){
-
Utility.font(g,15,1);
-
Utility.color(g,0,0,0);
-
if(_select!=0){
-
g.drawImage(_arrow,168,227+_select*20,null);
- }
-
-
g.drawString("开始新游戏",195,260);
-
g.drawString("载入记录",203,280);
-
g.drawString("退出游戏",203,300);
-
for(inti=0;i<3;i++){
-
if(_currentX>195&&_currentX<270&&_currentY>i*20+235
-
&&_currentY<i*20+275){
-
_select=i+1;
- }
- }
- repaint();
-
Utility.wait(20);
-
if(State.l_clk&&!State.lock_lck){
-
State.lock_lck=true;
-
if(_select==1){
-
System.out.println("您选择了:开始");
- }
-
if(_select==2){
-
System.out.println("您选择了:继续");
- }
-
if(_select==3){
-
System.out.println("您选择了:结束");
-
System.exit(0);
- }
- }
-
if(!State.l_clk&&State.lock_lck){
-
State.lock_lck=false;
- }
- }
- }
运行效果如下图:当您看见此行文字时,我的CSDN上传功能还无法使用……
分享到:
相关推荐
关于绘制光标及绘制窗体响应鼠标事件的示例
JavaSLG游戏开发入门示例及其源码(源码在jar内)
python库。 资源全名:slg-dev-ops-1.6.2.tar.gz
这是一个自制的SLG的Java PC游戏用例,本利仅为游戏本身,源码将随blog更新发布,当然有兴趣的允许反编译,未加密。
python库。 资源全名:slg-dev-ops-1.12.1.tar.gz
python库。 资源全名:slg-dev-ops-1.4.1.tar.gz
资源来自pypi官网。 资源全名:slg-dev-ops-1.0.4.tar.gz
资源来自pypi官网。 资源全名:slg_dev_ops-1.6.4-py3-none-any.whl
资源分类:Python库 所属语言:Python 资源全名:slg-dev-ops-1.17.11.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
一个J2ME SLG游戏范例,是学习SLG游戏编程的好例子,一定会收获不少 !
J2ME中的SLG游戏示例代码,SLG战略实现 时间 2005年4月14日16:44 李波 小图模式 1:光标移动OK 2:滚屏OK 3:人物动作OK 4:人物移动OK 5:移动范围限定OK 6:显示菜单OK 7:多人物模式OK ...
这是一个精简的Java版SLG入门示例(源码在jar内),仅演示了最基本的SLG游戏功能,具体请参阅博文[Java版战棋(SLG)游戏AI及寻径处理入门]。
SLG游戏类的游戏可谓“棋盘式游戏”,如三国志2、4、5,机器人大战,梦幻模拟战等都是典型的SLG游戏。该游戏的一大特点就是:走格子。移动,攻击 范围都是以格子为攻击单位。其实SLG游戏的特点远不止这些。在这里,...
LGame-J2SE版发布过的旧例子,移植到Android环境之下,源码并没有太大变动(当然,调整为触摸屏了),算是最为基础的SLG实现,移动方式为最短距离寻径。
2021-2025年中国SLG类移动游戏行业调研及可持续发展战略究报告.pdf
SLG示例源代码,基于J2ME,可以学习一下哦!
非常罕见的完整Java版SLG游戏,其中包含日文原版与笔者的反编译修正版及其源码,绝对的物超所值!
2019年中国SLG类移动游戏线上营销市场研究报告