我Java实验报告
时间:2020-10-30 12:37:27 来源:勤学考试网 本文已影响 人
我的Java实验报告
刘方然 学号:200103100311
本实验报告分为以下部分:
1:项目目标:
2:名词与概念:
3:系统总体分析。
3:类的功能划分及相互关系:
4:技术重点攻关几主要算法分析:
5:部分类的具体实现:
6:拓展:
1:项目目标:
这次我要实现的是一个游戏界面的框架及简单的游戏操作。
游戏界面大体上有一个观察窗,一张小地图(MiniMap),两个按钮与相邻帧的间隔时间组成。在大地图上有一些可控制的单位(Unit)。
完成的效果如下:
单位 U
单位 Unit
观察窗
小地图
MiniMap
退出按钮
作者信息按钮
观察窗在小地图中的视野框
单位在小地图中的微缩代表
玩家可进行地图视野移动,视野选定,单位选定,选定单位移动目的地,查寻作者信息,退出游戏等操作。
2:名词与概念:
1)游戏界面框架元素:
1观察窗:显示单位及其他框架元素的载体。
2 小地图:微缩显示地图。
3 退出按钮:点击退出。
4 作者信息按钮:点击显示作者信息。
5 单位:操作的对象,可移动。
7 单位在小地图中的微缩代表:指示单位在地图中的相对位置。
8 观察窗在小地图中的视野框:指示观察窗在地图中的相对位置。
2) 简单的游戏操作:
1选定单位:
a.集体选定:单击鼠标左键,拖动鼠标产生一个选择框,释放鼠标,则在选择框内的单位就被集体选定。
b.单个选定:单击某一单位,则该单位就被选中。当该位置有多个单位时,随机选定其中一单位。
2选定目的地:
c.在观察窗中选定:在选定单位后,在观察窗中单击鼠标右键于目的地,则目的地被选定。
d.在小地图中选定:在选定单位后,在小地图中单击鼠标右键于目的地,则目的地被选定。
3改变视野:
a.移动视野:将鼠标移至观察窗边界,则视野会向相应方向移动,直至视野到达地图边界。
b.直接选定视野:鼠标左键单击小地图,视野直接移至相应位置。
4显示作者信息:鼠标左键单击作者信息按钮,则跳出作者信息。
5退出游戏:鼠标左键单击退出按钮。
3: 系统总体分析。
1)组成要素:
1单位:
a.单位运动(Movement)
b.单位管理(Management)
c.单位控制(Control)
d.单位显示(Show)
2界面:
a.界面显示管理
b.界面鼠标响应管理
c.按钮响应
3视频:
a.分辨率调整
b.全屏显示
c.重绘管理(Repaint Management)
2)要素关系:
由于关系复杂,用下图表示:
界面控制重绘管理
视频
视频
全屏设置
分辨率调整
界面
界面鼠标响应管理
按钮响应
单位
单位运动
界面
通过
控制 界面
管理 显示
单位
3)运行框架
设置视频
设置视频
取得视频环境
取得视频设备
保存原有视频模式
界面初始化
1. 添加单位
满足退出条件
结束
恢复视频模式
推出全屏显示
主过程
单位管理更新
视野坐标更新
取得绘图区
绘制绘图区
鼠标响应
Yes
影响
主过程
No
4:技术重点攻关及主要算法分析:
1)关于视频
1如何实现全屏:
使用如下框架:
GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment ();
GraphicsDevicegraphics Device = graphicsEnvironment.getDefaultScreenDevice();
DisplayMode originalDisplayMode = graphicsDevice.getDisplayMode();
try {
graphicsDevice.setFullScreenWindow(helk); // Set the full screen
//: Anything I want to do is written here.
} finally {
graphicsDevice.setDisplayMode(originalDisplayMode);
graphicsDevice.setFullScreenWindow(null); // Set off.
}
System.exit(0);
}
2如何改变分辨率
if(graphicsDevice.isDisplayChangeSupported()) {
graphicsDevice.setDisplayMode(displayMode);
}
在本程序中分辨率为 640 * 480。
2)关于单位
1 单位如何运动:
a.在本项目中使用了基于浮点的体系(区别与基于网格的体系)。
基于浮点的体系
位置(Position)P(1.234, 5.678)
方向(Direction)All direction
位移(Displacement)D(0.0343, 0.5443)
基于浮点的体系 基于网格的体系
位置(Position)P(2,4)
方向(Dirction)Four or Eight directions
位移(Displacement)D(1,0)
b.如何运动
原有位置 (curPosX, curPosY)
目标位置 (desPosX, desPosY)
运动速率 (vel);
有了以上参数就可以实现对下一位置的计算
double sclX, sclY;
double distance = distanceBetween(curPos, desPos);
sclX = (desPos.x - curPos.x) / distance;
sclY = (desPos.y - curPos.y) / distance;
curPos.x += vel * sclX;
curPos.y += vel * sclY;
c. 如何确定已到达目标
如果只使用以上代码则会出现无法停止或distance == 0造成除零的危险。
解决的方法是在距离目标位置很短的范围内(rngStop)停下来。
即当distance < rngStop时停下。
而且速率应当略小于这个范围,既 vel < rngStop,避免有除零的危险。
代码修正如下:
if(!isMove) {
return;
}
double distance = distanceBetween(curPos, desPos);
if(distance < rngStop) {
isMove = false;
return;
}
sclX = (desPos.x - curPos.x) / distance;
sclY = (desPos.y - curPos.y) / distance;
curPos.x += vel * sclX;
curPos.y += vel * sclY;
2单位如何绘制
为了简化程序而又明晰物体的运动方向绘制效果如下:
选定圈方向条
选定圈
方向条
普通(Normal) 选定(Selected)
具体代码如下:
// Draw the Unit
g.drawOval((int)(curPos.x - sizeDraw.width / 2) - p.x, (int)(curPos.y - sizeDraw.height / 2) - p.y, sizeDraw.width, sizeDraw.height);
// Draw the Dirction Bar
g.drawLine((int)(curPos.x) - p.x, (int)(curPos.y) - p.y, (int)(sizeDraw.width * sclX / 2 + curPos.x) - p.x, (int)(sizeDraw.height * sclY / 2 + curPos.y) - p.y);
// If selected, draw the Selected Bar
if (isSlct) {
g.setColor(Color.GREEN);
g.drawOval((int)(curPos.x - size.width / 2) - p.x, (int)(curPos.y - size.height / 2) - p.y, size.width, size.height);
}
由于在程序的开始,sclX, sclY(运动方向分量比例)均为零,则时会出现无方向条的现象。为弥补此不足将绘方向条代码修改如下。
// Draw the Dirction Bar
if (sclX == sclY && sclX == 0) {
g.drawLine((int)(curPos.x) - p.x, (int)(curPos.y) - p.y, (int)(sizeDraw.width / 2 + curPos.x) - p.x, (int)(curPos.y) - p.y);
} else {
g.drawLine((int)(curPos.x) - p.x, (int)(curPos.y) - p.y, (int)(sizeDraw.width * sclX / 2 + curPos.x) - p.x, (int)(sizeDraw.height * sclY / 2 + curPos.y) - p.y);
}
3单位如何被驱动的
单位有一个executeCommand(Command cmd) 函数 可以通过执行Command的对象来改变自身状态。可移动单位(MobileUnit)可以执行MoveCommand来驱动它向目的地运动.代码如下:
public void executeCommand(Command cmd) {
if(cmd instanceof MoveCommand) {
gotoDestination(((MoveCommand)cmd).getPosition());
}
}
如果还想单位执行其它操作,也使用如上框架:如
if(cmd instanceof Command1) {
//Act 1
} else if(cmd instanceof Command2) {
//Act 2
} else if...
2)关于鼠标响应
1如何拖框(Drag a Selective frame): 当鼠标左键按下时,记录坐标P1(startX, startY)同时使P2(endX, endY)与P1重合,当鼠标拖动时更新P2至鼠标当前位置。有了P1,P2点的坐标就可以确定一个矩形,绘出此矩形便得到拖框效果。但当startX > endX 或 startY > endY 时矩形的边长是负值,不能画框,因此要稍作处理。交换startX 与 endX 或是startY 与endY。
2如何实现单位集体选中
拖动鼠标产生如上矩形,遍历所以单位,当单位在矩形内时将此单位设置成选中状态(isSlct = true)既可
3如何实现单位单个选中
单击鼠标左键,遍历所以单位,当点击位置与某一单位的距离小于单位的一半尺寸时,该单位便被选中。
4如何实现目的地选定
单击鼠标右键,点击位置即被确定为目的地位置。
4)关于单位的管理与控制
1单位的管理
任何一个单位生成后,都应向单位管理器(UnitManager)注册,由管理器管理。管理器负责对所有单位(在视野内)进行显示,微缩显示与更新。
public void createUnit(Unit unit) { // 单个单位向管理器注册
units.add(unit);
}
public void addUnitGroup(LinkedList list) { // 单位组向管理器注册
units.addAll(list);
}
public void updateAll() { // 对所有单位进行更新
ListIterator lit = units.listIterator();
Unit u;
while (lit.hasNext()) {
(u = (Unit)lit.next()).update();
}
}
public int showAll(Graphics g, Rectangle r) {
// 对所有单位(在视野内)进行显示
ListIterator lit = units.listIterator();
Unit u;
int i = 0;
while (lit.hasNext()) {
u = (Unit)lit.next();
if (r.contains((int)(u.getX()), (int)(u.getY()))) {
u.show(g, r.getLocation());
if(u.isSelected()) {
i++;
}
}
}
return i;
}
public void miniShowAll(Graphics g, Point p, int scale) {
// 对所有单位微缩显示
ListIterator lit = units.listIterator();
while (lit.hasNext()) {
// 调用所有单位的miniShow();
((Unit)(lit.next())).miniShow(g, p, scale);
}
}
2单位的控制
所有选中的单位都在单位控制器(UnitControler)中注册。实际上所有的鼠标对单位的控制都是通过单位控制器完成的。
public void addUnit(Unit unit) { // 添加单位
units.add(unit);
unit.setSelected(true);
}
public void removeUnit(Unit unit) { // 注销单位
if(units.remove(unit)) {
unit.setSelected(false);
}
}
public void removeAll() { // 清空控制器
ListIterator lit = units.listIterator();
while(lit.hasNext()) {
((Unit)(lit.next())).setSelected(false);
lit.remove();
}
}
public void setUnitGroup(LinkedList units) { // 重置控制器
removeAll(); // 先清空
ListIterator lit = units.listIterator();
this.units = units;
lit = units.listIterator();
Unit u;
while(lit.hasNext()) {
((Unit)(lit.next())).setSelected(true);
}
}
public void executeCommand(Command cmd) { // 对选定单位发布命令
ListIterator lit = units.listIterator();
while(lit.hasNext()) {
((Unit)lit.next()).executeCommand(cmd);
}
}
5)总体协调
1刷新率(画面的更新速度)的调整
我发现绘图是有很大开销的,当视野内的单位超过150 个时速度会变得很慢(500Mhz,64M条件下)。我通过调整睡眠时间(Sleep)来使动画平滑.
在UnitManager 中 showAll()不仅显示所有在视野内的单位而且还返回一个放映绘图量的整数 drawCounter;
将线程的睡眠时间设定为 Math.max(5,100 - drawCounter / 2);
则效果较好
2关于最大处理能力
为了使动画不致太慢,单位数应少于200(500Mhz,64M条件下)。
5:类的功能划分及相互关系:
1)自编类一览
Command 命令接口
ExitableJFrame 关闭后自动退出的Frame类
Helkcraft 主类
MiniMap 小地图
MobileUnit 可移动单位
MoveCommand 移动命令
Position 浮点型坐标类
Unit 单位接口
UnitControler 单位控制器
UnitLayout 单位排版器
UnitManager 单位管理器
2)相互关系
JFrame
JFrame
Helkcraft
MiniMap
Position
UnitControler
UnitLayout
UnitManager
MoveCommand
Command
MobileUnit
Unit
LinkedList
ExitableJFrame
ExitableJFrame
A B B使用 A
A B B继承 A
6: 部分类的具体实现:
对于关键类UnitManager 和 UnitControler 上面已经介绍过了,这里不在赘述。
接下来讲讲UnitLayout 和 主类 Helkcraft.
UnitLayout
为了方便单位在地图上的摆放,我设计了UnitLayout 这个辅助类。
实际上它只有一个square()函数。这个函数在地图某个位置摆上单位的N x N 的方阵。
它的返回值可以交给UnitManager来管理。具体代码如下:
static public LinkedList square(int n, Position p, int interval) {
Position pos = new Position(p);
LinkedList list = new LinkedList();
for(int i = 0; i < n; i++) {
pos.x = p.x;
for(int j = 0; j < n; j++) {
list.add(new MobileUnit(pos));
pos.x += interval;
}
pos.y += interval;
}
return list;
}
UnitLayout 还可以有任何摆单位的函数如
line(), random(), triangle() 等等。这样就能摆出各种各样的阵型。由于精力所
限, 我没有去拓展。
square
Line
Ramdon
Rriangle
Helkcraft
作为主类的Helkcrart在报告的一开始就已涉及到。在这里着重讲一讲它的鼠标监听部分。
Helkcraft 有两个监听器,一个MouseListener 一个 mouseMotionListener。
它们相互配合对鼠标进行监听并做出相应反应。
MouseListener 的
MouseListener 的方法伪代码
MousePressed()
if(LeftButtonDown) {
SetSelectedRectangleInvisible
If(PressInMiniMap) {
ControlerExecuteCommandInMiniMapWay
} else {
ControlerExecuteCommand
}
} else if (RightButtonDown){
if(PressQuitButton) {
QuitTheGame
Return
}else if(PressInfoButton) {
TriggleTheInfoShown
Return
}else if(PressMiniMap) {
MoveMiniMap
Return
} else if(PressUnit) {
SetUnitSelected
Return
}
RecordPressLocation
SetSingleSelectedTrue
}
mouseReleased
if(isSingleSelected) {
SetSingleSetlectedFalse
Return
}
if(LeftButtonUp) {
NormalizeSelectedRectangle
SetTheSelectedUnit
SetTheSelectRectShownFalse
}
MouseMotionListener 的
MouseMotionListener 的方法伪代码
MouseDragged()
if(isShowSelectRect) {
ShowSelectRect
Return
}
if(LeftButtonUp) {
NormalizeSelectedRectangle
SetTheSelectedUnit
SetTheSelectRectShownFalse
}
mouseMoved
GetCurrentLocation
7:拓展:
如果有时间与精力我会再添一个单位信息框和一个控制板。效果应该向下面那样:
单位信息框
单位信息框
控制板
控制按钮
如果还有时间与精力我会解决单位重叠的问题。
如果还有时间与精力我会使单位可已互相开仗。
如果还有时间与精力我会。。。
就写到这吧,再见。