Java多线程游戏——坦克大战

时间:2024-07-20 07:14:07

一.游戏登陆界面

package TankFight;

import javax.swing.*;
import java.awt.*;

public class GameUI {
    public void initUI() {
        JFrame jf = new JFrame();
        jf.setSize(1100, 900);//设置窗口大小
        jf.setTitle("坦克大战" );//设置窗口标题
        jf.setLocationRelativeTo(null);//设置窗口居中
        jf.setDefaultCloseOperation(3);//设置用户在此窗体上点击关闭按钮时默认执行的操作

        //游戏面板
        JPanel gamePanel = new JPanel();
        gamePanel.setBackground(Color.black);
        jf.add(gamePanel,BorderLayout.CENTER);
        jf.setVisible(true);

        Graphics g = gamePanel.getGraphics();//画笔

        //监听器
        Threadlistener mouse = new Threadlistener(g,gamePanel);
        jf.addKeyListener(mouse);

        //让窗体获取焦点
        jf.requestFocus();

    }
    public static void main(String[] args) {
        GameUI ui = new GameUI();
        ui.initUI();
    }
}

二.移动物体类(后面坦克类和子弹类的父类)

package TankFight;

public class MoveObject {
    private int x, y, size = 100;//坐标,尺寸
    private int speedX = 0, speedY = 0;//水平竖直方向速度
    private int direction;  //控制方向
    public MoveObject(){
    }
    public MoveObject(int x,int y){
        this.x = x;
        this.y = y;
    }
    //移动方法
    public void move(){
        y += speedY;
        x += speedX;
    }
    //获取坐标方法
    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 getSize() {
        return size;
    }
    public void setSize(int size) {
        this.size = size;
    }
    public int getSpeedX() {
        return speedX;
    }
    public void setSpeedX(int speedX) {
        this.speedX = speedX;
    }
    public int getSpeedY() {
        return speedY;
    }
    public void setSpeedY(int speedY) {
        this.speedY = speedY;
    }
    public int getDirection() {
        return direction;
    }
    public void setDirection(int direction) {
        this.direction = direction;
    }
}

三.坦克类

在此之前我们首先搜素坦克上下左右四个方向的图片各一张,放入picture包下,分别命名tank1,tank2,tank3,tank4。

package TankFight;

import javax.swing.*;
import java.awt.*;

public class MyTank extends MoveObject{
    public JPanel gamePanel;
    public ImageIcon[] tankImage = new ImageIcon[4];
    //地图1 砖块  2 石头   3 草地   4 水
    public int[][] Barriersmap =
            {{ 1, 1, 1, 1, 0, 1, 1, 1, 1},
                    { 2, 2, 1, 1, 0, 1, 1, 2, 2},
                    { 0, 0, 0, 0, 0, 0, 0, 0, 0},
                    { 3, 3, 3, 3, 0, 3, 3, 3, 3},
                    { 1, 1, 1, 1, 0, 1, 1, 1, 1},
                    { 3, 3, 0, 0, 0, 0, 0, 3, 3},
                    { 1, 1, 0, 1, 1, 1, 0, 1, 1},
                    { 1, 1, 0, 1, 4, 1, 0, 1, 1},
                    { 1, 1, 0, 1, 1, 1, 0, 1, 1}};
    public MyTank(int x, int y, JPanel gamePanel){
        super(x,y);
        this.gamePanel = gamePanel;
        this.setSize(60);

        //加载图片
        for(int i=0;i<4;i++){
            tankImage[i] = new ImageIcon("picture//tank"+i+".jpg");
        }
        //设置默认方法
    }
    //画我方坦克
    public void drawTank(Graphics g){
        ImageIcon image = isDirection();
        g.drawImage(image.getImage(),getX(),getY(),getSize(),getSize(),null);
    }
    //根据当前方法,选择合适的图片
    public ImageIcon isDirection(){
        if(getSpeedX() > 0 ){//向右移动
            setDirection(3);
        } else if(getSpeedX() < 0 ){//向左移动
            setDirection(2);
        }else if(getSpeedY() < 0 ){//向下移动
            setDirection(0);
        }else if(getSpeedY() > 0 ){//向上移动
            setDirection(1);
        }
        ImageIcon image =  tankImage[getDirection()];
        return image;
    }

    //移动方法
    public void move(){
        int xl=(getX())/100,yl=(getY())/100;
        int size=getSize();
        int xdl=(getX())/100,ydl=(getY()+size)/100;
        int xr=(getX()+size)/100,yr=(getY())/100;
        int xdr=(getX()+size)/100,ydr=(getY()+size)/100;
        System.out.println(xl+" "+yl+" "+Barriersmap[yl][xl]);
        switch(getDirection())//判断方向,加载不同方向对应的坦克图片,设置速度
        {
            case 0:
                if(Barriersmap[yl][xl]==1||Barriersmap[yr][xr]==1||Barriersmap[yl][xl]==2||Barriersmap[yr][xr]==2)
                {
                    setSpeedY(0);
                }
                break;
            case 1:
                if(Barriersmap[ydl][xdl]==1||Barriersmap[ydr][xdr]==1||Barriersmap[ydl][xdl]==2||Barriersmap[ydr][xdr]==2)
                {
                    setSpeedY(0);
                }
                break;
            case 2:
                if(Barriersmap[yl][xl]==1||Barriersmap[ydl][xdl]==1||Barriersmap[yl][xl]==2||Barriersmap[ydl][xdl]==2)
                {
                    setSpeedX(0);
                }
                break;
            case 3:
                if(Barriersmap[yr][xr]==1||Barriersmap[ydr][xdr]==1||Barriersmap[yr][xr]==2||Barriersmap[ydr][xdr]==2)
                {
                    setSpeedX(0);
                }
                break;
        }
        super.move();//移动
    }

}

四.子弹类

package TankFight;

import java.awt.*;

public class Bullet extends MoveObject {
    public int direc;//方向
    public MyTank mt;//坦克
    public boolean stop=false;//停止

    public Bullet(int x, int y, MyTank mt) {
        super(x, y);
        this.direc = mt.getDirection();
        this.mt = mt;

        setSize(10);//尺寸
        setSpeedY(-3);//速度
    }

    public void drawbullet(Graphics g) {
        g.setColor(Color.red);
        g.fillOval(getX(), getY(), getSize(), getSize());
    }
    //按方向重写move

    @Override
    public void move() {
        if(!stop)
        {
            switch (direc) {
                case 0:
                    setSpeedY(-4);
                    setSpeedX(0);
                    break;
                case 1:
                    setSpeedY(4);
                    setSpeedX(0);
                    break;
                case 2:
                    setSpeedY(0);
                    setSpeedX(-4);
                    break;
                case 3:
                    setSpeedY(0);
                    setSpeedX(4);
                    break;
            }
            super.move();
        }
    }
}

五.音乐类

从外网下载音乐包导入(自行),并下载你想要的坦克大战背景音乐加入music包下命名为bg1.mp3

package TankFight;

import javazoom.jl.player.Player;

import java.io.File;
import java.io.FileInputStream;

public class Music {
    //播放音乐类
    static Player player;
    public static void playMusic(){
        //匿名内部类
        new Thread(
                new Runnable() {
            @Override
            public void run() {
                String path = "music/bg1.mp3";
                FileInputStream fis = null;
                try {
                    //输入文件流
                    fis = new FileInputStream(new File(path));
                    player = new Player(fis);
                    player.play();

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
        ).start();
    }
    public static void close(){
        player.close();
    }
}

六.线程启动页面类

package TankFight;

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

//线程启动页面
public class ThreadGame implements Runnable {
    public Graphics g;//画笔
    public boolean start = false;//启动
    public  MyTank mt;//坦克
    public int mapsize =100;//地图尺寸
    public int changeablemapsize=100;
    public JPanel gamePanel;
    public BufferedImage bufferedImage;
    public ArrayList<MoveObject> listTank;//保存其他坦克
    public ArrayList<Bullet> listBullet;  //保存子弹
    //地图素材
    public Image[] mapArr = new Image[4];
    public Image boom=new ImageIcon("picture/boom.jpg").getImage();
    public int score=0;
    public int[][] Barriersmap;
    public int[][] countmap=new int[9][9];

    //初始化属性
    public ThreadGame(Graphics g,MyTank mt, ArrayList<Bullet> listBullet,JPanel gamePanel) {
        this.g = g;
        this.mt = mt;
        this.gamePanel=gamePanel;
        this.listBullet = listBullet;
        this.Barriersmap=mt.Barriersmap;

        //初始化图片素材
        for (int i = 1; i <= 4; i++) {
            mapArr[i-1] = new ImageIcon("picture//map" + i + ".png").getImage();
        }
    }
    public void isStart(boolean start) {
        this.start = start;
    }

    public void Drawmap(Graphics g){
        //画出障碍物
        for(int i = 0; i< Barriersmap.length; i++)
        {
            for(int j = 0; j< Barriersmap[0].length; j++)
            {
                if (Barriersmap[i][j] == 1) {
                    g.drawImage(mapArr[1], j * mapsize, i * mapsize, mapsize, mapsize, null);
                } else if (Barriersmap[i][j] == 2) {
                    g.drawImage(mapArr[0], j * mapsize, i * mapsize, mapsize, mapsize, null);
                } else if (Barriersmap[i][j] == 3) {
                    g.drawImage(mapArr[2], j * mapsize, i * changeablemapsize,changeablemapsize, changeablemapsize, null);
                } else if (Barriersmap[i][j] == 4) {
                    g.drawImage(mapArr[3], j * mapsize, i * mapsize, mapsize, mapsize, null);
                }

            }
        }
    }
    //启动线程后自动执行的方法
    //run 执行完,该线程的内存被回收,不能再启动
    public void run() {
        System.out.println(Thread.currentThread().getName() + ":启动...");
        //创建缓冲区
        //作为容器,从中获取画笔绘画
        bufferedImage = new BufferedImage(gamePanel.getWidth(),
                gamePanel.getHeight(),BufferedImage.TYPE_INT_RGB);
        Graphics bufferg =bufferedImage.getGraphics();
        while (true) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException ex) {
                throw new RuntimeException(ex);
            }

            if (!start) {
                //绘制开始按钮
                drawStr(bufferg,"按空格键开始游戏");
                continue;
            }

            bufferg.setColor(Color.black);
            bufferg.fillRect(0,0,gamePanel.getWidth(),gamePanel.getHeight());

            Drawmap(bufferg);

            //画控制方坦克
            mt.drawTank(bufferg);
            mt.move();

            //分数区
            drawScore(bufferg,"SCORE:"+score);

            //子弹
            for(int i=0;i<listBullet.size();i++){
                Bullet bullet=listBullet.get(i);
                bullet.drawbullet(bufferg);
                bullet.move();

            }

            attack(bufferg);
            //将缓冲区内绘画显示出来
            g.drawImage(bufferedImage,0,0,null);

        }
    }
    public void attack(Graphics bufferg){
        //子弹攻击功能
        for(int i=0;i<listBullet.size();i++){
            Bullet bullet=listBullet.get(i);
            bullet.drawbullet(bufferg);
            bullet.move();
            int x=bullet.getX()/100,y=bullet.getY()/100;
            if(x>=0&&x<9&&y>=0&&y<9)
            {
                if((Barriersmap[y][x]==1||Barriersmap[y][x]==2)&&!bullet.stop)
                {
                    bufferg.setColor(Color.black);
                    countmap[y][x]++;
                    System.out.println(countmap[y][x]);
                    bullet.setSize(0);
                    bullet.stop=true;
                    if(countmap[y][x]==10)
                    {
                        Barriersmap[y][x]=0;
                        score++;
                    }
                }
            }
        }

        g.drawImage(bufferedImage,0,0,null);

    }

    public void drawStr(Graphics bufferg,String s){//写文字
        bufferg.setColor(Color.RED);
        bufferg.setFont(new Font("楷体",0,50));
        bufferg.drawString(s,400,400);
        g.drawImage(bufferedImage,0,0,null);
    }
    public void drawScore(Graphics bufferg,String s){//写分数
        bufferg.setColor(Color.RED);
        bufferg.setFont(new Font("楷体",0,30));
        bufferg.drawString(s,935,50);
        g.drawImage(bufferedImage,0,0,null);
    }
}

七.监听器类

主要是键盘监听器:1.↑↓←→键控制方向 2.j键发射子弹 3.空格键启动音乐

package TankFight;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;

public class Threadlistener implements KeyListener {
    public Graphics g;
    public ThreadGame tg;
    public int bu_small =25;
    public int bu_big =55;
    public JPanel gamePanel;
    public MyTank mt;
    public ArrayList<Bullet> listBullet = new ArrayList<>();
    public Threadlistener(Graphics g,JPanel gamePanel){
        this.g=g;
        this.gamePanel=gamePanel;

        //初始化的时候就创建线程
        if (tg == null) {
            //创建我方坦克
            mt = new MyTank(210,700,gamePanel);
            //限制线程只启动一次
            //2.实现Runnable接口启动方式
            tg = new ThreadGame(g,mt,listBullet,gamePanel);
            new Thread(tg).start();
        }
    }
    public void keyTyped(KeyEvent e){}
    public void keyPressed(KeyEvent e){
        int key = e.getKeyCode();
        switch(key){
            case KeyEvent.VK_UP:
                if(mt.getSpeedX()==0)
                     mt.setSpeedY(-3);
                break;
            case KeyEvent.VK_LEFT:
                if(mt.getSpeedY()==0)
                    mt.setSpeedX(-3);
                break;
            case KeyEvent.VK_RIGHT:
                if(mt.getSpeedY()==0)
                    mt.setSpeedX(3);
                break;
            case KeyEvent.VK_DOWN:
                if(mt.getSpeedX()==0)
                    mt.setSpeedY(3);
                break;
            case KeyEvent.VK_SPACE:
                tg.start=true;
                Music.playMusic();
                break;
            case KeyEvent.VK_J:
                switch (mt.getDirection())
                {
                    case 0:
                        Bullet bullet = new Bullet(mt.getX()+ bu_small, mt.getY(),mt);
                        listBullet.add(bullet);
                        break;
                    case 1:
                        bullet = new Bullet(mt.getX()+ bu_small, mt.getY()+ bu_big,mt);
                        listBullet.add(bullet);
                        break;
                    case 2:
                        bullet = new Bullet(mt.getX(), mt.getY()+ bu_small,mt);
                        listBullet.add(bullet);
                        break;
                    case 3:
                        bullet = new Bullet(mt.getX()+ bu_big, mt.getY()+ bu_small,mt);
                        listBullet.add(bullet);
                        break;
                }
                break;

        }
    }
    public void keyReleased(KeyEvent e) {
        int key = e.getKeyCode();
        switch (key) {
            case KeyEvent.VK_UP:
                mt.setSpeedY(0);
                break;
            case KeyEvent.VK_LEFT:
                mt.setSpeedX(0);
                break;
            case KeyEvent.VK_RIGHT:
                mt.setSpeedX(0);
                break;
            case KeyEvent.VK_DOWN:
                mt.setSpeedY(0);
                break;
        }
    }
}
八.任务线程

package TankFight;

import java.util.ArrayList;

//任务线程
public class TimeThread extends Thread{
    public long time =20;
    public ArrayList<MoveObject> listTank;
    public TimeThread(ArrayList<MoveObject> listTank){
        this.listTank=listTank;
    }

    public void run(){
        while(true){
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            MoveObject tank=new MoveObject();
            listTank.add(tank);
        }
    }
}