mytank07.java文件
/**
* 功能:坦克游戏的2.01
* 1、画出我的坦克
* 2、让我的坦克动起来
* 3、让我的坦克按下空格(space)键发射子弹
* 4、让我的坦克可以连发子弹(最多连发5颗子弹)
* 5、打到敌人坦克,敌人坦克就消失
* 6、加入坦克被击中爆炸的效果
* 7、让敌人的坦克可以自由随机移动
* 8、控制坦克在指定的MyPanel面板中移动,不可越界
* 9、让敌人的坦克发射子弹
* 10、当我的坦克被敌人子弹击中,我的坦克爆炸
* 11、防止敌人坦克重叠运动
* 12、可以分关--做一个开始的Panel,它是空的主要是提示关卡
* 13、游戏可以暂停、继续--暂停时将子弹、坦克速度设为0,坦克方向不变
* 14、可以记录玩家的成绩
* 15、java如何操作声音文件
*/
package com.haiding.tank_7;
import java.awt.*;
import java.awt.event.ActionEvent;//活动事件
import java.awt.event.ActionListener;//活动监听
import java.awt.event.KeyEvent;//键盘事件
import java.awt.event.KeyListener;//键盘监听
import java.io.File;//导入java.io包下的file类
import javax.imageio.ImageIO;//java图像处理
import javax.swing.*;
import java.util.*;//复杂的包
import javax.sound.sampled.*;//实现音频播放
public class MyTank07 extends JFrame implements ActionListener{ //定义mytank07这个子类,
//定义组件
MyPanel mp=null; //都是java UI编程里的内容 31~45
//定义一个开始面板
MyStartPanel msp=null;
//做出菜单
JMenuBar jmb=null;
//开始游戏
JMenu jm1=null;
JMenuItem jmi1=null;
//退出游戏
JMenuItem jmi2=null;
//存盘退出
JMenuItem jmi3=null;
//接上局
JMenuItem jmi4=null;
public static void main(String[] args) {
MyTank07 mt=new MyTank07(); //定义类的对象mt
}
//构造函数
public MyTank07(){ //java子类构造器;其父类是JFrame
//创建菜单及菜单选项
jmb=new JMenuBar();
jm1=new JMenu("游戏(G)");
//设置快捷方式
jm1.setMnemonic('G');
jmi1=new JMenuItem("开始新游戏(N)");
jmi1.setMnemonic('N');
//对jmi1相应
jmi1.addActionListener(this);//this是指向调用对象本身的引用名;this在java GUI中的作用?
jmi1.setActionCommand("newgame");//作用就是另外设置一个字符串来判断你究竟选择的是哪一个组件,还是不懂啊
jmi2=new JMenuItem("退出游戏(E)");
jmi2.setMnemonic('E');
jmi2.addActionListener(this);
jmi2.setActionCommand("exit");
jmi3=new JMenuItem("存盘退出(S)");
jmi3.setMnemonic('S');
jmi3.addActionListener(this);
jmi3.setActionCommand("save");
jmi4=new JMenuItem("继续游戏(C)");
jmi4.setMnemonic('C');
jmi4.addActionListener(this);
jmi4.setActionCommand("congame");
jm1.add(jmi1);
jm1.add(jmi2);
jm1.add(jmi3); // add()作用:在不同类间相互静态调用,类名.add() //或则add()起到加入作用
jm1.add(jmi4);
jmb.add(jm1);
this.setJMenuBar(jmb);
//构建组件
msp=new MyStartPanel();
Thread t=new Thread(msp);
t.start();
this.add(msp);
//设置JFrame窗体
this.setTitle("坦克大战");//JFrame标题
this.setSize(600, 500);//JFrame窗体大小
this.setLocationRelativeTo(null);//在屏幕中心显示
this.setVisible(true);//显示
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//退出并关闭JFrame
}
public void actionPerformed(ActionEvent e) {
//对用户不同的点击,做出不同的处理
if(e.getActionCommand().equals("newgame")){
//创建战场面板
mp=new MyPanel("newgame");
//启动mp线程
Thread ta=new Thread(mp);
ta.start();
//先删除旧的开始面板
this.remove(msp);
//加入组件
this.add(mp);
//监听
this.addKeyListener(mp); //键盘监听
//显示,刷新JFrame
this.setVisible(true);
}else if(e.getActionCommand().equals("exit")){
//用户点击了退出菜单
//保存用户游戏记录数据
Recorder.keepRecording();
System.exit(0);
}else if(e.getActionCommand().equals("save")){
//用户点击保存菜单
//保存击毁敌人的数量和敌人的坐标
Recorder.setEts(mp.ets);
Recorder.keepRecAndEnemyTank();
System.exit(0);
}else if(e.getActionCommand().equals("congame")){
//继续上次游戏
//创建战场面板
mp=new MyPanel("congame");
//启动mp线程
Thread ta=new Thread(mp);
ta.start();
//先删除旧的开始面板
this.remove(msp);
//加入组件
this.add(mp);
//监听
this.addKeyListener(mp);
//显示,刷新JFrame
this.setVisible(true);
}
}
}
//开始面板--起提示作用
class MyStartPanel extends JPanel implements Runnable{
int times=0;
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.black);
g.fillRect(0, 0, 400, 300);
//提示信息
if(times%2==0){
g.setColor(Color.yellow);
//开关信息的字体
Font myFont=new Font("华文新魏", Font.BOLD, 30);
g.setFont(myFont);
g.drawString("Stage: 1", 150, 150);
}
}
public void run() {
while(true){
//休眠
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
times++;
//重画
this.repaint();
}
}
}
//我的面板Panel
class MyPanel extends JPanel implements KeyListener,Runnable{//MyPanel继承Jpanel面板,创建KeyListener键盘接口和Runnable线程接口
//定义一个我的坦克
Hero hero=null;
//定义声音播放
AePlayWave apw=null;
//定义敌人的坦克组
Vector ets=new Vector();
Vector nodes=new Vector();
//定义炸弹集合
Vector bombs=new Vector();
int enSize=3;//初始敌人坦克数量
//定义爆炸图片
Image image1=null;
Image image2=null;
Image image3=null;
//构造函数
public MyPanel(String flag){
hero=new Hero(200, 270);//我的坦克初始位置
//恢复游戏记录
Recorder.getRecoring();
if(flag.equals("newgame")){
//播放开战声音
apw=new AePlayWave("/Users/a1/eclipse-workspace/MyTank07/Monody.wav");
apw.start();
//初始化敌人的坦克
for(int i=0;i6){
g.drawImage(image1, b.x, b.y, 30, 30, this);
}else if(b.life>3){
g.drawImage(image2, b.x, b.y, 30, 30, this);
}else {
g.drawImage(image3, b.x, b.y, 30, 30, this);
}
//让b的生命值减少
b.lifeDown();
//如果炸弹生命值为0,就把该炸弹从bombs向量中去掉
if(b.life==0){
bombs.remove(b);
}
}
//画出敌人的坦克
for(int i=0;iet.x&&s.xet.y&&s.yet.x&&s.xet.y&&s.y
members.java文件
package com.haiding.tank_7;
import java.util.Vector;//Vector 可实现自动增长的对象数组。java.util.vector提供了向量类(vector)以实现类似动态数组的功能
import java.io.*;//导入java.io包
import javax.sound.sampled.*;//
//播放声音的类
class AePlayWave extends Thread {
private String filename;
public AePlayWave(String wavfile) {
filename = wavfile;
}
public void run() {
File soundFile = new File(filename);//导入音频文件
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e1) {
e1.printStackTrace();
return;
}
AudioFormat format = audioInputStream.getFormat();
SourceDataLine auline = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
} catch (Exception e) {
e.printStackTrace();
return;
}
auline.start();
int nBytesRead = 0;
//这是缓冲
byte[] abData = new byte[2048];
try {
while (nBytesRead != -1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0)
auline.write(abData, 0, nBytesRead);
}
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
auline.drain();
auline.close();
}
}
}
//记录恢复点
class Node{
int x,y,direct;
public Node(int x,int y,int direct){
this.x=x;
this.y=y;
this.direct=direct;
}
}
//记录类,同时也可以保存玩家的设置
class Recorder{
//记录每关有多少敌人
private static int enNum=20;
//设置我有多少可用的人
private static int myLife=3;
//记录总共消灭了多少敌人的坦克
private static int allEnNum=0;
//从文件中恢复记录点
private static Vector nodes=new Vector();
private static FileWriter fw=null;
private static BufferedWriter bw=null;
private static FileReader fr=null;
private static BufferedReader br=null;
private static Vector ets=new Vector();
//完成读取任务点任务
public static Vector getNodesAndEnNums(){
try {
fr=new FileReader("e:\\tankgame\\tanksave.txt"); //放到其他其他下,可能无法读取点任务文件
br=new BufferedReader(fr);
String n="";
//先读一行
n=br.readLine();
allEnNum=Integer.parseInt(n);
while((n=br.readLine())!=null){
String []Recovery=n.split(" ");//split方法可以按一行字符中有多少个空间来返回数组
Node node=new Node(Integer.parseInt(Recovery[0]),Integer.parseInt(Recovery[1]),Integer.parseInt(Recovery[2]));
nodes.add(node);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
br.close();
fr.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return nodes;
}
//保存击毁敌人的数量和敌人坦克坐标、方向
public static void keepRecAndEnemyTank(){
try {
//创建
fw=new FileWriter("e:\\tankgame\\tanksave.txt");
bw=new BufferedWriter(fw);
bw.write(allEnNum+"\r\n");
//保存当前还活着的敌人坦克坐标、方向
for(int i=0;i getEts() {
return ets;
}
public static void setEts(Vector ets) {
Recorder.ets = ets;
}
//敌人坦克死亡就减少坦克数
public static void reduceEnNum(){
enNum--;
}
//当消灭敌人的时候
public static void addEnNumRec(){
allEnNum++;
}
}
//炸弹类
class Bomb{
//定义炸弹的坐标
int x,y;
int life=9;//炸弹的生命
boolean isLive=true;
public Bomb(int x,int y){
this.x=x;
this.y=y;
}
//减少炸弹生命值
public void lifeDown(){
if(life>0){
life--;
}else{
this.isLive=false;
}
}
}
//子弹类
class Shot implements Runnable{
int x,y,direct,speed=3;//初始子弹x,y坐标,direct子弹方向,speed子弹速度
//子弹是否还活着
boolean isLive=true;//默认为活着
public Shot(int x,int y,int direct){
this.x=x;
this.y=y;
this.direct=direct;
}
public void run(){
while(true){
try {
Thread.sleep(50);//让子弹休息50毫秒,防止快速消费内存
} catch (Exception e) {
e.printStackTrace();
}
switch(direct){
case 0://向上
y-=speed;
break;
case 1://向下
y+=speed;
break;
case 2://向 左
x-=speed;
break;
case 3://向右
x+=speed;
break;
}
//子弹何时死亡
//判断该子弹是否碰到MyPanel面板的边缘
if(x<0||x>400||y<0||y>300){
this.isLive=false;
break;
}
}
}
}
//定义坦克类
class Tank{
//表示坦克的X横坐标Y纵坐标
int x=0,y=0;
//direct坦克方向,0向上、1向下、2向左、3向右
int direct=0;
//坦克的速度
int speed=1;
//坦克颜色
int color;
boolean isLive=true;
public Tank(int x,int y){
this.x=x;
this.y=y;
}
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 int getDirect() {
return direct;
}
public void setDirect(int direct) {
this.direct = direct;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
}
//敌人坦克,把敌人坦克做成线程类
class EnemyTank extends Tank implements Runnable{
int move=30;//敌人坦克移动步长(区域)
int times=0;
//定义一个向量,可以访问到MyPanel上所有敌人坦克
Vector ets=new Vector();
//定义一个向量,可以存放敌人的子弹
Vector ss=new Vector();
//敌人添加子弹,应在创建坦克和敌人的坦克子弹死亡后
public EnemyTank(int x,int y){
super(x,y);
}
//得到MyPanel的敌人坦克向量
public void setEts(Vector tank){
this.ets=tank;
}
//判断敌人坦克是否重叠
public boolean isTouchOtherEnemy(){
boolean b=false;
switch(this.direct){
case 0://敌人当前坦克向上
//取出所有敌人坦克
for(int i=0;i=et.x&&this.x<=et.x+20&&this.y>=et.y&&this.y<=et.y+30){
return true;
}
if(this.x+20>=et.x&&this.x+20<=et.x+20&&this.y>=et.y&&this.y<=et.y+30){
return true;
}
}
//如果敌人同伴的坦克向左或向右
if(et.direct==2||et.direct==3){
//判断敌人当前坦克右轮与同伴坦克(向左或向右)的位置比较
if(this.x>=et.x&&this.x<=et.x+30&&this.y>=et.y&&this.y<=et.y+20){
return true;
}
if(this.x+20>=et.x&&this.x+20<=et.x+30&&this.y>=et.y&&this.y<=et.y+20){
return true;
}
}
}
}
break;
case 1://敌人当前坦克向下
for(int i=0;i=et.x&&this.x<=et.x+20&&this.y+30>=et.y&&this.y+30<=et.y+30){
return true;
}
if(this.x+20>=et.x&&this.x+20<=et.x+20&&this.y+30>=et.y&&this.y+30<=et.y+30){
return true;
}
}
if(et.direct==2||et.direct==3){
if(this.x>=et.x&&this.x<=et.x+30&&this.y+30>=et.y&&this.y+30<=et.y+20){
return true;
}
if(this.x+20>=et.x&&this.x+20<=et.x+30&&this.y+30>=et.y&&this.y+30<=et.y+20){
return true;
}
}
}
}
break;
case 2://敌人当前坦克向左
for(int i=0;i=et.x&&this.x<=et.x+20&&this.y>=et.y&&this.y<=et.y+30){
return true;
}
if(this.x>=et.x&&this.x<=et.x+20&&this.y+20>=et.y&&this.y+20<=et.y+30){
return true;
}
}
if(et.direct==2||et.direct==3){
if(this.x>=et.x&&this.x<=et.x+30&&this.y>=et.y&&this.y<=et.y+20){
return true;
}
if(this.x>=et.x&&this.x<=et.x+30&&this.y+20>=et.y&&this.y+20<=et.y+20){
return true;
}
}
}
}
break;
case 3://敌人当前坦克向右
for(int i=0;i=et.x&&this.x+30<=et.x+20&&this.y>=et.y&&this.y<=et.y+30){
return true;
}
if(this.x+30>=et.x&&this.x+30<=et.x+20&&this.y+20>=et.y&&this.y+20<=et.y+30){
return true;
}
}
if(et.direct==2||et.direct==3){
if(this.x+30>=et.x&&this.x+30<=et.x+30&&this.y>=et.y&&this.y<=et.y+20){
return true;
}
if(this.x+30>=et.x&&this.x+30<=et.x+30&&this.y+20>=et.y&&this.y+20<=et.y+20){
return true;
}
}
}
}
break;
}
return b;
}
//重写run()函数
public void run() {
while(true){
switch(this.direct){
case 0://坦克正在向上移动
for(int i=0;i0&&!this.isTouchOtherEnemy()){//判断敌人坦克向上走不会越界
y-=speed;
}
try {
Thread.sleep(50);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
case 1://向下移动
for(int i=0;i0&&!this.isTouchOtherEnemy()){//判断敌人坦克向左走不会越界
x-=speed;
}
try {
Thread.sleep(50);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
case 3://向右移动
for(int i=0;i ss=new Vector();//Vector线程安全的集合类
Shot s=null;
public Hero(int x,int y){
super(x,y);
}
//坦克开火
public void shotEnemy(){
switch(this.direct){//判断坦克方向来对应子弹运行方向
case 0://向上
//创建一颗子弹
s=new Shot(x+10, y, 0);
//将子弹加入到向量集中
ss.add(s);
break;
case 1://向下
s=new Shot(x+10, y+29, 1);
ss.add(s);
break;
case 2://向左
s=new Shot(x, y+10, 2);
ss.add(s);
break;
case 3://向右
s=new Shot(x+29, y+10, 3);
ss.add(s);
break;
}
//启动子弹线程
Thread t=new Thread(s);
t.start();
}
//坦克向上移动
public void moveUp(){
y-=speed*10;
}
//坦克向右移动
public void moveRight(){
x+=speed*10;
}
//坦克向下移动
public void moveDown(){
y+=speed*10;
}
//坦克向左移动
public void moveLeft(){
x-=speed*10;
}
}
本人使用的是eclipse软件,代码中的图片文件、音频文件都丢失,固执行后可能没有爆炸效果,没有音频效果。忘谅解!
使用者可以替换掉其中的音频文件、图片文件。