作为一个男孩子,从小就喜欢晚一些游戏。今天就用java写一个类似马里奥的冒险闯关小游戏,但这也不是一两天能完成的事情,我将会持续更新这个游戏(有什么好的介意也非常欢迎大家提出来,也能在我的基础上自己接着写)。目前完成的功能有:人物的流畅运动、跳跃以及自由下落,障碍物(地面)的添加,怪物的添加、移动以及死亡。(代码基本上是完整的,直接粘贴复制就能用)


游戏介绍

和马里奥差不太多,左右键控制移动,空格跳,碰到怪物死亡,可以踩死怪物。目前也就这些功能,也会不断添加新的功能。

代码讲解

目录结构

view里面是创建页面,handle里写控制方法,pic里存一些需要的图片。

创建Frame

没啥好讲的。

import javax.swing.*;

public class GameFrame {
    public static void main(String[] args) {
        JFrame jf = new JFrame("冒险闯关小游戏");

        jf.add(new GamePanel());

        jf.setSize(806,600);
        jf.setLocationRelativeTo(null);     //居中
        jf.setResizable(false);
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jf.setVisible(true);
    }
}

 JPanel

这里定义了玩家、怪物、障碍物的一些属性,然后将他们画出来。其实更好的方法是定义三个类,用的时候实例化一下就行,这里后面我也会改。

import game2.handle.MonsterMove;
import game2.handle.MoveHandle;

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

public class GamePanel extends JPanel {
    ImageIcon b = new ImageIcon("src\\game2\\pic\\b.jpg");
    ImageIcon xyq = new ImageIcon("src\\game2\\pic\\xyq.png");
    public boolean up = false;
    public boolean down = false;
    public boolean left = false;
    public boolean right = false;

    public int hero_x;
    public int hero_y;
//    public int hero_width = xyq.getIconWidth();
//    public int hero_height = xyq.getIconHeight();
    public int hero_width = 30;
    public int hero_height = 60;

    public Vector<int[]> v = new Vector<>();
    int[] f0 = {0,500,800,10};
    int[] f1 = {300,500-80,200,10};
    int[] f2 = {500,500-40,50,40};
    int[] f3 = {100,500-150,80,30};
    int[] f4 = {200,500-250,340,10};
    {
        v.add(f0);
        v.add(f1);
        v.add(f2);
        v.add(f3);
        v.add(f4);
    }

    public Vector<int[]> ms = new Vector<>();    //怪物列表
    public int[] m0 = {600,500-40,40,40,600,750,1}; //x,y,w,h,起点,终点,速度
    public int[] m1 = {0,500-40,40,40,0,100,1};
    {
        ms.add(m0);
        ms.add(m1);
    }
    public boolean mIsDie = false;


    public GamePanel() {
        setFocusable(true);

        MoveHandle moveHandle = new MoveHandle(this);
        addKeyListener(moveHandle);
        Thread thread = new Thread(moveHandle);
        thread.start();

        MonsterMove monsterMove = new MonsterMove(this);
        Thread thread2 = new Thread(monsterMove);
        thread2.start();

        init();
    }

    public void init() {
        hero_x = 200;
        hero_y = 500-hero_height;
    }

    @Override
    public void paint(Graphics g) {
        super.paintComponent(g);
        b.paintIcon(this,g,0,0);
        g.setColor(Color.blue);
        g.fillRect(hero_x, hero_y, hero_width, hero_height);
//        xyq.paintIcon(this,g,hero_x,hero_y);
        g.setColor(Color.red);
        for(int i=0;i<ms.size();i++){
            g.fillRect(ms.get(i)[0],ms.get(i)[1],ms.get(i)[2],ms.get(i)[3]);
        }
        paintRect(g,v);
    }

    private void paintRect(Graphics g,Vector<int[]> v){
        g.setColor(Color.black);
        for(int i = 0; i<v.size(); i++){
            int[] f = v.get(i);
            g.fillRect(f[0],f[1],f[2],f[3]);
        }
    }
}

MoveHandle

我觉得我这里最好的一点代码就在这里面,其实从学写swing时候,就发现如果用键盘控制人物移动的时候它的移动并不顺畅。我这里是用线程的方法做成了顺畅移动。

简单讲,就是创建一个进程,一直让他循环执行,每当按下右(左)键,就会一直循环执行向右(左)走的方法,每次运行方法中间间隔几毫秒(不然移动的太快根本看不到)。

然后中间再添加一些其他判断,如是否碰到障碍物,是否碰到怪物等。

import game2.view.GamePanel;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class MoveHandle implements KeyListener, Runnable {

    GamePanel gamePanel;
    JumpHandle jump;

    public MoveHandle(GamePanel gamePanel) {
        this.gamePanel = gamePanel;
        jump = new JumpHandle(gamePanel);
        Thread thread1 = new Thread(jump);
        thread1.start();
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        switch (code) {
            case KeyEvent.VK_LEFT:
                gamePanel.left = true;
                break;
            case KeyEvent.VK_RIGHT:
                gamePanel.right = true;
                break;
            case KeyEvent.VK_SPACE:
                jump.isSky = true;
                if (jump.c < 2) {
                    jump.isJump = true;
                }
                break;
            default:
                break;
        }

        gamePanel.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {
        int code = e.getKeyCode();
        switch (code) {
            case KeyEvent.VK_LEFT:
                gamePanel.left = false;
                break;
            case KeyEvent.VK_RIGHT:
                gamePanel.right = false;
                break;
            default:
                break;

        }
    }

    @Override
    public void run() {
        while (true) {
            move();
            if (!jump.isSky) {
                loop:
                while (true) {
                    for (int i = 0; i < gamePanel.v.size(); i++) {
                        if (gamePanel.hero_x + gamePanel.hero_width > gamePanel.v.get(i)[0]
                                && gamePanel.hero_x < gamePanel.v.get(i)[0] + gamePanel.v.get(i)[2]) {
                            if (gamePanel.hero_y == gamePanel.v.get(i)[1] - gamePanel.hero_height) {
                                break loop;
                            }
                        }
                    }
                    gamePanel.hero_y += 1;
                    for(int i=0;i<gamePanel.ms.size();i++) {
                        if (gamePanel.hero_y + gamePanel.hero_height == gamePanel.ms.get(i)[1]
                                && gamePanel.hero_x + gamePanel.hero_width > gamePanel.ms.get(i)[0]
                                && gamePanel.hero_x < gamePanel.ms.get(i)[0] + gamePanel.ms.get(i)[2]) {
                            gamePanel.ms.remove(i);
                            break ;
                        }
                    }
                    gamePanel.repaint();
                    try {
                        Thread.sleep(3);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    move();
                }
            }
            gamePanel.repaint();
            try {
                Thread.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void move() {
        if (gamePanel.right) {
            if (gamePanel.hero_x + gamePanel.hero_width < 800 && isMoveRight()) {
                gamePanel.hero_x += 1;
            }
        } else if (gamePanel.left) {
            if (gamePanel.hero_x > 0 && isMoveLeft()) {
                gamePanel.hero_x -= 1;
            }
        }
        isDie();
    }

    private boolean isMoveRight() {
        for (int i = 0; i < gamePanel.v.size(); i++) {
            if (gamePanel.hero_x + gamePanel.hero_width == gamePanel.v.get(i)[0]
                    && gamePanel.hero_y + gamePanel.hero_height > gamePanel.v.get(i)[1]
                    && gamePanel.hero_y < gamePanel.v.get(i)[1] + gamePanel.v.get(i)[3]) {
                return false;
            }
        }
        return true;
    }

    private boolean isMoveLeft() {
        for (int i = 0; i < gamePanel.v.size(); i++) {
            if (gamePanel.hero_x == gamePanel.v.get(i)[0] + gamePanel.v.get(i)[2]
                    && gamePanel.hero_y + gamePanel.hero_height > gamePanel.v.get(i)[1]
                    && gamePanel.hero_y < gamePanel.v.get(i)[1] + gamePanel.v.get(i)[3]) {
                return false;
            }
        }
        return true;
    }

    private void isDie() {
        for(int i=0;i<gamePanel.ms.size();i++) {
            int[] m = gamePanel.ms.get(i);
            if ((gamePanel.hero_x + gamePanel.hero_width == m[0] || gamePanel.hero_x == m[0] + m[2])
                    && gamePanel.hero_y + gamePanel.hero_height > m[1]
                    && gamePanel.hero_y < m[1] + m[3]) {
                gamePanel.init();;
            }
        }
    }
}

JumpHandle

这段是用来实现跳跃的功能,我这里设置的上下跳跃是匀速的,可以自己改一下,让它符合真实物理情况。

这里我设置了最多跳两次。

并且在下降的时候增加了两个判断:1是是否落到实体障碍物上,2是是否踩到怪物,踩到怪物就被判断死亡。

import game2.view.GamePanel;

import java.util.Arrays;

public class JumpHandle implements Runnable {
    GamePanel gamePanel;
    boolean isJump = false;
    boolean isSky = false;
    int c;

    public JumpHandle(GamePanel gamePanel) {
        this.gamePanel = gamePanel;
    }

    @Override
    public void run() {
        while (true) {
            c = 0;

            if (isJump) {
                isJump = false;
                jumpUp();
                jumpDown();
            }
            try {
                Thread.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void jumpDown() {
        loop:
        while (true) {
            for (int i = 0; i < gamePanel.v.size(); i++) {
                if (gamePanel.hero_x  + gamePanel.hero_width> gamePanel.v.get(i)[0]
                        && gamePanel.hero_x < gamePanel.v.get(i)[0] + gamePanel.v.get(i)[2]) {
                    if (gamePanel.hero_y == gamePanel.v.get(i)[1] - gamePanel.hero_height) {
                        isSky = false;
                        break loop;
                    }
                }
            }
            if (isJump && c < 2) {
                isJump = false;
                jumpUp();
            }
            gamePanel.hero_y += 1;
            for(int i=0;i<gamePanel.ms.size();i++) {
                if (gamePanel.hero_y + gamePanel.hero_height == gamePanel.ms.get(i)[1]
                        && gamePanel.hero_x + gamePanel.hero_width > gamePanel.ms.get(i)[0]
                        && gamePanel.hero_x < gamePanel.ms.get(i)[0] + gamePanel.ms.get(i)[2]) {
                    gamePanel.ms.remove(i);
                    break ;
                }
            }
            try {
                Thread.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void jumpUp() {
        c++;
        for (int i = 0; i < 80; i++) {
            if (isJump && c < 2) {
                isJump = false;
                jumpUp();
                break;
            }
            if(!isJumpD()){
                break;
            }
            gamePanel.hero_y -= 1;

            try {
                Thread.sleep(3);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private boolean isJumpD() {
        for (int i = 0; i < gamePanel.v.size(); i++) {
            if (gamePanel.hero_y == gamePanel.v.get(i)[1] + gamePanel.v.get(i)[3]
                    && gamePanel.hero_x  + gamePanel.hero_width> gamePanel.v.get(i)[0]
                    && gamePanel.hero_x < gamePanel.v.get(i)[0] + gamePanel.v.get(i)[2]) {
                return false;
            }
        }
        return true;
    }
}

MonsterMove

这里是实现怪物的移动。

import game2.view.GamePanel;

public class MonsterMove implements Runnable {
    GamePanel gamePanel;

    public MonsterMove(GamePanel gamePanel) {
        this.gamePanel = gamePanel;
    }

    @Override
    public void run() {

        while(true) {
            for (int i = 0; i < gamePanel.ms.size(); i++) {
                gamePanel.ms.get(i)[0]+=gamePanel.ms.get(i)[6];
                if(gamePanel.ms.get(i)[0]==gamePanel.ms.get(i)[4]||gamePanel.ms.get(i)[0]+gamePanel.ms.get(i)[2]==gamePanel.ms.get(i)[5]){
                    gamePanel.ms.get(i)[6] = -gamePanel.ms.get(i)[6];
                }
            }
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }
}

更多推荐

java 300行代码 冒险闯关小游戏(代码+讲解)