Java游戏编程初步.docx
- 文档编号:10044495
- 上传时间:2023-05-23
- 格式:DOCX
- 页数:21
- 大小:27.98KB
Java游戏编程初步.docx
《Java游戏编程初步.docx》由会员分享,可在线阅读,更多相关《Java游戏编程初步.docx(21页珍藏版)》请在冰点文库上搜索。
Java游戏编程初步
Java游戏编程初步
现在流行的游戏似乎都是用C或C++来开发的。
在java平台上几乎没有很大型及可玩的流行游戏。
由于java是个新生语言,他的许多特性还有待大家的发掘,但是我们不能否认Java在游戏编程方面的强大性。
本文将带领大家一步一步学习编写Java游戏。
最终打造属于自己的Java游戏。
在开始之前我们得确认你已经安装了JavaJDK,并已经安装了浏览器软件如IE。
本章是以Internet为开发对象,一步一步教大家认识Java的Thread、Applets….以及游戏编程要注意的一些方方面面并在每一小部分附上了相应的源代码以供大家参考,最后我们还会对我们的游戏程序进行指导性的提示。
在文章中我们还穿插了很多建设性的问题,让读者参与到我们的开发中来。
但是由于本章指在带领大家进入这个门槛,大部分知识并不会很详细说明,有兴趣的读者可查阅相关的资料补充。
在开始之前我们还得确认你已经知道类,继承和java语言的一些基本属性了。
基本applet
Applets是一种Web浏览器上的小程序,由于applet对系统而言绝对安全,所以它做的事比aaplication有限,但是对于客户端的程序,applets仍然是个很强大的工具。
为了浏览和运行方便,我们就以applet为开发对象。
开发Applets程序,我们得继承Applet类,并覆写必要的函数,下面几个函数控制了Web页面上的applet生成与执行。
函数作用
Init()这个函数会被自动调用,执行applet的初始化动作—包括组件在版面上的分配,你一定得覆写它
Start()每当浏览器显示applet内容时,都会调用它,让applet开启其正规工作(尤其是那些被stop()关闭的工作),调用init()之后也会调用这个函数
Stop()每当浏览器不显示内容时,都会调用它。
让applet关闭某些耗资源的工作,调用destory()之后也会调用这个函数
Destroy()浏览器将applet自网页移除之际,便会调用它,以执行”applet不再被使用”应该做的最后释放资源等动作
Paint()让你在Applet界面上进行相应的绘画动作,每次刷新时都会重画
所有的applet文件源文件名和java应用程序一样都是.java为扩展名,编译后的执行文件扩展名为.class,由于在applet中已经没有了main()函数,它是和html自动集成,所以我们要执行applet,要在html源文件中放入一特定的标签(tag),才能告诉网页如何装载并执行这个applet,这里有一点要注意,我们执行的网页必须能执行java程序。
普通Html源码格式
<HTML>
<APPLETCODE="HelloWorld.class"WIDTH=300HEIGHT=500>
</APPLET>
</HTML
<appletcode="HelloWorld.class"width=300height=500>这行即applet的执行处。
applet执行文档为="HelloWorld.class"告诉网页”applet”扩展文件为HelloWorld.class
width和height告诉浏览器这个显示的applet的大小
有关标签(tag)的说明,大家可在网上找到很多相关的说明文档。
线程
由于apllet,java应用程序的执行都和线程有关。
我们来大概了解一下线程的概念。
线程也称为轻型进程(LWP)。
每个线程只能在单个进程的作用域内活动、协作和数据交换,并且在计算资源方面非常廉价。
线程需要操作系统的支持,因此不是所有的机器都提供线程。
Java编程语言,作为相当新的一种语言,已将线程支持与语言本身合为一体,这样就对线程提供了强健的支持。
Thread类是一个具体的类,即不是抽象类,该类封装了线程的行为。
要创建一个线程,程序员必须创建一个从Thread类导出的新类。
程序员必须覆盖Thread的run()函数来完成有用的工作。
用户并不直接调用此函数;而是必须调用Thread的start()函数,该函数再调用run()。
但是使用Thread类实现线程,增加了程序的类层次,所以一般程序员都由另一个java线程接口Runnable接口来实现,Runnable接口只有一个函数run(),此函数必须由实现了此接口的类实现。
线程中有几个重要的方法是我们得了解:
Thread.start():
启动一个线程
Thread.stop():
停止一个线程
Thread.sleep(timeinmilliseconds):
暂停线程在一个等待时间内。
动画技术
自由降落动画
了解了一些基本概念后,下面我们就开始我们的实质性的工作。
我们设计一个球从屏幕顶上降落到屏幕下面,程序实现比较简单,但是这是游戏动画中不可少的一部分。
在开始之前我们来看看我们的applet开始语句。
importjava.awt.*;
importjava.applet.*;
publicclassBall
extendsAppletimplementsRunnable
{
publicvoidinit(){}
publicvoidstart(){}
publicvoidstop(){}
publicvoiddestroy(){}
publicvoidrun(){}
publicvoidpaint(Graphicsg){}
}
在开始函数中我们要新建程序的主线程,并启动这个线程。
一旦做好这些准备工作以后,当applet第一次被显示时,就会创建线程对象的一个实例,并把this对象作为建构方法的参数,之后就可以启动动画了
publicvoidstart()
{
//定义一个新的线程
Threadth=newThread(this);
//启动线程
th.start();
}
现在我们来看看线程的run方法,它在循环while(),中每隔20毫秒重画动画场景。
sleep这个方法很重要,如果在run循环中没有这部分,圆的重画动作将执行得很快,其他方法将得不到有效执行,也即我们在屏幕上将看不到球的显示。
publicvoidrun()
{
//
while(true)
{
//重画applet画面
repaint();
try
{
//暂停线程20毫秒
Thread.sleep(20);
}
catch(InterruptedExceptionex)
{
}
}
}
我们接着读下去之前,有几个问题需要回答。
你也许会问,浏览器调用Java小程序的start和stop方法吗?
run方法是如何被调用的?
情况是这样的,当浏览器启动了一个内部线程时,就相应地启动了applet的运行。
当网页显示时,就启动了applet的start方法。
Start方法创建一个线程对象,并把applet自身传送给线程,以实现run方法。
此时,两个线程在运行:
由浏览器启动的初始线程,以及处理动画的线程。
快速查看applet的start方法,可以知道它创建了线程,并启动了它。
类似地,当网页被隐藏后,applet的stop方法就调用了线程的stop方法。
注意:
在Applets和Threads中的start/stop子程序
在Applet和Thread两个类中都有start和stop方法,但它们的功能不同。
一旦Applet显示时,就调用applet的start方法,一旦applet隐藏时,就调用applet的stop方法。
相反,线程的start方法将调用run方法,线程的stop方法将停止正在执行的线程。
publicvoidpaint(Graphicsg);
paint()方法所传入的参数——java.awt.Graphics对象将是一个经裁剪的相关显示区的图像代表(而不会是整个显示区)。
我们对圆球图形元素的绘制就是在通过重写paint()方法,在其中对传入的Graphics对象g进行操作完成的。
当我们应用程序的逻辑要对系统界面进行更新时,调用repaint()方法来通知AWT线程进行刷新操作。
repaint()方法实际会让AWT线程去调用另外一个方法,update。
update方法在默认情况下会做两件事,一是清除当前区域内容,二是调用其paint()方法完成实际绘制工作。
paint、repaint、update三个方法关系如图所示:
但是如何让我们的圆运动呢?
这里我们利用函数Graphics类的fillOval函数来设置了圆的起始位置x,y。
现在我们只要在线程run方法中每单位时间增大y的值,线程将在每一个单位时间内重画圆的位置。
每单位时间y值越大,下降的速度就会越快。
在屏幕上我们就将看到这个圆球做自由降落运动。
如下代码所示:
while(true)
{
//设置动画移动速度
y+=1;
}
publicvoidpaint(Graphicsg)
{
//设置球的颜色
g.setColor(Color.blue);
//从x,y位置处画一个实心的圆
g.fillOval(x,y,2*r,2*r);
}
在这之前我们需要在开始处设置一些变量,定义好x,y的默认位置值。
r在此处是我们画的圆的半径大小。
intx=100;
inty=20;
intr=10;
我们的自由降落的动画就完了。
是不是很简单,如果还有地方不明白,大家可在此处下载完整的代码及应用程序。
看看真实的演示效果和代码。
下面每一部分我们也将在最后附上相应的源代码及应用程序下载。
如果大家有兴趣,可改变y的值,及x的值,你会得到不同的下降效果。
双缓冲,消除闪烁
大家可能注意到了上面例子中的我们下降的圆看起来不是很清晰,带着很严重的闪烁。
这种现象在写游戏程序中是普遍存在的现象。
这是由于我们的repaint()函数导致的结果,由于它在调用paint()函数前会自动清除屏幕,所以在一个毫秒内我们会看到一个空白的屏幕,在快速的变换操作中就出现了闪烁现象。
解决这种闪烁现象有几种方法,下面是两种方法的列举说明,其他的方式大家可以自己尝试。
第一种:
我们始终不清除屏幕显示,但是这个方法会带来个附作用,我们下降的圆不在是一个圆了,而是一条直线,因为它的下降过程中没有了断点,保留了所有的圆球的影象。
我们只要在Ball.java内加上如下代码update(Graphicsg){paint(g)},你就会看到一条很长的线拉出来。
有兴趣的朋友可以试试。
第二种:
使用双缓冲机制(Doublebuffering)
现在大部分的游戏都是采用双缓冲机制来解决屏幕的闪烁现象,我们就以此为例来进行说明,有关缓冲区及相关缓冲机制的概念,大家可参考附录的缓冲说明。
而我们的程序中简单的说就是在显示我们想要的图画之前,把所有的图画先在后台绘制好并存放到相应的图像变量中去。
当需要显示时直接复制到前台屏幕就可以了。
具体实现:
1.首先我们用createImage方法新建一后台图像类变量
2.然后使用getGraphics()方法得到当前图像的图形关联
3.在后台处理所有相关的处理,如清除屏幕,后台绘画等等
当完成所有的后台工作后,复制已经绘制好的图像到前台,并覆盖前台的存在图像。
这样我们的所有操作都是在后台前行,在屏幕显示新的图像前,这些内容都已经存在于后台了。
所以你也将在任何时刻都看不到空屏幕的存在。
也即代表闪烁消除了。
下面我们来看看相关的代码说明:
在开始之前我们得先在程序的开始部分声明两个实例变量用来存储后台图画。
如下:
privateImagebgImage;
privateGraphicsbg;
然后我们利用update()方法来实现双缓冲机制。
Update()方法要实现下面三个步骤:
1.清除屏幕上的组件
2.设置相关联组件的前景色
3.调用paint方法重画屏幕
publicvoidupdate(Graphicsg)
{
//初始化buffer
if(bgImage==null)
{
bgImage=createImage(this.getSize().width,this.getSize().height);
bg=bgImage.getGraphics();
}
//后台清屏,即设置圆球组件和后台一样的颜色,大小
bg.setColor(getBackground());
bg.fillRect(0,0,this.getSize().width,this.getSize().height);
//绘制相应的元素组件
bg.setColor(getForeground());
paint(bg);
//在屏幕上重画已经绘制好的圆
g.drawImage(bgImage,0,0,this);
}
此处g为屏幕图形,bg为g的后台关联。
而bgimage包含了bg图形。
请于此处来看看我们的源代码例子及演示效果。
改变运动方向
我们已经解决了动画的两个很重要的问题,移动动画和闪烁消除。
但是我们很快会发现一个问题,球从屏幕顶上落下来后,就不见了。
这可不是我们所需要的。
我们要的是一个生动的画面。
如何让我们的球不穿过屏幕而始终在屏幕上活动呢?
在开始之前,我建议大家自己想办法解决,如果你能自己处理好了。
你的水平将会有一个很大的提高。
如果没有想出好办法,没关系,下面我们将很详细的说明球的方向改变的技术。
不知道大家注意了没有,在上面我们说到球的移动时,我们是通过增加y的值,让线程重画新的圆位置和图形。
如果改变y的值的大小球的下降速度也会改变。
不错,这就是我们的解决方法,我们只要用一个变量来存储这个速度的大小而不用固定的值。
在线程执行也即run方法处我们用代码改变速度的方向,球的方向也会改变。
即设置这个变量”speed”为”-1”。
当然在设置值前我们要进行判断,你是想让球穿过屏幕从别一边开始显示,还是来回反弹呢!
如果想来回反弹,我们只要不让球的半径值超过applet屏幕显示区域就可以了。
此处我们用r/2来表示球的半径。
//反弹下落球
if(y>appletsize_y–r/2)
{
//改变方向
x_speed=-1;
}
//反弹上升球
elseif(<r/2)
{
//改变方向
x_speed=+1;
}
至于如何让球穿过从屏幕顶上重新下降,我们在此没有说明,也不会说明了。
留给大家自己去想想,已经很简单了。
在下面我们附上了两种方式的源代码和执行文件。
如果大家运行程序,大家可能会发现,我们的球的大小和速度有一些改变。
这里是为了更好的反应演示效果。
多媒体
使用多媒体声音
多媒体功能在游戏中是必不少的一部分,优美的音乐,漂亮的界面往往是一个成功游戏必需具备的条件。
在开始之前我们先了解一下主要的小型声音文件类型:
AU-(扩展名为AU或SND)适用于短的声音文件,为Solaris和下一代机器的通用文件格式,也是JAVA平台的标准的音频格式。
AU类型文件使用的三种典型音频格式为:
8位μ-law类型(通常采样频率为8kHz),8位线性类型,以及16位线性类型。
WAV-(扩展名为WAV)由Microsoft和IBM共同开发,对WAV的支持已经被加进Windows95并且被延伸到Windows98.WAV文件能存储各种格式包括μ-law,a-law和PCM(线性)数据。
他们几乎能被所有支持声音的Windows应用程序播放。
AIFF-(扩展名为AIF或IEF)音频互换文件格式是为Macintosh计算机和SiliconGraphics(SGI)计算机所共用的标准音频文件格式。
AIFF和AIFF-C几乎是相同的,除了后者支持例如μ-law和IMAADPCM类型的压缩。
MIDI-(扩展名为MID)乐器数字接口MIDI是为音乐制造业所认可的标准,主要用于控制诸如合成器和声卡之类的设备。
在JDK1.0上,java只支持*.au格式的声音文件,但是java2的API以及声音包提供了很强大的对声音技术的支持。
而此部分为了让大家快速掌握游戏编程的基本知识,我们仅使用了AudioClip接口类来实现播放"*.wav"。
如果大家有兴趣可参考sunjava网站的声音sapmle,上面提供了完备的实例和教程说明。
使用AudioClip接口比较简单,我们只要实例对象,加载声音文件后,再在任何地方播放即可。
恢复和播放声音最简单的方法是通过Applet类的play()方法。
AudioClip接口
1.播放play
2.循环loop
3.停止stop
启动和停止声音文件,或循环播放,你必须用applet的getAudioClip方法把它装载进入AudioClip对象,getAudioClip方法要用一个或两个参数,当作播放的指示。
第一个或唯一的一个参数是URL参数,用来指示声音文件的位置,第二参数是文件夹路径指针。
下列代码行举例说明加载声音文件进入剪贴对象:
下面的"gun.wav"是指当前目录下的声音文件。
我们也可用*.au格式的文件代替。
AudioClipco=getAudioClip(getCodeBase(),"gun.wav");
getAudioClip()方法仅仅能被applet内调用。
随着JAVA2的引入,应用程序也能用Applet类的newAudioClip方法装入声音文件。
前一例子可以改写如下以用于Java应用程序:
AudioClipco=newAudioClip(“gun.wav”)
我们现在可在任何地方使用方法play()播放我们的声音了。
play()一旦被调用立刻开始恢复和播放声音。
但这有一点要注意:
如果声音文件不能被查找,将不会有出错信息,仅仅是沉默。
源代码及应用程序请于此处下载.
图片处理技术
图片的处理和声音的处理在一样简单。
设置图片变量,得到图形,最后绘制图形。
我们就直接从代码来分析。
在此我们绘制一幅applet的背景图。
开始绘制前,我们先要声明图形变量,用来存放图形文件。
ImagebackImage;
//加载图片文件
backImgage=getImage(getCodeBase(),"black.gif");
下面在我们的paint()方法中利用函数drawImage绘制我们图形。
g.drawImage(backImage,0,0,this);
DrawImage参数中的blackImage即我们得到的图形,而后面的0,0分别代表图形的x坐标和y坐标.this:
为图形代表的类,这里指的即picture类。
在这里建议大家使用*.gif格式的图片文件。
因为如果是internet网上,文件的大小也决定了你的applet加载时的快慢,没有人很愿意等很长时间来玩你的游戏,即使你的游戏比较出色。
源代码及演示程序下载.
大家在玩游戏时是不是见过人物图像行走?
动物来回跑动的动画?
这些都是基于图形技术来实现的。
我们只要把上面的代码稍微修改,用数组变量来存储我们得到的图形文件组,再利用drawImage()方法播放出来就可实现动画图片的播放.
Image[]backImage;
//加载图片文件
for(inti=4,i<backImage.length,i++)
{
backImgage[i]=getImage(getCodeBase(),"t1"+i+".gif");
}
大家可参考JDK包中的Animation例子,它就是一个很好的播放一组图片文件的例子。
事件处理
鼠标监听技术
玩游戏时,不管是小型的扑克牌和大型的RPG游戏,都要参与者溶入到游戏的角色当中。
不错,交互,游戏有了交互的功能才可以说是一个完整的游戏。
即使是编程游戏如机器人足球,Robocode都要程序员参与编写代码,观察比赛。
有两种主流方法可实现游戏的交互:
鼠标和键盘。
当然还包括手操杆等,但现在大部分Pc机上使用的还是鼠标和键盘。
我们就以这两项为基础来说明游戏中事件的响应过程。
要判断相应的鼠标所进行的动作:
是点击,还是移动。
我们必须对我们鼠标进行监听。
要监听鼠标事件就必须调用这些接口之一,或扩展一个鼠标适配器(mouseadapters)类.AWT提供了两种监听接口(listenerinterface):
java.awt.event.MouseListener和java.awt.event.MouseMotionListener.
现在我设计一个鼠标事件,当点击applet屏幕时,下降的球向反方向运动。
以实现了对游戏的简单控制。
MouseListener一共有5个方法,主要用来实现鼠标的点击事件。
这里要注意一点:
由于MouseListener是接口我们要在实现的类中重载它的所有方法.
Mouse点击事件
·mousePressed()当用户按下鼠标按钮时发生.
·mouseReleased()当用户松开鼠标按钮时发生.
·mouseClicked()当用户按下并松开鼠标按钮时发生.用户在选择或双击图标的时候通常会点击鼠标按钮.用户如果在松开鼠标之前移动鼠标,点击不会导致鼠标相应事件出现.
·因为点击鼠标是按下鼠标和松开鼠标的结合,在事件分配给mouseClicked()方法之前,mousePressed()和mouseReleased()方法已同时被调用.
鼠标状态处理:
mouseEntered()当鼠标离开当前组件并进入你所监听的组件时激活事件.
mouseExited()当鼠标离开你所监听的组件时发生.
Mouse移动事件
鼠标移动主要通过接口MouseMotionListener来实现:
mouseDragged()当用户按下鼠标按钮并在松开之前进行移动时发生.在m
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Java 游戏 编程 初步