用JAVA实现吃豆人小游戏
游戏运行效果
Model.java
package pacman;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class Model extends JPanel implements ActionListener {
private Dimension d; //窗口的宽度
private final Font smallFont = new Font("Arial",Font.BOLD,14); //游戏内文字字体及字号
private boolean inGame = false; //判断游戏是否开始
private boolean dying = false; //判断Pacman是否存活
private final int BLOCK_SIZE = 24; //豆 横排个数: 24
private final int N_BLOCK = 15; //豆 竖排个数: 15
private final int SCREEN_SIZE = N_BLOCK * N_BLOCK; //共计:24 * 15 = 360 (个)
private final int MAX_GHOSTS = 12; //游戏内敌人的数量
private final int PACMAN_SPEED = 6; //Pacman移动的速度
private int N_GHOSTS = 6; //敌人数量
private int lives,score; //生命值,关卡得分
private int [] dx, dy;
private int [] ghost_x, ghost_y, ghost_dx, ghost_dy, ghostSpeed;
private Image heart, ghost;
private Image up, down, left, right;
private int pacman_x, pacman_y, pacmand_x, pacmand_y;
private int req_dx, req_dy;
private final int validSpeeds[] = {1,2,3,4,6,8};
private final int maxSpeed = 6;
private int currentSpeed = 3;
private short [] screenDate;
private Timer timer;
/**
* 0 = blue蓝色 4 = right border右边款
* 1 = left border左边框 8 = bottom border底边框
* 2 = top border顶边框 16 = white dots白点豆
*/
private final short levelData[] = {
19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 22,
17, 16, 16, 16, 16, 24, 16, 16, 16, 16, 16, 16, 16, 16, 20,
25, 24, 24, 24, 28, 0, 17, 16, 16, 16, 16, 16, 16, 16, 20,
0, 0, 0, 0, 0, 0, 17, 16, 16, 16, 16, 16, 16, 16, 20,
19, 18, 18, 18, 18, 18, 16, 16, 16, 16, 24, 24, 24, 24, 20,
17, 16, 16, 16, 16, 16, 16, 16, 16, 20, 0, 0, 0, 0, 21,
17, 16, 16, 16, 16, 16, 16, 16, 16, 20, 0, 0, 0, 0, 21,
17, 16, 16, 16, 24, 16, 16, 16, 16, 20, 0, 0, 0, 0, 21,
17, 16, 16, 20, 0, 17, 16, 16, 16, 16, 18, 18, 18, 18, 20,
17, 24, 24, 28, 0, 25, 24, 24, 16, 16, 16, 16, 16, 16, 20,
21, 0, 0, 0, 0, 0, 0, 0, 17, 16, 16, 16, 16, 16, 20,
17, 18, 18, 22, 0, 19, 18, 18, 16, 16, 16, 16, 16, 16, 20,
17, 16, 16, 20, 0, 17, 16, 16, 16, 16, 16, 16, 16, 16, 20,
17, 16, 16, 20, 0, 17, 16, 16, 16, 16, 16, 16, 16, 16, 20,
25, 24, 24, 24, 26, 24, 24, 24, 24, 24, 24, 24, 24, 24, 28
};
public Model() {
loadImages();
initVariables();
addKeyListener(new TAdapter());
setFocusable(true);
initGame();
}
/*导入图片—吃豆人的每一个动作图*/
private void loadImages() {
down = new ImageIcon("images/down.gif").getImage();
up = new ImageIcon("images/up.gif").getImage();
left = new ImageIcon("images/left.gif").getImage();
right = new ImageIcon("images/right.gif").getImage();
ghost = new ImageIcon("images/ghost.gif").getImage();
heart = new ImageIcon("images/heart.png").getImage();
}
/*游戏标题文字*/
public void showIntroScreen(Graphics2D graphics2D) {
String start = "Press SPACE to start"; //游戏开始文字
graphics2D.setColor(Color.yellow); //文字颜色
graphics2D.drawString(start,(SCREEN_SIZE) / 4, 150); //文字在窗体的位置
}
/*分数模块*/
public void drawScore(Graphics2D graphics2D) {
graphics2D.setFont(smallFont); //分数字体 : 小号字体
graphics2D.setColor(new Color(5,151,79)); //分数文字颜色 :重构颜色RGB格式
String s = "Score: " + score;
graphics2D.drawString(s,SCREEN_SIZE / 2 + 96,SCREEN_SIZE + 16);
for (int i = 0; i < lives; i++) {
graphics2D.drawImage(heart,i * 28 + 8, SCREEN_SIZE + 1,this);
}
}
private void initVariables() {
screenDate = new short[N_BLOCK * N_BLOCK];
d = new Dimension(400,400);
ghost_x = new int[MAX_GHOSTS];
ghost_dx = new int[MAX_GHOSTS];
ghost_y = new int[MAX_GHOSTS];
ghost_dy = new int[MAX_GHOSTS];
dx = new int[4];
dy = new int[4];
timer = new Timer(60,this); //每40ms 绘制一次图形及游戏运行速度(可以作为游戏难度调整功能)
timer.start();
}
/*游戏初始化*/
private void initGame() {
lives = 3; //初始化生命值数量
score = 0; //初始化分数为0
initLevel();
N_GHOSTS = 6; //初始化敌人数量
currentSpeed = 3; //初始化移动速度
}
/*游戏关卡范围*/
private void initLevel() {
int i;
for (i = 0; i < N_BLOCK * N_BLOCK; i++) {
screenDate[i] = levelData[i];
}
//continueLevel();
}
//游戏图形化初始
private void playGame(Graphics2D graphics2D) {
if (dying) {
death();
} else {
movePacman();
drawPacman(graphics2D);
moveGhost(graphics2D);
checkMaze();
}
}
public void movePacman() {
int pos;
short ch;
if (pacman_x % BLOCK_SIZE == 0 && pacman_y % BLOCK_SIZE == 0) {
pos = pacman_x / BLOCK_SIZE + N_BLOCK * (int) (pacman_y / BLOCK_SIZE);
ch = screenDate[pos];
if ((ch & 16 ) != 0) { //判断pacman吃到豆子(16)
screenDate[pos] = (short) (ch & 15);
score++;
}
if (req_dx != 0 || req_dy != 0 ) {
if (!((req_dx == -1 && req_dy == 0 && (ch & 1) != 0)
|| (req_dy == 1 && req_dy == 0 && (ch & 4) != 0)
|| (req_dx == 0 && req_dy == -1 && (ch & 2) != 0)
|| (req_dx == 0 && req_dy == 1 && (ch & 8) != 0))) {
pacmand_y = req_dy;
pacmand_x = req_dx;
}
}
if (( pacmand_x == -1 && pacmand_y == 0 && (ch & 1) != 0)
|| (pacmand_x == 1 && pacmand_y == 0 && (ch & 4) != 0)
|| (pacmand_x == 0 && pacmand_y == -1 && (ch & 2) != 0)
|| (pacmand_x == 0 && pacmand_y == 1 && (ch & 8) != 0)) {
pacmand_x = 0;
pacmand_y = 0;
}
}
pacman_x = pacman_x + PACMAN_SPEED * pacmand_x;
pacman_y = pacman_y + PACMAN_SPEED * pacmand_y;
}
/*绘制Pacman移动模型*/
public void drawPacman(Graphics2D graphics2D) {
if (req_dx == -1) {
graphics2D.drawImage(left,pacman_x + 1, pacman_y + 1,this);
}else if (req_dx == 1) {
graphics2D.drawImage(right,pacman_x + 1, pacman_y + 1,this);
}else if (req_dy == -1) {
graphics2D.drawImage(up,pacman_x + 1, pacman_y + 1,this);
}else {
graphics2D.drawImage(down,pacman_x + 1,pacman_y + 1,this);
}
}
/*Ghost移动模型算法*/
public void moveGhost(Graphics2D graphics2D) {
int pos;
int count;
for (int i = 0; i < N_GHOSTS; i++) {
if (ghost_x[i] % BLOCK_SIZE == 0 && ghost_y[i] % BLOCK_SIZE == 0) {
pos = ghost_x[i] / BLOCK_SIZE + N_BLOCK * (int) (ghost_y[i] / BLOCK_SIZE);
count = 0;
if ((screenDate[pos] & 1 ) == 0 && ghost_dx[i] != 1 ) {
dx[count] = -1;
dy[count] = 0;
count++;
}
if ((screenDate[pos] & 2 ) == 0 && ghost_dy[i] != 1 ) {
dx[count] = 0;
dy[count] = -1;
count++;
}
if ((screenDate[pos] & 4 ) == 0 && ghost_dx[i] != -1 ) {
dx[count] = 1;
dy[count] = 0;
count++;
}
if ((screenDate[pos] & 8 ) == 0 && ghost_dy[i] != -1 ) {
dx[count] = 0;
dy[count] = 1;
count++;
}
if (count == 0) {
if ((screenDate[pos] & 15) == 15) {
ghost_dy[i] = 0;
ghost_dx[i] = 0;
}else {
ghost_dy[i] = -ghost_dy[i];
ghost_dx[i] = -ghost_dx[i];
}
} else {
count = (int) (Math.random() * count);
if (count > 3) {
count = 3;
}
ghost_dx[i] = dx[count];
ghost_dy[i] = dy[count];
}
}
ghost_x[i] = ghost_x[i] + (ghost_dx[i] * ghostSpeed[i]);
ghost_y[i] = ghost_y[i] + (ghost_dy[i] * ghostSpeed[i]);
drawGhost(graphics2D,ghost_x[i] + 1,ghost_y[i] + 1);
if (pacman_x > (ghost_x[i] - 12) && pacman_x < (ghost_x[i] + 12)
&& pacman_y > (ghost_y[i] - 12) && pacman_y < (ghost_y[i] + 12)
&& inGame) {
dying = true;
}
}
}
/*绘制Ghost移动模型*/
public void drawGhost(Graphics2D graphics2D,int x, int y) {
graphics2D.drawImage(ghost,x,y,this);
}
public void checkMaze() {
int i = 0;
boolean finished = true;
while (i < N_BLOCK * N_BLOCK && finished ) {
if ((screenDate[i] & 48 ) != 0 ) {
finished = false;
}
} i++;
if (finished) {
score += 50;
if (N_GHOSTS < MAX_GHOSTS) {
N_GHOSTS++;
}
if (currentSpeed < maxSpeed) {
currentSpeed++;
}
} initLevel();
}
/*死亡机制判定*/
private void death() {
lives--; //生命值自减一
if (lives == 0) { //判断当生命值等于0的时候,使游戏结束
inGame = false;
}
continueLevel();
}
/*角色随机移动速度算法*/
private void continueLevel() {
int dx = 1;
int random;
for (int i = 0; i < N_GHOSTS; i++) {
ghost_y[i] = 4 * BLOCK_SIZE;
ghost_x[i] = 4 * BLOCK_SIZE;
ghost_dy[i] = 0;
ghost_dx[i] = dx;
dx = -dx;
random = (int) (Math.random() * (currentSpeed +1));
if (random > currentSpeed) {
random = currentSpeed;
}
ghostSpeed[i] = validSpeeds[random];
}
pacman_x = 7 * BLOCK_SIZE;
pacman_y = 11 * BLOCK_SIZE;
pacmand_x = 0;
pacmand_y = 0;
req_dx = 0;
req_dy = 0;
dying = false;
}
public void drawMaze(Graphics2D graphics2D) {
short i = 0;
int x,y;
for (y = 0; y < SCREEN_SIZE; y += BLOCK_SIZE) {
for (x = 0; x < SCREEN_SIZE; x += BLOCK_SIZE) {
graphics2D.setColor(new Color(0,72,251));
graphics2D.setStroke(new BasicStroke(5));
if ((screenDate[i] == 0)) {
graphics2D.fillRect(x,y, BLOCK_SIZE,BLOCK_SIZE);
}
if ((screenDate[i] & 1) != 0) {
graphics2D.drawLine(x,y,x,y + BLOCK_SIZE - 1);
}
if ((screenDate[i] & 2) != 0) {
graphics2D.drawLine(x,y,x + BLOCK_SIZE - 1,y);
}
if ((screenDate[i] & 4) != 0) {
graphics2D.drawLine(x + BLOCK_SIZE - 1,y,x + BLOCK_SIZE - 1,y + BLOCK_SIZE - 1);
}
if ((screenDate[i] & 8) != 0) {
graphics2D.drawLine(x,y + BLOCK_SIZE - 1,x + BLOCK_SIZE - 1,y + BLOCK_SIZE - 1);
}
if ((screenDate[i] & 4) != 0) {
graphics2D.setColor(new Color(255,255,255));
graphics2D.fillOval(x + 10, y + 10, 6, 6);
}
i++;
/*
* 数值说明:
* 0 = blue 4 = right border
* 1 = left border 8 = bottom border
* 2 = top border 16 = white dots
* */
}
}
}
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics2D graphics2D = (Graphics2D) graphics;
graphics2D.setColor(Color.black);
graphics2D.fillRect(0,0, d.width,d.height);
drawMaze(graphics2D);
drawScore(graphics2D);
if (inGame) {
playGame(graphics2D);
}else {
showIntroScreen(graphics2D);
}
Toolkit.getDefaultToolkit().sync();
}
/*键盘控制部分*/
class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (inGame) { //首先判断是否游戏开始
if (key == KeyEvent.VK_LEFT) { //监听到键盘方向左键触发 向左移动一格子,Y轴不变
req_dx = -1;
req_dy = 0;
} else if (key == KeyEvent.VK_RIGHT) { //监听到键盘方向右键触发 向右移动一格子,Y轴不变
req_dx = 1;
req_dy = 0;
} else if (key == KeyEvent.VK_UP) { //监听到键盘方向上键触发 向上移动一格子,Z轴不变
req_dx = 0;
req_dy = -1;
} else if (key == KeyEvent.VK_DOWN) { //监听到键盘方向下键触发 向下移动一格子,Z轴不变
req_dx = 0;
req_dy = 1;
} else if (key == KeyEvent.VK_ESCAPE && timer.isRunning()) { //监听到键盘ESC时或者时间结束,退出游戏
inGame = false;
} else {
if (key == KeyEvent.VK_SPACE) { //监听到键盘SPACE时,开始游戏
inGame = true;
initGame();
}
}
}
}
}
@Override
public void actionPerformed(ActionEvent e) { repaint(); }
}
Pacman.java
package pacman;
import javax.swing.*;
public class Pacman extends JFrame {
public Pacman() {
add(new Model());
}
public static void main(String[] args) {
Pacman pacman = new Pacman();
pacman.setVisible(true);
pacman.setTitle("Pacman Game"); //窗体标题
pacman.setSize(380,420); //窗体的大小
pacman.setDefaultCloseOperation(EXIT_ON_CLOSE);
pacman.setLocationRelativeTo(null);
}
}
完整的游戏代码及资源文件
下载地址https://download.csdn.net/download/weixin_50679163/78951807