⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 game.java

📁 一款Java开发的打飞机小游戏
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.MemoryImageSource;
import java.util.Random;
import java.util.Vector;

/**
 * 飞行游戏的主程序
 * @author  fantasyer
 * @version 1.0
 */
public class Game extends JFrame
{
    private LogoPanel logoPanel;
    private GamePanel gamePanel;
    //该类唯一实例
    private static Game game;

    Game()
    {
        super("Space Invader");

        //全屏模式
        setUndecorated(true);
        setResizable(false);
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();
        if (gd.isFullScreenSupported())
        {
            gd.setFullScreenWindow(this);
            gd.setDisplayMode(new DisplayMode(800, 600, 32, 75));
        }

        //隐藏鼠标指针
        int[] pixels = new int[16*16];
        Image image = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(16, 16, pixels, 0, 16));
        Cursor transparentCursor = Toolkit.getDefaultToolkit().createCustomCursor
                                   (image, new Point(0, 0), "Transparent");
        this.setCursor(transparentCursor);

        gamePanel = new GamePanel();
        addKeyListener(gamePanel);
        logoPanel = new LogoPanel();
        getContentPane().add(logoPanel, "Center"); //播放开场动画的面板
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }

    /**
     * 获取该类的唯一实例
     */
    public static Game getInstance()
    {
        if (game == null)
        {
            game = new Game();
        }
        return game;
    }

    /**
     * 播放完开场画面,进入游戏区域
     */
    public void start()
    {
       try
       {
           synchronized(game)
           {
               //等待Logo动画结束
               game.wait();
               //这里暂缓一秒钟,否则界面显示有点问题(界面来不及刷新)
               Thread.sleep(1000);
               getContentPane().add(gamePanel, "Center");
               validate();
           }
       }
       catch (Exception e)
       {
           e.printStackTrace();
       }
    }

    public static void main(String[] args)
    {
        Game.getInstance().start();
    }
}

/**
 * 完成游戏绘制的面板
 */
class GamePanel extends JPanel implements Runnable, KeyListener, MouseListener
{
    private int width, height;                   //面板的高度和宽度
    private int y, totalY;                       //背景移动的速度、整个背景运行的高度
    private int gamestate;                       //游戏状态
    private int level;                           //关卡数

    private int menuIndex;                       //菜单索引
    private int fontWidth;                       //菜单文字的宽度
    private Font menuFont, keyFont, textFont;    //菜单的字体、按键的字体、显示得分的字体
    private String[] menuIndexDes = {"开始游戏", "按键帮助", "退出游戏"}; //菜单文字

    private Image[] bgImage;                     //背景图片
    private Image heroImage, hpImage, overImage; //英雄飞机、血条图片、游戏结束图片

    //敌机、Boss、子弹、爆炸图片、奖品图片
    private Image[] enemyImages, bossImages, bulletImages, blastImages, awardImages;
    private int bgHeight;                        //背景图片的高度

    private Plane heroPlane;
    private Vector heroBullets, enemyBullets;    //英雄的子弹、敌人的子弹
    private Vector enemyPlanes;                  //敌机
    private Vector blast;                        //敌机的爆炸
    private Vector planeBlast;                   //飞机的爆炸
    private Vector award;                        //奖品
    private int heroNumber;                      //玩家的飞机数目

    private Random random;                       //用于随机产生敌机坐标等
    private boolean[] keys;                      //记录用户的按键
    private int fps;                             //游戏运行的FPS
    private String fpsStr;                       //描述FPS的字符串
    private long startTime;                      //游戏运行的起始时间(用于计算游戏的FPS)

    private int unbeatTime, levelTime;           //飞机刚出生处于无敌状态的时间、关卡之间间隔的时间
    private int newPlaneTime;                    //新的飞机重生的间隔时间

    private Thread bgThread;                     //控制背景移动的线程

    /**
     * 加载声音图片资源,初始化相关属性
     */
    GamePanel()
    {
        //确定游戏画面的大小
        width = Utility.GAME_WIDTH;
        height = Utility.GAME_HEIGHT;
        setPreferredSize(new Dimension(Utility.SCREEN_WIDTH,Utility.SCREEN_HEIGHT));

        //确定菜单文字的字体以及宽度
        menuFont = new Font("华文仿宋", Font.BOLD, 36);
        keyFont = new Font("黑体", Font.PLAIN, 20);
        textFont = new Font("黑体", Font.PLAIN, 14);
        setFont(menuFont);
        Font f = this.getFont();
        FontMetrics fm = getFontMetrics(f);
        fontWidth = fm.stringWidth(menuIndexDes[0]);

        //初始化英雄飞机、敌机等相关属性
        heroPlane = new Plane();
        enemyPlanes = new Vector();
        heroBullets = new Vector();
        enemyBullets = new Vector();
        blast = new Vector();
        planeBlast = new Vector();
        award = new Vector();
        heroNumber = Utility.HERO_NUMBER;

        //游戏初始状态设置
        random = new Random(System.currentTimeMillis());
        gamestate = Utility.GAME_START;
        level = 1;
        menuIndex = 0;
        startTime = System.currentTimeMillis();
        fpsStr = "";
        unbeatTime = levelTime = 0;
        //加载资源
        loadResource();

        //初始化keys数组
        keys = new boolean[256];
        for (int i = 0; i<keys.length; i++)
        {
            keys[i] = false;
        }

        //添加键盘事件
        addKeyListener(this);
        requestFocus();
        loadLevelData(1);

        //启动背景移动的线程
        bgThread = new Thread(this);
        PlayMidi.play(true);
    }

    /**
     * 加载游戏中用到的声音和图片资源
     */
    public void loadResource()
    {
        PlayMidi.loadMidi("Audio/bg.mid");

        //等待图片加载进来
        MediaTracker mt = new MediaTracker(this);

        bgImage = new Image[Utility.BACKGROUND_IMAGE_NUMBER];
        for (int i = 0; i<bgImage.length; i++)
        {
            bgImage[i] = Toolkit.getDefaultToolkit().getImage(GamePanel.class.getResource("Images/background"+i+".gif"));
            mt.addImage(bgImage[i], i);
        }

        enemyImages = new Image[Utility.ENEMY_IMAGE_NUMBER];
        for (int i = 0; i<enemyImages.length; i++)
        {
            enemyImages[i] = Toolkit.getDefaultToolkit().getImage(GamePanel.class.getResource("Images/enemy"+i+".gif"));
            mt.addImage(enemyImages[i], bgImage.length+i);
        }

        bossImages = new Image[Utility.BOSS_IMAGE_NUMBER];
        for (int i = 0; i<bossImages.length; i++)
        {
            bossImages[i] = Toolkit.getDefaultToolkit().getImage(GamePanel.class.getResource("Images/boss"+i+".gif"));
            mt.addImage(bossImages[i], bgImage.length+enemyImages.length+i);
        }

        bulletImages = new Image[2];
        for (int i = 0; i<bulletImages.length; i++)
        {
            bulletImages[i] = Toolkit.getDefaultToolkit().getImage(GamePanel.class.getResource("Images/bullet"+i+".gif"));
            mt.addImage(bulletImages[i], 17+i);
        }

        blastImages = new Image[8];
        for (int i = 0; i<blastImages.length; i++)
        {
            blastImages[i] = Toolkit.getDefaultToolkit().getImage(GamePanel.class.getResource("Images/bomb"+i+".gif"));
            mt.addImage(blastImages[i], 19+i);
        }

        awardImages = new Image[3];
        for (int i = 0; i<awardImages.length; i++)
        {
            awardImages[i] = Toolkit.getDefaultToolkit().getImage(GamePanel.class.getResource("Images/award"+i+".gif"));
            mt.addImage(awardImages[i], 27+i);
        }

        heroImage = Toolkit.getDefaultToolkit().getImage(GamePanel.class.getResource("Images/hero.gif"));
        overImage = Toolkit.getDefaultToolkit().getImage(GamePanel.class.getResource("Images/gameover.gif"));
        hpImage = Toolkit.getDefaultToolkit().getImage(GamePanel.class.getResource("Images/hp.gif"));
        mt.addImage(heroImage, 30);
        mt.addImage(overImage, 31);
        mt.addImage(hpImage, 32);

        try
        {
            mt.waitForAll();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        //记录背景图片的高度
        bgHeight = bgImage[0].getHeight(this);
    }

    /**
     * 加载该关卡数据
     * @param level 关卡编号
     */
    public void loadLevelData(int level)
    {
        enemyPlanes.clear();
        enemyPlanes = DataManager.loadData("level_"+level+".dat");
    }

    /**
     * 绘制游戏区域
     * @param g 用于绘图的Graphics对象
     */
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        //绘制两边不动的区域
        g.drawImage(bgImage[0], 0, 0,(Utility.SCREEN_WIDTH-Utility.GAME_WIDTH)/2,Utility.SCREEN_HEIGHT, this);
        g.drawImage(bgImage[0], (Utility.SCREEN_WIDTH+Utility.GAME_WIDTH)/2, 0,(Utility.SCREEN_WIDTH-Utility.GAME_WIDTH)/2,
                    Utility.SCREEN_HEIGHT, this);

        //绘制游戏中心区域
        g.translate((Utility.SCREEN_WIDTH-Utility.GAME_WIDTH)/2, 0);

        //绘制背景
        g.drawImage(bgImage[level], 0, y, width, bgHeight, this);
        g.drawImage(bgImage[level], 0, y-bgHeight, width, bgHeight, this);

        if (gamestate==Utility.GAME_START)
        {
            //绘制菜单项
            g.setFont(menuFont);
            for (int i = 0; i<menuIndexDes.length; i++)
            {
                if (i==menuIndex)
                {
                    //g.setColor(new Color(200,200,200));
                    g.setColor(new Color(255, 0, 0));
                }
                else
                {
                    g.setColor(new Color(100, 100, 100));
                }
                g.drawString(menuIndexDes[i], (width-fontWidth)/2,height/2-50+i*50);
            }
        }
        else if (gamestate==Utility.KEY_HELP)
        {
            g.setFont(keyFont);
            g.setColor(Color.red);

            g.drawString("W    向上", width/2-60, height/2-140);
            g.drawString("S    向下", width/2-60, height/2-120);
            g.drawString("A    向左", width/2-60, height/2-100);
            g.drawString("D    向右", width/2-60, height/2-80);
            g.drawString("K    子弹", width/2-60, height/2-60);
            g.drawString("P    暂停", width/2-60, height/2-40);
            g.drawString("R    恢复", width/2-60, height/2-20);
            g.drawString("ESC  退出", width/2-60, height/2);

            g.drawString("按 BackSpace 返回主菜单", width/2-130, height/2+50);
        }
        else if (gamestate==Utility.GAME_RUNNING||gamestate==Utility.GAME_PAUSE)
        {
            g.setColor(Color.red);
            setFont(textFont);

            //绘制血条、分数、剩余飞机数目
            g.drawImage(hpImage, 0, 10, heroPlane.life, 10, this);
            g.drawString("分数:"+heroPlane.score, width/2-20, 20);
            for (int i = 1; i<heroNumber; i++)
            {
                g.drawImage(heroImage, width-i*20, 10, 15, 15, this);
            }
            //g.drawString(fpsStr,300,20);

            //绘制英雄飞机
            if (heroPlane.getVisible())
            {
                g.drawImage(heroImage, heroPlane.x, heroPlane.y,heroPlane.width, heroPlane.height, this);
            }

            //绘制敌机
            for (int i = 0; i<enemyPlanes.size(); i++)
            {
                Enemy emy = (Enemy)enemyPlanes.get(i);
                if (emy.getVisible())
                {
                    if (emy.kind<10)
                    {
                        g.drawImage(enemyImages[emy.kind-1], emy.x, emy.y,emy.width, emy.height, this);
                    }
                    else
                    {
                        g.drawImage(bossImages[emy.kind-10-1], emy.x, emy.y,emy.width, emy.height, this);
                    }
                }
            }

            //绘制飞机爆炸效果
            for (int i = 0; i<planeBlast.size(); i++)
            {
                Blast b1 = (Blast)planeBlast.elementAt(i);
                g.drawImage(blastImages[b1.index], b1.x, b1.y, b1.width,b1.height, this);
            }

            //绘制敌机爆炸效果
            for (int i = 0; i<blast.size(); i++)
            {
                Blast b1 = (Blast)blast.elementAt(i);
                g.drawImage(blastImages[b1.index], b1.x, b1.y, b1.width,b1.height, this);
            }

            //绘制敌机的子弹
            for (int i = 0; i<enemyBullets.size(); i++)
            {
                Bullet b1 = (Bullet)enemyBullets.get(i);
                g.drawImage(bulletImages[0], b1.x, b1.y, b1.width, b1.height, this);
            }

            //绘制英雄的子弹
            for (int i = 0; i<heroBullets.size(); i++)
            {
                Bullet b1 = (Bullet)heroBullets.get(i);
                g.drawImage(bulletImages[1], b1.x, b1.y, b1.width, b1.height, this);
            }

            //绘制奖品
            for (int i = 0; i<award.size(); i++)
            {
                Award a = (Award)award.get(i);
                g.drawImage(awardImages[a.kind-Utility.AWARD_1], a.x, a.y,a.width, a.height, this);
            }
        }
        else if (gamestate==Utility.GAME_OVER)
        {
            g.setColor(Color.black);
            g.fillRect(0, 0, width, height);
            int imgWidth = overImage.getWidth(this);
            int imgHeight = overImage.getHeight(this);
            g.drawImage(overImage, (Utility.GAME_WIDTH-imgWidth)/2,(Utility.GAME_HEIGHT-imgHeight)/2,imgWidth, imgHeight, this);
        }

        g.translate(-(Utility.SCREEN_WIDTH-Utility.GAME_WIDTH)/2, 0);
    }

    /**
     * 控制背景移动,游戏中的逻辑计算
     */
    public void run()
    {
        while (true)
        {
            if (gamestate==Utility.GAME_RUNNING)
            {
                //是否进入下一关
                if (enemyPlanes.size()==0)
                {
                    levelTime++;
                    if (levelTime>100)
                    {
                        levelTime = 0;
                        level++;
                        if (level>3) //目前最多只有三关
                        {
                            level = 1;
                        }
                        loadLevelData(level);
                        totalY = Utility.CURRENT_Y = 0;
                        heroPlane.setLife(Utility.HERO_HP);
                        heroPlane.setDefaultLocation();
                    }
                }

                long roundStartTime = System.currentTimeMillis();
                doGameLogic();      //这是真个游戏的核心部分,处理相关的逻辑运算
                moveBackground();   //移动背景地图
                caculateFPS();      //计算FPS

                //控制背景移动同时将游戏的速率稳定在40fps/s
                //这种方法不是很精确,实际只有20多
                long roundEndTime = System.currentTimeMillis();
                try
                {
                    if ( (roundEndTime-roundStartTime)<25 )
                    {
                        Thread.sleep(25-(roundEndTime-roundStartTime));
                    }
                }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -