游戏介绍
迷宫游戏总共有10个关卡,随着关卡等级的提高,积木会变多,难度也有相应的增加。游戏目的:了解方向积木、循环积木、以及判断积木的使用;游戏等级:1-10级;运行程序:单机可以执行积木脚本,积木脚本将控制企鹅运动,直到脚本执行完成或找到地图图标标志;方向积木:向左转、向右转;循环积木:重复执行直到,for或while循环;判断积木:如果前方可以通行,if or ifelse;
分析实现
积木定义
旋转方向积木
Blockly.Blocks['maze_turn'] = { init: function() { //控制积木左转、右转 var DIRECTIONS = [[BlocklyGames.getMsg('Maze_turnLeft'), 'turnLeft'], [BlocklyGames.getMsg('Maze_turnRight'), 'turnRight']]; // Append arrows to direction messages. DIRECTIONS[0][0] += Maze.Blocks.LEFT_TURN; DIRECTIONS[1][0] += Maze.Blocks.RIGHT_TURN; this.setColour(Maze.Blocks.MOVEMENT_HUE); //添加元素下拉列表 this.appendDummyInput() .appendField(new Blockly.FieldDropdown(DIRECTIONS), 'DIR'); this.setPreviousStatement(true); this.setNextStatement(true); this.setTooltip(BlocklyGames.getMsg('Maze_turnTooltip')); }};Blockly.JavaScript['maze_turn'] = function(block) { // 获得下拉列表值 var dir = block.getFieldValue('DIR'); return dir + '('block_id_' + block.id + '');';};
循环积木
Blockly.Blocks['maze_forever'] = { init: function() { this.setColour(Maze.Blocks.LOOPS_HUE); //添加图标 this.appendDummyInput() .appendField(BlocklyGames.getMsg('Maze_repeatUntil')) .appendField(new Blockly.FieldImage(Maze.SKIN.marker, 12, 16)); //添加执行语句 this.appendStatementInput('DO') .appendField(BlocklyGames.getMsg('Maze_doCode')); this.setPreviousStatement(true);this.setTooltip(BlocklyGames.getMsg('Maze_whileTooltip')); }};Blockly.JavaScript['maze_forever'] = function(block) { // Generate JavaScript for repeat loop. var branch = Blockly.JavaScript.statementToCode(block, 'DO'); if (Blockly.JavaScript.INFINITE_LOOP_TRAP) { branch = Blockly.JavaScript.INFINITE_LOOP_TRAP.replace(/%1/g, ''block_id_' + block.id + ''') + branch; } //循环执行branch直到碰到地图图标 return 'while (notDone()) {' + branch + '}';};
判断积木
Blockly.Blocks['maze_if'] = { //判断积木是否可以前进、左转、右转 init: function() { var DIRECTIONS = [[BlocklyGames.getMsg('Maze_pathAhead'), 'isPathForward'], [BlocklyGames.getMsg('Maze_pathLeft'), 'isPathLeft'], [BlocklyGames.getMsg('Maze_pathRight'), 'isPathRight']]; // Append arrows to direction messages. DIRECTIONS[1][0] += Maze.Blocks.LEFT_TURN; DIRECTIONS[2][0] += Maze.Blocks.RIGHT_TURN; this.setColour(Maze.Blocks.LOGIC_HUE); //添加元素下拉列表 this.appendDummyInput() .appendField(new Blockly.FieldDropdown(DIRECTIONS), 'DIR'); //判断执行代码 this.appendStatementInput('DO') .appendField(BlocklyGames.getMsg('Maze_doCode')); this.setTooltip(BlocklyGames.getMsg('Maze_ifTooltip')); this.setPreviousStatement(true); this.setNextStatement(true); }};Blockly.JavaScript['maze_if'] = function(block) { // 获取下拉列表if中的条件代码 var argument = block.getFieldValue('DIR') + '('block_id_' + block.id + '')'; var branch = Blockly.JavaScript.statementToCode(block, 'DO'); var code = 'if (' + argument + ') {' + branch + '}'; return code;};
迷宫生成
企鹅迷宫对象:Maze.map,随着等级的变化map中的路线图也会变化地图图标位置:Maze.finish[y, x],用于判断企鹅是否到达finsih点企鹅当前位置:[pegmanY, pegmanX]企鹅方向:NORTH: 0:[pegmanY-1, pegmanX],EAST: 1:[pegmanY, pegmanX+1],SOUTH: 2:[pegmanY+1, pegmanX],WEST: 3:[pegmanY-1, pegmanX+1]
// 添加地图图标 var finishMarker = Blockly.utils.dom.createSvgElement('image', { 'id': 'finish', 'height': 34, 'width': 20 }, svg); finishMarker.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', Maze.SKIN.marker);// 添加企鹅图标 var pegmanIcon = Blockly.utils.dom.createSvgElement('image', { 'id': 'pegman', 'height': Maze.PEGMAN_HEIGHT, 'width': Maze.PEGMAN_WIDTH * 21, // 49 * 21 = 1029 'clip-path': 'url(#pegmanClipPath)' }, svg); pegmanIcon.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', Maze.SKIN.sprite);
积木执行
企鹅移动企鹅移动对象为[command, id],comand为东南西北四个方向,id为积木的id。
Maze.move = function(direction, id) {//判断企鹅某个方向是否可以移动 if (!Maze.isPath(direction, null)) { Maze.log.push(['fail_' + (direction ? 'backward' : 'forward'), id]); throw false; } var effectiveDirection = Maze.pegmanD + direction; var command; //构造企鹅移动方向对象 switch (Maze.constrainDirection4(effectiveDirection)) { case Maze.DirectionType.NORTH: Maze.pegmanY--; command = 'north'; break; case Maze.DirectionType.EAST: Maze.pegmanX++; command = 'east'; break; case Maze.DirectionType.SOUTH: Maze.pegmanY++; command = 'south'; break; case Maze.DirectionType.WEST: Maze.pegmanX--; command = 'west'; break; } Maze.log.push([command, id]);};
企鹅转动方向
Maze.turn = function(direction, id) { if (direction) { // Right turn (clockwise). Maze.pegmanD++; Maze.log.push(['right', id]); } else { // Left turn (counterclockwise). Maze.pegmanD--; Maze.log.push(['left', id]); } Maze.pegmanD = Maze.constrainDirection4(Maze.pegmanD);};
企鹅某个方向是否可移动
Maze.isPath = function(direction, id) { var effectiveDirection = Maze.pegmanD + direction; var square; var command; switch (Maze.constrainDirection4(effectiveDirection)) { case Maze.DirectionType.NORTH: square = Maze.map[Maze.pegmanY - 1] && Maze.map[Maze.pegmanY - 1][Maze.pegmanX]; command = 'look_north'; break; case Maze.DirectionType.EAST: square = Maze.map[Maze.pegmanY][Maze.pegmanX + 1]; command = 'look_east'; break; case Maze.DirectionType.SOUTH: square = Maze.map[Maze.pegmanY + 1] && Maze.map[Maze.pegmanY + 1][Maze.pegmanX]; command = 'look_south'; break; case Maze.DirectionType.WEST: square = Maze.map[Maze.pegmanY][Maze.pegmanX - 1]; command = 'look_west'; break; } if (id) { Maze.log.push([command, id]); } return square !== Maze.SquareType.WALL && square !== undefined;};
脚本执行回调
Maze.initInterpreter = function(interpreter, scope) { var wrapper; moveForward = function(id) { Maze.move(0, id);//前进 }; moveBackward = function(id) { Maze.move(2, id);//后退 }; turnLeft = function(id) { Maze.turn(0, id);//左转 }; turnRight = function(id) { Maze.turn(1, id);//右转 }; isPathForward = function(id) { return Maze.isPath(0, id);//是否可前进 }; isPathRight = function(id) { return Maze.isPath(1, id); }; isPathBackward = function(id) { return Maze.isPath(2, id); }; isPathLeft = function(id) { return Maze.isPath(3, id); }; notDone = function() {//游戏是否结束 return Maze.notDone(); };};
其他
迷宫游戏某个等级,脚本区只能使用固定数量的积木,此函数提示脚本区剩余积木数量。
Maze.updateCapacity = function() { var cap = BlocklyInterface.workspace.remainingCapacity(); var p = document.getElementById('capacity'); if (cap == Infinity) { p.style.display = 'none'; } else { p.style.display = 'inline'; p.innerHTML = ''; cap = Number(cap); var capSpan = document.createElement('span'); capSpan.className = 'capacityNumber'; capSpan.appendChild(document.createTextNode(cap)); if (cap == 0) { var msg = BlocklyGames.getMsg('Maze_capacity0'); } else if (cap == 1) { var msg = BlocklyGames.getMsg('Maze_capacity1'); } else { var msg = BlocklyGames.getMsg('Maze_capacity2'); } var parts = msg.split(/%d/); for (var i = 0; i < parts.length; i++) { p.appendChild(document.createTextNode(parts[i])); if (i != parts.length - 1) { p.appendChild(capSpan.cloneNode(true)); } } }};