纯Java实现坦克大战游戏,源码公开

简介: 纯Java实现坦克大战游戏,源码公开

前言


近日最做项目,很多网友在问题是否有游戏的代码分享,故总结了去年开发的一款小游戏坦克大战,源码公开,大家一起研究改进


 * 功能:坦克大战游戏
 * 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;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.util.*;
import javax.sound.sampled.*;
public class MyTank07 extends JFrame implements ActionListener{
  //定义组件
  MyPanel mp=null;
  //定义一个开始面板
  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();
  }
  //构造函数
  public MyTank07(){
    //创建菜单及菜单选项
    jmb=new JMenuBar();
    jm1=new JMenu("游戏(G)");
    //设置快捷方式
    jm1.setMnemonic('G');
    jmi1=new JMenuItem("开始新游戏(N)");
    jmi1.setMnemonic('N');
    //对jmi1相应
    jmi1.addActionListener(this);
    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);
    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<EnemyTank> ets=new Vector<EnemyTank>();
  Vector<Node> nodes=new Vector<Node>();
  //定义炸弹集合
  Vector<Bomb> bombs=new Vector<Bomb>();
  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("e:\\tankgame\\tankmusic.wav");
      apw.start();
      //初始化敌人的坦克
      for(int i=0;i<enSize;i++){
        //创建一辆敌人的坦克对象
        EnemyTank et=new EnemyTank((i+1)*50, 0);
        //初始敌人坦克颜色
        et.setColor(2);
        //初始敌人坦克的方向
        et.setDirect(1);
        //将MyPanel的敌人向量交给该敌人坦克
        et.setEts(ets);
        //启动敌人坦克进程
        Thread t=new Thread(et);
        t.start();
        //给敌人坦克添加一颗子弹
        Shot s=new Shot(et.x+10, et.y+30, 1);
        //把子弹加入给敌人
        et.ss.add(s);
        Thread t2=new Thread(s);
        t2.start();
        //加入敌人坦克
        ets.add(et);
      }
    }else if(flag.equals("congame")){
      nodes=new Recorder().getNodesAndEnNums();
      //初始化敌人的坦克
      for(int i=0;i<nodes.size();i++){
        Node node=nodes.get(i);
        //创建一辆敌人的坦克对象
        EnemyTank et=new EnemyTank(node.x, node.y);
        //初始敌人坦克颜色
        et.setColor(2);
        //初始敌人坦克的方向
        et.setDirect(node.direct);
        //将MyPanel的敌人向量交给该敌人坦克
        et.setEts(ets);
        //启动敌人坦克进程
        Thread t=new Thread(et);
        t.start();
        //给敌人坦克添加一颗子弹
        Shot s=new Shot(et.x+10, et.y+30, 1);
        //把子弹加入给敌人
        et.ss.add(s);
        Thread t2=new Thread(s);
        t2.start();
        //加入敌人坦克
        ets.add(et);
      }
    }
    //初始化爆炸图片
    try {
      image1=ImageIO.read(new File("bomb1.gif"));
      image2=ImageIO.read(new File("bomb2.gif"));
      image3=ImageIO.read(new File("bomb3.gif"));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  //画出提示信息
  public void showInfo(Graphics g){
    //画出提示信息坦克(该坦克不参与战斗,只是用于显示提示信息)
    this.drawTank(80, 330, g, 1, 0);
    g.setColor(Color.BLACK);
    g.setFont(new Font("宋体",Font.BOLD,20));
    g.drawString(Recorder.getEnNum()+"", 110, 350);//显示敌人坦克数量
    this.drawTank(140, 330, g, 0, 0);
    g.setColor(Color.BLACK);
    g.setFont(new Font("宋体",Font.BOLD,20));
    g.drawString(Recorder.getMyLife()+"", 170, 350);//显示我的坦克数量
    //画出玩家的总成绩
    g.setColor(Color.black);
    g.setFont(new Font("宋体",Font.BOLD,20));
    g.drawString("您的总成绩", 420, 30);
    this.drawTank(420, 60, g, 1, 0);
    g.setColor(Color.black);
    g.setFont(new Font("宋体",Font.BOLD,20));
    g.drawString(Recorder.getAllEnNum()+"", 460, 80);
  }
  //重写paint函数
  public void paint(Graphics g){
    super.paint(g);//调用父类paint方法
    //画出提示信息
    this.showInfo(g);
    //设置Panel底色
    g.setColor(Color.black);
    g.fillRect(0, 0, 400, 300);//fillRect(0,0,X?,Y?)中X?/Y?为活动区域
    //画出自己的坦克
    if(hero.isLive==true){
      this.drawTank(hero.getX(), hero.getY(), g, 0, this.hero.direct);
    }
    //从ss向量中取出每一颗子弹并画出
    for(int i=0;i<this.hero.ss.size();i++){
      Shot myShot=hero.ss.get(i);
      //画出一颗子弹,判断子弹是否为空
      if(myShot!=null&&myShot.isLive==true){
        g.draw3DRect(myShot.x, myShot.y, 1, 1, false);
      }
      //判断子弹是否死亡
      if(myShot.isLive==false){
        //从向量ss中删除该子弹
        hero.ss.remove(myShot);
      }
    }
    //画出炸弹
    for(int i=0;i<bombs.size();i++){
      //取出炸弹
      Bomb b=bombs.get(i);
      if(b.life>6){
        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;i<ets.size();i++){
      EnemyTank et=ets.get(i);
      if(et.isLive){
        this.drawTank(et.getX(), et.getY() , g, 1, et.getDirect());
        //再画出敌人坦克的子弹
        for(int j=0;j<et.ss.size();j++){
          //取出子弹
          Shot enemyShot=et.ss.get(j);
          if(enemyShot.isLive){
            g.draw3DRect(enemyShot.x, enemyShot.y, 1, 1, false);
          }else{
            //如果敌人的坦克死亡了就从向量Vector中去掉
            et.ss.remove(enemyShot);
          }
        }
      }
    }
  }
  //判断我的子弹是否击中敌人的坦克
  public void hitEnemyTank(){
    //遍历Vector集合类
    for(int i=0;i<hero.ss.size();i++){
      //先取子弹
      Shot myShot=hero.ss.get(i);
      //判断子弹是否有效
      if(myShot.isLive){
        //取出每一个敌人坦克与子弹进行判断
        for(int j=0;j<ets.size();j++){
          //取出坦克
          EnemyTank et=ets.get(j);
          //判断敌人坦克是否还活着
          if(et.isLive){
            if(this.hitTank(myShot, et)){
              apw=new AePlayWave("e:\\tankgame\\tank_explosion.wav");
              apw.start();
              //调用reduceEnNum()减少敌人坦克统计数
              Recorder.reduceEnNum();
              //调用addEnNumRec()增加消灭敌人坦克统计数
              Recorder.addEnNumRec();
            }
          }
        }
      }
    }
  }
  //判断敌人的子弹是否击中我的坦克
  public void hitMe(){
    //取出每一个敌人的坦克
    for(int i=0;i<this.ets.size();i++){
      //取出敌人的坦克
      EnemyTank et=ets.get(i);
      //取出每一颗敌人的子弹
      for(int j=0;j<et.ss.size();j++){
        //取出子弹
        Shot enemyShot=et.ss.get(j);
        if(hero.isLive){
          if(this.hitTank(enemyShot, hero)){
          }
        }
      }
    }
  }
  //写一个函数专门判断子弹是否击中敌人坦克
  public boolean hitTank(Shot s,Tank et){
    boolean b=false;
    //判断该敌人坦克的方向
    switch(et.direct){
    case 0://敌人坦克向上或向下
    case 1:
      if(s.x>et.x&&s.x<et.x+20&&s.y>et.y&&s.y<et.y+29){
        //击中方向为上或下的敌人坦克
        //子弹死亡
        s.isLive=false;
        //敌人坦克死亡
        et.isLive=false;
        b=true;
        //创建一颗炸弹
        Bomb bomb=new Bomb(et.x, et.y);
        //放入Vector向量中管理
        bombs.add(bomb);
      }
      break;
    case 2://敌人坦克向左或向右
    case 3:
      if(s.x>et.x&&s.x<et.x+29&&s.y>et.y&&s.y<et.y+20){
        //击中方向为左或右的敌人坦克
        //子弹死亡
        s.isLive=false;
        //敌人坦克死亡
        et.isLive=false;
        b=true;
        //创建一颗炸弹
        Bomb bomb=new Bomb(et.x, et.y);
        //放入Vector向量中管理
        bombs.add(bomb);
      }
      break;
    }
    return b;
  }
  //画出坦克的函数
  public void drawTank(int x,int y,Graphics g,int type,int direct){
    //判断是什么类型的坦克
    switch(type){
    case 0:
      g.setColor(Color.cyan);//我的坦克颜色
      break;
    case 1:
      g.setColor(Color.yellow);//敌人坦克颜色
      break;
    case 2:
      g.setColor(Color.red);
      break;
    }
    //判断坦克的方向
    switch(direct){
    //向上走的坦克
    case 0:
      //画出我的坦克(到时再封装成一个函数)
      //1、画出左边的矩形
      g.fill3DRect(x, y, 5, 30, false);
      //2、画出右边的矩形
      g.fill3DRect(x+15, y, 5, 30, false);
      //3、画出中间矩形
      g.fill3DRect(x+5, y+5, 10, 20, false);
      //4、画出中间圆形
      g.fillOval(x+5, y+10, 10, 10);
      //5、画出线(炮筒)
      g.drawLine(x+10, y+15, x+10, y);
      break;
    //向下走的坦克
    case 1:
      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+29);
      break;
    //向左走的坦克
    case 2:
      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, y+10);
      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+29, y+10);
      break;
    }
  }
  public void keyPressed(KeyEvent e) {//按下键事件a向左s向下d向右w向上
    if(e.getKeyCode()==KeyEvent.VK_W||e.getKeyCode()==KeyEvent.VK_UP){
      //向上
      this.hero.setDirect(0);
      this.hero.moveUp();
    }else if(e.getKeyCode()==KeyEvent.VK_S||e.getKeyCode()==KeyEvent.VK_DOWN){
      //设置我的坦克的方向,向下
      this.hero.setDirect(1);
      this.hero.moveDown();
    }else if(e.getKeyCode()==KeyEvent.VK_A||e.getKeyCode()==KeyEvent.VK_LEFT){
      //向左
      this.hero.setDirect(2);
      this.hero.moveLeft();
    }else if(e.getKeyCode()==KeyEvent.VK_D||e.getKeyCode()==KeyEvent.VK_RIGHT){
      //向右
      this.hero.setDirect(3);
      this.hero.moveRight();
    }
    //判断玩家是否按下空格键,不可接上面else if。不然不能同时按方向键和空格(space)键
    if(e.getKeyCode()==KeyEvent.VK_SPACE){
      apw=new AePlayWave("e:\\tankgame\\tank_Shelling_sound.wav");
      apw.start();
      //控制子弹连发
      if(this.hero.ss.size()<=4){
        //按下空格后开火
        this.hero.shotEnemy();
      }
    }
    //调用repaint()函数,来重绘界面
    this.repaint();
  }
  public void keyReleased(KeyEvent e) {//弹起键事件
  }
  public void keyTyped(KeyEvent e) {//按键输出值
  }
  //重写run函数
  public void run() {
    while(true){
      try {
        Thread.sleep(100);//休息100毫秒后重绘MyPanel面板
      } catch (Exception e) {
        e.printStackTrace();
      }
      this.hitEnemyTank();
      //判断敌人的子弹是否击中我的坦克
      this.hitMe();
      //重绘MyPanel面板
      this.repaint();
    }
  }
}


目录
相关文章
|
28天前
|
Java
Java实现贪吃蛇游戏
本文介绍了如何使用Java实现一个简单的贪吃蛇游戏。
56 4
|
2月前
|
XML Java 编译器
Java注解的底层源码剖析与技术认识
Java注解(Annotation)是Java 5引入的一种新特性,它提供了一种在代码中添加元数据(Metadata)的方式。注解本身并不是代码的一部分,它们不会直接影响代码的执行,但可以在编译、类加载和运行时被读取和处理。注解为开发者提供了一种以非侵入性的方式为代码提供额外信息的手段,这些信息可以用于生成文档、编译时检查、运行时处理等。
83 7
|
2天前
|
JavaScript 安全 Java
智慧产科一体化管理平台源码,基于Java,Vue,ElementUI技术开发,二开快捷
智慧产科一体化管理平台覆盖从备孕到产后42天的全流程管理,构建科室协同、医患沟通及智能设备互联平台。通过移动端扫码建卡、自助报道、智能采集数据等手段优化就诊流程,提升孕妇就诊体验,并实现高危孕产妇五色管理和孕妇学校三位一体化管理,全面提升妇幼健康宣教质量。
27 12
|
6天前
|
人工智能 监控 安全
Java智慧工地(源码):数字化管理提升施工安全与质量
随着科技的发展,智慧工地已成为建筑行业转型升级的重要手段。依托智能感知设备和云物互联技术,智慧工地为工程管理带来了革命性的变革,实现了项目管理的简单化、远程化和智能化。
28 4
|
24天前
|
JavaScript Java 测试技术
基于Java+SpringBoot+Vue实现的车辆充电桩系统设计与实现(系统源码+文档+部署讲解等)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
55 6
|
28天前
|
IDE Java API
Java游戏开发基础:从零开始制作一个简单的2D游戏
本文介绍了使用Java开发一个简单的2D避障游戏的基础流程。
71 10
|
1月前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
|
2月前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
150 13
|
2月前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
126 1
|
2月前
|
人工智能 移动开发 安全
家政上门系统用户端、阿姨端源码,java家政管理平台源码
家政上门系统基于互联网技术,整合大数据分析、AI算法和现代通信技术,提供便捷高效的家政服务。涵盖保洁、月嫂、烹饪等多元化服务,支持多终端访问,具备智能匹配、在线支付、订单管理等功能,确保服务透明、安全,适用于家庭生活的各种需求场景,推动家政市场规范化发展。

热门文章

最新文章