`
javasee
  • 浏览: 965308 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Java版SLG游戏开发入门[0]--让绘制的窗口响应鼠标事件

阅读更多
什么是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的状态下是无法完整的显示在窗体中的。

可我们明明见到很多游戏中的光标是不规则不成比例的,究竟如何做到呢?其实很简单,自己绘制就好了。

绝大多数不合规矩的东西,我们都可以自己把它“画出来”,只要能确定它的坐标。

如下代码记录了键盘及鼠标状态下的图标移动:
  1. /**
  2. *键盘事件设置
  3. *
  4. */
  5. publicvoidsetKeyset(){
  6. addKeyListener(newKeyAdapter(){
  7. publicvoidkeyTyped(KeyEvente){
  8. }
  9. publicvoidkeyReleased(KeyEvente){
  10. }
  11. publicvoidkeyPressed(KeyEvente){
  12. if(e.getKeyCode()==KeyEvent.VK_RIGHT){
  13. currentX=currentX+move;
  14. }
  15. if(e.getKeyCode()==KeyEvent.VK_LEFT){
  16. currentX=currentX-move;
  17. }
  18. if(e.getKeyCode()==KeyEvent.VK_UP){
  19. currentY=currentY-move;
  20. }
  21. if(e.getKeyCode()==KeyEvent.VK_DOWN){
  22. currentY=currentY+move;
  23. }
  24. repaint();
  25. }
  26. });
  27. }
  28. /**
  29. *鼠标事件设置
  30. *
  31. */
  32. publicvoidsetMouse(){
  33. addMouseListener(newMouseAdapter(){
  34. publicvoidmousePressed(MouseEvente){
  35. }
  36. publicvoidmouseReleased(MouseEvente){
  37. }
  38. });
  39. addMouseMotionListener(newMouseMotionAdapter(){
  40. publicvoidmouseMoved(MouseEventex){
  41. currentX=ex.getX();
  42. currentY=ex.getY();
  43. repaint();
  44. }
  45. publicvoidmouseDragged(MouseEventex){
  46. currentX=ex.getX();
  47. currentY=ex.getY();
  48. repaint();
  49. }
  50. });
  51. }
此时,我们只需将光标在指定位置drawImage一下,自然就会得到想要的结果。但是有一点需要注意,那就是系统的Cursor此时还存在,如果我们不进行处理,画面上会出现两个游标的尴尬局面。但是Java并没有提供给我们直接取消光标的方法,这时该怎么办呢?很简单,我们将其“隐形”即可。

比如这样:
  1. CursorFramef=newCursorFrame();
  2. int[]pixels=newint[256];
  3. Imageimage=Toolkit.getDefaultToolkit().createImage(
  4. newMemoryImageSource(16,16,pixels,0,16));
  5. CursortransparentCursor= Toolkit.getDefaultToolkit()
  6. .createCustomCursor(image,newPoint(0,0),"hidden");
  7. f.setCursor(transparentCursor);

我们绘制一张16x16的透明图作为游标,在使用者看来,就只能见到我们drawImage出的“伪游标”罢了。

现在我们据此制作一个假单的仿Langrisser2开始界面,代码如下:
  1. packageorg.slg.simple;
  2. importjava.awt.Color;
  3. importjava.awt.Cursor;
  4. importjava.awt.Graphics;
  5. importjava.awt.Graphics2D;
  6. importjava.awt.Image;
  7. importjava.awt.Panel;
  8. importjava.awt.Point;
  9. importjava.awt.Toolkit;
  10. importjava.awt.event.KeyAdapter;
  11. importjava.awt.event.KeyEvent;
  12. importjava.awt.event.MouseAdapter;
  13. importjava.awt.event.MouseEvent;
  14. importjava.awt.event.MouseMotionAdapter;
  15. importjava.awt.image.BufferedImage;
  16. importjava.awt.image.MemoryImageSource;
  17. /**
  18. *Copyright2008
  19. *
  20. *LicensedundertheApacheLicense,Version2.0(the"License");youmaynot
  21. *usethisfileexceptincompliancewiththeLicense.Youmayobtainacopyof
  22. *theLicenseat
  23. *
  24. *http://www.apache.org/licenses/LICENSE-2.0
  25. *
  26. *Unlessrequiredbyapplicablelaworagreedtoinwriting,software
  27. *distributedundertheLicenseisdistributedonan"ASIS"BASIS,WITHOUT
  28. *WARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.Seethe
  29. *Licenseforthespecificlanguagegoverningpermissionsandlimitationsunder
  30. *theLicense.
  31. *
  32. *@projectloonframework
  33. *@authorchenpeng
  34. *@email:ceponline@yahoo.com.cn
  35. *@version0.1
  36. */
  37. publicclassExemplePanelextendsPanel{
  38. /**
  39. *
  40. */
  41. privatestaticfinallongserialVersionUID=1L;
  42. finalstaticintcurrentWidth=480;
  43. finalstaticintcurrentHeight=360;
  44. //背景缓冲图
  45. finalImage_background;
  46. //鼠标指针图形组
  47. finalImage[]_mouses;
  48. //背景图
  49. finalImage_backgroundImage;
  50. Graphics_backgroundGraphics;
  51. Image_mouse;
  52. Image_arrow;
  53. //选中项,默认指向第一条
  54. int_select=1;
  55. //游标x轴
  56. int_currentX=0;
  57. //游标y轴
  58. int_currentY=0;
  59. int_move=5;
  60. publicExemplePanel(){
  61. //创建一个背景缓存用image
  62. _background=newBufferedImage(currentWidth,currentHeight,
  63. BufferedImage.TYPE_INT_ARGB);
  64. //导入开始时背景图像
  65. _backgroundImage=Utility.loadImage("image/start.gif");
  66. //导入光标图系列,以列宽46读取到image数组
  67. _mouses=Utility.getImageColumns(
  68. Utility.loadImage("image/cursor.png"),46);
  69. //初始背景为黑色
  70. setBackground(newColor(0,0,0));
  71. _arrow=Utility.loadImage("image/arrow.png");
  72. _backgroundGraphics=_background.getGraphics();
  73. //设定键盘监听
  74. setKeyset();
  75. //设定鼠标监听
  76. setMouse();
  77. //设置鼠标动画(本例只是一个简单示例,实际应根据相应事件变更游标造型)
  78. ThreadmouseAnimation=newThread(){
  79. publicvoidrun(){
  80. intcursorMax=_mouses.length;
  81. intcursorIndex=0;
  82. do{
  83. if(cursorIndex<cursorMax){
  84. _mouse=_mouses[cursorIndex];
  85. try{
  86. Thread.sleep(500);
  87. }catch(InterruptedExceptione){
  88. e.printStackTrace();
  89. }
  90. repaint();
  91. }else{
  92. cursorIndex=0;
  93. }
  94. cursorIndex++;
  95. }while(true);
  96. }
  97. };
  98. //开启鼠标动画
  99. mouseAnimation.start();
  100. }
  101. publicvoidpaint(Graphicsg){
  102. //绘制背景
  103. _backgroundGraphics.drawImage(_backgroundImage,0,0,this);
  104. //绘制光标
  105. _backgroundGraphics.drawImage(_mouse,_currentX,_currentY,this);
  106. drawTitle((Graphics2D)_backgroundGraphics);
  107. //加载缓存图
  108. g.drawImage(_background,0,0,this);
  109. }
  110. publicvoidupdate(Graphicsg){
  111. paint(g);
  112. }
  113. /**
  114. *键盘事件设置
  115. *
  116. */
  117. publicvoidsetKeyset(){
  118. addKeyListener(newKeyAdapter(){
  119. publicvoidkeyTyped(KeyEvente){
  120. }
  121. publicvoidkeyReleased(KeyEvente){
  122. }
  123. publicvoidkeyPressed(KeyEvente){
  124. if(e.getKeyCode()==KeyEvent.VK_RIGHT){
  125. _currentX=_currentX+_move;
  126. }
  127. if(e.getKeyCode()==KeyEvent.VK_LEFT){
  128. _currentX=_currentX-_move;
  129. }
  130. if(e.getKeyCode()==KeyEvent.VK_UP){
  131. _currentY=_currentY-_move;
  132. }
  133. if(e.getKeyCode()==KeyEvent.VK_DOWN){
  134. _currentY=_currentY+_move;
  135. }
  136. repaint();
  137. }
  138. });
  139. }
  140. /**
  141. *鼠标事件设置
  142. *
  143. */
  144. publicvoidsetMouse(){
  145. int[]pixels=newint[256];
  146. Imageimage=Toolkit.getDefaultToolkit().createImage(
  147. newMemoryImageSource(16,16,pixels,0,16));
  148. //制作一个透明的游标
  149. CursortransparentCursor=Toolkit.getDefaultToolkit()
  150. .createCustomCursor(image,newPoint(0,0),"hidden");
  151. //插入透明游标,以此模拟无游标状态
  152. setCursor(transparentCursor);
  153. addMouseListener(newMouseAdapter(){
  154. publicvoidmousePressed(MouseEvente){
  155. if(e.getButton()==1){
  156. State.l_clk=true;
  157. }
  158. if(e.getButton()==3){
  159. State.r_clk=true;
  160. }
  161. }
  162. publicvoidmouseReleased(MouseEvente){
  163. if(e.getButton()==1){
  164. State.l_clk=false;
  165. }
  166. if(e.getButton()==3){
  167. State.r_clk=false;
  168. }
  169. }
  170. });
  171. addMouseMotionListener(newMouseMotionAdapter(){
  172. publicvoidmouseMoved(MouseEventex){
  173. _currentX=ex.getX();
  174. _currentY=ex.getY();
  175. repaint();
  176. }
  177. publicvoidmouseDragged(MouseEventex){
  178. _currentX=ex.getX();
  179. _currentY=ex.getY();
  180. repaint();
  181. }
  182. });
  183. }
  184. /**
  185. *绘制标题选项
  186. *
  187. *@paramg
  188. */
  189. voiddrawTitle(Graphics2Dg){
  190. Utility.font(g,15,1);
  191. Utility.color(g,0,0,0);
  192. if(_select!=0){
  193. g.drawImage(_arrow,168,227+_select*20,null);
  194. }
  195. //PS:如果不想在程序中绘制,也可以直接在准备好的背景图上写文字,pc版的Langrisser就是那样......
  196. g.drawString("开始新游戏",195,260);
  197. g.drawString("载入记录",203,280);
  198. g.drawString("退出游戏",203,300);
  199. for(inti=0;i<3;i++){
  200. if(_currentX>195&&_currentX<270&&_currentY>i*20+235
  201. &&_currentY<i*20+275){
  202. _select=i+1;
  203. }
  204. }
  205. repaint();
  206. Utility.wait(20);
  207. if(State.l_clk&&!State.lock_lck){
  208. State.lock_lck=true;
  209. if(_select==1){
  210. System.out.println("您选择了:开始");
  211. }
  212. if(_select==2){
  213. System.out.println("您选择了:继续");
  214. }
  215. if(_select==3){
  216. System.out.println("您选择了:结束");
  217. System.exit(0);
  218. }
  219. }
  220. if(!State.l_clk&&State.lock_lck){
  221. State.lock_lck=false;
  222. }
  223. }
  224. }

运行效果如下图:




当您看见此行文字时,我的CSDN上传功能还无法使用……


分享到:
评论

相关推荐

    Java下SLG游戏开发入门0

    关于绘制光标及绘制窗体响应鼠标事件的示例

    SLG游戏用例Java版

    这是一个自制的SLG的Java PC游戏用例,本利仅为游戏本身,源码将随blog更新发布,当然有兴趣的允许反编译,未加密。

    JavaSLG游戏开发入门示例及源码

    JavaSLG游戏开发入门示例及其源码(源码在jar内)

    SLG 游戏源码测试

    LGame是一个轻量级的游戏开发框架,它允许开发者使用Java语言进行游戏开发,而J2SE则是Java标准版,适用于桌面应用。当我们将一个J2SE项目移植到Android时,需要考虑到Android系统的特性和API差异。 首先,我们需要...

    Python库 | slg-dev-ops-1.6.2.tar.gz

    "slg-dev-ops-1.6.2.tar.gz" 是一个针对Python开发者的库,其版本号为1.6.2。这个压缩包文件很可能包含了源代码、文档和其他相关资源,供用户在自己的项目中集成和使用。下面将详细讨论Python库、开发语言Python以及...

    游戏策划入门--先学游戏GM.rar

    游戏策划是游戏开发的核心环节,它涉及到游戏设计的方方面面,包括但不限于故事背景、角色设定、关卡设计、游戏机制、用户界面以及经济系统等。在这个压缩包“游戏策划入门--先学游戏GM.rar”中,我们可以找到一份名...

    PyPI 官网下载 | slg-dev-ops-1.0.4.tar.gz

    《PyPI官网下载:slg-dev-ops-1.0.4.tar.gz——探索Python库的发布与使用》 在Python的世界里,PyPI(Python Package Index)是开发者们分享和下载开源软件包的主要平台。它为全球的Python开发者提供了一个便捷的...

    Python库 | slg-dev-ops-1.4.1.tar.gz

    《Python库slg-dev-ops-1.4.1详解》 在信息技术领域,Python作为一门强大而易学的编程语言,受到了广大开发者们的热烈欢迎。它的生态系统中有大量的库,这些库极大地丰富了Python的功能,使得开发工作变得更加高效...

    J2ME中的SLG游戏示例代码

    这个“J2ME中的SLG游戏示例代码”提供了使用J2ME开发策略类游戏(Strategy Game,简称SLG)的基础示例。SLG游戏通常涉及复杂的决策制定和资源管理,例如《文明》系列或《三国志》等经典游戏。通过研究这些源代码,...

    PyPI 官网下载 | slg_dev_ops-1.6.4-py3-none-any.whl

    《PyPI官网下载:slg_dev_ops-1.6.4-py3-none-any.whl——深入了解Python库的发布与安装》 PyPI(Python Package Index),是Python开发者们分享和下载开源软件包的主要平台。它为全球的Python社区提供了一个集中化...

    slg.rar_game slg_j2me_j2me 游戏_slg_游戏 j2me

    在这个名为"slg.rar"的压缩包中,我们找到了一个基于J2ME(Java 2 Micro Edition)平台开发的SLG游戏范例。J2ME是Java平台的一个子集,专门用于嵌入式设备,如早期的移动电话和掌上电脑,用于开发移动应用和游戏。 ...

    Python库 | slg-dev-ops-1.12.1.tar.gz

    "slg-dev-ops-1.12.1.tar.gz" 是一个针对Python开发者的库,版本号为1.12.1。这个压缩包包含了名为 "slg-dev-ops-1.12.1" 的子目录或文件,很可能是一个Python项目或者工具集。在Python的世界里,库是开发者用来扩展...

    J2ME中的SLG游戏

    在J2ME平台上开发SLG游戏,意味着这款游戏是为移动设备,如早期的诺基亚、摩托罗拉等手机设计的,使用Java Micro Edition(J2ME)技术栈。J2ME是一种轻量级的Java平台,用于嵌入式系统,如移动电话和数字电视。 ...

    android游戏开发入门级经典实例

    "android游戏开发入门级经典实例"这个主题旨在为初学者提供简单易懂的游戏开发实践,帮助他们快速进入Android游戏开发的世界。虽然这个实例集要求学习者具备一定的J2SE(Java 2 Platform, Standard Edition)基础,...

    SLG源码博客使用

    在IT行业中,SLG源码可能是用于开发策略类游戏的代码库或者框架。"SLG源码博客使用"这个标题暗示了这是一个关于如何在实际项目中应用或学习SLG游戏开发的教程或案例。 描述中的"cping1982写的slg例子"表明这是一位...

    Python库 | slg-dev-ops-1.17.11.tar.gz

    资源分类:Python库 所属语言:Python 资源全名:slg-dev-ops-1.17.11.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059

    slg游戏之多人对战版

    简陋版已经完成,提供下载 但是因为只是想学习一下如何做网络游戏,简单实现下功能而已,而且是在原来代码上改的,可以说代码写的乱七八糟, 如果想看一看,AS和JAVA如何通信的话,可以参照一下,如果想学习的话,就...

    C语言小游戏开发

    ### C语言小游戏开发知识点详解 #### 一、创建角色 在C语言中开发小游戏的第一步是创建游戏中的角色。这通常涉及到使用基本的输入输出功能以及屏幕操作。 **知识点1:基本的C语言编程环境设置** - **开发工具选择...

Global site tag (gtag.js) - Google Analytics