Java游戏开发拼图游戏经典版

作者:墨染秦月 时间:2023-10-10 16:23:08 

游戏介绍:

拼图游戏是一款经典的益智游戏,游戏难度分为 简单、正常、困难 三种难度,分别对应3*3,4*4,5*5布局,游戏开始前图片被随机打乱,空块位于最右下角,玩家通过点击空块周围图片或者按键方式对图片和空块进行相互交换,直到所有图片都回到原位即为游戏胜利。

本次制作的拼图游戏运行界面如下:

Java游戏开发拼图游戏经典版

使用素材文件夹:

Java游戏开发拼图游戏经典版

链接: https://pan.baidu.com/s/10qE7yq6IwU-vWprvc5Axgw   提取码: p16e

游戏设计的思路

对拼图界面的图像信息可以采用二维数组map进行存储,数组存储的是图片ID,拼图完成的map数组存储的内容应该为从左到右,从上到下,图片ID顺序为1~8,最右下角的数 组元素存储的图片ID为-1(BLANK_STATE)。所有的移动操作可以简化为对map的移动操作,每次移动完成调用repaint()对图片按ID进行绘画即可。使用文本存储历史记录,每次过关对当前步数和历史记录进行比较和更新。考虑到数组map要求打乱后可以通过移动被还原,所以对数组的打乱必须有所讲究,这里我们采用系统对原有图片执行10000次上下左右按键事件来对图片进行打乱,最后再将空块移动到最右下角,这样图片就顺利地做到了随机打乱。

图片的获取及显示:

先根据关卡level来获取关卡图片,不同的关卡将分成不同数量的小块,假如是简单难度3*3地图,小图片的宽w是大图片的宽的三分之一,小图片的高h是大图片的高的三分之一,第i张图片的左上角起点的x值为图片所在列数*小图片宽(i%3*w),y值为图片所在行数*小图片高(i/3*h):


private void getPics() {

BufferedImage bufferedImage = null;
int width = 0,height = 0;
try {
 bufferedImage = ImageIO.read(new File("D:/Game/JigsawGame/pic"+level+".png"));
 width = bufferedImage.getWidth();
 height = bufferedImage.getHeight();
} catch (IOException e) {
 e.printStackTrace();
}

if(level==EASY){

pics = new Image[9];

int w = width/3;
int h = height/3;

for(int i=0;i<8;i++){
int x = i%3*w;
int y = i/3*h;
pics[i] = bufferedImage.getSubimage(x, y, w, h);
}

}else if(level==NORMAL){

pics = new Image[16];

int w = width/4;
int h = height/4;

for(int i=0;i<15;i++){
int x = i%4*w;
int y = i/4*h;
pics[i] = bufferedImage.getSubimage(x, y, w, h);
}

}else{

pics = new Image[25];

int w = width/5;
int h = height/5;

for(int i=0;i<24;i++){
int x = i%5*w;
int y = i/5*h;
pics[i] = bufferedImage.getSubimage(x, y, w, h);
}

}

}

public void paint(Graphics g){

g.clearRect(0, 0, this.getWidth(), this.getHeight());

for(int i=0;i<map.length;i++)
for(int j=0;j<map.length;j++){

if(map[i][j]!=BLANK_STATE){
//画图
g.drawImage(pics[map[i][j]-1],leftX+j*W,leftY+i*W,W,W,this);
}

}
}

游戏逻辑

对玩家执行不同的操作进行分别处理:

①当玩家鼠标点击

当玩家鼠标点击的小图片位于空块上下左右方时,点击的小图片与空块交换位置,否则点击无效。

②当玩家按键移动

当空块位于第一行时,moveDown()无效;

当空块位于最后一行时,moveUp()无效;

当空块位于第一列时,moveRight()无效;

当空块位于最后一列时,moveLeft()无效;

此处的moveLeft()指的是小图片移动的方向,也就是空块移动的反方向。鼠标点击事件的移动可以复用按键事件的移动方法,只需要将点击的小图片与数组下标进行转换,再判断下调用哪个方法即可。


public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub

int x = e.getX()-leftX;
int y = e.getY()-leftY;

if(x<0||y<0||x>600||y>600){//超出地图范围
return ;
}

//存储数组行列下标
int i = y/W;
int j = x/W;

if(blank_x == i-1&&blank_y == j){//空块在当前点击块的上侧
moveUp();
}else if(blank_x == i+1&&blank_y == j){//空块在当前点击块的下侧
moveDown();
}else if(blank_x == i&&blank_y == j-1){//空块在当前点击块的左侧
moveLeft();
}else if(blank_x == i&&blank_y == j+1){//空块在当前点击块的右侧
moveRight();
}else{
return ;
}

repaint();

isWin();

}

public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if(e.getKeyCode() == KeyEvent.VK_UP&&blank_x!=level+1){//上
moveUp();
}else if(e.getKeyCode() == KeyEvent.VK_DOWN&&blank_x!=0){//下
moveDown();
}else if(e.getKeyCode() == KeyEvent.VK_LEFT&&blank_y!=level+1){//左
moveLeft();
}else if(e.getKeyCode() == KeyEvent.VK_RIGHT&&blank_y!=0){//右
moveRight();
}else{
return ;
}

repaint();
isWin();

}

小图片的移动

交换小图片与空块的值,并对空块的数组下标重新赋值:


//空块与上一格交换
private void moveDown(){

map[blank_x][blank_y] = map[blank_x-1][blank_y];
map[blank_x-1][blank_y] = BLANK_STATE;
blank_x = blank_x-1;
step++;
HelpPanel.nowStep.setText(step+"");
}

//空块与下一格交换
private void moveUp(){

map[blank_x][blank_y] = map[blank_x+1][blank_y];
map[blank_x+1][blank_y] = BLANK_STATE;
blank_x = blank_x+1;
step++;
HelpPanel.nowStep.setText(step+"");
}

//空块与左一格交换
private void moveRight(){

map[blank_x][blank_y] = map[blank_x][blank_y-1];
map[blank_x][blank_y-1] = BLANK_STATE;
blank_y = blank_y-1;
step++;
HelpPanel.nowStep.setText(step+"");
}

//空块与右一格交换
private void moveLeft(){

map[blank_x][blank_y] = map[blank_x][blank_y+1];
map[blank_x][blank_y+1] = BLANK_STATE;
blank_y = blank_y+1;
step++;
HelpPanel.nowStep.setText(step+"");
}

打乱地图信息

使用Math.Random()获取随机值,各个方向按键事件的概率是1/4,当符合条件时执行移动方法并且移动次数+1,移动10000次实现随机打乱地图。


private void RandomTheMap() {

int i =0;

//尝试移动一万次
while(i<10000){
int rate = (int) (Math.random()*100);
if(rate<25&&blank_x!=level+1){
moveUp();
i++;
}else if(rate<50&&blank_x!=0){
moveDown();
i++;
}else if(rate<75&&blank_y!=level+1){
moveLeft();
i++;
}else if(rate<100&&blank_y!=0){
moveRight();
i++;
}
}

//再将空块移动到最右下角

while(blank_x<level+1){
moveUp();
}

while(blank_y<level+1){
moveLeft();
}

step=0;
}

判断输赢

将现有map信息与正确的map信息一一对比,如果都相等,过关,比较当前记录和历史记录,如果刷新历史记录进行记录的更新,然后询问是否开始下一关。如果开始下一关,进行level++并对地图及面板信息进行初始化:


private void isWin() {

boolean flag = true;

for(int i=0;i<successMap.length;i++){
for(int j=0;j<successMap.length;j++){
if(map[i][j] != successMap[i][j]){
flag = false;
break;
}
}
}

if(flag){
String msg;
int type;
int choice;
int record;
String title;
switch(level){//通关,是否进入下一关
case EASY:
this.removeKeyListener(this);
this.removeMouseListener(this);
record = mapUtil.getRecord(level);//历史记录
if(step<record){
msg = "恭喜你通过简单关卡并刷新历史记录,完成步数是"+step+"\n历史记录是"+record+",是否要进入下一关?";
mapUtil.writeRecord(level, step);//更新历史记录
}else{
msg = "恭喜你通过简单关卡,完成步数是"+step+"\n是否要进入下一关?";
}
type = JOptionPane.YES_NO_OPTION;
title = "过关";
choice = 0;
choice = JOptionPane.showConfirmDialog(null, msg,title,type);
if(choice==1){
System.exit(0);
}else if(choice == 0){
level++;
map = mapUtil.getMap(level);
successMap = mapUtil.getMap(level);
record = mapUtil.getRecord(level);//获取正常难度的历史记录
initializeMap();//初始化地图相关变量信息
RandomTheMap();//打乱图案顺序
step = 0;
HelpPanel.histotyStep.setText(record+"");
HelpPanel.panelCenter.setSuccessPic(level);
HelpPanel.nowLevel.setText("正常");
HelpPanel.nowStep.setText(step+"");
getPics();
this.addKeyListener(this);
this.addMouseListener(this);
repaint();
}
;break;
case NORMAL:
this.removeKeyListener(this);
this.removeMouseListener(this);
record = mapUtil.getRecord(level);//历史记录
if(step<record){
msg = "恭喜你通过正常关卡并刷新历史记录,完成步数是"+step+"\n历史记录是"+record+",是否要进入下一关?";
mapUtil.writeRecord(level, step);//更新历史记录
}else{
msg = "恭喜你通过正常关卡,完成步数是"+step+"\n是否要进入下一关?";
}
type = JOptionPane.YES_NO_OPTION;
title = "过关";
choice = 0;
choice = JOptionPane.showConfirmDialog(null, msg,title,type);
if(choice==1){
System.exit(0);
}else if(choice == 0){
level++;
map = mapUtil.getMap(level);
successMap = mapUtil.getMap(level);
initializeMap();//初始化地图相关变量信息
RandomTheMap();//打乱图案顺序
getPics();
step = 0;
record = mapUtil.getRecord(level);//获取困难难度的历史记录。
HelpPanel.histotyStep.setText(record+"");
HelpPanel.panelCenter.setSuccessPic(level);
HelpPanel.nowStep.setText(step+"");
HelpPanel.nowLevel.setText("困难");
this.addKeyListener(this);
this.addMouseListener(this);
repaint();
}
;break;
case HARD:
this.removeKeyListener(this);
this.removeMouseListener(this);
record = mapUtil.getRecord(level);//历史记录
if(step<record){
msg = "恭喜你通过困难关卡并刷新历史记录,完成步数是"+step+"\n历史记录是"+record;
JOptionPane.showMessageDialog(this, msg);
mapUtil.writeRecord(level, step);//更新历史记录
}else{
msg = "恭喜通过困难关卡,完成步数是"+step;
JOptionPane.showMessageDialog(this, msg);
}
;break;
}

}

}

历史记录的读写

采用文本形式对记录进行保存,初始情况下,读取记录的时候如果没有记录文件进行文件的新建并初始所有历史记录为9999步;记录的保存采用两个逗号对三个关卡的历史记录进行分割,读取后进行array.split(",")分割操作;写入时,先清空原有文本信息,再将记录合成字符串写入文件。


//获取关卡历史记录
public int getRecord(int level){
File file = new File("D://GameRecordAboutSwing");

if(!file.exists()){
file.mkdirs();
}
File record = new File("D://GameRecordAboutSwing/recordJigsawGame.txt");

try{
if(!record.exists()){//如果不存在,新建文本
record.createNewFile();
fos = new FileOutputStream(record);
dos = new DataOutputStream(fos);
String s = "9999,9999,9999";
dos.writeBytes(s);
System.out.println(record.isFile());;
}
//读取记录
fis = new FileInputStream(record);
dis = new DataInputStream(fis);
String str = dis.readLine();
array = str.split(",");

}catch(Exception e){
e.printStackTrace();
}finally{
try {
if(fis!=null)
fis.close();
if(dis!=null)
dis.close();
if(fos!=null)
 fos.close();
if(dos!=null)
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

return Integer.parseInt(array[level-1]);
}

//更新关卡历史记录
public void writeRecord(int level,int step){
File record = new File("D://GameRecordAboutSwing/recordJigsawGame.txt");

try {
//清空原有记录
FileWriter fileWriter =new FileWriter(record);
fileWriter.write("");
fileWriter.flush();
fileWriter.close();
//重新写入文本
fos = new FileOutputStream(record);
dos = new DataOutputStream(fos);
array[level-1] = step+"";
String s = array[0]+","+array[1]+","+array[2];
dos.writeBytes(s);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if(fos!=null)
 fos.close();
if(dos!=null)
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

}

到这里核心的游戏逻辑及游戏面板的相关内容已经说明完了,涉及辅助面板类的东西会有些错综复杂,这里就不详细介绍了。

完整源码如下:

MapUtil类:


package 人物拼图;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;

public class MapUtil {

int[][] map;
FileInputStream fis = null;
FileOutputStream fos = null;
DataInputStream dis = null;
DataOutputStream dos = null;
String array[] = null;

int level = 1;

public static final int EASY = 1,NORMAL = 2,HARD = 3,BLANK_STATE = -1;

public int[][] getMap(int level){
switch(level){
case EASY:
map = new int[3][3];
for(int i=0;i<3;i++)
for(int j=0;j<3;j++){
map[i][j] = 3*i+j+1;
}
map[2][2] = BLANK_STATE;
;break;
case NORMAL:
map=new int[4][4];
for(int i=0;i<4;i++)
for(int j=0;j<4;j++){
map[i][j] = 4*i+j+1;
}
map[3][3] = BLANK_STATE;
break;
case HARD:
map=new int[5][5];
for(int i=0;i<5;i++)
for(int j=0;j<5;j++){
map[i][j] = 5*i+j+1;
}
map[4][4] = BLANK_STATE;
break;
}
return map;
}

//获取关卡历史记录
public int getRecord(int level){
File file = new File("D://GameRecordAboutSwing");

if(!file.exists()){
file.mkdirs();
}
File record = new File("D://GameRecordAboutSwing/recordJigsawGame.txt");

try{
if(!record.exists()){//如果不存在,新建文本
record.createNewFile();
fos = new FileOutputStream(record);
dos = new DataOutputStream(fos);
String s = "9999,9999,9999";
dos.writeBytes(s);
System.out.println(record.isFile());;
}
//读取记录
fis = new FileInputStream(record);
dis = new DataInputStream(fis);
String str = dis.readLine();
array = str.split(",");

}catch(Exception e){
e.printStackTrace();
}finally{
try {
if(fis!=null)
fis.close();
if(dis!=null)
dis.close();
if(fos!=null)
 fos.close();
if(dos!=null)
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

return Integer.parseInt(array[level-1]);
}

//更新关卡历史记录
public void writeRecord(int level,int step){
File record = new File("D://GameRecordAboutSwing/recordJigsawGame.txt");

try {
//清空原有记录
FileWriter fileWriter =new FileWriter(record);
fileWriter.write("");
fileWriter.flush();
fileWriter.close();
//重新写入文本
fos = new FileOutputStream(record);
dos = new DataOutputStream(fos);
array[level-1] = step+"";
String s = array[0]+","+array[1]+","+array[2];
dos.writeBytes(s);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if(fos!=null)
 fos.close();
if(dos!=null)
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

}

}

MapUtil类主要用做对地图数组信息的初始化以及历史记录的读写。

GamePanel类


package 人物拼图;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class GamePanel extends JPanel implements ActionListener ,MouseListener,KeyListener{

Image pics[];
int leftX=50,leftY=50;
int level,W;
int[][] map;
int[][] successMap;//最后结果
int blank_x,blank_y;//记录空白块的数组下标
int step = 0;
MapUtil mapUtil = new MapUtil();
int record;//存储当前关卡记录
public static final int EASY = 1,NORMAL = 2,HARD = 3,BLANK_STATE = -1;

public GamePanel(int level){
setSize(600, 600);
this.level = level;
map = mapUtil.getMap(level);
successMap = mapUtil.getMap(level);
initializeMap();//初始化地图相关变量信息
RandomTheMap();//打乱图案顺序
this.setVisible(true);
this.addKeyListener(this);
this.addMouseListener(this);
this.setFocusable(true);
getPics();
record = mapUtil.getRecord(level);
HelpPanel.histotyStep.setText(record+"");
HelpPanel.nowStep.setText(step+"");
repaint();
}

public void paint(Graphics g){

g.clearRect(0, 0, this.getWidth(), this.getHeight());

for(int i=0;i<map.length;i++)
for(int j=0;j<map.length;j++){

if(map[i][j]!=BLANK_STATE){
//画图
g.drawImage(pics[map[i][j]-1],leftX+j*W,leftY+i*W,W,W,this);
}

}
}

private void initializeMap(){
switch(level){
case EASY:
blank_x=2;blank_y=2;
W = 200;
;break;
case NORMAL:
blank_x=3;blank_y=3;
W = 150;
;break;
case HARD:
blank_x=4;blank_y=4;
W = 120;
;break;
}
}

private void RandomTheMap() {

int i =0;

//尝试移动一万次
while(i<10000){
int rate = (int) (Math.random()*100);
if(rate<25&&blank_x!=level+1){
moveUp();
i++;
}else if(rate<50&&blank_x!=0){
moveDown();
i++;
}else if(rate<75&&blank_y!=level+1){
moveLeft();
i++;
}else if(rate<100&&blank_y!=0){
moveRight();
i++;
}
}

//再将空块移动到最右下角

while(blank_x<level+1){
moveUp();
}

while(blank_y<level+1){
moveLeft();
}

step=0;
}

//空块与上一格交换
private void moveDown(){

map[blank_x][blank_y] = map[blank_x-1][blank_y];
map[blank_x-1][blank_y] = BLANK_STATE;
blank_x = blank_x-1;
step++;
HelpPanel.nowStep.setText(step+"");
}

//空块与下一格交换
private void moveUp(){

map[blank_x][blank_y] = map[blank_x+1][blank_y];
map[blank_x+1][blank_y] = BLANK_STATE;
blank_x = blank_x+1;
step++;
HelpPanel.nowStep.setText(step+"");
}

//空块与左一格交换
private void moveRight(){

map[blank_x][blank_y] = map[blank_x][blank_y-1];
map[blank_x][blank_y-1] = BLANK_STATE;
blank_y = blank_y-1;
step++;
HelpPanel.nowStep.setText(step+"");
}

//空块与右一格交换
private void moveLeft(){

map[blank_x][blank_y] = map[blank_x][blank_y+1];
map[blank_x][blank_y+1] = BLANK_STATE;
blank_y = blank_y+1;
step++;
HelpPanel.nowStep.setText(step+"");
}

private void getPics() {

BufferedImage bufferedImage = null;
int width = 0,height = 0;
try {
 bufferedImage = ImageIO.read(new File("D:/Game/JigsawGame/pic"+level+".png"));
 width = bufferedImage.getWidth();
 height = bufferedImage.getHeight();
} catch (IOException e) {
 e.printStackTrace();
}

if(level==EASY){

pics = new Image[9];

int w = width/3;
int h = height/3;

for(int i=0;i<8;i++){
int x = i%3*w;
int y = i/3*h;
pics[i] = bufferedImage.getSubimage(x, y, w, h);
}

}else if(level==NORMAL){

pics = new Image[16];

int w = width/4;
int h = height/4;

for(int i=0;i<15;i++){
int x = i%4*w;
int y = i/4*h;
pics[i] = bufferedImage.getSubimage(x, y, w, h);
}

}else{

pics = new Image[25];

int w = width/5;
int h = height/5;

for(int i=0;i<24;i++){
int x = i%5*w;
int y = i/5*h;
pics[i] = bufferedImage.getSubimage(x, y, w, h);
}

}

}

@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub

}

@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if(e.getKeyCode() == KeyEvent.VK_UP&&blank_x!=level+1){//上
moveUp();
}else if(e.getKeyCode() == KeyEvent.VK_DOWN&&blank_x!=0){//下
moveDown();
}else if(e.getKeyCode() == KeyEvent.VK_LEFT&&blank_y!=level+1){//左
moveLeft();
}else if(e.getKeyCode() == KeyEvent.VK_RIGHT&&blank_y!=0){//右
moveRight();
}else{
return ;
}

repaint();
isWin();

}

@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub

}

@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub

}

@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub

int x = e.getX()-leftX;
int y = e.getY()-leftY;

if(x<0||y<0||x>600||y>600){//超出地图范围
return ;
}

//存储数组行列下标
int i = y/W;
int j = x/W;

if(blank_x == i-1&&blank_y == j){//空块在当前点击块的上侧
moveUp();
}else if(blank_x == i+1&&blank_y == j){//空块在当前点击块的下侧
moveDown();
}else if(blank_x == i&&blank_y == j-1){//空块在当前点击块的左侧
moveLeft();
}else if(blank_x == i&&blank_y == j+1){//空块在当前点击块的右侧
moveRight();
}else{
return ;
}

repaint();

isWin();

}

private void isWin() {

boolean flag = true;

for(int i=0;i<successMap.length;i++){
for(int j=0;j<successMap.length;j++){
if(map[i][j] != successMap[i][j]){
flag = false;
break;
}
}
}

if(flag){
String msg;
int type;
int choice;
int record;
String title;
switch(level){//通关,是否进入下一关
case EASY:
this.removeKeyListener(this);
this.removeMouseListener(this);
record = mapUtil.getRecord(level);//历史记录
if(step<record){
msg = "恭喜你通过简单关卡并刷新历史记录,完成步数是"+step+"\n历史记录是"+record+",是否要进入下一关?";
mapUtil.writeRecord(level, step);//更新历史记录
}else{
msg = "恭喜你通过简单关卡,完成步数是"+step+"\n是否要进入下一关?";
}
type = JOptionPane.YES_NO_OPTION;
title = "过关";
choice = 0;
choice = JOptionPane.showConfirmDialog(null, msg,title,type);
if(choice==1){
System.exit(0);
}else if(choice == 0){
level++;
map = mapUtil.getMap(level);
successMap = mapUtil.getMap(level);
record = mapUtil.getRecord(level);//获取正常难度的历史记录
initializeMap();//初始化地图相关变量信息
RandomTheMap();//打乱图案顺序
step = 0;
HelpPanel.histotyStep.setText(record+"");
HelpPanel.panelCenter.setSuccessPic(level);
HelpPanel.nowLevel.setText("正常");
HelpPanel.nowStep.setText(step+"");
getPics();
this.addKeyListener(this);
this.addMouseListener(this);
repaint();
}
;break;
case NORMAL:
this.removeKeyListener(this);
this.removeMouseListener(this);
record = mapUtil.getRecord(level);//历史记录
if(step<record){
msg = "恭喜你通过正常关卡并刷新历史记录,完成步数是"+step+"\n历史记录是"+record+",是否要进入下一关?";
mapUtil.writeRecord(level, step);//更新历史记录
}else{
msg = "恭喜你通过正常关卡,完成步数是"+step+"\n是否要进入下一关?";
}
type = JOptionPane.YES_NO_OPTION;
title = "过关";
choice = 0;
choice = JOptionPane.showConfirmDialog(null, msg,title,type);
if(choice==1){
System.exit(0);
}else if(choice == 0){
level++;
map = mapUtil.getMap(level);
successMap = mapUtil.getMap(level);
initializeMap();//初始化地图相关变量信息
RandomTheMap();//打乱图案顺序
getPics();
step = 0;
record = mapUtil.getRecord(level);//获取困难难度的历史记录。
HelpPanel.histotyStep.setText(record+"");
HelpPanel.panelCenter.setSuccessPic(level);
HelpPanel.nowStep.setText(step+"");
HelpPanel.nowLevel.setText("困难");
this.addKeyListener(this);
this.addMouseListener(this);
repaint();
}
;break;
case HARD:
this.removeKeyListener(this);
this.removeMouseListener(this);
record = mapUtil.getRecord(level);//历史记录
if(step<record){
msg = "恭喜你通过困难关卡并刷新历史记录,完成步数是"+step+"\n历史记录是"+record;
JOptionPane.showMessageDialog(this, msg);
mapUtil.writeRecord(level, step);//更新历史记录
}else{
msg = "恭喜通过困难关卡,完成步数是"+step;
JOptionPane.showMessageDialog(this, msg);
}
;break;
}

}

}

@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub

}

@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub

}

@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub

}

@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub

}

}

GamePanel类主要涉及游戏面板的小图片的读取和显示,以及全部游戏的逻辑。

SuccessPanel类:


package 人物拼图;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class SuccessPanel extends JPanel{

int level;
Image[] pics;
int[][] map;
int W ;
MapUtil mapUtil;
private int leftX=10;
private int leftY=150;

public static final int EASY=1,NORMAL=2,HARD=3,BLANK_STATE=-1;

public SuccessPanel(int level){
setSuccessPic(level);
}

public void setSuccessPic(int level) {

mapUtil = new MapUtil();
this.level = level;

BufferedImage bufferedImage = null;
int width = 0,height = 0;
try {
 bufferedImage = ImageIO.read(new File("D:/Game/JigsawGame/pic"+level+".png"));
 width = bufferedImage.getWidth();
 height = bufferedImage.getHeight();
} catch (IOException e) {
 e.printStackTrace();
}

if(level == EASY){
pics = new Image[9];
map = mapUtil.getMap(level);
W = 40;

int w = width/3;
int h = height/3;

for(int i=0;i<8;i++){
int x = i%3*w;
int y = i/3*h;
pics[i] = bufferedImage.getSubimage(x, y, w, h);
}
}else if(level == NORMAL){
pics = new Image[16];
map = mapUtil.getMap(level);
W = 30;

int w = width/4;
int h = height/4;

for(int i=0;i<15;i++){
int x = i%4*w;
int y = i/4*h;
pics[i] = bufferedImage.getSubimage(x, y, w, h);
}
}else{
pics = new Image[25];
map = mapUtil.getMap(level);
W = 24;

int w = width/5;
int h = height/5;

for(int i=0;i<24;i++){
int x = i%5*w;
int y = i/5*h;
pics[i] = bufferedImage.getSubimage(x, y, w, h);
}
}

repaint();
}

public void paint(Graphics g){

for(int i=0;i<map.length;i++)
for(int j=0;j<map.length;j++){

if(map[i][j]!=BLANK_STATE){
//画图
g.drawImage(pics[map[i][j]-1],leftX+j*W,leftY+i*W,W,W,this);
}

}
}

}

SuccessPanel类负责游戏运行界面右下角完整拼图顺序的小图片显示;

HelpPanel类:


package 人物拼图;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class HelpPanel extends JPanel {

private int level = 1;
public static final int EASY = 1,NORMAL = 2,HARD = 3,BLANK_STATE = -1;
static JLabel nowStep = new JLabel("0");
static JLabel histotyStep = new JLabel("9999");
static JLabel nowLevel = new JLabel();
JLabel levelLabel = new JLabel("当前难度:");
JLabel nowStepLabel = new JLabel("当前步数:");
JLabel historyStepLabel = new JLabel("历史记录:");
JButton button1 = new JButton("退出");
BorderLayout panel1 = new BorderLayout();//右侧
JPanel panelNorth = new JPanel(new GridLayout(4,2,10,30));
static SuccessPanel panelCenter = new SuccessPanel(1);

public HelpPanel(int level){
setLevel(level);
this.setVisible(true);
this.setLayout(new BorderLayout());//当前面板

panelNorth.add(levelLabel);
panelNorth.add(nowLevel);
panelNorth.add(nowStepLabel);
panelNorth.add(nowStep);
panelNorth.add(historyStepLabel);
panelNorth.add(histotyStep);//历史记录
panelNorth.add(button1);

this.add(panelNorth,BorderLayout.NORTH);
this.add(panelCenter,BorderLayout.CENTER);

button1.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
System.exit(1);
}
});;
}

public void setLevel(int level){
this.level = level;
panelCenter.setSuccessPic(level);
if(level == EASY){
nowLevel.setText("简单");
}else if(level == NORMAL){
nowLevel.setText("正常");
}else{
nowLevel.setText("困难");
}

}

}

HelpPanel类负责游戏运行界面右边辅助面板的显示,其中装载了SuccessPanel;

GameClient类:


package 人物拼图;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class GameClient extends JFrame{

GamePanel panel2;

public GameClient(){

HelpPanel panel = new HelpPanel(1);
panel2 = new GamePanel(1);//难度简单
panel2.setLayout(new BorderLayout());

this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(panel,BorderLayout.EAST);
this.getContentPane().add(panel2,BorderLayout.CENTER);
this.setSize(850,750);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("人物拼图游戏");
this.setVisible(true);

}

public static void main(String[] args) {
new GameClient();
}

}

GameClient类是游戏窗口类,装载了游戏面板和辅助面板,用来开始游戏。

源码已经粘贴完毕,最后再展示两张游戏运行截图:

Java游戏开发拼图游戏经典版

Java游戏开发拼图游戏经典版

来源:https://blog.csdn.net/A1344714150/article/details/84888599

标签:Java,游戏开发,拼图游戏
0
投稿

猜你喜欢

  • 详解Spring Boot微服务如何集成fescar解决分布式事务问题

    2022-01-21 18:43:51
  • Java使用Random类生成随机数示例

    2022-08-19 04:22:19
  • mybatis中使用InsertProvider注解报错解决全过程

    2021-06-25 18:36:42
  • C#实现动态创建接口并调用的实例

    2021-11-12 16:38:17
  • C++ 中二分查找递归非递归实现并分析

    2023-06-19 06:51:31
  • spring如何动态指定具体实现类

    2022-04-13 07:52:21
  • android中处理各种触摸事件的方法浅谈

    2021-06-25 00:51:57
  • 基于java构造方法Vector查找元素源码分析

    2023-11-29 04:33:30
  • Maven 多profile及指定编译问题的解决

    2022-04-22 23:43:24
  • android使用SwipeRefreshLayout实现ListView下拉刷新上拉加载

    2022-07-15 08:39:50
  • C++中智能指针如何设计和使用

    2023-03-02 01:43:53
  • Android通过Handler与AsyncTask两种方式动态更新ListView(附源码)

    2022-04-14 03:32:22
  • c# 中文转拼音without CJK

    2023-06-08 23:59:31
  • java如何删除以逗号隔开的字符串中某一个值

    2023-06-12 11:59:19
  • 一文详解Jetpack Android新一代导航管理Navigation

    2022-12-08 20:40:14
  • java中Scanner输入用法实例

    2023-09-03 18:25:36
  • c# 基于GMap.NET实现电子围栏功能(WPF版)

    2023-01-28 05:13:01
  • 深入理解java中的重载和覆盖

    2023-01-05 00:24:22
  • 详解SpringBoot 快速整合MyBatis(去XML化)

    2022-08-19 16:42:54
  • Java字符流和字节流对文件操作的区别

    2022-06-08 10:32:01
  • asp之家 软件编程 m.aspxhome.com