Java游戏开发——RGP走迷宫

游戏介绍

RGP走迷宫游戏就是玩家通过方向键控制主角RGP人物从迷宫左上角走到右下角绿色出口处。游戏可以提高玩家观察力,训练思维力,开发想象力。

本篇博文一共开发了两种难度的走迷宫游戏,简单难度是全图点亮状态的;而正常难度只显示主角身边一个圆的区域(其余区域黑暗,如果实在走不出可以参考辅助地图)运行效果如下:

使用素材文件夹

素材及完整工程源码链接:https://pan.baidu.com/s/1WUyvBR-JwzYSBluNFZFDmQ 提取码: 2i5g 

游戏设计思路

设计一个地图工具类,专门用于迷宫生成,迷宫信息使用二维数组存储;人物的移动是在按键事件中处理的,如果人物的移动不会碰到墙壁则可以移动;使用manX、manY表示人物位于数组的哪个位置,使用manIndex控制人物帧数;当人物移动到出口时,游戏过关。迷宫生成原理可以参考博主之前写的博文:https://blog.csdn.net/A1344714150/article/details/86587307

游戏具体实现

ⅠRGP人物移动实现

通过按键事件进行处理,如果玩家按的键位是上,判断主角上方一格是不是墙;如果不是,则可以移动,接着判断上方一格是不是出口;判断上一次移动的方向是上吗?如果是向上,帧数变量+1,帧数如果已经是最后一张,帧数变量归零;如果上一次移动的方向不是向上,改变移动方向direction为UP,并且帧数变量归0;先将之前人物所在数组元素置空值,人物所在行数-1,再将人物当前所在数组元素值置为MAN

    public static final int BLANK=-1,MAN=0,WALL=1,EXIT=2,UP=1,DOWN=2,LEFT=3,RIGHT=4;
		

    public void keyPressed(KeyEvent e) {
		switch(e.getKeyCode()){
		case KeyEvent.VK_UP:
			if(map[manX-1][manY]!=WALL){
				if(map[manX-1][manY]==EXIT){
					JOptionPane.showMessageDialog(this, "恭喜过关");
					return ;
				}		
				
				if(direction==UP){
					manIndex=manIndex+1==4?0:++manIndex;
				}else{
					manIndex=0;
					direction=UP;
				}				
		
				map[manX][manY] = BLANK;
				manX -= 1;
				map[manX][manY] = MAN;
			}
			;break;
		case KeyEvent.VK_DOWN:
			if(map[manX+1][manY]!=WALL){
				if(map[manX+1][manY]==EXIT){
					JOptionPane.showMessageDialog(this, "恭喜过关");
					return ;
				}		
				
				if(direction==DOWN){
					manIndex=manIndex+1==4?0:++manIndex;
				}else{
					manIndex=0;
					direction=DOWN;
				}
				
				map[manX][manY] = BLANK;
				manX += 1;
				map[manX][manY] = MAN;	
			}
			;break;
		case KeyEvent.VK_LEFT:
			if(map[manX][manY-1]!=WALL){
				if(map[manX][manY-1]==EXIT){
					JOptionPane.showMessageDialog(this, "恭喜过关");
					return ;
				}		
				
				if(direction==LEFT){
					manIndex=manIndex+1==4?0:++manIndex;
				}else{
					manIndex=0;
					direction=LEFT;
				}
				map[manX][manY] = BLANK;
				manY -= 1;
				map[manX][manY] = MAN;	
			}
			;break;
		case KeyEvent.VK_RIGHT:
			if(map[manX][manY+1]!=WALL){
				if(map[manX][manY+1]==EXIT){
					JOptionPane.showMessageDialog(this, "恭喜过关");
					return ;
				}		
				if(direction==RIGHT){
					manIndex=manIndex+1==4?0:++manIndex;
				}else{
					manIndex=0;
					direction=RIGHT;
				}
				map[manX][manY] = BLANK;
				manY += 1;
				map[manX][manY] = MAN;	
			}
			;break;
		}
		repaint();
	}

Ⅱ 图片的获取及显示

在这里,每张图片边长20像素,leftX和leftY表示迷宫水平和垂直方向的偏移量,墙对应素材pic0.png,地砖对应素材pic1.png,出口对应素材pic2.png,人物素材pic3~18.png,其中3~6人物向上,7~10人物向下,11~14人物向左,15~18人物向右;根据帧数变量manIndex和移动方向direction去显示主角图像;


	private void getPics() {
		for(int i=0;i<20;i++){
			pics[i] = Toolkit.getDefaultToolkit().getImage("D:/Game/MazeGameEasy/pic"+i+".png");
		}
	}

	public void paint(Graphics g){
		
		g.clearRect(0, 0, getWidth(), getHeight());
 		for(int i=0;i<2*row+1;i++){
			for(int j=0;j<2*col+1;j++){
				if(map[i][j]==WALL){
					g.drawImage(pics[0],leftX+20*j, leftY+20*i, 20, 20, this);
				}else if(map[i][j]==MAN){
					
					switch(direction){
					case UP:
						g.drawImage(pics[1],leftX+20*j, leftY+20*i, 20, 20,this);
						g.drawImage(pics[3+manIndex], leftX+20*j, leftY+20*i, 20, 20, this);
						break;
					case DOWN:
						g.drawImage(pics[1],leftX+20*j, leftY+20*i, 20, 20,this);
						g.drawImage(pics[7+manIndex], leftX+20*j, leftY+20*i, 20, 20, this);
						break;
					case LEFT:
						g.drawImage(pics[1],leftX+20*j, leftY+20*i, 20, 20,this);
						g.drawImage(pics[11+manIndex], leftX+20*j, leftY+20*i, 20, 20, this);
						break;
					case RIGHT:
						g.drawImage(pics[1],leftX+20*j, leftY+20*i, 20, 20,this);
						g.drawImage(pics[15+manIndex], leftX+20*j, leftY+20*i, 20, 20, this);
						break;
					}
					
				}else if(map[i][j]==BLANK){
					g.drawImage(pics[1],leftX+20*j, leftY+20*i, 20, 20,this);
				}else{
					g.drawImage(pics[2],leftX+20*j, leftY+20*i, 20, 20,this);
				}
			}
		}	
	}

Ⅲ 圆形区域的显示

在正常难度的迷宫里,假设了玩家是位于黑暗山洞手持灯笼的情况,只显示了玩家附近一个小圆的区域,其余黑暗;

首先先画出以主角为中心的九宫格图像(这是一个大矩形),然后从矩形的左上角开始,挨个像素遍历到矩形右下角,如果遍历到的像素位于圆外,对该像素点进行擦除;需要说明的是,矩形的左上角像素坐标是(20*(manY-1),20*(manX-1)),矩形的右下角像素坐标是(20*(manY+2),20*(manX+2)),因为图案边长是20,而manX和manY表示的是人物所在的行数和列数。

		for(int i=manX-1;i<=manX+1;i++){//画主角周围九宫格图案
			for(int j=manY-1;j<=manY+1;j++){
				if(map[i][j]==WALL){
					g.drawImage(pics[0],leftX+20*j, leftY+20*i, 20, 20, this);
				}else if(map[i][j]==MAN){
					
					switch(direction){
					case UP:
						g.drawImage(pics[1],leftX+20*j, leftY+20*i, 20, 20,this);
						g.drawImage(pics[3+manIndex], leftX+20*j, leftY+20*i, 20, 20, this);
						break;
					case DOWN:
						g.drawImage(pics[1],leftX+20*j, leftY+20*i, 20, 20,this);
						g.drawImage(pics[7+manIndex], leftX+20*j, leftY+20*i, 20, 20, this);
						break;
					case LEFT:
						g.drawImage(pics[1],leftX+20*j, leftY+20*i, 20, 20,this);
						g.drawImage(pics[11+manIndex], leftX+20*j, leftY+20*i, 20, 20, this);
						break;
					case RIGHT:
						g.drawImage(pics[1],leftX+20*j, leftY+20*i, 20, 20,this);
						g.drawImage(pics[15+manIndex], leftX+20*j, leftY+20*i, 20, 20, this);
						break;
					}
					
				}else if(map[i][j]==BLANK){
					g.drawImage(pics[1],leftX+20*j, leftY+20*i, 20, 20,this);
				}else{//出口
					g.drawImage(pics[2],leftX+20*j, leftY+20*i, 20, 20,this);
				}
			}
		}
	   
     g.drawOval(leftX+20*(manY-1), leftX+20*(manX-1), 60, 60);//画圆
		
        for(int i=20*(manY-1);i<=20*(manY+2);i++){
			for(int j=20*(manX-1);j<=20*(manX+2);j++){
				if((i-(20*manY+10))*(i-(20*manY+10))+(j-(20*manX+10))*(j-(20*manX+10))>30*30){
					g.fillRect(i, j, 1, 1);
				}
			}
		}

Ⅳ 辅助地图的显示

基于博主小时候玩的FC游戏(《荆轲新传》)主角走山洞带来的阴影,我觉得非常有必要加入辅助地图的功能;

在游戏面板类GamePanel加入一个getCloneMap()方法,用来返回去除人物后的地图数组,将数组作为辅助地图类HelpPanel的构造参数,HelpPanel用来显示一个全亮的地图。绘制过程和游戏面板一致,默认辅助地图关闭,取消注释显示全亮地图。

public int[][] getCloneMap(){
		
		int[][] temp = new int[map.length][map[0].length];
		for(int i=0;i<temp.length;i++){
			for(int j=0;j<temp[0].length;j++){
				temp[i][j] = map[i][j];
			}
		}
		
		temp[manX][manY] = BLANK;
		
		return temp;
	}

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.*;

public class HelpPanel extends JPanel{

	int[][] map;
	int leftX,leftY;
	Image[] pics = new Image[20];
	
	public static final int BLANK=-1,MAN=0,WALL=1,EXIT=2,UP=1,DOWN=2,LEFT=3,RIGHT=4;

	public HelpPanel(int[][] cloneMap) {
		map = cloneMap;
		getPics();
		setPreferredSize(new Dimension((map[0].length)*20,(map.length)*20));//map[0].length是列数,map.length是行数
	}

	private void getPics() {
		for(int i=0;i<20;i++){
			pics[i] = Toolkit.getDefaultToolkit().getImage("D:/Game/MazeGameEasy/pic"+i+".png");
		}
	}
	
	public void paint(Graphics g){
		
		g.clearRect(0, 0, getWidth(), getHeight());
		
		for(int i=0;i<map.length;i++){
			for(int j=0;j<map[0].length;j++){
				if(map[i][j]==WALL){
					g.drawImage(pics[0],leftX+20*j, leftY+20*i, 20, 20, this);
				}else if(map[i][j]==BLANK){
					g.drawImage(pics[1],leftX+20*j, leftY+20*i, 20, 20,this);
				}else{
					g.drawImage(pics[2],leftX+20*j, leftY+20*i, 20, 20,this);
				}
			}
		}	

	}

}

后续说明

Ⅰ如何展示辅助地图

Ⅱ 迷宫怎样才算困难难度?

基于当前正常迷宫难度的工程,可以做以下措施提升游戏的难度

①增加迷宫的层数并增加迷宫上下楼的功能;

②让主角初始随机生成在迷宫的某个角落,并将主角始终显示在屏幕中心,不显示主角相对整体迷宫所在位置;

③改变出口及上下楼梯的位置,让其初始情况随机化

 


版权声明:本文为A1344714150原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。