资源描述
学号
- 第二学期
《软件工程设计》
课程设计汇报
题目:
自主模式匹配攻击双坦克运动计划程序设计
专业:
计算机科学和技术
班级:
10级(2)班
姓名:
项莹莹
学号:
指导老师:
王源
成绩:
计算机和信息工程系
5月24日
目 录
1.绪论 3
2. 开发环境介绍 3
3.课程设计目标和要求 4
3.1 课程设计目标 4
3.2 课程设计试验环境 4
3.3 课程设计预备知识 4
3.4 课程设计关键内容 4
4.系统分析 5
4.1可行性分析 5
4.1.1技术可行性 5
4.1.2经济可行性 5
4.2需求分析 5
5.课程设计内容 7
5.1 程序中关键方法、变量和函数 7
5.2程序具体设计 7
5.3游戏主窗口 11
5.3.1游戏数据输入和运行 11
5.3.2游戏数据输出和保留 14
6.设计体会和小结 15
7.参考文件 15
8.源程序 15
1.绪论
Java是一个简单,跨平台,面向对象,分布式,解释,健壮安全,结构中立,可移植,性能很优异多线程,动态语言。当1995年SUN推出Java语言以后,全世界眼光全部被这个神奇语言所吸引。
Java是一个纯面向对象程序设计语言,它继承了 C++ 语言面向对象技术关键,Java舍弃了C ++语言中轻易引发错误指针(以引用替换)、运算符重载(operator overloading)、多重继承(以接口替换)等特征,增加了垃圾回收器功效用于回收不再被引用对象所占据内存空间,使得程序员不用再为内存管理而担忧。
Java 不一样于通常编译实施计算机语言和解释实施计算机语言。它首先将源代码编译成二进制字节码(bytecode),然后依靠多种不一样平台上虚拟机来解释实施字节码,从而实现了“一次编译、四处实施”跨平台特征。
现在,Java语言不仅是一门被广泛使用编程语言,而且已成为软件设计开发者应该掌握一门基础语言。因为很多新技术领域全部包含到Java语言,中国外很多大学已将Java语言列入本科教学计划,而IT行业对Java人才需求也在不停增加,所以,掌握Java已经成为共识。
2. 开发环境介绍
Robocode 是7月在美国IBM Web 站点alphaWorks 上公开机器人(其图形为坦克形状) 战斗仿真引擎。和通常玩游戏不一样是:你必需利用Java 对机器人动作进行编程,给机器人设计智能来自动指挥它, 而不是由键盘鼠标来控制它。不管你是初学者还是顶级程序员,你全部可在Robocode 世界中找到旗鼓相当对手。把你写机器人放到战场中,在和她人编写机器人战斗中考验自己编程水平。在不停完善过程中你将体会到学习所带来无穷乐趣。当你机器人融入了你思想你将会发觉你已经打开了Java编程甚至任何编程语言大门。
因为Robocode 是基于Java 而产生软件,所以它也含有了Java“一处编写,四处运行”特点。Robocode 这个游戏为全世界Java 开发者实现这个愿望,它把游戏风潮变成了教学工具,Robocode小东西有着巨大能量,Robocode 是一个比较上瘾游戏,大家对它上瘾程度令人吃惊。
战场是机器人之间进行战斗直至分出胜败场地。关键仿真引擎被置于其中,而且许可您在这里创建战斗、保留战斗和打开新建或现有战斗。经过界面区域内控件,您能够暂停或继续战斗、终止战斗、消亡任何机器人个体或获取任何机器人统计数据。图2中三个机器人活动地方就是战场。另外,在编译器界面下您能够经过菜单调用Robot Editor,它是Robocode本身自带Java 语言编辑器,这个编辑器是发挥你创意所在。它能够用于编辑生成机器人 Java 源文件。
3.课程设计目标和要求
3.1 课程设计目标
《JAVA面向对象程序设计》是计算机科学和技术专业必修专业基础课程,其实践性、应用性很强。实践教学步骤是必不可少一个关键步骤。本课程程序设计专题实际是计算机相关专业学生学习完《JAVA面向对象程序设计》课程后,进行一次全方面综合训练,JAVA程序设计设计目标是加深对理论教学内容了解和掌握,使学生综合利用所学知识,利用软件工程为基础进行软件开发、并在实践应用方面打下一定基础。
3.2 课程设计试验环境
JAVA程序设计语言及对应集成开发环境,J2SDK和Robocode开发工具。
3.3 课程设计预备知识
熟悉JAVA语言和Robocode软件。
3.4 课程设计关键内容
坦克大战游戏是在Robocode环境下编程游戏,其中包含对坦克移动策略编写、坦克射击策略编写、坦克模式匹配策略编写、结构函数编写等等。游戏关键实现功效有:
(1).坦克能够随机移动;
(2).坦克能够依据模式匹配策略射击敌方坦克;
(3).坦克能够根据一定策略发子弹;
(4).我方坦克打败敌方坦克时,会显示爆炸效果并消失;
(5).我方坦克被击中后,会显示爆炸效果;
4.系统分析
4.1可行性分析
4.1.1技术可行性
Robocode软件使用面向对象设计语言JAVA技术实现,这已是很成熟技术,之前已经有相当多使用这些技术成功案例,故现使用这些技术是可行。
Robocode软件为你处理好一切细节。你所做就是为你机器人坦克编写智能程序,让它能够移动、进攻、防御、躲避、开火。而它对手就是跟你一样其它程序员编写机器人程序。
这就是Robocode魅力所在,最简单,只用几十行代码,就能立即发明出一个简单但完整机器人,你能够立即将它装入Robocode 引擎中,再从Robocode 自带那些水平不一示例机器人中选择一个进行一番对战。你能够不停修改你程序,设计新射击模型、躲避模型、移动模型,当你打败了那些示例机器人,你还能够在网上下载由其它程序员编写水平更高机器人,和它们比试一下,看看自己水平到底怎样。
开发Robocode,也是一个极佳学习Java 语言过程。对于初学者来说,这是学习多种基础语法好路径:类,方法,事件处理等等。当你入门以后,需要深入提升机器人“智力”水平,就需要使用愈加好策略:怎样估计对手行动路线,怎样躲避对手攻击......你不得不创建更多类来应对更多情况,你将学习使用接口、继承等等Java 高级语言特征。伴随你机器人“智力”水平提升,你编程能力也就跟着水涨船高了。
4.1.2经济可行性
本软件为无偿软件,将无偿提供软件下载、运行和维护服务,软件暂无收入,待公布以后伴随使用者越来越多,将添加对应广告、服务,从而增加收入,若使用者寥 寥无几,将再次分析是否重新策划软件或放弃开发,以降低损失。
硬件要求也比较低,系统安装最小环境要求:CPU:Pentium2/400MHz 以上内存:64MB 以上硬盘:10M 以上
4.2需求分析
利用Robocode软件编译器,将全部游戏元素全部在此界面上表现出来。界面中包含我方坦克、敌人坦克、双方坦克生命值、比赛速度、比赛回合等。
坦克:坦克分为两种:我方坦克和敌方坦克。我方和敌方坦克均能够发射子弹,能够改变路径行走,且在行走过程中碰到墙等阻碍物和游戏边界时要改变方向,而不能一直顶着障碍物不放,这些全部能够在程序中设计。坦克之间不能穿越,碰撞到后自动调换方向。
墙:游戏中边界王家坦克和敌人坦克全部不能越过,坦克子弹也不能穿过。我方坦克要满足离墙不能太近,而且假如要过去这一点,我需要用方向要满足不能和目前正在运动方向相差太少,意思就是说,方向要变多些,不能看起来跟没改变差不多,也不能向着敌人冲过去。
运动方法:随机运动,这种运动方法关键用来混乱敌人估计。
爆炸:当子弹射击到对方坦克身上时,要产生爆炸效果。
子弹:子弹能够由敌方和用户方发射,且发射出去子弹能够依据雷达觉察到敌人时有所动作。机器人保持和敌人成30度倾向角。本身成 90 度角静止并逐步靠近目标。假如机器人觉察到能量下降介于 0.1 和 3.0 之间(火力范围),那么机器人就立即切换方向,向左或向右移动。直到碰到障碍物就消失。敌方坦克受到子弹数次攻击后会爆炸从而造成死亡,死亡后坦克消失。我方受到子弹攻击后会降低寿命,此时如还有敌方坦克存在,则我方输掉此次游戏。
战场:战场是机器人之间进行战斗直至分出胜败场地。关键仿真引擎被置于其中,而且许可您在这里创建战斗、保留战斗和打开新建或现有战斗。经过界面区域内控件,您能够暂停或继续战斗、终止战斗、消亡任何机器人个体或获取任何机器人统计数据。getBattleFieldWidth()和getBattleFieldHeight()能够得到目前这一回合战场尺寸。
射击策略:射击策略关键思绪是用一个800长度数组来纪录一个直线提前量每个统计点全部统计从自己子弹到敌人这段时间(子弹假定能量为3,敌人假定为不动,即使这么不正确,不过也只能这么,你知道敌人怎样动?假如知道你还计算啥?)。 需要射击时,寻求一个历史中(全部以前统计节点中)完成了累加,而且和现在估计角度值最相同统计节点(也就是以估计角度值最相同就视为运动方法最相同),那么,敌人以后运动因该和历史中那段运动情况很相同(也就是历史重现)。找到了历史要重现地方了,那么用那段历史中平均估计角度值作为射击角度射击,这种射击方法就是寻求历史中和你现在运动相同情况,所以假如我方坦克运动有规律话,敌方坦克能很好找出我方坦克下一步会怎样走,那么,我方坦克被命中几率就很大,这也正是采取随机运动原因。
5.课程设计内容
5.1 程序中关键方法、变量和函数
getX( ) , getY( )
捕捉机器人坐标
setMaxVelocity( )
设置机器人最大运动速度
setAhead( )
让机器人向前移动一定距离
setTurnRightRadians( )
向右随机旋转机器人
setTurnGunRightRadians( )
向右随机旋转火炮
setTurnRadarRightRadians( )
向右随机旋转雷达反射镜
setBodyColor( )
设置车身颜色
setGunColor( )
设置炮管颜色
setRadarColor( )
设置雷达颜色
setBulletColor( )
设置子弹颜色
setAdjustGunForRobotTurn()
控制火炮是否向下锁定
setAdjustRadarForGunTurn()
控制雷达是否向下锁定
double firePower
设置坦克火力大小
double linearPredictionAngle
计算需要射击角度
double distToWall
检验坦克离墙壁最短距离
static double[][] pattern
存放全部相关敌人信息
public void run()
坦克运动函数
public double angle_180( double ang )
设置坦克转动角度函数
5.2程序具体设计
因为Robocode软件自带图形用户界面游戏窗口,所以就不需要另外设计游戏窗口了。游戏运行也是自动完成,只需要在游戏开始前设置下游戏速度即可,也能够在游戏运行时经过窗口下方速度标尺来自行调整。
Robocode平台坐标系统和我们数学书中坐标系统有较大区分,首先要搞清楚多个概念:
1、【坐标系】:Robocode整个坐标系全部是战场屏幕以左下角为原点。getX()和getY()能够捕捉到机器人目前所在战场中坐标。
2、【绝对方向系】:Robocode中不管机器人在哪个方向全部是以静态战场屏幕为参考物绝对角度(Heading),正上方为0 度角。即是向北为0,向东为90,向南为180,向西为270。
3、【相对方向系】:相对方向是以机器人动态heading角度为参考物角度差,不再以整个静态屏幕为参考了。叫它相对是因为机器人heading 是伴随机器人移动而不停在改变,heading 只是个相对物体。
4、【Heading】:是机器人方向和屏幕正上方角度差,方向在0 到360 之间。getHeading()、getGunHeading()和getRadarHeading()分别能够得出坦克车、炮或雷达目前方向,该方向是以角度表示。
5、【Bearing】:是机器人某个部件如雷达发觉目标和方向角度差,顺时针为正角度在- 180 到180 之间。
大家全部知道,坦克有很多个,不过每一个坦克全部离不开三个部分,车身,炮,雷达。Robocode中机器人也有这三个部件。
车身是一个比较粗笨部分,它基础操作有:turnLeft(double degree)和turnRight(double degree)分别是使机器人(左右)转过一个指定角度。在AdvancedRobot 坦克中能够使用setTurnRightRadians(double degree)函数使机器人转过一定弧度。 setAhead(double distance)和setBack(double distance)分别是使机器人(前后)移动指定像素点距离;这两个方法在机器人碰到墙或碰到另外一个机器人时即告完成。
本设计中设置车身参数以下:
double ourX = getX();
double ourY = getY();
double testX = Math.random() * getBattleFieldWidth();
double testY = Math.random() * getBattleFieldHeight();
setTurnRightRadians( angle_180( turnAngle ) );
setAhead( moveDirection * Point2D.Double.distance( ourX , ourY , testX , testY ) );
炮是用来发射炮弹攻击敌人武器,它基础操作有:TurnGunLeft(double degree) 和TurnGunRight(double degree)分别是使炮能够独立于坦克车方向(左右)转动指定角度。在AdvancedRobot 坦克中,经过设置setTurnGunRightRadians(double degree)函数来让炮按一定弧度转动。利用setFire(double power)发射指定能量炮弹。
本设计中设置炮参数以下:
setTurnGunRightRadians( angle_180( targetBearing - getGunHeadingRadians() + linearPredictionAngle ) );
double firePower = Math.min( 3 , 30 * getEnergy() / e.getDistance() );
if ( getEnergy() > Math.min( e.getEnergy() + firePower + 0.1 , 3.1 ) ) {
setFire( firePower );
雷达是机器人取得敌人信息关键器官,它基础操作有:turnRadarLeft(double degree)和turnRadarRight(double degree)分别是使炮上面雷达(左右)转动指定角度,转动方向也独立于炮方向(和坦克车方向)。在AdvancedRobot 坦克中,经过设置setTurnRadarRightRadians(double degree)函数来让雷达按一定弧度转动。
本设计中设置雷达参数以下:
setTurnRadarRightRadians( Math.tan( targetBearing - getRadarHeadingRadians() ) * 3 );
本设计中最关键两个策略是模式匹配策略和坦克移动策略。
坦克模式匹配策略代码以下所表示:
int match = 0;
pattern[ time ][0] = e.getDistance() / ( 20 - 3 * firePower );
pattern[ time ][1] = e.getVelocity() * Math.sin( e.getHeadingRadians() - targetBearing );
//也就是说pattern[ time ][1]统计是直线提前量射击角度和自己子弹速度乘积
pattern[ time ][2] = pattern[ time ][3] = 0;
for ( int a = 0; a < storedInfo; a++ ) {
//每个统计点pattern[a]中,假如目前时间是在我子弹抵达敌人之前则累加计算到myBulletVelocity*Math.sin(predictionAngle)值;
//同时统计累加了多少次(pattern[ a ][3]值)
if ( pattern[ a ][0] > 0 ) {
pattern[ a ][2] += e.getVelocity() * Math.sin( e.getHeadingRadians() -targetBearing );
pattern[ a ][0]--;
pattern[ a ][3]++;
}
}
//在历史中(全部统计中)寻求一个和现在myBulletVelocity*Math.sin(predictionAngle)值最相近统计点(这个纪录点必需是累加完成点pattern[a][0]<0)
//把这个纪录点数组下表统计到match中
for ( int a = 0; a < storedInfo; a++ ) {
double testAngle = pattern[ time ][1];
if ( pattern[ a ][0] < 0 && Math.abs( testAngle - pattern[ a ][1] ) < Math.abs( testAngle - pattern[ match ][1] ) )
{ match = a; }
}
坦克移动策略代码以下所表示:
if ( nextMove-- <= 0 ) {
for ( double a = 0 ; a < 500 ; a++ ) {
double testX = Math.random() * getBattleFieldWidth();
double testY = Math.random() * getBattleFieldHeight();
double distToWall = Math.min( testX , getBattleFieldWidth() - testX )* Math.min( testY , getBattleFieldHeight() - testY );
if ( distToWall > 7600 ) {
double ourAngleToPoint = getAngle( ourX , ourY , testX , testY );
double minimumAngleDifference = ( ( 500 - a ) / 500 ) * Math.PI / 6;
if ( Math.abs( angle_180( targetBearing ) - ourAngleToPoint ) > 2 * minimumAngleDifference&& Math.abs( angle_180( getHeadingRadians() ) ourAngleToPoint ) > minimumAngleDifference ) {
double turnAngle = angle_180( getAngle( ourX , ourY , testX , testY ) -getHeadingRadians() );
double moveDirection = 1;
if ( Math.abs( turnAngle ) > Math.PI / 2 ) {
moveDirection = - 1;
turnAngle += Math.acos( moveDirection ); }
setTurnRightRadians( angle_180( turnAngle ) );
setAhead( moveDirection * Point2D.Double.distance( ourX , ourY , testX , testY ) );
break;
}
}
}
nextMove = e.getDistance() / ( 29 - 3 * firePower );
}
setMaxVelocity( getTurnRemaining() > 45 ? 0.001 : 8 );
5.3游戏主窗口
游戏主窗口是人机交互窗口,对玩家而言,她们只和游戏主窗口打交道,并不关心游戏内部是怎样实现,所以游戏主窗口部分最关键便是游戏数据输入、输出。
Robocode游戏主窗口图所表示:
5.3.1游戏数据输入和运行
第一步:双击桌面上Robocode图标,运行Robocode。
第二步:在Robocode窗口中,选择“Robot”菜单中额“Editor”选项,打开Robot Editor窗口,然后实施“File”→“New” →“Java File”选项,在弹出窗口中编写Java文件。以下图所表示:
第三步:Java文件编写完成后实施“Compiler” →“Compile”选项,或按组合键Ctrl+B实施编译命令。假如没有出项错误或警告,将会显示Compiled successfully.
第四步:关闭“Compiled successfully.”窗口,打开Robocode窗口,然后实施“Battle”→“New”命令,弹出“New Battle”窗口,在“Battle”选项卡中选择自己创建机器人和系统自带两个机器人,最终单击“Start Battle”按钮开始比赛,
界面以下图所表示:
第五步:单击“Start Battle”按钮后将进入比赛场地,其中红色是我方坦克,以下图所表示:
5.3.2游戏数据输出和保留
比赛结束后,会弹出一个表格样式窗口(图4),这就是记分牌,也即你设置N个回合比赛结束后成绩单。它可是你分析数据及参与联赛关键依据。此时能够单击“Save”按钮保留比赛结果,以下图:
6.设计体会和小结
Robocode魅力所在是只要用几十行Java代码,就能立即发明出一个简单但完整机器人,还能够立即将它装入Robocode 引擎中,再从Robocode 自带那些水平不一示例机器人中选择一个进行一番对战。你能够不停修改你程序,设计新射击模型、躲避模型、移动模型,当你打败了那些示例机器人,你还能够在网上下载由其它程序员编写水平更高机器人,和它们比试一下,看看自己水平到底怎样。
开发Robocode,也是一个极佳学习Java 语言过程。对于初学者来说,这是学习多种基础语法好路径:类,方法,事件处理等等。当你入门以后,需要深入提升机器人“智力”水平,就需要使用愈加好策略:怎样估计对手行动路线,怎样躲避对手攻击......你不得不创建更多类来应对更多情况,你将学习使用接口、继承等等Java 高级语言特征。伴随你机器人“智力”水平提升,你编程能力也就跟着水涨船高了。
7.参考文件
[1].Java程序设计和应用开发(第2版) 於东军、杨静宇、李千目、王国全 著 清华大学出版社
[2].Java语言实用教程(第2版) 丁振凡 著 北京邮电大学出版社
[3].Java语言学习利器 赵超鸿、周小刚 著 中国水利水电出版社
8.源程序
程序源代码:
package xyy;
import robocode.*;
import java.awt.Color;
import java.awt.geom.Point2D;
public class moshipipei extends AdvancedRobot
{ static double nextMove;
final static int storedInfo = 800;
static double[][] pattern = new double[storedInfo][4];
public void run() {
setBodyColor(Color.red);
setRadarColor(Color.yellow);
setGunColor(Color.blue);
setBulletColor(Color.yellow);
setAdjustRadarForGunTurn(true);
setAdjustGunForRobotTurn(true);
while( true ) {
turnRadarRightRadians( Double.POSITIVE_INFINITY );
}
}
public void onScannedRobot(ScannedRobotEvent e) {
int time = (int) getTime() % storedInfo;
double targetBearing = getHeadingRadians() + e.getBearingRadians();
double ourX = getX();
double ourY = getY();
double firePower = Math.min( 3 , 30 * getEnergy() / e.getDistance() );
//下面是移动策略
if ( nextMove-- <= 0 ) {
for ( double a = 0 ; a < 500 ; a++ ) {
double testX = Math.random() * getBattleFieldWidth();
double testY = Math.random() * getBattleFieldHeight();
double distToWall = Math.min( testX , getBattleFieldWidth() - testX ) * Math.min( testY , getBattleFieldHeight() - testY );
if ( distToWall > 7600 ) {
double ourAngleToPoint = getAngle( ourX , ourY , testX , testY );
double minimumAngleDifference = ( ( 500 - a ) / 500 ) * Math.PI / 6;
if(Math.abs(angle_180(targetBearing)-ourAngleToPoint)>2*minimumAngleDifference&&Math.abs(angle_180(getHeadingRadians())-ourAngleToPoint)>minimumAngleDifference ) {
double turnAngle = angle_180( getAngle( ourX , ourY , testX , testY ) - getHeadingRadians() );
double moveDirection = 1;
if ( Math.abs( turnAngle ) > Math.PI / 2 ) {
moveDirection = - 1;
turnAngle += Math.acos( moveDirection );
}
setTurnRightRadians( angle_180( turnAngle ) );
setAhead( moveDirection * Point2D.Double.distance(ourX ,ourY , testX , testY ) );
break; } } }
nextMove = e.getDistance() / ( 29 - 3 * firePower ); }
setMaxVelocity( getTurnRemaining() > 45 ? 0.001 : 8 );
// 移动算法结束
// 以下是模式匹配算法
int match = 0;
pattern[time][0]=e.getDistance()/( 20 - 3 * firePower );
pattern[time][1]=e.getVelocity()*Math.sin(e.getHeadingRadians()
-targetBearing);
//也就是说pattern[ time ][1]统计是直线提前量射击角度和自己子弹速度乘积
pattern[ time ][2] = pattern[ time ][3] = 0;
for ( int a = 0; a < storedInfo; a++ ) {
//每个统计点pattern[a]中,假如目前时间是在我子弹抵达敌人之前则累加计算到myBulletVelocity*Math.sin(predictionAngle)值;
//同时统计累加了多少次(pattern[ a ][3]值)
if ( pattern[a][0] > 0 ) {
pattern[a][2]+=e.getVelocity()*Math.sin(e.getHeadingRadians()
-targetBearing );
pattern[ a ][0]--;
pattern[ a ][3]++;
}
}
//在历史中(全部统计中)寻求一个和现在myBulletVelocity*Math.sin(predictionAngle)值最相近统计点(这个纪录点必需是累加完成点pattern[a][0]<0)
//把这个纪录点数组下表统计到match中
for ( int a = 0; a < storedInfo; a++ ) {
double testAngle = pattern[ time ][1];
if ( pattern[ a ][0] < 0 && Math.abs( testAngle - pattern[ a ][1] ) < Math.abs( testAngle - pattern[ match ][1] ) ) {
match = a;
}
}
//模式匹配分析结束
Double linearPredictionAngle = pattern[ match ][2] / ( pattern[ match ][3] * ( 20 - 3 * firePower ) );
linearPredictionAngle=linearPredictionAngle>= 0? linearPredictionAngle: 0 ;
setTurnGunRightRadians( angle_180( targetBearing - getGunHeadingRadians() + linearPredictionAngle ) );
setTurnRadarRightRadians( Math.tan( targetBearing - getRadarHeadingRadians() ) * 3 );
if ( getEnergy() > Math.min( e.getEnergy() + firePower + 0.1 , 3.1 )
{ setFire( firePower );
}
scan();
}
public double angle_180( double ang ) {
return Math.atan2( Math.sin( ang ), Math.cos( ang ) );
}
double getAngle( double x1 , double y1 , double x2 , double y2 )
{ return Math.atan2( x2 - x1 , y2 - y1 );
}
}
展开阅读全文