第四章 算法详细设计
4.1 程序描述
本坦克大战游戏通过监听用户的键盘输入对我方坦克即游戏的相关模式进行相应的操作。
用户只要给出坦克方向,坦克便会根据方向相应的改变坦克的坐标,再通过坦克大战管理类的线程重画不断的将坦克画出,从而达到坦克连续移动的效果:当用户按住方向键,我方坦克的move方法就会执行,松开按键就会关闭移动方法。将方向判断和移动方法分开处理,而方向是由键盘监听实现的,这样就可以避免监听事件不均匀造成的坦克移动卡顿的问题。
游戏中的敌方坦克和子弹都是通过改变坐标,或者设定是否存活的属性并通坦克大战管理类线程重画不断的将当前屏幕中存活的子弹数和坦克数画出来实现动态的改变效果的。
4.2 算法
4.2.1 坦克大战游戏管理类算法
1、坦克大战管理类是启动游戏的主类。游戏界面的启动还有游戏应该有的成员(敌我坦克,子弹,墙体等等)都在这个管理类内添加和重画。
2、在解决屏幕闪屏的时候,使用了双缓冲技术。根据线程在调用repaint方法重画时会先调用update方法然后再调用paint方法,可以通过重写update方法解决这个问题。
3、游戏坦克,子弹的增加和删除是通过对坦克大战管理类的各项集合进行增删操作来实现的。
4、坦克大战管理类设计源码:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
public class TankClient extends Frame {
public static final int screenWeight = 800;
public static final int screenHeight = 600;
Image offImageScreen = null;
public static int num = 0;//无尽模式使用次数(次数越多,敌方坦克越多)
private boolean challenge = false;//求败模式开关
Tank myTank = null ;
List tanks = new ArrayList();//敌方坦克集合
List shells = new ArrayList();//弹药集合
List walls = new ArrayList();//墙体集合
Blood blood = null;
public static void main(String[] args) {
TankClient tc = new TankClient();
tc.lunchClient();
}
public boolean isChallenge() {
return challenge;
}
public void setChallenge(boolean challenge) {
this.challenge = challenge;
}
//启动面板(游戏)
public void lunchClient(){
myTank = new Tank(50,50,true,this);
//窗口出来前加入10辆敌方坦克
for(int i = 0;i < 10;i++)
{
Tank t = new Tank(200 + 40*i,myTank.getY(),false,this);
t.eTank();
tanks.add(t);
}
//启动游戏时加入墙体
Wall w1 = new Wall(200,200,500,20,0,this);
walls.add(w1);
Wall w2 = new Wall(220,220,20,300,1,this);
walls.add(w2);
setSize(screenWeight,screenHeight);
setTitle("TankWar");
setLocation(100,100);
setBackground(Color.BLACK);
this.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
setVisible(true);
this.setResizable(false);
this.addKeyListener(new KeyMonitor());
new Thread(new ThreadClient()).start();
}
public void paint(Graphics g){
Color c = g.getColor();
g.setColor(Color.green);
g.drawString("屏幕中存在的子弹数 : " + shells.size() , 30, 50);
g.drawString("屏幕中的敌方坦克数 : " + tanks.size(), 30, 70);
g.drawString("复 活 : F2", 30, 90);
g.drawString("超 级 火 力 : O", 30, 110);
g.drawString("无 尽 模 式 : F3", 30, 130);
g.drawString("独 孤 求 败 : F4", 30, 150);
g.drawString("等 级" + myTank.getLevel(), 700, 530);
g.drawString("分 数" + myTank.getScore(), 700, 550);
g.drawString("提示:我方坦克卡死," +"\n" + "请按F12自杀", 600, 570);
g.setColor(c);
//回血胶囊
//随机出现回复血条
Random rn = new Random();
int visit = rn.nextInt(300);
if(visit == 31)
blood = new Blood(1,this);
else if(visit == 30)
blood = new Blood(0,this);
if(blood != null)
blood.drawBlood(g);
//每次重画检测碰撞
hitCheck();
//墙体画出
if(walls.size() != 0)
{
for(int i = 0;i < walls.size();i++)
walls.get(i).drawWall(g);
}
//弹药画出
if(shells.size() != 0){
for(int i = 0;i < shells.size();i++)
{
Shell s = shells.get(i);
if(s.isLive())
s.drawShell(g);
else
shells.remove(s);
}
}
//我放坦克画出
if(myTank.isLive())
myTank.drawTank(g);
//敌方坦克画出
if(tanks.size() != 0)
for(int i = 0;i < tanks.size();i++)
{
Tank t = tanks.get(i);
if(t.isLive())
t.drawTank(g);
t.eTank();//敌方坦克移动
t.hitTank(myTank, g);//敌方攻击我方
}
myTank.hitTanks(g);//我方攻击敌方
}
//双缓冲解决闪屏问题(调用repaint方法重画时会先调用update方法然后再调用paint方法)
//重写update方法设置背景
public void update(Graphics g){
if(offImageScreen == null){
offImageScreen = this.createImage(screenWeight, screenHeight);
}
Graphics gOffScreen = offImageScreen.getGraphics();
Color c = gOffScreen.getColor();
gOffScreen.setColor(Color.BLACK);
gOffScreen.fillRect(0, 0, screenWeight, screenHeight);
gOffScreen.setColor(c);
paint(gOffScreen);
g.drawImage(offImageScreen, 0, 0, null);
}
//按键监听调用Tank类的方法
class KeyMonitor extends KeyAdapter {
public void keyPressed(KeyEvent e){
myTank.keyPressed(e);
}
public void keyReleased(KeyEvent e){
myTank.keyReleased(e);
}
}
//重画配置
class ThreadClient implements Runnable {
public void run() {
while(true){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println("1号错误");
}
repaint();
}
}
}
public void hitCheck(){
//两辆坦克不能重合
for(int i = 0;i < tanks.size();i++)
{
if(myTank.getRect().intersects(tanks.get(i).getRect()))
{
tanks.get(i).stay();
myTank.stay();
}
for(int j = 0;j < tanks.size();j++)
{
if(i == j) continue;
if(tanks.get(i).getRect().intersects(tanks.get(j).getRect()))
{
tanks.get(i).stay();
tanks.get(j).stay();
}
}
}
//坦克与墙的碰撞检测
for(int j = 0;j < walls.size();j++)
{
if(myTank.getRect().intersects(walls.get(j).getRect()))
{
myTank.stay();
}
for(int i = 0;i < tanks.size();i++)
{
if(tanks.get(i).getRect().intersects(walls.get(j).getRect()))
{
tanks.get(i).stay();
}
}
}
//子弹与墙
for(int i = 0;i < shells.size();i++)
{
for(int j = 0;j < walls.size();j++)
{
if(shells.get(i).getRect().intersects(walls.get(j).getRect()) && walls.get(j).getNumber() != 1)
{
shells.get(i).setLive(false);
}
}
}
for(int i = 0;i < shells.size();i++)
{
for(int j = 0;j < shells.size();j++)
{
if(i == j) continue;
if(shells.get(i).getRect().intersects(shells.get(j).getRect()) &&
shells.get(i).isGood() != shells.get(j).isGood())
{
shells.get(i).setLive(false);
shells.get(j).setLive(false);
}
}
}
}
}