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 & getterpublic 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, elmoprivate 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();}// 初始化elmoprivate 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();}// 对于开始游戏界面// 对于各个操作键的响应// 如果成功了, 则更新stagepublic 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();                    }});}// 对于开始界面的时候// doNothingpublic 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的字符串表示// 此处的实现为 不足两位, 在前面填充0private 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);}}// 使当前线程休眠sleepMilluspublic static void sleep(int sleepMillus) {try {Thread.sleep(sleepMillus);} catch (InterruptedException e) {e.printStackTrace();}}// 根据地图文件生成mappublic 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;}// 获取文件的所有的行, 存储在一个结果的Listpublic 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 原版截图

过关成功

过关失败

09 智慧桥/ 艾摩君相关推荐

  1. 智慧人生 仁者见仁 与君共勉

    [智慧] 美女住酒店一晚结账时账单800元,她抱怨太贵.经理说这是标准收费,酒店附设泳池.健身房和wifi.美女说自己完全没使用,经理说饭店有提供,是她自己不用. 女客人打开皮包掏钱付账,但说要扣除经 ...

  2. 智慧环保智能化环境系统运用实例

    "智慧环保"是"数字环保"定义的拓宽和扩展,它是依靠物联网,把感应开关和配备置入到各类环境监管目标中,根据高性能计算机和云计算技术将环保行业物联网技术融合起来, ...

  3. 学python对数学要求吗_python 学习和数学知识 - 文章分类 - 风中小郎君 - 博客园...

    文章分类 - python 学习和数学知识 http://www.cnblogs.com/vamei 摘要:它们的区别在于应用的对象不同.1.map()map() 是一个Series的函数,DataF ...

  4. 过去一年中国智慧物流行业发展得如何?十分钟让你知晓!

    2019年2月21日,全球领先的新经济行业数据挖掘和分析机构iiMedia Research(艾媒咨询)权威发布<2018-2019中国智慧物流行业研究报告>.iiMedia Resear ...

  5. 第十七届全国大学生智能车竞赛线上比赛直播链接

    §01 直播信息 惠州学院赛点比赛时间安排表以及直播链接 7月25日上午 组别 学校&队伍名称 时间 直播 B站直播链接   四轮电磁 东江-白夜(惠州学院) 9:00-9:20 直播1 ht ...

  6. 8305天距离梦想还有8,352 千米 2012-03-31 23:18:53 柏林勃兰登堡门 再过两天就是我22周岁生日了,我在生命网站上摁下自己的出生年月,上面显示我已经度过了8305天,走

    8305天距离梦想还有8,352 千米   http://www.douban.com/note/207745712/ 2012-03-31 23:18:53 柏林勃兰登堡门 再过两天就是我22周岁生 ...

  7. 发个上海英雄会聚会沙龙的公告 希望和大家一起见面交流探讨

    最新公告:欢迎参加"创业与团队管理"主题沙龙 致   网友: 2008年9月4日晚8时,"创业与团队管理"主题沙龙将在上海市虹口区广灵四路116号智慧桥创意园二 ...

  8. python123监考系统_2020-2021学年第1学期 期末考试监考安排

    序号课程名称考试时间已排 人数监考教师1考场领试卷地点 1概率论与数理统计B2021-01-14   09:00-11:0041艾克凤卓越楼118卓越楼2楼教师休息室 2微观与宏观经济学2021-01 ...

  9. 巧用 cowsay 做个性化 motd

    Message Of The Day 网络工程师或软件工程师,特别是接触服务器比较多的人,登录各种终端是日常生活中的一部分.非图形界面下只有一堆字符略显单调,因此有些人会用 ASCII 图形来丰富登录 ...

最新文章

  1. 如何解决Keil5打红叉的问题
  2. JStorm/Storm源码解读(二)--启动篇
  3. Java8中的流操作-基本使用性能测试
  4. 预约 .NET Conf: Focus on F# 活动,赢得官方周边!
  5. Windows2008的安装
  6. spring-boot配置文件中server.context-path不起作用
  7. hit网络安全实验报告
  8. c语言算开方程序,C语言计算开方
  9. Shiro框架的搭建与使用
  10. 【Python古诗词鉴赏小程序】千古绝唱,精选中国最美古诗句,经典咏流传~
  11. 笛卡尔心形函数表达式_如何用几何画板画笛卡尔心形函数
  12. 360与QQ大战观感
  13. error: C++ requires a type specifier for all declarations
  14. 【私有,不喜勿入】健康
  15. 在kile中为stm32移植FreeRTOS
  16. ARMV8体系结构简介:AArch64系统级体系结构之Self-hosted debug
  17. openFeign夺命连环9问,这谁受得了?
  18. 日语学习的在线资料,朋友推荐,拿来分享
  19. 会话及会话技术、Cookie对象、Session对象 详解
  20. PHP 家长互助解决问题步骤,家长互助学习心得体会

热门文章

  1. 模式设计(七)Adapter
  2. java exchanger_java Exchanger
  3. android开发培训!作为一个Android程序员你还不会JetPack?安卓系列学习进阶视频
  4. Lite系列开发框架
  5. 50个使用标点符号设计的创意LOGO设计欣赏(下篇)
  6. 【论文笔记】ICNet:用于无监督医学图像配准的逆一致性模型
  7. POJ - 昂贵的聘礼(最短路)
  8. 12306能扛住明星出轨这种流量冲击吗?
  9. 面试鹅厂,我被虐的体无完肤
  10. 软文营销,你了解了吗?