Java版AVG游戏开发入门[1] —— CG的绘制
<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->
<!--[if gte mso 10]> <mce:style><! /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} --> <!--[endif]-->作为Adventure Game,AVG的图文部分向来便是整个游戏的核心之一,所以本回将以图像绘制为中心讲解AVG的CG生成问题。(CG,即Computer Graphics,直译可称[计算机图形],此处以其为AVG开发中图形部分的代称)。
在小时候,我们或许会被AVG游戏的华丽特效所折服。但现在,我们都知道完成那些不过是程序员的最基本能力罢了,即使不是专业的游戏开发者,也可以轻易做到。
众所周知,Java中图像绘制是非常容易的事情,无论您是通过ImageIO、ImageIcon或Toolkit.getDefaultToolkit().createImage乃至其他方式取得Image(或BufferedImage),处理的方式都完全相同的,即通过Graphics。
Graphics是一个抽象类,因此通常需要Image来引入其实例。
在Java AWT相关包内,Graphics的基本用法如下所示。
<!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:PunctuationKerning /> <w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing> <w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery> <w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery> <w:ValidateAgainstSchemas /> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:Compatibility> <w:SpaceForUL /> <w:BalanceSingleByteDoubleByteWidth /> <w:DoNotLeaveBackslashAlone /> <w:ULTrailSpace /> <w:DoNotExpandShiftReturn /> <w:AdjustLineHeightInTable /> <w:BreakWrappedTables /> <w:SnapToGridInCell /> <w:WrapTextWithPunct /> <w:UseAsianBreakRules /> <w:DontGrowAutofit /> <w:UseFELayout /> </w:Compatibility> <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" LatentStyleCount="156"> </w:LatentStyles> </xml><![endif]--><!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} --><!--[if gte mso 10]> <mce:style><! /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} --> <!--[endif]-->
Public void paint(Graphics g){ //设定颜色 g.setColor(…); //设定字体 g.setFont(…); //绘制文本 g.drawString(…); //绘制线段 g.drawLine(…); //绘制矩形 g.drawRect(…); //填充矩形 g.fillRect(…); //绘制椭圆 g.drawOval(…); //填充椭圆 g.fillOval(…); //绘制多边形 g.drawPolygon(…); //填充多边形 g.fillPolygon(…); //显示图像 g.drawImage(…); //其它请参考相关文档 //… }
但是,对于一些高级效果,则需要通过Graphics2D解决。
Graphics2D同样是一个抽象类, 继承自Graphics ,并且扩展了 Graphics,提供了对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制。它是用于在Java平台上呈现二维形状、文本和图像高级特性的基础类。
由于Graphics2D是Graphics的子类,故此可以直接转换Graphics获得。
在Java AWT相关包内,Graphics2D的基本用法如下所示。
Public void paint(Graphics g){ //获得Graphics2D实例 Graphics2D g2d = (Graphics2D) g; //原Graphics部分 //设定颜色 g2d.setColor(…); //设定字体 g2d.setFont(…); //绘制文本 g2d.drawString(…); //绘制线段 g2d.drawLine(…); //绘制矩形 g2d.drawRect(…); //填充矩形 g2d.fillRect(…); //绘制椭圆 g2d.drawOval(…); //填充椭圆 g2d.fillOval(…); //绘制多边形 g2d.drawPolygon(…); //填充多边形 g2d.fillPolygon(…); //显示图像 g2d drawImage(…); //Graphics2D部分新增功能 //设置Paint g2d.setPaint(…); //设置线条粗细 g2d.setStroke(…); //设置Composite(多用AlphaComposite) g2d.setComposite(…); //设置移动边距 g2d.translate(…); //设置刻度 g2d.scale(…); //设置旋转 g2d.rotate(…); //设置剪裁 g2d.shear(…); //设置坐标变形 g2d.setTransform(…); //创建特定Shape实例 Shape shape=new YourShape(…); //设定指定Shape g2d.draw(shape); //填充指定Shape g2d.draw(shape); //设定RenderingHints(绘图微调设定用类) g2d.setRenderingHint(…); //其它请参考相关文档 //… }
<!--[if gte mso 9]><xml> <w:WordDocument> <w:View>Normal</w:View> <w:Zoom>0</w:Zoom> <w:PunctuationKerning /> <w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing> <w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery> <w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery> <w:ValidateAgainstSchemas /> <w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid> <w:IgnoreMixedContent>false</w:IgnoreMixedContent> <w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText> <w:Compatibility> <w:SpaceForUL /> <w:BalanceSingleByteDoubleByteWidth /> <w:DoNotLeaveBackslashAlone /> <w:ULTrailSpace /> <w:DoNotExpandShiftReturn /> <w:AdjustLineHeightInTable /> <w:BreakWrappedTables /> <w:SnapToGridInCell /> <w:WrapTextWithPunct /> <w:UseAsianBreakRules /> <w:DontGrowAutofit /> <w:UseFELayout /> </w:Compatibility> <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel> </w:WordDocument> </xml><![endif]--><!--[if gte mso 9]><xml> <w:LatentStyles DefLockedState="false" LatentStyleCount="156"> </w:LatentStyles> </xml><![endif]--><!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} --><!--[if gte mso 10]> <mce:style><! /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-fareast-font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;} --> <!--[endif]-->
无论代码构建的如何复杂,Java绘图的基本流程也仅仅是Image-> Graphics->Paint罢了,只需利用一个循环的repaint函数,我们就可以无数次重复这一流程。由于在我先前其它博文中已多有涉及,故此处不再赘述。
说到底,AVG游戏中的CG产生,也无非是一次次将图像混合后展现出来,是这一流程的简单再现。
具体合成关系如下图所示:
就我个人认为,在2D的AVG中,分层仅需区别前景及背景两层即可。
原因在于,Graphics或Graphics2D在drawImage时,将顺序绘制图像,旧图会被新图所覆盖。故此,即使图像再多,也不过是在交替背景前景产生的过程,一次次覆盖,一次次交替,最终令唯一的CG被绘制到屏幕上去。
因而我们也可以得出一个AVG游戏开发的最基本概念,即图像添加时,背景图像添加应始终在前,前景图像添加需始终在后,图像的活动部分始终作为前景,而将非活动部分始终作为背景。
在本文的示例程序中,具体实现代码如下(详细请下载):
public void draw(final Graphics g) { if (sleep <= 0) { if (cg.getBackgroundCG() != null) { if (shakeNumber > 0) { graphics.drawImage(cg.getBackgroundCG(), shakeNumber / 2 - Control.rand.nextInt(shakeNumber), shakeNumber / 2 - Control.rand.nextInt(shakeNumber), null); } else { graphics.drawImage(cg.getBackgroundCG(), 0, 0, null); } } for (int i = 0; i < cg.getCharas().size(); i++) { Chara chara = (Chara) cg.getCharas().get(i); graphics.drawImage(chara.getCharacterCG(), chara.getX(), chara .getY(), null); } if (isMessage) { dialog.showDialog(dialogImage, graphics); for (int i = 0; i < stringMaxLine; i++) { graphics.setColor(Color.black); for (int j = 0; j < messages[i].length(); j++) { Utility.drawString(messages[i].substring(j, j + 1) .toString(), Lib.fontName, graphics, Lib.FONT * j + dialog.getMESSAGE_LINE_X() + 2, i * (Lib.FONT + Lib.FONT_SIZE) + Lib.FONT + 1 + dialog.getMESSAGE_LINE_Y(), 1); } if (flags[selectFlag] != -1) { graphics.setColor(Color.white); for (int j1 = 0; j1 < messages[selectFlag].length(); j1++) { Utility.drawString(messages[selectFlag].substring( j1, j1 + 1).toString(), Lib.fontName, graphics, Lib.FONT * j1 + dialog.getMESSAGE_LINE_X(), selectFlag * (Lib.FONT + Lib.FONT_SIZE) + Lib.FONT + dialog.getMESSAGE_LINE_Y(), 1); } dialog.showDialog(selectFlag, Lib.FONT, Lib.FONT_SIZE, dialogImage, graphics); } if (flags[i] == -1) { graphics.setColor(Color.white); } else { graphics.setColor(Color.gray); } for (int count = 0; count < messages[i].length(); count++) { Utility.drawString(messages[i].substring(count, count + 1).toString(), Lib.fontName, graphics, Lib.FONT * count + dialog.getMESSAGE_LINE_X(), i * (Lib.FONT + Lib.FONT_SIZE) + Lib.FONT + dialog.getMESSAGE_LINE_Y(), 1); } } } } else { sleep--; if (color != null) { graphics.setColor(color); graphics.fillRect(0, 0, Lib.WIDTH, Lib.HEIGHT); Utility.wait(20); } } // 设置背景 g.drawImage(screen, 0, 0, null); g.dispose(); }
下一次,我们将开始讲解AVG的剧情发展及脚本定制。
示例代码界面如下图:
、
示例程序下载地址:http://download.****.net/source/999273(源码在jar内)