JGridWorld是使用Java制作的一款以二维方格类游戏为主的游戏平台
下载JGridWorld-core-v0.1.0.jar,将它加入到工程的类库中。如果你使用的开发环境是Eclipse,请在构建路径中配置。
新建一个类,假设为MyGridGame,使它继承自GridGame:
public class MyGridGame extends GridGame{
@Override
public boolean action(Step step) {
...
}
}
其中,action方法是继承至GridGame的方法,表示每个步骤方格状态的改变。Step表示步骤类,它有以下几个属性:
UP("U")
,DOWN("D")
,LEFT("L")
,RIGHT("R")
,UPLEFT("UL")
,UPRIGHT("UR")
,DOWNLEFT("DL")
,DOWNRIGHT("DR")
;LEFT_CLICK("L")
,RIGHT_CLICK("R")
,DOUBLE_CLICK("D")
;新建一个类专门用于初始化MyGridGame,假设为MyGridGameCreator,使它实现GridGameCreator接口:
public class MyGridGameCreator implements GridGameCreator{
@Override
public MyGridGame factory(String filePath) {
int[][] map = FileUtil.getMap(filePath);
MyGridGame game = new MyGridGame();
int[][] status = new int[map.length][map[0].length];
... //将map转化为status
game.status = status;
... //其他操作
}
}
其中,factory方法是工厂方法,表示读取filePath路径的文本文件到二维数组中,将此二维数组再转化为GridGame的实际状态,从而初始化一个GridGame,下面是文本文件的例子:
1,1,1,1,1,1,1
1,1,0,0,0,1,1
1,0,1,4,2,0,1
1,0,4,3,0,0,1
1,0,2,0,2,0,1
1,1,0,0,0,1,1
1,1,1,1,1,1,1
现在我们来完善 public boolean action(Step step) 方法,这是方格游戏中最核心的部分。我们现在来实现一种叫“点灯”的游戏,游戏规则是在鼠标点击位置及其上下左右5个地方实现翻转(当灯熄灭时点亮,当灯点亮时熄灭)。游戏逻辑如下:
public static final int SLAKE = 0; //熄灭的状态
public static final int LIGHT = 1; //点亮的状态
@Override
public boolean action(Step step) {
if(step == null || step.location == null) {
return false;
}
Location location = step.location; //获得鼠标点击位置
if(isOutOfRange(location)) return false; //位置不在有效范围内
flip(location); //对当前位置实现翻转
for(Direction d : Direction.FOUR) { //对上下左右4个方向
location.move(d); //当前位置往该方向移动一步
flip(location); //对该位置实现翻转
location.move(d.reverse()); //该位置往反方向移动一步,相当于撤销前面所做的移动
}
if(fullOfItem(LIGHT)) { //如果所有方格都是点亮的状态
win = true; //游戏获胜
finished = true; //游戏结束
}
return true;
}
//翻转的实现
private void flip(Location loc) {
if(isOutOfRange(loc)) return ;
if(status[loc.row][loc.col] == SLAKE) status[loc.row][loc.col] = LIGHT;
else status[loc.row][loc.col] = SLAKE;
}
Location、Direction是最基础的类,GridGame类包含了结合这两个类进行演绎的基本方法。另外,Composite类是多方格合成类,CGridGame扩展了GridGame,并包含演绎Composite的方法;DGridGame继承自GridGame,是双人方格游戏的基础类。
对于方格游戏的展示方面,是否需要手工写大量的代码来完善它呢?答案是否定的,我们采用配置的方式来实现,而且是使用JSON格式的文件进行配置。下面我们来说明一下这些配置项的含义:
{
"offsetX" : 32, //方格面板在X轴上的偏移量
"offsetY" : 32, //方格面板在Y轴上的偏移量
"gridWidth" : 32, //方格的宽度
"gridHeight" : 32, //方格的高度
"drawGrid" : true, //是否画出方格的线条
"drawGridOnCenter" : false, //是否在中心位置画方格的线条
"bgColor" : "gray", //方格面板的背景色,所有涉及到color的配置或者是颜色名,如"white",或者是十六进制值,如"0xFFFFFF"
"drawComposites" : false, //是否画出合成方格
"selectedColor" : "red", //被选定方格的颜色
"itemConfigArray" : //对不同物品的方格配置
[
{
"item" : "0", //代表物品的int值,可以用类似"0..9"来表示从0到9的范围
"width" : 32, //绘制该物品时的宽度
"height" : 32, //绘制该物品时的高度
"draw" : true, //是否绘制该物品
"useImage" : false, //是否使用图片
"imagePath" : "", //图片的位置,如果前面的"item"是一个范围,且"imagePath"包含{item},则将{item}替换为实际值
"bgColor" : "", //绘制该物品时的背景色
"shape" : "RECT", //该物品的形状,三种基本形状分别是 RECT:矩形、OVAL:椭圆形、NUM:数字
"color" : "white" //该物品的前景色
},
{
"item" : "1",
"width" : 32,
"height" : 32,
"draw" : true,
"useImage" : false,
"imagePath" : "",
"bgColor" : "",
"shape" : "RECT",
"color" : "yellow"
}
]
}
但是我们要注意的是,在渲染方格面板时,不一定是使用status二维数组
,而是使用这样的规则:当renderMap二维数组不为空时,根据renderMap的值来渲染,否则根据status的值进行渲染。这么做有一个好处,就是可以根据需要将status转化为renderMap来渲染,通过添加方法convertRenderMap来实现,这样就不会将方格面板的渲染配置和status绑定了。
新建一个类,假设为LightingFrame,使它继承自JFrame,添加GridPanel属性:
public class LightingFrame extends JFrame {
Lighting game = new LightingCreator().factory("data/map/Lighting/1");
PaintConfig pc = PaintConfig.readConfig("config/Lighting.json");
GridPanel panel;
public LightingFrame() {
...
panel = new GridPanel();
panel.game = game;
panel.pc = pc;
getContentPane().add(panel);
...
//如果游戏是以鼠标点击进行,则添加鼠标点击事件
panel.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
if(game.finished) {
return ;
}
Step step = GuiUtil.getStep(panel, e, null); //根据事件取得Step对象
game.action(step);
panel.repaint();
if(game.win) {
GuiUtil.showMessageDialog("Game.win");
}
}
...
}
//如果游戏是以按键进行,则添加按键事件
this.addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent e) {
if(game.finished) {
return;
}
Step step = GuiUtil.getStep(panel, null, e); //根据事件取得Step对象
game.action(step);
panel.repaint();
if(game.win) {
GuiUtil.showMessageDialog("Game.win");
}
}
...
});
}
}
系统定义了Resolver接口,专门用于计算机解题:
public interface Resolver {
Step[] resolve(GridGame game);
}
同时,系统实现了A*
算法和IDA*
算法,参见org.jgridworld.core.AI.AStar包