作为一个男孩子,从小就喜欢晚一些游戏。今天就用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;}@Overridepublic 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();}@Overridepublic void keyTyped(KeyEvent e) {}@Overridepublic 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();}@Overridepublic 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;}}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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);}}}
}