我写的一个小坦克程序
我写的一个小坦克程序,但发现它运行起来比较慢,请各位给点建议。运行程序后,点击start按钮,再用鼠标点击一下画面中间,然后按下上下左右箭头键就可以让坦克动起来。
程序名为Tank.java,只有一个文件。因为太长,无法一次贴完,所以分两次发出。
--------------------------------------
import java.util.*;
import java.applet.*;
import java.awt.event.*;
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.Color;
import java.io.*;
import java.lang.Math.*;
import java.text.DecimalFormat;
class OneTank {
//坦克的长度
double tank_length = 30;
// 坦克的宽度
double tank_width = 20;
//履带的宽度
double panel_width = 6;
// 坦克中心部分的宽度
double core_width = tank_width - panel_width;
// 坦克中心部分的长度
double core_length = tank_length * 0.75;
// 坦克炮管的长度
double canon_length = tank_length / 2;
//坦克炮管的宽度
double canon_width = 4;
//----------------
// 坦克所处的中心位置
double[] center;
//坦克旋转的角度
double angle;
// 敌我双方的哪一方
String side;
//坦克颜色
Color color;
//坦克速度
double speed;
//坦克生命值
double value;
double[] pt1, pt2, pt3, pt4, pt5, pt6, pt7, pt8, pt9, pt10, pt11, pt12, pt13, pt14, pt15, pt16;
OneTank() {
}
void draw(Graphics g, Color c) {
Graphics2D d2=(Graphics2D)g;
d2.setColor(c);
/*
AffineTransform at=new AffineTransform();
at.setToIdentity();
at.translate((int) center[0], (int)center[1]);
at.rotate(angle);
d2.setTransform(at);
*/
d2.drawLine((int) pt1[0], (int)pt1[1], (int) pt2[0], (int)pt2[1]);
d2.drawLine((int) pt2[0], (int)pt2[1], (int) pt4[0], (int)pt4[1]);
d2.drawLine((int) pt4[0], (int)pt4[1], (int) pt3[0], (int)pt3[1]);
d2.drawLine((int) pt3[0], (int)pt3[1], (int) pt1[0], (int)pt1[1]);
d2.drawLine((int) pt5[0], (int)pt5[1], (int) pt7[0], (int)pt7[1]);
d2.drawLine((int) pt7[0], (int)pt7[1], (int) pt8[0], (int)pt8[1]);
d2.drawLine((int) pt8[0], (int)pt8[1], (int) pt6[0], (int)pt6[1]);
d2.drawLine((int) pt6[0], (int)pt6[1], (int) pt5[0], (int)pt5[1]);
d2.drawLine((int) pt10[0], (int)pt10[1], (int) pt9[0], (int)pt9[1]);
d2.drawLine((int) pt9[0], (int)pt9[1], (int) pt11[0], (int)pt11[1]);
d2.drawLine((int) pt11[0], (int)pt11[1], (int) pt12[0], (int)pt12[1]);
d2.drawLine((int) pt12[0], (int)pt12[1], (int) pt10[0], (int)pt10[1]);
//炮管
d2.drawLine((int) pt13[0], (int)pt13[1], (int) pt14[0], (int)pt14[1]);
d2.drawLine((int) pt14[0], (int)pt14[1], (int) pt15[0], (int)pt15[1]);
d2.drawLine((int) pt15[0], (int)pt15[1], (int) pt16[0], (int)pt16[1]);
d2.drawLine((int) pt16[0], (int)pt16[1], (int) pt13[0], (int)pt13[1]);
}
}
class TankSys extends JFrame implements ActionListener, KeyListener{
boolean firstTimeRunning = true;
// 标志线程是否运行
boolean ThreadRunning = false;
// 目前哪一个星球是被聚焦的,默认是0号,即第一个
int WhichPlanetFocus= 0;
double PI =Math.PI;
double PI20 = PI * 2.0;
double PI05 = PI / 2.0;
double[] original_pt = new double[] {0, 0};
double final_angle, temp_angle, temp;
// 这是绘画所有运动星球图画的区域
// 初始化记录所有星球类
ArrayList<OneTank> tanks = new ArrayList<OneTank>();
// 这是在cvs上面的图像,它用于在上面画星球的图像
Image image;
// 这是image的Graphics
Graphics cvsimage, gimage;
// 获取屏幕大小
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize = kit.getScreenSize();
// 屏幕宽度
int swidth = screenSize.width;
// 屏幕高度
int sheight = screenSize.height;
// 屏幕中心位置
int ScreenCenterx = (int)(swidth / 2);
int ScreenCentery = (int)(sheight / 2);
// 这是用鼠标点击屏幕所获得的绘画中心的偏移量
int CenterOffsetx = ScreenCenterx;
int CenterOffsety = ScreenCentery;
Canvas cvs;
// 这是cvs的大小
int cvsw = swidth;
int cvsh = sheight - 100;
// 这是按钮区
JPanel btnpan;
JButton btnstart;
// 一旦按下这个开始键,程序开始运行太阳系
boolean StartToRun = false;
public TankSys() {
// 这是整个图框的大小
this.setSize(swidth, sheight);
this.setVisible(true);
btnpan = new JPanel();
btnpan.setLayout(new FlowLayout());
this.getContentPane().add(btnpan, BorderLayout.NORTH);
// 开始游戏的按钮
btnstart = new JButton("Start");
btnpan.add(btnstart);
btnstart.addActionListener(this);
cvs = new Canvas();
// 画图区的大小
cvs.setSize(cvsw, cvsh);
this.getContentPane().add(cvs, BorderLayout.CENTER);
cvs.createBufferStrategy(2);
// 用户必须点击CVS来获得聚焦点,这时候才能接受键盘输入
cvs.addKeyListener(new KeyHandler());
cvs.addMouseListener(new MouseHandler());
cvsimage = cvs.getGraphics();
cvs.setBackground(Color.BLACK);
// 这是在cvs上面的图像,它用于在上面画星球的图像
image = createImage(cvsw, cvsh);
gimage = image.getGraphics();
this.pack();
}
class MouseHandler implements MouseListener{
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e){
}
public void mouseReleased(MouseEvent e){
}
public void mouseEntered(MouseEvent e){
}
public void mouseExited(MouseEvent e){
}
}
public void keyReleased(KeyEvent e) {//键盘弹起事件
}
public void keyPressed(KeyEvent e) {
}
public void keyTyped (KeyEvent e) {// 键盘按下事件
}
class KeyHandler extends KeyAdapter{
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_ADD://按下数字键盘上的+
case KeyEvent.VK_PAGE_UP://按下PageUp键
break;
case KeyEvent.VK_SUBTRACT://按下数字键盘上的-
case KeyEvent.VK_PAGE_DOWN://按下PageDown
break;
case KeyEvent.VK_SPACE://按下空格键
case KeyEvent.VK_P://按下PauseBreak
break;
case KeyEvent.VK_UP://按下向上键
// 提高星球的线速度
temp = tanks.get(0).center[0] + tanks.get(0).speed * Math.cos(tanks.get(0).angle - PI05);
tanks.get(0).center[0] = temp;
temp = tanks.get(0).center[1] + tanks.get(0).speed * Math.sin(tanks.get(0).angle - PI05);
tanks.get(0).center[1] = temp;
forward_tank(tanks.get(0));
break;
case KeyEvent.VK_DOWN://按下向下键
// j降低星球的线速度
temp = tanks.get(0).center[0] + tanks.get(0).speed * Math.cos(tanks.get(0).angle + PI05);
tanks.get(0).center[0] = temp;
temp = tanks.get(0).center[1] + tanks.get(0).speed * Math.sin(tanks.get(0).angle + PI05);
tanks.get(0).center[1] = temp;
forward_tank(tanks.get(0));
break;
case KeyEvent.VK_LEFT://按下向左键
// 第一个坦克一定是我方坦克
temp_angle = tanks.get(0).angle - 5.0/180.0 * PI;
if (temp_angle > PI20) {
final_angle = temp_angle - PI20;
} else if (temp_angle < 0) {
final_angle = PI20 + temp_angle;
} else {
final_angle = temp_angle;
}
tanks.get(0).angle = final_angle;
forward_tank(tanks.get(0));
// 降低vx方向的速度
break;
case KeyEvent.VK_RIGHT://按下向右键
temp_angle = tanks.get(0).angle + 5.0/180.0 * PI;
if (temp_angle > PI20) {
final_angle = temp_angle - PI20;
} else if (temp_angle < 0) {
final_angle = PI20 + temp_angle;
} else {
final_angle = temp_angle;
}
tanks.get(0).angle = final_angle;
forward_tank(tanks.get(0));
break;
default:
}
}
}
// 这是主程序
void DrawTank() {
if (firstTimeRunning) {
firstTimeRunning = false;
// 创建我方坦克
double[] center_pos = new double[] {500, 500};
OneTank one = new OneTank();
one.center = center_pos;
one.angle = PI;
double[][] re= rotate_tank(center_pos, one.angle, one.tank_length, one.tank_width, one.panel_width, one.core_width, one.core_length, one.canon_length, one.canon_width);
one.pt1=re[0];
one.pt2=re[1];
one.pt3=re[2];
one.pt4=re[3];
one.pt5=re[4];
one.pt6=re[5];
one.pt7=re[6];
one.pt8=re[7];
one.pt9=re[8];
one.pt10=re[9];
one.pt11=re[10];
one.pt12=re[11];
one.pt13=re[12];
one.pt14=re[13];
one.pt15=re[14];
one.pt16=re[15];
one.side="2";
one.color=Color.white;
one.speed=4;
one.value=50;
tanks.add(one);
}
while (ThreadRunning) {
// 把图像以前在上面所画的所有图像用黑色抹掉
gimage.setColor(Color.black);
gimage.fillRect(0, 0, cvsw, cvsh);
for (int i = 0; i < tanks.size(); i++) {
tanks.get(i).draw(gimage, tanks.get(i).color);
}
cvsimage.drawImage(image, 0, 0, this);
// 计算所有星球的速度和位置
for (int i = 0; i < tanks.size(); i++) {
//forward_tank(tanks.get(i));
}
}
}
// 由一点和角度方向和距离决定一点坐标
double[] point_and_angle (double[] pt0, double angle, double dist) {
double x = pt0[0]+ dist * Math.cos (angle);
double y = pt0[1] + dist * Math.sin (angle);
return new double[] {x, y};
}
[解决办法]
之所以会运行起来慢,是因为你把操作都放到键盘监听里了,正确的做法应该是:
创建一个全局变量:private static boolean keyDown[256]; //256个按键的状态
键盘监听:if key Down{
keyDown[keyCode] = true;
}
if key Release{
keyDown[keyCode] = false;
}
键盘的监听里只改变状态,不进行任何操作。
对于操作,在你的游戏线程里进行。
例如,你可以在游戏线程里再写这样一段代码:
.....
if(keyDwon[KeyEvent.VK_UP]){
...}
else if
...
保证不卡