1. 前言
最近, 实在是闲的淡疼, 所以 没事的时候, 想起了以前的这个游戏[fc, 智慧桥 or 艾摩君], 以前小的时候玩的时候感觉非常难啊, 然后 后来大概是高中高考之后自己郁闷的时候, 又回来完了完吧, 当时候是玩到了44关, 但是没有 玩完啊, 深表遗憾
说实话 这个游戏是挺好玩的, 就像一道一道的难题, 在解决难题之前, 总是要进行很多次的想到的尝试方案的执行, 然而 当你解决问题之后, 你会感觉到一股喜悦, 这样的喜悦会让你感觉生活充满了意义, 但是 同时也有一种哀伤, 毕竟陪伴自己的这段时间的这个难题, 对于自己来说不再是难题了, 以后基本上都不会再来思考这个难题了
就好比 同学聚会的时候, 聚会之前是充满喜悦的, 然后聚会之后, 当你一个人沉思的时候, 你总会有一种莫名其妙的伤感..
又或者是一部好看的电视剧 或者电影
好了, 最近 闲的淡疼时候, 就(ˇˍˇ) 想~做做游戏, 这次就拿这个开刀吧, 还是花费了一些时间的的, 不过也有一些收获的
第一 : 是在控制左右方向方面 [这一次的控制不是按一下键, 调用一下方法, 而是在按下键盘的时候设置标志位, 释放键盘灯的时候, 设置回标志位, 在标志位为true这段时间, 使用一个线程, 隔一段时间定时判断一下, 如果为true, 则调用一下方法]
第二 : 双缓冲问题, 先将需要绘制的数据绘制到一个Image缓存中, 然后 在绘制到屏幕上
第三 : 状态模式的时候, 之前曾经看过一次状态模式的场景, 这还是第一次真正的使用呢
这个, 并没有完成, 只是完成了简单的东西, 也就是完成了第一关需要的东西, 因为最近 不想花多的时间来完成剩余的东西了, 因为最近 还需要去看看其他的东西。
难点 : 各个元素绘制, 以及方向键和跳跃键的兼容, 以及判断是否能够移动元素的判断
这个涉及到多线程的是挺多的, 但是并没有太多涉及线程同步的地方
规则 : 捡到所有的boy, 并且进入门就过关 [某些元素可以攻击, 某些元素是否可以穿过]
元素介绍 :
elmo : 我们的主角, 用户控制的角色
boy : 哭闹的孩子, elmo需要收集到所有的boy, 才能够进入门, 进入下一个关卡
brick : 砖块, elmo可以站在上面, elmo可以攻击, elmo不能穿过, 不能独立存在于空中
floor : 地板砖, elmo可以站在上面, elmo不可以攻击, elmo不能穿过, 能独立存在于空中
rack : 岩石, elmo可以站在上面, elmo不可以攻击, elmo不能穿过, 能独立存在于空中
iron : 刚块, elmo可以站在上面, elmo不可以攻击, elmo不能穿过, 能独立存在
door : elmo收集完元素之后的目的地, 到达之后就可以进入下一个关卡
元素继承关系
2. 基本的数据结构介绍
2.1 Element : 所有元素的基类
/**
* file name : Element.java
* created at : 7:35:42 PM Oct 26, 2015
* created by 970655147
*/
package com.hx.elmo;
// 元素
public class Element {
// 坐标, 图片
protected int x;
protected int y;
protected Image img;
// 初始化
public Element() {
}
public Element(int x, int y) {
setXY(x, y);
}
// 绘制当前元素
public void paint(Graphics g) {
g.drawImage(img, x, y, Constants.GRID_WIDTH, Constants.GRID_HEIGHT, null);
}
// 驱动元素变化
public void move() {
}
// setter & getter
// ...
// for debug ...
public String toString() {
return this.getClass().getName();
}
}
2.2 Elmo : 主角, 控制角色的各种操作
/**
* file name : Elmo.java
* created at : 7:32:53 PM Oct 26, 2015
* created by 970655147
*/
package com.hx.elmo;
// 艾摩君
public class Elmo extends Element {
// 水平方向上移动一次的偏移, 竖直方向上移动一次的偏移
private int moveHorizonOff = Constants.ELMO_MOVE_HORIZON_OFF;
private int moveVerticalOff = Constants.ELMO_MOVE_VERTICAL_OFF;
// panel
// 移动的方向, 主面板, elmo的当前图像 [向左 或右]
// 地图model, 是否向左, 是否向右, 是否向下, 是否在跳
// 是否工具, 是否成功
private int direction;
private MainPanel panel;
private Image[] imgs = Constants.elmoRight;
private Map map;
private long lastRunnable;
private boolean isLeft;
private boolean isRight;
private boolean isDown;
private boolean isJump;
private boolean isAtt;
private boolean isSuccess;
// 初始化
public Elmo() {
}
public Elmo(int x, int y, Map map) {
super(x, y);
this.map = map;
direction = Constants.RIGHT;
this.img = imgs[Constants.STAND];
isDown = false;
isJump = false;
isLeft = false;
isRight = false;
isAtt = false;
isSuccess = false;
}
// 移动相关
// 如果能够向左移动, 则向左移动, 并做移动之后需要做事情
public void left() {
if(canLeft(map)) {
setDirection(Constants.LEFT);
setX(this.x - moveHorizonOff);
moveHorizonOff = Constants.ELMO_MOVE_HORIZON_OFF;
doStuffAfterMove(map);
}
}
// 如果能够右移动, 则向右移动, 并做移动之后需要做事情
public void right() {
if(canRight(map)) {
setDirection(Constants.RIGHT);
setX(this.x + moveHorizonOff);
moveHorizonOff = Constants.ELMO_MOVE_HORIZON_OFF;
doStuffAfterMove(map);
}
}
// 下操作
public void down() {
if(canDown(map)) {
isDown = true;
setImage(imgs[Constants.DOWN]);
}
}
// 下的逆操作
public void undown() {
isDown = false;
setImage(imgs[Constants.STAND]);
}
// 跳跃
public void jump() {
if(canJump(map)) {
isJump = true;
panel.putTask(new JumpRunnable(this, map));
doStuffAfterMove(map);
}
}
// 落下
private void gravity(int upOff) {
setY(this.y + upOff);
}
// 攻击旁边的元素
public void attack() {
if(canAttack(map)) {
isAtt = true;
doAttack(map);
panel.putTask(new AttackRunnable(this, map));
}
}
// setter & getter
public void setImage(Image img) {
this.img = img;
}
public void setPanel(MainPanel panel) {
this.panel = panel;
}
public void setX(int otherX) {
this.x = Tools.formatX(otherX);
}
public void setY(int otherY) {
this.y = Tools.formatY(otherY);
}
public void setAtt(boolean isAtt) {
this.isAtt = isAtt;
}
public void setDirection(int direction) {
if(this.direction != direction) {
this.direction = direction;
if(this.direction == Constants.LEFT) {
this.imgs = Constants.elmoLeft;
} else {
this.imgs = Constants.elmoRight;
}
}
}
public void setLeft(boolean isLeft) {
this.isLeft = isLeft;
}
public void setRight(boolean isRight) {
this.isRight = isRight;
}
public boolean isJump() {
return isJump;
}
public void setJump(boolean isJump) {
this.isJump = isJump;
}
public boolean isLeft() {
return isLeft;
}
public boolean isRight() {
return isRight;
}
public boolean isSuccess() {
return isSuccess;
}
// 获取上一次按键到当前按键 的时间差
public boolean isLastRunnableOk() {
return true;
}
// 判断是否能够向左右走 [受限于环境]
// 获取左边的一个元素, 然后判断其是否crossable
// 如果 当前x为其左边的元素的x相同, 设置当前移动的位移为0, 返回true
// 如果 当前再向左移动一步之后x会小于左边元素的x, 更新此次移动的位移为到达左边的元素的位置
private boolean canLeft(Map map) {
if(isDown) {
return false;
}
int row = Tools.getRowByY(this.y);
int col = Tools.getColByX(this.x);
Element leftEle = getLeftELe(map, row, col);
if(ifBeTurePreJudge(leftEle)) {
return true;
} else {
if(this.x == Tools.getXByCol(col)) {
moveHorizonOff = 0;
return true;
} else if(this.x - moveHorizonOff < Tools.getXByCol(col)) {
moveHorizonOff = this.x - Tools.getXByCol(col);
return true;
} else {
return true;
}
}
}
// 类似于canLeft [受限于环境]
private boolean canRight(Map map) {
if(isDown) {
return false;
}
int row = Tools.getRowByY(this.y);
int col = Tools.getColByX(this.x);
Element rightEle = getRightELe(map, row, col);
if(ifBeTurePreJudge(rightEle) ) {
return true;
} else {
if(this.x + Constants.GRID_WIDTH == Tools.getXByCol(col+1) ) {
moveHorizonOff = 0;
return true;
} else if(this.x + Constants.GRID_WIDTH + moveHorizonOff < Tools.getXByCol(col+1)) {
moveHorizonOff = Tools.getXByCol(col+1) - this.x - Constants.GRID_WIDTH;
return true;
// can't be there ...
} else {
return true;
}
}
}
// 是否可以向下操作 [受限于环境]
private boolean canDown(Map map) {
if(isJump) {
return false;
}
return true;
}
// 是否可以跳跃操作 [受限于环境]
private boolean canJump(Map map) {
if(isJump) {
return false;
}
return true;
}
// 是否可以攻击操作 [受限于环境]
private boolean canAttack(Map map) {
if(isAtt) {
return false;
}
return true;
}
// 是否可以向下掉落 [受限于环境]
// 与上面的canRight的区别在于移动到支持元素上面, 就不能在向下面移动了
private boolean canGravity(Map map) {
int row = Tools.getRowByY(this.y);
int col = Tools.getColByX(this.x);
Element downLeftEle = map.getEle(Tools.formatRow(row+1), col );
Element downRightEle = null;
if(x != Tools.getXByCol(col) ) {
downRightEle = map.getEle(Tools.formatRow(row+1), Tools.formatCol(col+1) );
}
if((downLeftEle == null) && (downRightEle == null) ) {
moveVerticalOff = Constants.ELMO_MOVE_VERTICAL_OFF;
return true;
} else {
if(!(downLeftEle instanceof Prop) && (! (downRightEle instanceof Prop)) ) {
moveVerticalOff = Constants.ELMO_MOVE_VERTICAL_OFF;
return true;
} else {
if( ((downLeftEle == null) || (! ((Prop) downLeftEle).isStandable())) && ((downRightEle == null) || (! ((Prop) downRightEle).isStandable())) ) {
moveVerticalOff = Constants.ELMO_MOVE_VERTICAL_OFF;
return true;
} else {
if(this.y + Constants.GRID_HEIGHT == Tools.getYByRow(row+1) ) {
return false;
} else if(this.y + Constants.GRID_HEIGHT + moveVerticalOff < Tools.getYByRow(row+1)) {
moveVerticalOff = Tools.getYByRow(row+1) - this.y - Constants.GRID_HEIGHT;
return true;
// can't be there ...
} else {
return true;
}
}
}
}
}
// 获取当前元素"左边"的元素, 判断规则详见下面的注释
private Element getLeftELe(Map map, int row, int col) {
Element leftEle = null;
// 如果是和物品在同一水平线上,则判断左方向的物品
// 否则 判断脚的左方向上的物品
if(this.y == Tools.getYByRow(row) ) {
leftEle = map.getEle(row, Tools.formatCol(col-1) );
} else {
leftEle = map.getEle(Tools.formatRow(row+1), Tools.formatCol(col-1) );
}
return leftEle;
}
// 获取当前位置的右边的元素
private Element getRightELe(Map map, int row, int col) {
Element rightEle = null;
// 如果是和物品在同一水平线上,则判断右方向的物品
// 否则 判断脚的右下方向的物品
if(this.y == Tools.getYByRow(row) ) {
rightEle = map.getEle(row, Tools.formatCol(col+1) );
} else {
rightEle = map.getEle(Tools.formatRow(row+1), Tools.formatCol(col+1) );
}
return rightEle;
}
// canRight, canLeft 的公共判断部分
private boolean ifBeTurePreJudge(Element ele) {
if(ele == null) {
return true;
} else {
if(! (ele instanceof Prop) ) {
return true;
} else {
if(((Prop) ele).isCrossable() ) {
return true;
} else {
return false;
}
}
}
}
// 一些左右移动之后需要做的事情
// 1. 校验是否可落下, 可落下, 则落下
// 2. 校验是否可获取到boy
// 3. 校验是否到达门处, 是否完成任务
private void doStuffAfterMove(Map map) {
// ------------------ 1 ------------------
if(!isJump) {
if(canGravity(map)) {
panel.putTask(new GravityRunnable(this, map));
}
}
// ------------------ 2 ------------------
int row = Tools.getRowByY(this.y);
int col = Tools.getColByX(this.x);
Element ele = null;
ele = map.getEle(row, col);
if(ele instanceof Boy) {
map.propBeAttacked(ele);
}
// ------------------ 3 ------------------
if(ele instanceof Door) {
if(map.boysLeft() == 0) {
isSuccess = true;
}
}
}
// 攻击操作, 根据当前的方向 获取需要攻击的对象, 然后更新map中的model
private void doAttack(Map map) {
int row = Tools.getRowByY(this.y);
int col = Tools.getColByX(this.x);
Element tarEle = null;
if(this.y == Tools.getYByRow(row) ) {
if(imgs == Constants.elmoLeft) {
tarEle = map.getEle(row, Tools.formatCol(col-1) );
} else {
tarEle = map.getEle(row, Tools.formatCol(col+1) );
}
} else {
if(imgs == Constants.elmoLeft) {
tarEle = map.getEle(Tools.formatRow(row+1), Tools.formatCol(col-1) );
} else {
tarEle = map.getEle(Tools.formatRow(row+1), Tools.formatCol(col+1) );
}
}
if((tarEle != null) && (tarEle instanceof Prop) ) {
if(((Prop) tarEle).isAttackable() ) {
map.propBeAttacked(tarEle);
}
}
}
// 重写move方法 控制移动 [否则 移动不流畅]
public void move() {
if(isLeft) {
left();
}
if(isRight) {
right();
}
}
// 重写paint方法 更新控制艾摩君的大小
public void paint(Graphics g) {
g.drawImage(img, x, y, Constants.ELMO_WIDTH, Constants.ELMO_HEIGHT, null);
}
// elmo移动的时候, 创建一个, 添加到线程池中执行, 切换elmo的脚步 [STAND -> GO -> STAND]
static class MoveRunnable implements Runnable {
private Elmo elmo;
public MoveRunnable(Elmo elmo) {
this.elmo = elmo;
}
public void run() {
elmo.setImage(elmo.imgs[Constants.GO]);
Tools.sleep(Constants.ELMO_MOVE_CHANGE_PIC_INTERVAL);
elmo.setImage(elmo.imgs[Constants.STAND]);
}
}
// elmo跳跃的时候, 创建一个, 添加到线程池中执行, 先分成ELMO_JUMP_UP_TIMES 阶段来向上移动
// 然后 向下掉落
static class JumpRunnable implements Runnable {
private Elmo elmo;
private Map map;
public JumpRunnable(Elmo elmo, Map map) {
this.elmo = elmo;
this.map = map;
}
public void run() {
int upOff = elmo.moveVerticalOff / Constants.ELMO_JUMP_UP_TIMES;
elmo.setImage(elmo.imgs[Constants.GO]);
for(int i=0; i<Constants.ELMO_JUMP_UP_TIMES; i++) {
elmo.setY(elmo.y - upOff);
Tools.sleep(Constants.JUMP_CHANGE_PIC_INTERVAL);
}
new GravityRunnable(elmo, map).run();
}
}
// elmo向下掉落的时候, 创建一个, 添加到线程池中执行
// 如果 当前元素下面的元素不可standable, 则向下掉落
static class GravityRunnable implements Runnable {
private Elmo elmo;
private Map map;
public GravityRunnable(Elmo elmo, Map map) {
this.elmo = elmo;
this.map = map;
}
public void run() {
int upOff = elmo.moveVerticalOff / Constants.ELMO_JUMP_UP_TIMES;
elmo.setImage(elmo.imgs[Constants.GO]);
while(elmo.canGravity(map)) {
elmo.gravity(upOff);
Tools.sleep(Constants.JUMP_CHANGE_PIC_INTERVAL);
}
elmo.setImage(elmo.imgs[Constants.STAND]);
elmo.isJump = false;
elmo.moveVerticalOff = Constants.ELMO_MOVE_VERTICAL_OFF;
}
}
// elmo攻击的时候, 创建一个, 添加到线程池中执行
// 如果 更新显示的图片, 一段时间后更新回来
static class AttackRunnable implements Runnable {
private Elmo elmo;
private Map map;
public AttackRunnable(Elmo elmo, Map map) {
this.elmo = elmo;
this.map = map;
}
public void run() {
elmo.setImage(elmo.imgs[Constants.ATT]);
Tools.sleep(Constants.ELMO_ATTACK_CHANGE_PIC_INTERVAL);
elmo.setImage(elmo.imgs[Constants.STAND]);
}
}
}
2.3 Enemy : 敌人[这里没有实现]
/**
* file name : Enemy.java
* created at : 7:39:06 PM Oct 26, 2015
* created by 970655147
*/
package com.hx.elmo;
// 敌人
public class Enemy extends Element {
// 初始化
public Enemy() {
}
public Enemy(int x, int y) {
super(x, y);
}
}
2.3 Prop : 道具[所有的非elmo 以及非enemy的其他元素] [控制了影响elmo, enemy的性质]
/**
* file name : Prop.java
* created at : 2:17:30 PM Oct 27, 2015
* created by 970655147
*/
package com.hx.elmo;
// 道具
public class Prop extends Element {
// 是否可站立, 是否可攻击, 是否可穿过, 是否可以独立存在于高空
protected boolean standable;
protected boolean attackable;
protected boolean crossable;
protected boolean standaloneable;
// 初始化
public Prop() {
}
public Prop(int x, int y) {
super(x, y);
standable = true;
attackable = false;
crossable = false;
standaloneable = false;
}
// setter & getter
// 省略若干...
}
2.4 Boy : elmo需要收集的boy, 注意更新的move方法 [由MainPanel.threadPool中的一条线程定时调用]
/**
* file name : Boy.java
* created at : 7:35:33 PM Oct 26, 2015
* created by 970655147
*/
package com.hx.elmo;
// 哭闹的小孩..
public class Boy extends Prop {
// 当前图片的索引
Image[] imgs = Constants.boys;
int idx = Tools.nextRandom(imgs.length);
// 初始化
public Boy() {
}
public Boy(int x, int y) {
super(x, y);
this.img = imgs[idx];
crossable = true;
standable = false;
}
// 累增idx, 并制造一个"循环"
private void incIdx() {
idx ++;
if(idx == imgs.length) {
idx = 0;
}
}
// 驱动boy的"移动"
public void move() {
incIdx();
img = imgs[idx];
}
}
2.5 Brick : 砖头 [可被攻击][这里, 我们只介绍一个Brick元素]
/**
* file name : Brice.java
* created at : 2:22:35 PM Oct 27, 2015
* created by 970655147
*/
package com.hx.elmo;
// 砖
public class Brick extends Prop {
// 初始化
public Brick() {
}
public Brick(int x, int y) {
super(x, y);
this.attackable = true;
this.img = Constants.brick;
}
}
2.6 MainPanel : 控制着状态的改变, 以及响应用户的操作
/**
* file name : MainPanel.java
* created at : 2:15:01 PM Oct 26, 2015
* created by 970655147
*/
package com.hx.elmo;
// 主面板
public class MainPanel extends JPanel {
// 全局变量
// 每一个元素宽度, 高度
private static int gridWidth = Constants.GRID_WIDTH;
private static int gridHeight = Constants.GRID_HEIGHT;
// 选择的位置, 是否绘制选中的文字 [用于闪烁选中的文字]
// 当前的状态, 是否游戏结束, 是否开始游戏
private Point selected;
private boolean isDrawSelected;
private State state;
private boolean isOver;
private boolean isStart;
// 业务数据
// 关卡id, 剩余的人数, map model, elmo
private int stageId = 1;
private int rest = 3;
private Map map;
private Elmo elmo;
// 其他数据
private ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(Constants.N_THREADS);
// 初始化
public MainPanel() {
state = State.START_UP;
isDrawSelected = true;
isOver = false;
isStart = false;
map = new Map(Tools.generateMap(Constants.STAGE_00) );
initElmo();
}
// 初始化elmo
private void initElmo() {
elmo = map.getElmo();
elmo.setPanel(this);
}
// 重写paint方法, 绘制panel
// 根据不同的状态, 执行不同的业务
public void paint(Graphics g) {
switch(state) {
case IN_GAME :
drawInGame(g);
break ;
case START_UP :
drawInStartUp(g);
break ;
case STAGE_INFO :
drawInStageInfo(g);
break ;
default :
Log.err("error state : " + state.toString() );
break ;
}
}
// 重写update方法 [双缓冲, 先将g中的数据缓冲到一个Image中, 然后在将其绘制到屏幕]
public void update(Graphics g){ //覆盖update方法,截取默认的调用过程
Image buffer = createImage(this.getWidth(), this.getHeight()); //创建图形缓冲区
Graphics bufferGraphics = buffer.getGraphics(); //获取图形缓冲区的图形上下文
paint(bufferGraphics); //用paint方法中编写的绘图过程对图形缓冲区绘图
bufferGraphics.dispose(); //释放图形上下文资源
g.drawImage(buffer, 0, 0, this); //将图形缓冲区绘制到屏幕上
}
// 绘制在开始状态
// 1. 必要的话初始化selected
// 2. 绘制背景
// 3. 绘制文字
// 4. 必要的话清空当前选择的文字 [闪烁控制]
// 5. 绘制选择图标
private void drawInStartUp(Graphics g) {
if(selected == null) {
selected = Constants.START_UP_START_POS;
}
drawStartUpBg(g);
g.setColor(Constants.START_UP_COLOR);
g.setFont(Constants.START_UP_FONT);
Tools.assert0(Constants.START_UPS_WORDS.length, Constants.START_UPS_WORDS_POS.length);
for(int i=0; i<Constants.START_UPS_WORDS.length; i++) {
drawString(g, Constants.START_UPS_WORDS, Constants.START_UPS_WORDS_POS, i);
}
if(!isDrawSelected) {
g.setColor(Constants.START_BG_COLOR);
int selectedWordIdx = 0;
if(selected == Constants.START_UP_START_POS) {
selectedWordIdx = 2;
} else {
selectedWordIdx = 3;
}
drawString(g, Constants.START_UPS_WORDS, Constants.START_UPS_WORDS_POS, selectedWordIdx);
}
g.drawImage(Constants.elmoRight[Constants.STAND], selected.x, selected.y, gridWidth, gridHeight, this);
}
// 绘制正在游戏的 的图像
// 1. 绘制背景图片
// 2. 绘制所有的元素
private void drawInGame(Graphics g) {
drawInGameBg(g);
Iterator<Element> eles = map.elements();
while(eles.hasNext() ) {
Element e = eles.next();
e.paint(g);
}
}
// 绘制关卡信息
// 1. 绘制背景
// 2. 绘制关卡数, 剩余的人数
private void drawInStageInfo(Graphics g) {
drawStageInfoBg(g);
g.setColor(Constants.STAGE_INFO_COLOR);
g.setFont(Constants.STAGE_INFO_FONT);
Tools.assert0(Constants.STAGE_INFO_WORDS.length, Constants.STAGE_INFO_WORDS_POS.length);
drawString(g, Constants.STAGE_INFO_WORDS[0] + " " + getStageIdString(stageId), Constants.STAGE_INFO_WORDS_POS[0]);
drawString(g, Constants.STAGE_INFO_WORDS[1] + " " + getStageIdString(rest), Constants.STAGE_INFO_WORDS_POS[1]);
}
// 绘制开始状态, 关卡信息, 游戏开始 的背景图片
private void drawStartUpBg(Graphics g) {
g.drawImage(Constants.startBg, 0, 0, Constants.FRAME_WIDTH, Constants.FRAME_HEIGHT, this);
}
private void drawInGameBg(Graphics g) {
g.drawImage(Constants.inGameBg, 0, 0, Constants.FRAME_WIDTH, Constants.FRAME_HEIGHT, this);
}
private void drawStageInfoBg(Graphics g) {
g.drawImage(Constants.stageInfoBg, 0, 0, Constants.FRAME_WIDTH, Constants.FRAME_HEIGHT, this);
}
// 键盘业务处理
// 对于开始界面的时候
// 点击选择键, 更新选择图标的位置
// 点击开始键, 绘制选择文字闪烁的情况, 并切换到关卡信息页面
public void dealKeyPressInStart(KeyEvent e) {
if(e.getKeyCode() == Constants.SELECT) {
if(selected == Constants.START_UP_START_POS) {
selected = Constants.START_UP_CONTINUE_POS;
} else {
selected = Constants.START_UP_START_POS;
}
} else if(e.getKeyCode() == Constants.START) {
if(! isStart) {
isStart = true;
selected = null;
threadPool.execute(new Runnable() {
public void run() {
for(int i=0; i<Constants.START_TWINKLE_TIMES; i++) {
isDrawSelected = !isDrawSelected;
repaint();
Tools.sleep(Constants.START_TWINKLE_INTERVAL);
}
startRepaint();
showStageInfo();
startGame();
}
});
}
}
repaint();
}
// 对于开始游戏界面
// 对于各个操作键的响应
// 如果成功了, 则更新stage
public void dealKeyPressInGame(KeyEvent e) {
if(e.getKeyCode() == Constants.GO_LEFT) {
elmo.setLeft(true);
} else if(e.getKeyCode() == Constants.GO_RIGHT) {
elmo.setRight(true);
elmo.right();
} else if(e.getKeyCode() == Constants.GO_DOWN) {
elmo.down();
} else if(e.getKeyCode() == Constants.GO_JUMP) {
elmo.jump();
} else if(e.getKeyCode() == Constants.GO_ATTACK) {
elmo.attack();
}
if(elmo.isSuccess() ) {
setStage(getNextStageMap(stageId) );
}
}
// 更新关卡
// 更新stageId, rest, 更新isOver 停止所有的线程, 等待所有的线程执行完成
// 更新map, 更新isOver
// 启动repaint线程, 绘制关卡信息, 启动游戏 [更新可移动元素, 更新移动elmo, 绘制elmo移动时候的步伐]
public void setStage(Integer[][] map) {
stageId ++;
rest ++;
isOver = true;
Tools.awaitTasksEnd(threadPool, Constants.DEFAULT_CHECK_THREADPOOL_INTERVAL);
this.map = new Map(map );
initElmo();
isOver = false;
threadPool.execute(new Runnable() {
public void run() {
startRepaint();
showStageInfo();
startGame();
}
});
}
// 对于开始界面的时候
// doNothing
public void dealKeyReleaseStartUp(KeyEvent e) {
}
// 对于开始游戏界面
// 响应键盘的操作
public void dealKeyReleaseInGame(KeyEvent e) {
if(e.getKeyCode() == Constants.GO_LEFT) {
elmo.setLeft(false);
} else if(e.getKeyCode() == Constants.GO_RIGHT) {
elmo.setRight(false);
} else if(e.getKeyCode() == Constants.GO_DOWN) {
elmo.undown();
} else if(e.getKeyCode() == Constants.GO_ATTACK) {
elmo.setAtt(false);
}
}
// 启动定时重绘线程
public void startRepaint() {
threadPool.execute(new Runnable() {
public void run() {
while(! isOver) {
Tools.sleep(Constants.REFRESH_INTERVAL);
repaint();
}
}
});
}
// 显示关卡信息 [依赖于定时刷新线程]
private void showStageInfo() {
state(State.STAGE_INFO);
Tools.sleep(Constants.STAGE_INFO_INTERVAL);
}
// 开始游戏 [更新可移动元素, 更新移动elmo, 绘制elmo移动时候的步伐][依赖于定时刷新线程]
private void startGame() {
state(State.IN_GAME);
putTask(new Runnable() {
public void run() {
while(! isOver) {
Iterator<Element> it = map.movableElements();
while(it.hasNext() ) {
it.next().move();
}
Tools.sleep(Constants.MOVABLE_ELE_REFRESH_INTERVAL);
}
}
});
putTask(new Runnable() {
public void run() {
while(! isOver) {
Elmo elmo = map.getElmo();
elmo.move();
Tools.sleep(Constants.ELMO_MOVABLE_REFRESH_INTERVAL);
}
}
});
putTask(new Runnable() {
public void run() {
while(! isOver) {
Elmo elmo = map.getElmo();
if(!elmo.isJump() && (elmo.isLeft() || elmo.isRight()) ) {
putTask(new MoveRunnable(elmo));
}
Tools.sleep(Constants.ELMO_MOVABLE_STEP_REFRESH_INTERVAL);
}
}
});
}
// 绘制给定的索引对应的字符串
private void drawString(Graphics g, String[] words, Point[] poses, int idx) {
drawString(g, words[idx], poses[idx]);
}
private void drawString(Graphics g, String word, Point pos) {
g.drawString(word, pos.x, pos.y);
}
// 获取stageId的字符串表示
// 此处的实现为 不足两位, 在前面填充0
private String getStageIdString(int stageId) {
if(stageId < 10) {
return "0" + String.valueOf(stageId);
}
return String.valueOf(stageId);
}
// 获取下一个关卡的地图
public Integer[][] getNextStageMap(int stageId) {
return Tools.generateMap(Constants.STAGE_01);
}
// 想线程池抛去一个任务
public void putTask(Runnable run) {
threadPool.execute(run);
}
// setter & getter
// 省略若干...
}
2.7 State : 各个状态的枚举
/**
* file name : State.java
* created at : 2:31:26 PM Oct 26, 2015
* created by 970655147
*/
package com.hx.elmo;
// 状态 [当前游戏的状态]
public enum State {
// 三个状态 [开始状态, 显示关卡信息, 正在游戏状态]
START_UP("startUp"), STAGE_INFO("stageInfo"), IN_GAME("inGame");
// 名称
private String name;
// 初始化
private State() {
this(Constants.DEFAULT_STATE_NAME);
}
private State(String name) {
this.name = name;
}
// for debug ..
public String toString() {
return name;
}
}
2.8 Map : 地图model, 控制着所有元素的存取 取出元素有两种方式, 一种是按照坐标, 另一种是从存储的List中存取
/**
* file name : Map.java
* created at : 5:02:16 PM Oct 26, 2015
* created by 970655147
*/
package com.hx.elmo;
// 地图model
public class Map {
// 地图model
// 艾摩君, 孩子, 敌人, 其他元素, 门
private Integer[][] map;
private Element[][] eleMap;
private List<Element> elmos;
private List<Element> boys;
private List<Element> enemys;
private List<Element> props;
private List<Element> doors;
// 初始化
public Map() {
}
public Map(Integer[][] map) {
Tools.assert0(map.length, Constants.ROW_MAX);
Tools.assert0(map[0].length, Constants.COL_MAX);
this.map = map;
elmos = new ArrayList<>();
boys = new ArrayList<>();
enemys = new ArrayList<>();
props = new ArrayList<>(100);
doors = new ArrayList<>(1);
eleMap = new Element[map.length][map[0].length];
init(map, this);
}
// 初始化, 构造对象
// 根据map生成eleMap的model, 以及收集各种类型的元素
private void init(Integer[][] map, Map mapObj) {
for(int row=0; row<map.length; row++) {
for(int col=0; col<map[row].length; col++) {
Element curEle = null;
if(Tools.isEle(map[row][col], Constants.elmo) ) {
curEle = new Elmo(Tools.getXByCol(col), Tools.getYByRow(row), this );
elmos.add(curEle );
curEle = null;
map[row][col] = Constants.NULL;
} else if(Tools.isEle(map[row][col], Constants.boy) ) {
curEle = new Boy(Tools.getXByCol(col), Tools.getYByRow(row) );
boys.add(curEle);
} else if(Tools.isEnemy(map[row][col]) ) {
curEle = new Enemy(Tools.getXByCol(col), Tools.getYByRow(row) );
enemys.add(curEle );
map[row][col] = Constants.NULL;
curEle = null;
} else if(Tools.isProps(map[row][col]) ) {
if(Tools.isEle(map[row][col], Constants.brick)) {
curEle = new Brick(Tools.getXByCol(col), Tools.getYByRow(row) );
} else if (Tools.isEle(map[row][col], Constants.floor)) {
curEle = new Floor(Tools.getXByCol(col), Tools.getYByRow(row) );
} else if (Tools.isEle(map[row][col], Constants.rack)) {
curEle = new Rack(Tools.getXByCol(col), Tools.getYByRow(row) );
} else if (Tools.isEle(map[row][col], Constants.iron)) {
curEle = new Iron(Tools.getXByCol(col), Tools.getYByRow(row) );
}
props.add(curEle );
} else {
if(map[row][col] != Constants.NULL) {
curEle = new Door(Tools.getXByCol(col), Tools.getYByRow(row), Constants.idToImg.get(map[row][col]));
doors.add(curEle );
}
}
eleMap[row][col] = curEle;
}
}
}
// 返回所有元素的一个迭代器
// 最后获取elmo, 不然他就变成背景啦 [主要用于主面板重新绘制]
public Iterator<Element> elements() {
return new Iterator<Element>() {
Iterator<Element> boysIt = boys.iterator();
Iterator<Element> enemysIt = enemys.iterator();
Iterator<Element> propsIt = props.iterator();
Iterator<Element> doorIt = doors.iterator();
Iterator<Element> elmosIt = elmos.iterator();
Iterator<Element> curIt = boysIt;
public boolean hasNext() {
if(curIt.hasNext() ) {
return true;
}
if(curIt == boysIt) {
curIt = enemysIt;
return hasNext();
} else if(curIt == enemysIt) {
curIt = propsIt;
return hasNext();
} else if(curIt == propsIt) {
curIt = doorIt;
return hasNext();
} else if(curIt == doorIt) {
curIt = elmosIt;
return hasNext();
} else {
return false;
}
}
public Element next() {
if(hasNext() ) {
return curIt.next();
}
return null;
}
public void remove() {
throw new RuntimeException("unsupproted exception ...");
}
};
}
// 返回可移动元素的一个迭代器 [主要用于主面板, 定期调度这些元素的move方法, 比如 : 孩子需要哭, 敌人需要移动, 攻击等等]
public Iterator<Element> movableElements() {
return new Iterator<Element>() {
Iterator<Element> boysIt = boys.iterator();
Iterator<Element> enemysIt = enemys.iterator();
Iterator<Element> curIt = boysIt;
public boolean hasNext() {
if(curIt.hasNext() ) {
return true;
}
if(curIt == boysIt) {
curIt = enemysIt;
return hasNext();
} else {
return false;
}
}
public Element next() {
if(hasNext() ) {
return curIt.next();
}
return null;
}
public void remove() {
throw new RuntimeException("unsupproted exception ...");
}
};
}
// 某个元素被攻击了
// 如果是道具, 则操作该位置的元素 [如果其之上的元素不能"腾空"的话, 将其移动下来]
// 如果是敌人, 多态
// 啊 这里不是可以在基类中封装一个beAttacked方法嘛...
public void propBeAttacked(Element prop) {
int row = Tools.getRowByY(prop.y);
int col = Tools.getColByX(prop.x);
int id = map[row][col];
if(Tools.isProps(id) ) {
map[row][col] = Constants.NULL;
eleMap[row][col] = null;
if(! props.remove(prop)) {
boys.remove(prop);
}
downIfNotStandaloneable(row, col);
} else if(Tools.isEnemy(id) ) {
}
}
// 获取剩余的小孩的个数
public int boysLeft() {
return boys.size();
}
// 如果当前位置上面的元素不能独立存在的话, 则将上面的元素, 移到当前位置, 并递归更新
private void downIfNotStandaloneable(int row, int col) {
Element above = eleMap[row-1][col];
if((above != null) && (above instanceof Prop) ) {
if(! ((Prop) above).isStandaloneable() ) {
map[row][col] = map[row-1][col];
eleMap[row][col] = eleMap[row-1][col];
eleMap[row][col].setXY(Tools.getXByCol(col), Tools.getYByRow(row) );
map[row-1][col] = Constants.NULL;
eleMap[row-1][col] = null;
downIfNotStandaloneable(row-1, col);
}
}
}
// setter & getter
// 省略若干...
}
2.9 Tools : 常用的工具函数
/**
* file name : Tools.java
* created at : 2:37:02 PM Oct 26, 2015
* created by 970655147
*/
package com.hx.elmo;
// 工具 常量,方法
public class Tools {
// 工具常量
public static String CRLF = "\r\n";
public static Random ran = new Random();
// 工具方法
// 确保val 和expected相同, 否则 抛出异常
public static void assert0(int val, int expect) {
assert0(val, expect, true);
}
public static void assert0(int val, int expect, boolean isEquals) {
if(isEquals ^ (val == expect)) {
String symbol = null;
if(isEquals) {
symbol = "!=";
} else {
symbol = "==";
}
throw new RuntimeException("assert0Exception : " + val + " " + symbol + " " + expect);
}
}
public static <T> void assert0(T val, T expect) {
assert0(val, expect, true);
}
public static <T> void assert0(T val, T expect, boolean isEquals) {
if(isEquals ^ (val == expect)) {
throw new RuntimeException("assert0Exception : " + val + " != " + expect);
}
}
// 使当前线程休眠sleepMillus
public static void sleep(int sleepMillus) {
try {
Thread.sleep(sleepMillus);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 根据地图文件生成map
public static Integer[][] generateMap(String path) {
List<String> lines = null;
try {
lines = getContentWithList(new File(path));
} catch (IOException e) {
// TODO Auto-generated catch block
}
Tools.assert0(lines, null, false);
Iterator<String> it = lines.iterator();
Integer[][] res = new Integer[lines.size()][];
int idx = 0;
while(it.hasNext()) {
String[] splits = it.next().split("\\s+");
res[idx] = new Integer[splits.length];
for(int i=0; i<splits.length; i++) {
res[idx][i] = Integer.valueOf(splits[i]);
}
idx ++;
}
return res;
}
// 获取文件的所有的行, 存储在一个结果的List
public static List<String> getContentWithList(File file) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)) );
List<String> lines = new LinkedList<>();
String line = null;
while((line = br.readLine()) != null) {
lines.add(line);
}
br.close();
return lines;
}
// 通过行列的数据, 获取坐标
public static int getXByCol(int col) {
return col * Constants.GRID_WIDTH;
}
public static int getYByRow(int row) {
return row * Constants.GRID_HEIGHT;
}
public static int getColByX(int x) {
return x / Constants.GRID_WIDTH;
}
public static int getRowByY(int y) {
return y / Constants.GRID_HEIGHT;
}
// 判断是否是给定的元素
public static boolean isEle(Integer id, Image img) {
return Constants.idToImg.get(id) == img;
}
public static boolean isEnemy(Integer id) {
return false;
}
public static boolean isProps(Integer id) {
return isEle(id, Constants.brick) || isEle(id, Constants.floor) || isEle(id, Constants.rack) || isEle(id, Constants.iron) || isEle(id, Constants.boy);
}
// 获取一个随机数
public static int nextRandom(int range) {
return ran.nextInt(range);
}
// 使坐标合法化 [求模]
public static int formatX(int x) {
if(x < 0 || x >= Constants.FRAME_WIDTH) {
x = (x + Constants.FRAME_WIDTH) % Constants.FRAME_WIDTH;
}
return x;
}
public static int formatY(int y) {
if(y < 0 || y >= Constants.FRAME_HEIGHT) {
y = (y + Constants.FRAME_HEIGHT) % Constants.FRAME_HEIGHT;
}
return y;
}
public static int formatRow(int row) {
if(row < 0 || row >= Constants.ROW_MAX) {
row = (row + Constants.ROW_MAX) % Constants.ROW_MAX;
}
return row;
}
public static int formatCol(int col) {
if(col < 0 || col >= Constants.COL_MAX) {
col = (col + Constants.COL_MAX) % Constants.COL_MAX;
}
return col;
}
// 等待 线程池中任务结束 [并不关闭线程池]
public static void awaitTasksEnd(ThreadPoolExecutor threadPool, int checkInterval) {
while (! threadPool.isShutdown() ) {
int acitveTaskCount = threadPool.getActiveCount();
if(acitveTaskCount == 0) {
break ;
} else {
Tools.sleep(checkInterval);
}
}
}
}
2.10 Constants : 存放常量
/**
* file name : Constants.java
* created at : 2:27:39 PM Oct 26, 2015
* created by 970655147
*/
package com.hx.elmo;
// 常量配置
public class Constants {
// 游戏属性配置 [平常元素的宽高, 以及elmo的宽高]
public static int GRID_WIDTH = 40;
public static int GRID_HEIGHT = 36;
public static int ELMO_WIDTH = 36;
public static int ELMO_HEIGHT = 32;
// 主窗口的宽高, 最多的行数, 列数
public static int FRAME_WIDTH = 640;
public static int FRAME_HEIGHT = 500;
public static int ROW_MAX = 13;
public static int COL_MAX = 16;
// 控制配置
// 开始, 选择, 上下左右, 跳跃, 攻击
public static int START = KeyEvent.VK_1;
public static int SELECT = KeyEvent.VK_3;
public static int GO_UP = KeyEvent.VK_W;
public static int GO_RIGHT = KeyEvent.VK_D;
public static int GO_DOWN = KeyEvent.VK_S;
public static int GO_LEFT = KeyEvent.VK_A;
public static int GO_JUMP = KeyEvent.VK_K;
public static int GO_ATTACK = KeyEvent.VK_J;
// 方向
public static int RIGHT = 0;
public static int LEFT = 1;
// 各个需要的图片的路径, 以及Image对象, 以及数字到图片的映射[构建地图]
// 三张背景图 + 元素图 + 门 + elmo的左右两个方向的各自四张图, boy哭的四张图
public static String START_BG_BG = System.getProperty("user.dir") + "/src/com/hx/elmo/startUpBG.png";
public static String STAGE_INFO_BG = System.getProperty("user.dir") + "/src/com/hx/elmo/stageInfo.png";
public static String IN_GAME_BG = System.getProperty("user.dir") + "/src/com/hx/elmo/inGameBG.png";
public static String BRICK = System.getProperty("user.dir") + "/src/com/hx/elmo/brick.png";
public static String FLOOR = System.getProperty("user.dir") + "/src/com/hx/elmo/floor.png";
public static String RACK = System.getProperty("user.dir") + "/src/com/hx/elmo/rack.png";
public static String IRON = System.getProperty("user.dir") + "/src/com/hx/elmo/iron.png";
public static String LEFT_UP_DOOR = System.getProperty("user.dir") + "/src/com/hx/elmo/leftUpDoor.png";
public static String LEFT_DOWN_DOOR = System.getProperty("user.dir") + "/src/com/hx/elmo/leftDownDoor.png";
public static String RIGHT_UP_DOOR = System.getProperty("user.dir") + "/src/com/hx/elmo/rightUpDoor.png";
public static String RIGHT_DOWN_DOOR = System.getProperty("user.dir") + "/src/com/hx/elmo/rightDownDoor.png";
public static int STAND = 0;
public static int GO = 1;
public static int ATT = 2;
public static int SLEEP = 3;
public static int DOWN = 4;
public static String[] ELMO_LEFT = new String[] {
System.getProperty("user.dir") + "/src/com/hx/elmo/elmoStandLeft.png",
System.getProperty("user.dir") + "/src/com/hx/elmo/elmoGoLeft.png",
System.getProperty("user.dir") + "/src/com/hx/elmo/elmoAttLeft.png",
System.getProperty("user.dir") + "/src/com/hx/elmo/elmoSleepLeft.png",
System.getProperty("user.dir") + "/src/com/hx/elmo/elmoDownLeft.png"
};
public static String[] ELMO_RIGHT = new String[] {
System.getProperty("user.dir") + "/src/com/hx/elmo/elmoStandRight.png",
System.getProperty("user.dir") + "/src/com/hx/elmo/elmoGoRight.png",
System.getProperty("user.dir") + "/src/com/hx/elmo/elmoAttRight.png",
System.getProperty("user.dir") + "/src/com/hx/elmo/elmoSleepRight.png",
System.getProperty("user.dir") + "/src/com/hx/elmo/elmoDownRight.png"
};
public static String[] BOYS = new String[] {
System.getProperty("user.dir") + "/src/com/hx/elmo/boy_1.png",
System.getProperty("user.dir") + "/src/com/hx/elmo/boy_2.png",
System.getProperty("user.dir") + "/src/com/hx/elmo/boy_3.png",
System.getProperty("user.dir") + "/src/com/hx/elmo/boy_4.png"
};
// 默认配置的关卡0, 1, 默认的StageName Stage中使用, 背景颜色
public static String STAGE_00 = System.getProperty("user.dir") + "/src/com/hx/elmo/map00.txt";
public static String STAGE_01 = System.getProperty("user.dir") + "/src/com/hx/elmo/map01.txt";
public static String DEFAULT_STATE_NAME = "unknowName";
public static Color START_BG_COLOR = new Color(144, 208, 255);
// 各个id, 图片
public static int NULL = 0;
public static int RACK_ID = 1;
public static int FLOOR_ID = 2;
public static int ELMO_ID = 3;
public static int BRICK_ID = 4;
public static int BOY_ID = 5;
public static int IRON_ID = 6;
public static int LEFT_UP_DOOR_ID = 7;
public static int LEFT_DOWN_DOOR_ID = 8;
public static int RIGHT_UP_DOOR_ID = 9;
public static int RIGHT_DOWN_DOOR_ID = 10;
public static Image startBg;
public static Image stageInfoBg;
public static Image inGameBg;
public static Image brick;
public static Image floor;
public static Image rack;
public static Image iron;
public static Image leftUpDoor;
public static Image leftDownDoor;
public static Image rightUpDoor;
public static Image rightDownDoor;
public static Image elmo;
public static Image[] elmoLeft;
public static Image[] elmoRight;
public static Image boy;
public static Image[] boys;
public static java.util.Map<Integer, Image> idToImg;
// 初始化各个图片, 建立id 到图片的映射
static {
try {
startBg = ImageIO.read(new File(START_BG_BG) );
stageInfoBg = ImageIO.read(new File(STAGE_INFO_BG) );
inGameBg = ImageIO.read(new File(IN_GAME_BG) );
brick = ImageIO.read(new File(BRICK) );
floor = ImageIO.read(new File(FLOOR) );
rack = ImageIO.read(new File(RACK) );
iron = ImageIO.read(new File(IRON) );
leftUpDoor = ImageIO.read(new File(LEFT_UP_DOOR) );
leftDownDoor = ImageIO.read(new File(LEFT_DOWN_DOOR) );
rightUpDoor = ImageIO.read(new File(RIGHT_UP_DOOR) );
rightDownDoor = ImageIO.read(new File(RIGHT_DOWN_DOOR) );
boys = new Image[BOYS.length];
elmoLeft = new Image[ELMO_LEFT.length];
elmoRight = new Image[ELMO_RIGHT.length];
for(int i=0; i<ELMO_LEFT.length; i++) {
elmoLeft[i] = ImageIO.read(new File(ELMO_LEFT[i]) );
elmoRight[i] = ImageIO.read(new File(ELMO_RIGHT[i]) );
}
for(int i=0; i<BOYS.length; i++) {
boys[i] = ImageIO.read(new File(BOYS[i]) );
}
elmo = elmoLeft[0];
boy = boys[0];
} catch (IOException e) {
e.printStackTrace();
}
idToImg = new HashMap<>();
idToImg.put(RACK_ID, rack);
idToImg.put(FLOOR_ID, floor);
idToImg.put(ELMO_ID, elmo);
idToImg.put(BRICK_ID, brick);
idToImg.put(BOY_ID, boys[0]);
idToImg.put(IRON_ID, iron);
idToImg.put(LEFT_UP_DOOR_ID, leftUpDoor);
idToImg.put(LEFT_DOWN_DOOR_ID, leftDownDoor);
idToImg.put(RIGHT_UP_DOOR_ID, rightUpDoor);
idToImg.put(RIGHT_DOWN_DOOR_ID, rightDownDoor);
}
// 开始按钮的时候 选中文字的闪烁的次数, 每一次闪烁间隔的时间
// MainPanel中线程的个数, 显示stage信息的时候 停滞的时间
public static int START_TWINKLE_TIMES = 5;
public static int START_TWINKLE_INTERVAL = 200;
public static int N_THREADS = 10;
public static int STAGE_INFO_INTERVAL = 1000;
// 游戏画面重绘的周期, 可移动元素的重绘的时间周期[boy, enemy], elmo移动的时间周期 [这里和其他的可移动的元素是分开的]
// elmo绘制其脚步变化的周期 [在移动才更新图片], elmo移动的时候绘制跑的图片的时间长度
// elmo跳跃的时候 相邻的两个高度绘制的时间间隔, elmo水平移动的长度, elmo竖直方向上移动的长度
// elmo 跳跃一次分为多少个阶段绘制, elmo攻击的时候显示攻击图片的时间
// 过关的时候, 等待所有的线程停止的检查时间
public static int REFRESH_INTERVAL = 30;
public static int MOVABLE_ELE_REFRESH_INTERVAL = 100;
public static int ELMO_MOVABLE_REFRESH_INTERVAL = 40;
public static int ELMO_MOVABLE_STEP_REFRESH_INTERVAL = 400;
public static int ELMO_MOVE_CHANGE_PIC_INTERVAL = 200;
public static int JUMP_CHANGE_PIC_INTERVAL = 50;
public static final int ELMO_MOVE_HORIZON_OFF = 5;
public static final int ELMO_MOVE_VERTICAL_OFF = GRID_HEIGHT + 10;
public static final int ELMO_JUMP_UP_TIMES = 5;
public static int ELMO_ATTACK_CHANGE_PIC_INTERVAL = 1000;
public static int DEFAULT_CHECK_THREADPOOL_INTERVAL = 200;
// 开始界面需要绘制的数字, 以及其位置
public static Color START_UP_COLOR = Color.WHITE;
public static Font START_UP_FONT = new Font("宋体", Font.BOLD, 24);
public static String[] START_UPS_WORDS = new String[] {
"@ KONAMI 1990",
"PLAY SELECT",
"START",
"CONTINUE"
};
public static Point[] START_UPS_WORDS_POS = new Point[] {
new Point(200, 230),
new Point(220, 280),
new Point(160, 310),
new Point(350, 310)
};
public static Point START_UP_START_POS = new Point(110, 280);
public static Point START_UP_CONTINUE_POS = new Point(300, 280);
// 显示关卡页面需要绘制的数字, 以及其位置
public static Color STAGE_INFO_COLOR = new Color(224, 80, 0);
public static Font STAGE_INFO_FONT = new Font("宋体", Font.BOLD, 24);
public static String[] STAGE_INFO_WORDS = new String[] {
"STAGE ",
"REST "
};
public static Point[] STAGE_INFO_WORDS_POS = new Point[] {
new Point(260, 230),
new Point(260, 280)
};
}
3 下载链接 [包含图片, 源码] :
http://download.csdn.net/detail/u011039332/9221627
游戏截图 :
fc 原版截图
过关成功
过关失败