目 录
摘 要 I
Abstract II
1 引言 3
1.1 项目背景 3
1.2 电脑游戏的发展历史 3
1.3国内游戏项目研究现状 5
1.4项目主要工作 6
1.5本文组织结构 7
1.6 电脑游戏的策划 7
2 开发平台与开发技术 8
2.1 Eclipse 8
2.2 Eclipse平台 8
2.3 Java 9
2.4游戏图形界面的开发基础 11
2.5Java游戏中的基本框架 14
3 雷电游戏模块设计 16
3.1 用户需求分析 16
3.2 可行性分析 16
3.3 总体设计原则 17
3.4 功能模块设计 18
3.4.1 游戏状态控制功能 18
3.4.2 游戏难度的调整 18
3.4.3 游戏界面绘画功能 18
3.4.4 玩家游戏控制功能 19
3.5 关键技术 19
4 雷电功能实现 20
4.1 游戏程序设计的思路 20
4.1.1 游戏的素材选择 20
4.1.2 游戏中子弹、飞机的实现 20
4.1.3 多线程应用的途径 20
4.2 游戏首页的实现 22
4.2.1 界面实现 22
4.2.2 流程图 22
4.2.3 核心代码 23
4.3 游戏开始模块的实现 24
4.3.1 界面实现 24
4.3.2 流程图 25
4.3.3 核心代码 26
4.4 发射子弹模块的实现 27
4.4.1 界面实现 27
4.4.2 流程图 28
4.4.3 核心代码 28
5 系统测试 31
5.1 测试的定义及其重要性 31
5.1.1 测试的定义 31
5.1.2 测试的重要性 31
5.2 测试实例的研究与选择 32
5.3 测试结果 35
总结和展望 37
参考文献 38
致 谢 39
1.4 项目主要工作
本次项目开发是基于JAVA的雷电游戏。
此雷电游戏通俗来说就是我方飞机和敌方之间的对决,先要做的应该是通过一个界面来达到装载整个游戏,然后就是我方飞机的移动方式(也就是通过键盘来移动),接着就是生成我方飞机的子弹(依据子弹类型的不同有不同的实现形式),准备就绪后会有敌方飞机的出现,每一个飞机会对应发射不同种类的子弹,最后是我方飞机通过键盘进行移动、射击,显示出游戏结果,然后结束游戏。
该雷电应该满足以下一些要求:
(1)游戏状态控制功能
在进行游戏的设计时,我们应该考虑到,如何进行游戏状态的划分。简单来说,我们需要设置开始,并且要考虑到游戏中断,以及中断后回到游戏中。玩家点击开始之后,程序会调用启动页面的代码,然后进入游戏,在游戏的过程中,玩家如果由于其它工作需要离开时,可以将其中断,比如单击空格键,当需要恢复游戏现场时,再单击空格键,就可以继续游戏,当自己控制的飞机被击毁时,会有游戏结束的显现。
(2)游戏难度的调整
随着游戏的进行、关卡的提高,敌机的速度会越来越快、敌方飞机的数目会越来越多、子弹数量也会越快且越多。此时,带给游戏玩家的视觉冲击变得更强,需要玩家更加冷静地去躲闪以及攻击敌机。
(3)游戏界面绘画功能
游戏主屏主要用来输出用户对我方的控制与敌方的动作显示。在游戏屏幕的左下角有全屏爆破次数的显示,这相当于游戏玩家的特殊技能,可以瞬间清除当前屏幕上的所有敌机以及子弹,在游戏屏幕的右下角会呈现玩家飞机血条,代表着当前我方飞机的状态。当血条格为空时,表示我方飞机已经被击毁,整个雷电游戏也将结束。
(4)玩家游戏控制功能
对于我方飞机的移动和子弹的发射,游戏用户可以通过控制键盘来控制。飞机的左右移动通过键盘的上、下、左、右键来实现,而我方飞机子弹的释放方式有两种,z键会释放出点状子弹,而x键会释放出线状子弹,可供游戏玩家依据需要自行选择。
3.4 功能模块设计
3.4.1 游戏状态控制功能
雷电的阶段包括开始、暂停、恢复和结束,最先需要等待游戏的加载启动,假若游戏过程中,玩家如果因为特殊事情需要离开可以选择暂停比赛,等到再次回来可以进行比赛的恢复。
3.4.2 游戏难度的调整
随着游戏的进行,游戏的难度会相应的增加,比如敌机的数量会越来越多、敌机子弹的数量也会有所增加,这些都是对玩家造成伤害的因素,这些伤害因素越多,游戏的难度相应就越大,最终每一关卡都有一个怪兽守关,它的血条、子弹都造成了游戏难度的增加。
3.4.3 游戏界面绘画功能
游戏主屏用来输出用户对己方的控制与敌方的动作显示。在屏幕的右下角会有己方飞机的生命值的显示,在游戏的左下角会有全屏爆破的剩余次数显示,通过这些显示,可以增加玩家的游戏体验性,达到一个更加人性化的界面,为用户提供更好的界面舒适度。
3.4.4 玩家游戏控制功能
用户玩家可以通过键盘的上、下、左、右键控制飞机的移动,通过移动来躲避敌方飞机带来的伤害,通过z、x键控制子弹的发射,通过发射子弹来对敌机造成伤害。
3.5 关键技术
(1)游戏美工。游戏中需要使用的游戏素材有自己控制的飞机、敌方飞机、游戏过程当中飞机所产生的子弹、飞机被命中的爆炸图片等。这些素材的选择尤为重要,游戏中清新亮丽的画面可以给玩家带来充足的美感和游戏体验。所以,在这个“雷电”游戏的素材选择中,应挑选一些立体感强的图片,给玩家更大的视觉冲击。
(2)多线程技术的实现。多线程编程能够提供程序两个或两个以上并发执行任务的能力,极大改善程序的响应性能,有效提高资源的利用效率。采取Runnable接口的方法达到定义用户线程的功能,这样既不会对继承其他类有所变化,也不会改变实现其它接口。
(3)用户飞机子弹与敌方飞机的相撞测试。包括自己控制的飞机与敌方飞机或子弹的相撞等。在这一过程中,本文转载自http://www.biyezuopin.vip/onews.asp?id=11237将所有子弹对象的矩形区域与敌机对象的矩形区域逐个以此进行检测,如果出现重叠则说明子弹与敌机发生了碰撞。
(4)游戏地图滚动原理的实现。我们在坐火车时都产生过一种错觉:自己乘坐的火车没有发生移动,但如果旁边有其他火车发生移动,我们就会感到是自己的火车在移动。这种现象与飞机射击类游戏的地图原理类似,即通过背景图片的来回滚动,给游戏玩家一种是自己操纵的飞机向前飞行的感觉。
package com.ideabobo.game.leidian;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import com.ideabobo.game.leidian.Boss;
public class Battle extends Role {
private static Battle battle = new Battle();
private int tamaIntCount;
private float speed;
private float oldx;
private float oldy;
public static float vx;
public static float vy;
public static boolean keygo = false;
private float tv[] = { -1F, -7F, 0.0F, -8F, 1.0F, -7F };
public int power;
public int powerMax;
public Battle() {
super(GamePanel.heroImage);
speed = 3F;
tamaIntCount = 0;
x = ((float) app.getWidth() - WIDTH) / 2.0F;
y = (float) app.getHeight() - HEIGHT * 2.0F;
power = 600;
powerMax = power;
}
public static Battle getInstance() {
return battle;
}
public void move() {
oldx = x;
oldy = y;
if (Key.left) {
if (Key.xkey)
x -= (double) speed / 4D;
else
x -= speed;
if (x <= 0.0F)
x = 0.0F;
}
if (Key.right) {
if (Key.xkey)
x += (double) speed / 4D;
else
x += speed;
if (x + WIDTH >= (float) app.getWidth())
x = (float) app.getWidth() - WIDTH;
}
if (Key.down) {
if (Key.xkey)
y += (double) speed / 4D;
else
y += speed;
if (y + HEIGHT >= (float) app.getHeight())
y = (float) app.getHeight() - HEIGHT;
}
if (Key.up) {
if (Key.xkey)
y -= (double) speed / 4D;
else
y -= speed;
if (y <= 0.0F)
y = 0.0F;
}
//**//--///loonframewrk提供
vx = x - oldx;
vy = y - oldy;
if (tamaIntCount > 0)
tamaIntCount--;
if (Key.zkey && tamaIntCount <= 0) {
for (int i = 0; i < tv.length; i += 2) {
GamePanel.addList(new BattleBasic(x + WIDTH / 2.0F, y, tv[i],
tv[i + 1]));
tamaIntCount = 8;
}
}
if (Key.xkey && !Key.zkey && tamaIntCount <= 0) {
GamePanel.addList(new BattleBeam(x + WIDTH / 2.0F, y, 0.0F, -8F));
tamaIntCount = 2;
}
if(Key.space){
if(!keygo){
GamePanel.skillCount--;
}
app.skillAnime();
if(GamePanel.skillCount < 0){
GamePanel.skillCount = 0;
}
if(GamePanel.skillCount>0){
for (int i = 0; i < GamePanel.list.size(); i++) {
Role chara1 = (Role) GamePanel.list.get(i);
if(!(chara1 instanceof Battle) && chara1.x>0 && chara1.y>0 && !(chara1 instanceof BossA) && !(chara1 instanceof BossB) && !(chara1 instanceof BossC)){
GamePanel.list.remove(i);
}else if((chara1 instanceof BossA) || (chara1 instanceof BossB) || (chara1 instanceof BossC)){
Boss cb = (Boss)chara1;
cb.power-=50;
}
}
}
keygo = true;
}
if(!Key.space){
keygo = false;
}
}
public boolean checkHit(Role chara) {
if ((chara instanceof EnemyA) || (chara instanceof EnemyB)|| (chara instanceof EnemyC) || (chara instanceof EnemyShot)) {
if ((x + WIDTH) - 14F > chara.x && x + 14F < chara.x + chara.WIDTH
&& (y + HEIGHT) - 12F > chara.y
&& y + 12F < chara.y + chara.HEIGHT) {
//如果碰到敌人,敌人死亡
chara.dead();
//如果碰到子弹血量减少
if (chara instanceof EnemyBeam){
power--;
}
power -= 50;
if (power <= 0) {
dead();
//绘制爆炸图片
GamePanel.burst = new Burst(x, y);
}
return true;
}
} else if ((chara instanceof Boss) && (x + WIDTH) - 14F > chara.x + 50F
&& x + 14F < (chara.x + chara.WIDTH) - 50F
&& (y + HEIGHT) - 12F > chara.y + 50F
&& y + 12F < (chara.y + chara.HEIGHT) - 80F) {
power--;
if (power <= 0) {
dead();
GamePanel.burst = new Burst(x, y);
}
return true;
}
return false;
}
public void setX(float x) {
this.x = x;
}
public void setY(float y) {
this.y = y;
}
public float getWidth() {
return WIDTH;
}
public float getHeight() {
return HEIGHT;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public Image getImage() {
return img;
}
public int getPower() {
return power;
}
public int getPowerMax() {
return powerMax;
}
public void setPower(int power) {
this.power = power;
}
public void drawPower(Graphics g) {
g.setColor(Color.white);
g.drawRect(380, 450, 50, 15);
g.setColor(Color.red);
g.fillRect(381, 451,
(int) ((50D / (double) (float) powerMax) * (double) power) - 1,
14);
}
public void drawSkillCount(Graphics g){
g.setColor(Color.white);
Font font = new Font("宋体", 1, 20);
g.setFont(font);
g.drawString("全屏爆破:" + GamePanel.skillCount, 0, 450);
}
}