游戏介绍
迷宫游戏总共有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 + '\');\n';
};
循环积木
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()) {\n' + branch + '}\n';
};
判断积木
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 + ') {\n' + branch + '}\n';
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));
}
}
}
};