本科做的小项目,现在整理一下:
package T1;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
import java.util.Vector;
//1
public class Tank1 extends JFrame implements ActionListener{//1
MyPanel mp=null;
GuankaPanel gkmp=null;
JMenuBar cdl=null;
JMenu cd1=null;
JMenuItem cdxl=null;
public static void main(String[] args) {
Tank1 t1=new Tank1();
}
public Tank1(){
// mp=new MyPanel();
//
// this.add(mp);
// //9,事件响应写完后,必须添加一个监听,否则坦克是动不起来的
// this.addKeyListener(mp);
// Thread t=new Thread(mp);//子弹可以自己运动,而不是随着坦克运动
// t.start();
cdl=new JMenuBar();
cd1=new JMenu("游戏(G)");
cd1.setMnemonic('G');
cdxl=new JMenuItem("新游戏(N)");
cdxl.addActionListener(this);
cdxl.setActionCommand("xyx");
cd1.add(cdxl);
cdl.add(cd1);
gkmp=new GuankaPanel();
Thread t=new Thread(gkmp);
t.start();
this.setJMenuBar(cdl);
this.add(gkmp);
this.setTitle("坦克大战");
this.setSize(600, 500);
this.setLocation(300, 280);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getActionCommand().equals("xyx")) {
mp=new MyPanel();
this.remove(gkmp);//删除旧面板
this.add(mp);
//9,事件响应写完后,必须添加一个监听,否则坦克是动不起来的
this.addKeyListener(mp);
Thread t=new Thread(mp);//子弹可以自己运动,而不是随着坦克运动
t.start();
this.setVisible(true);
}
}
}
class GuankaPanel extends JPanel implements Runnable{
int times=0;
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 400, 300);
if(times%2==0) {
g.setColor(Color.YELLOW);
Font myFont=new Font("华文行楷",Font.BOLD,38);
g.setFont(myFont);
g.drawString("第一关", 140, 140);
}
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
try {
Thread.sleep(600);
}catch(Exception e) {}
times++;
this.repaint();
}
}
}
class MyPanel extends JPanel implements KeyListener,Runnable{//4
MyTank mt=null;
Vector<DiTank> dtk=new Vector<DiTank>();
//下一行子弹击中爆炸的diamagnetic
//Vector<Baozha> bzjh=new Vector<Baozha>();
//这个集合类只能放敌方坦克,所以用了泛型,避免强转
//敌方坦克是要编成坦克组的,所以需要集合类,Vector和ArrayList类似,但是ArrayList是单线程的
//全部由用户可控制用单线程ArrayList,随机性用多线程Vector
int tksl=3;
//下三行子弹击中爆炸的代码
// Image tp1=null;
// Image tp2=null;
// Image tp3=null;
//MyTank mt1=null;可以画第二个坦克,3,4,5,6,
public MyPanel() {
mt=new MyTank(140,232);
for(int i=0;i<tksl;i++) {
DiTank dt=new DiTank((i)*55+5,0);
dt.setFangxiang(2);
//下两行时为了敌人的坦克随机动而添加的代码,画出一辆坦克,启动一个线程,画出一辆,启动一个线程
Thread t2=new Thread(dt);
t2.start();
Zidan zd=new Zidan(dt.x+10,dt.y+30,2);
dt.dzd.add(zd);
Thread t3=new Thread(zd);
t3.start();
dtk.add(dt);//不是太懂
}
//下三行子弹击中爆炸的代码
// tp1=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/tank1.jpg"));
// tp2=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/tank2.jpg"));
// tp3=Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/tank3.jpg"));
//再画一个坦克
//mt1=new MyTank(300,100);
}
public void tjsj(Graphics g) {
this.drawTank(80, 330, g, 0, 0);
g.setColor(Color.black);
g.drawString(Jilu.getMtsl()+"", 116, 350);//整型数据再后面加上双引号以后,会把正i选哪个数据转换成字符串
this.drawTank(150, 330, g, 0, 1);
g.setColor(Color.black);
g.drawString(Jilu.getDtsl()+"", 186, 350);
}
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 400, 300);
this.tjsj(g);
//绘制画布,因为默认主界面是白色的,所以需要绘制填充矩形,填充矩形默认是黑色
//g.setColor(Color.YELLOW);
//g.fill3DRect(mt.getX(), mt.getY(), 5, 30, false);//坦克左边的一个矩形
//g.fill3DRect(mt.getX()+15, mt.getY(), 5, 30, false);//坦克最右边的那个矩形
//g.fill3DRect(mt.getX()+5, mt.getY()+5, 10, 20, false);//坦克中间的小矩形
//g.fillOval(mt.getX()+5, mt.getY()+10, 10, 10);//坦克中间的椭圆
//g.drawLine(mt.getX()+10, mt.getY()+15, mt.getX()+10, mt.getY()-3);
//为了程序的扩展性,将画tank的函数单独出来
if(mt.shengming) {
this.drawTank(mt.getX(),mt.getY(),g,mt.fangxiang,0);//坦克的方向问题只需要在此传进去mt.fangxiang即可
}
//this.drawTank(mt1.getX(),mt1.getY(),g,0,1);
//绘制敌方坦克
for(int i=0;i<dtk.size();i++) {
DiTank dt=dtk.get(i);//自己编的
if(dt.shengming) {
this.drawTank(dt.getX(), dt.getY(), g, dt.fangxiang,1);
for(int j=0;j<dt.dzd.size();j++) {
Zidan dtzd=dt.dzd.get(j);
if(dtzd.shengming) {
g.setColor(Color.white);
g.fill3DRect(dtzd.x, dtzd.y, 5, 5,false);
}else {
dt.dzd.remove(dtzd);
}
}
}
}
for(int i=0;i<mt.aa.size();i++) {//为了解决只能发射一个子弹的问题
Zidan zd=mt.aa.get(i);
if(zd!=null&&zd.shengming==true) {//这个子弹不用mt.zd,直接用for循环里面的子弹
g.setColor(Color.RED);
g.fill3DRect(zd.x, zd.y, 5, 5, false);
}
if(zd.shengming==false){
mt.aa.remove(zd);
}
}
//子弹击中时爆炸的代码
// for(int i=0;i<bzjh.size();i++)
// {
// Baozha bz=bzjh.get(i);
// if(bz.shengcunqi>6)
// {
// g.drawImage(tp1, bz.x, bz.y, 30, 30, this);
//
// }else if(bz.shengcunqi>3)
// {
// g.drawImage(tp2, bz.x, bz.y, 30,30, this);
//
// }else {
// g.drawImage(tp3, bz.x, bz.y, 30, 30, this);
// }
// bz.suqsd();
// if(bz.shengcunqi==0) {
// bzjh.remove(bz);
//
// }
//
// }
}
public void jzwf() {
for(int i=0;i<this.dtk.size();i++) {//敌方的坦克一个一个取出来
DiTank dt=dtk.get(i);
for(int j=0;j<dt.dzd.size();j++) {//敌方的子弹一个一个取出来
Zidan zd=dt.dzd.get(j);
this.jzdf(zd, mt);//子弹和我方的坦克
}
}
}
public void jzdf1() {
for(int i=0;i<mt.aa.size();i++) {//每取出一颗子弹
Zidan zd=mt.aa.get(i);
if(zd.shengming) {//如果有子弹的话
for(int j=0;j<dtk.size();j++) {//每取出一个敌人的坦克,就是让我方所有的子弹何敌方所有的坦克进行比较
DiTank dt=dtk.get(j);
if(dt.shengming) {
this.jzdf(zd, dt);
}
}
}
this.repaint();
}
}
private void jzdf(Zidan zd, Tank dt) {//必须放在MyPanel类中,因为如果没击中需要重绘
// TODO Auto-generated method stub
switch(dt.fangxiang) {
//上和下是一样的
case 0:
case 2:
if(zd.x>dt.x && zd.x<dt.x+20 && zd.y>dt.y && zd.y<dt.y+30) {
zd.shengming=false;
dt.shengming=false;
Jilu.dtjs();
// Baozha bz=new Baozha(dt.x,dt.y);
// bzjh.add(bz);
}
break;
case 1:
case 3:
if(zd.x>dt.x && zd.x<dt.x+30 && zd.y>dt.y && zd.y<dt.y+20) {
zd.shengming=false;
dt.shengming=false;
Jilu.dtjs();
}
}
}
public void drawTank(int x,int y,Graphics g,int fangxiang,int leixing) {//5
//参数中必须传一个画笔进来
switch(leixing){
case 0://我的坦克
g.setColor(Color.YELLOW);
break;
case 1://敌人的坦克
g.setColor(Color.GREEN);
break;
}
switch(fangxiang) {
case 0://上
g.fill3DRect(x, y, 5, 30, false);
g.fill3DRect(x+15, y, 5, 30, false);
g.fill3DRect(x+5, y+5, 10,20, false);
g.fillOval(x+5,y+10, 10, 10);
g.drawLine(x+10, y+15, x+10, y-3);
break;
case 1://左
g.fill3DRect(x, y, 30, 5,false);
g.fill3DRect(x, y+15, 30, 5, false);
g.fill3DRect(x+5, y+5, 20, 10, false);
g.fillOval(x+10, y+5, 10,10);
g.drawLine(x+15,y+10, x-3,y+10);
break;
case 2://下
g.fill3DRect(x, y, 5, 30, false);
g.fill3DRect(x+15, y, 5, 30, false);
g.fill3DRect(x+5, y+5, 10,20, false);
g.fillOval(x+5, y+10, 10, 10);
g.drawLine(x+10, y+15, x+10, y+33);
break;
case 3://右
g.fill3DRect(x, y, 30, 5,false);
g.fill3DRect(x, y+15, 30, 5, false);
g.fill3DRect(x+5, y+5, 20, 10, false);
g.fillOval(x+10, y+5, 10,10);
g.drawLine(x+15,y+10, x+33, y+10);
break;
}
}
//8添加事件响应,只需要重写KeyPressed,其他两个方法不用管
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if(e.getKeyCode()==KeyEvent.VK_W) {
this.mt.setFangxiang(0);
this.mt.xiangshang();
}else if(e.getKeyCode()==KeyEvent.VK_A) {
this.mt.setFangxiang(1);
this.mt.xiangzuo();
}else if(e.getKeyCode()==KeyEvent.VK_S) {
this.mt.setFangxiang(2);
this.mt.xiangxia();
}else if(e.getKeyCode()==KeyEvent.VK_D) {
this.mt.setFangxiang(3);
this.mt.xiangyou();
}
if(e.getKeyCode()==KeyEvent.VK_J) {
if(this.mt.aa.size()<8) {//限制子弹的连发,不能一按就是一整串
this.mt.fszd();
}
}
this.repaint();
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
try {
Thread.sleep(100);//隔着100毫秒之后再重新绘制子弹,而不是无间断的重绘
}catch(Exception e) {}
for(int i=0;i<mt.aa.size();i++) {//有子弹的情况下
Zidan zd=mt.aa.get(i);//装进去
if(zd.shengming) {//子弹的生命有效
//二层循环的意思就是让每一发子弹和每个敌人坦克进行比较
for(int j=0;j<dtk.size();j++) {//让子弹和坦克的坐标进行比较
DiTank dt=dtk.get(j);//把敌人的坦克装进去
if(dt.shengming) {
this.jzdf(zd,dt);//调用击中敌方这个函数
}
}
}
this.repaint();
}
}
}
}
package T1;
import java.util.Vector;
class Tank{//2
//6充实坦克类
int x=0,y=0;//x为横坐标,y为纵坐标
//选中,右键-source-Generate Getters and Setters,生成下面的这些封装方法
//为坦克添加方向和速度,并且将方向和速度也封装起来
int fangxiang=0;
int sudu=5;
int Color;
boolean shengming=true;
public int getColor() {
return Color;
}
public void setColor(int color) {
Color = color;
}
public int getFangxiang() {
return fangxiang;
}
public void setFangxiang(int fangxiang) {
this.fangxiang = fangxiang;
}
public int getSudu() {
return sudu;
}
public void setSudu(int sudu) {
this.sudu = sudu;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
//然后写一个构造方法
public Tank(int x,int y) {
//初始化横纵坐标
this.x=x;
this.y=y;
}
}
class DiTank extends Tank implements Runnable{
int sudu=7;//为了让敌人的坦克比自己的坦克快
int time=0;
Vector<Zidan> dzd=new Vector<Zidan>();
Vector<DiTank> dtk=new Vector<DiTank>();
public DiTank(int x, int y) {
super(x, y);
// TODO Auto-generated constructor stub
}
public void dtkxl(Vector<DiTank> dxl) {//避免敌方坦克的重叠
this.dtk=dxl;
}
public boolean huxiangpengzhuang() {
boolean b=false;
switch(this.fangxiang) {
case 0:
for(int i=0;i<dtk.size();i++) {//取出每一辆敌坦克
DiTank dt=dtk.get(i);
if(dt!=this) {//如果敌人的坦克不等于自己
if(dt.fangxiang==0||dt.fangxiang==2) {
if(this.x>=dt.x && this.x<=dt.x+20 && this.y>=dt.y && this.y<=dt.y+30) {
return true;
}
if(this.x+20>=dt.x && this.x+20<dt.x+20 && this.y>=dt.y && this.y<=dt.y+30) {
return true;
}
}
if(dt.fangxiang==1||dt.fangxiang==3) {
if(this.x>=dt.x && this.x<=dt.x+20 && this.y>=dt.y && this.y<=dt.y+30) {
return true;
}
if(this.x+20>=dt.x && this.x+20<dt.x+30 && this.y>=dt.y && this.y<=dt.y+20) {
return true;
}
}
}
}
break;
case 1:
for(int i=0;i<dtk.size();i++) {//取出每一辆敌坦克
DiTank dt=dtk.get(i);
if(dt!=this) {//如果敌人的坦克不等于自己
if(dt.fangxiang==0||dt.fangxiang==2) {
if(this.x>=dt.x && this.x<=dt.x+20 && this.y>=dt.y && this.y<=dt.y+30) {
return true;
}
if(this.x+20>=dt.x && this.x+20<dt.x+20 && this.y>=dt.y && this.y<=dt.y+30) {
return true;
}
}
if(dt.fangxiang==1||dt.fangxiang==3) {
if(this.x>=dt.x && this.x<=dt.x+20 && this.y>=dt.y && this.y<=dt.y+30) {
return true;
}
if(this.x+20>=dt.x && this.x+20<dt.x+30 && this.y>=dt.y && this.y<=dt.y+20) {
return true;
}
}
}
}
break;
case 2:
for(int i=0;i<dtk.size();i++) {//取出每一辆敌坦克
DiTank dt=dtk.get(i);
if(dt!=this) {//如果敌人的坦克不等于自己
if(dt.fangxiang==0||dt.fangxiang==2) {
if(this.x>=dt.x && this.x<=dt.x+20 && this.y>=dt.y && this.y<=dt.y+30) {
return true;
}
if(this.x+20>=dt.x && this.x+20<dt.x+20 && this.y>=dt.y && this.y<=dt.y+30) {
return true;
}
}
if(dt.fangxiang==1||dt.fangxiang==3) {
if(this.x>=dt.x && this.x<=dt.x+20 && this.y>=dt.y && this.y<=dt.y+30) {
return true;
}
if(this.x+20>=dt.x && this.x+20<dt.x+30 && this.y>=dt.y && this.y<=dt.y+20) {
return true;
}
}
}
}
break;
case 3:
for(int i=0;i<dtk.size();i++) {//取出每一辆敌坦克
DiTank dt=dtk.get(i);
if(dt!=this) {//如果敌人的坦克不等于自己
if(dt.fangxiang==0||dt.fangxiang==2) {
if(this.x>=dt.x && this.x<=dt.x+20 && this.y>=dt.y && this.y<=dt.y+30) {
return true;
}
if(this.x+20>=dt.x && this.x+20<dt.x+20 && this.y>=dt.y && this.y<=dt.y+30) {
return true;
}
}
if(dt.fangxiang==1||dt.fangxiang==3) {
if(this.x>=dt.x && this.x<=dt.x+20 && this.y>=dt.y && this.y<=dt.y+30) {
return true;
}
if(this.x+20>=dt.x && this.x+20<dt.x+30 && this.y>=dt.y && this.y<=dt.y+20) {
return true;
}
}
}
}
break;
}
return b;//因为上面所有的return 都在循环里面,所以编译器会认为不一定会有return被执行
}
@Override
public void run() {
// TODO Auto-generated method stub
// while(true) {
// try {
// Thread.sleep(50);
// }catch(Exception e) {}
// switch(this.fangxiang) {
// case 0:
// y-=sudu;
// break;
// case 1:
// x-=sudu;
// break;
// case 2:
// y+=sudu;
// break;
// case 3:
// x+=sudu;
// break;
//
//
// }
// this.fangxiang=(int)(Math.random()*4);//随机出现0-3之间的数字
// if(this.shengming==false) {//只有生命为假时,才能没有,不能坦克自己飞着就没了
// break;
//
// }
//
// }
//修改后让敌人的坦克可以运动一段时间再换方向,而不是随意的改变方向
while(true) {
switch(this.fangxiang) {
case 0:
for(int i=0;i<30;i++) {
if(y>0&& !huxiangpengzhuang()) {
y-=sudu;}
try {
Thread.sleep(50);
}catch(Exception e) {}
}
break;
case 1:
for(int i=0;i<30;i++) {//30这个数越大,它向着一个方向走的时间就越长
if(x>0 && !huxiangpengzhuang()) {//限制边界
x-=sudu;}
try {
Thread.sleep(50);
}catch(Exception e) {}
}
break;
case 2:
for(int i=0;i<30;i++) {
if(y<250 && !huxiangpengzhuang()) {//限制边界
y+=sudu;}
try {
Thread.sleep(50);
}catch(Exception e) {}
}
break;
case 3:
for(int i=0;i<30;i++) {
if(x<360 && !huxiangpengzhuang()) {
x+=sudu;}
try {
Thread.sleep(50);
}catch(Exception e) {}
}
break;
}
this.fangxiang=(int)(Math.random()*4);//随机出现0-3之间的数字
if(this.shengming==false) {//只有生命为假时,才能没有,不能坦克自己飞着就没了
break;
}
this.time++;
if(time%2==0) {//减慢子弹的发射速度,这样就是偶数发子弹,奇数就不发子弹了
if(shengming) {//先判断生命是否为假
if(dzd.size()<5) {//应许发五个子弹
Zidan zd=null;
switch(fangxiang) {//坦克方向,
case 0:
zd=new Zidan(x+10,y,0);//输入的坐标 new一个,添加进去
dzd.add(zd);
break;
case 1:
zd=new Zidan(x,y+10,1);
dzd.add(zd);
break;
case 2:
zd=new Zidan(x+10,y+30,2);
dzd.add(zd);
break;
case 3:
zd=new Zidan(x+30,y+10,3);
dzd.add(zd);
break;
}
Thread t5=new Thread(zd);
t5.start();
}
}
}
}
}
}
//公共属性放在Tank类中,然后再建立一个MyTank和敌人的Tank,并且对Tank类进行继承,使用公共属性
class MyTank extends Tank{//子弹发射必须写进MyTank类里,因为子弹发射是需要随着我的坦克走的,子弹的功能大多和坦克有关
Vector<Zidan>aa=new Vector<Zidan>();//集合类要存就存,要取就取
//创建集合类是为了解决一次只能发送一颗子弹的问题
Zidan zd=null;
//3
//增加一个构造方法
public MyTank(int x, int y) {
super(x, y);
}
//7增加上下左右功能
public void xiangshang() {
y-=sudu;
}
public void xiangxia() {
y+=sudu;
}
public void xiangzuo() {
x-=sudu;
}
public void xiangyou() {
x+=sudu;
}
public void fszd() {
// TODO Auto-generated method stub
switch(this.fangxiang) {
//下面的左标就是画子弹的位置,不是子弹射出来,实质上是在相应的位置连续画出子弹,达到射击的效果
case 0://上
zd= new Zidan(x+10,y, 0);
aa.add(zd);//子弹只有一颗,为保证其连续性
break;
case 1://左
zd=new Zidan(x,y+10, 1);
aa.add(zd);
break;
case 2://下
zd=new Zidan(x+10,y+30, 2);
aa.add(zd);
break;
case 3://右
zd=new Zidan(x+30,y+10, 3);
aa.add(zd);
break;
}
//线程启动必须在Tank类中,因为子弹是随着坦克移动和发出的
Thread t=new Thread(zd);
t.start();
}
}
class Zidan implements Runnable{
int x;
int y;
int fangxiang;
int sudu=5;
boolean shengming=true;//这个参数就是为了防止子弹穿墙而过的
public Zidan(int x,int y,int fangxiang) {
this.x=x;
this.y=y;
this.fangxiang=fangxiang;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {//死循环下面一般都需要异常处理
try{
Thread.sleep(50);
}catch(Exception e) {}
switch(fangxiang) {
case 0://上
y-=sudu;
break;
case 1://左
x-=sudu;
break;
case 2://下
y+=sudu;
break;
case 3://右
x+=sudu;
break;
}
if(x<0||x>400||y<0||y>300) {//画布边界
this.shengming=false;
break;//如果超出边界,就停止绘制子弹
}
}
}
}
//爆炸类,爆炸的代码
//class Baozha{
// int x,y;
// int shengcunqi=9;
// boolean shengming=true;
// public Baozha(int x,int y) {
// this.x=x;
// this.y=y;
//
// }
// public void suqsd() {
// if(shengcunqi>0) {
// shengcunqi--;
//
// }
// else {
// this.shengming=false;
// }
//
// }
//}
class Jilu{
private static int dtsl=10;
private static int mtsl=2;
public static int getDtsl() {
return dtsl;
}
public static void setDtsl(int dtsl) {
Jilu.dtsl = dtsl;
}
public static int getMtsl() {
return mtsl;
}
public static void setMtsl(int mtsl) {
Jilu.mtsl = mtsl;
}
public static void dtjs() {//敌人坦克减少
dtsl--;
}
}
运行结果:(键盘中的ADSW分别为左下右上,J是发射子弹)