//这一版加入了所有延时和高亮效果,用以适应分布调试 var $builtinmodule = function (name) { let mod= {__name__: new Sk.builtin.str("blocklygame")}; var svg = d3.select(Sk.TurtleGraphics.target).append('svg'); //其他变量设置 var map=//迷宫布局 [[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 2, 1, 1, 1, 1, 3, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]] var DirectionType={//移动方向的类型 NORTH: 0, EAST: 1, SOUTH: 2, WEST: 3 } var ResultType = { UNSET: 0, SUCCESS: 1, FAILURE: -1, TIMEOUT: 2, ERROR: -2 } var tile_SHAPES = { '10010': [4, 0], // Dead ends '10001': [3, 3], '11000': [0, 1], '10100': [0, 2], '11010': [4, 1], // Vertical '10101': [3, 2], // Horizontal '10110': [0, 0], // Elbows '10011': [2, 0], '11001': [4, 2], '11100': [2, 3], '11110': [1, 1], // Junctions '10111': [1, 0], '11011': [2, 1], '11101': [1, 2], '11111': [2, 2], // Cross 'null0': [4, 3], // Empty 'null1': [3, 0], 'null2': [3, 1], 'null3': [0, 3], 'null4': [1, 3] } // 角色变量 var actor={ img : "../common/js/skulpt_mixcar/pic/pegman.png", height : 52, width : 49, direction : DirectionType.EAST, type:"animate", x : 0, y : 0, stepSpeed : 150, coin_point:0, marker_num:0, oil:1,//表示小车有充足的油量(为了适应教材而新增的变量) traffic_light:22,//表示红绿灯为绿灯 circulation_num:0,//小车在赛道中循环的次数 invisible_mark:0//在地图中不可显示的标记数目,用于检测小车是否沿着特定路线走。规定不可见的标记点INVIMAKER=24 }; //迷宫变量 var maze_SQUARE_SIZE = 50; var maze_ROWS=map.length; var maze_COLS=map[0].length; var maze_marker_num=0;//迷宫中标记点的数目 var maze={ mlevel:0, tiles: '../common/js/skulpt_mixcar/pic/maze_path.png',//地图路径图片 marker: '../common/js/skulpt_mixcar/pic/marker.png',//终点图标图片 background: '../common/js/skulpt_mixcar/pic/bg_astro.jpg',//地图背景图片 wall:'../common/js/skulpt_mixcar/pic/roadblock.png', award:'../common/js/skulpt_mixcar/pic/award.png', barrier:'', markers:[], SquareType :{//迷宫中方块的类型 WALL: 0, OPEN: 1, START: 2, FINISH: 3, AWARD:4,//金币奖励 INVIMAKER:24 }, //迷宫部分参数指定 MAZE_WIDTH : maze_SQUARE_SIZE * maze_COLS, MAZE_HEIGHT : maze_SQUARE_SIZE * maze_ROWS, PATH_WIDTH : maze_SQUARE_SIZE / 3, result : ResultType.UNSET, finish : {x:0,y:0}, type:1,//类型为用户自定义的 INVIMNUM : 0 }; //已经设置好的关卡的map var MAZE_setted=[ //第一关 { mlevel:1, map:[ [0, 1, 1, 13, 1, 1, 12, 0], [0, 1, 0, 1, 0, 0, 1, 0], [0, 1, 1, 9, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 10, 1, 1, 11, 0], [0, 0, 0, 0, 0, 0, 0, 0]], tiles: '../common/js/skulpt_mixcar/pic/tiles_road.png',//地图路径图片 marker: '../common/js/skulpt_mixcar/pic/Start_final.png',//终点图标图片 background: '../common/js/skulpt_mixcar/pic/bg1.jpg',//地图背景图片 wall:'', award:'', barrier:'', markers:['../common/js/skulpt_mixcar/pic/red.png','../common/js/skulpt_mixcar/pic/yellow.png','../common/js/skulpt_mixcar/pic/blue.png','../common/js/skulpt_mixcar/pic/green.png'], SquareType :{//迷宫中方块的类型 WALL: 0, OPEN: 1, MARKER1:10, MARKER2:11, MARKER3:12, MARKER4:13, S_F: 9,//既是起点又是终点 INVIMAKER:24 }, //迷宫部分参数指定 MAZE_WIDTH : maze_SQUARE_SIZE * 8, MAZE_HEIGHT : maze_SQUARE_SIZE * 8, PATH_WIDTH : maze_SQUARE_SIZE / 3, result : ResultType.UNSET, finish : {x:0,y:0}, type:0,//类型为非用户自定义的 INVIMNUM : 0 }, //第二关 { mlevel:2, map:[ [0, 1, 1, 13, 1, 1, 12, 0], [0, 1, 0, 5, 0, 0, 1, 0], [0, 1, 1, 9, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 10, 1, 1, 11, 0], [0, 0, 0, 0, 0, 0, 0, 0]], tiles: '../common/js/skulpt_mixcar/pic/tiles_road.png',//地图路径图片 marker: '../common/js/skulpt_mixcar/pic/Start_final.png',//终点图标图片 background: '../common/js/skulpt_mixcar/pic/bg2.jpg',//地图背景图片 wall:'', award:'', barrier:'../common/js/skulpt_mixcar/pic/barrier.png', markers:['../common/js/skulpt_mixcar/pic/red.png','../common/js/skulpt_mixcar/pic/yellow.png','../common/js/skulpt_mixcar/pic/blue.png','../common/js/skulpt_mixcar/pic/green.png'], SquareType :{//迷宫中方块的类型 WALL: 0, OPEN: 1, BARRIER:5, MARKER1:10, MARKER2:11, MARKER3:12, MARKER4:13, S_F: 9,//既是起点又是终点 INVIMAKER:24 }, //迷宫部分参数指定 MAZE_WIDTH : maze_SQUARE_SIZE * 8, MAZE_HEIGHT : maze_SQUARE_SIZE * 8, PATH_WIDTH : maze_SQUARE_SIZE / 3, result : ResultType.UNSET, finish : {x:0,y:0}, type:0,//类型为非用户自定义的 INVIMNUM : 0 }, //第三关 { mlevel:3, map:[ [0, 1, 1, 13, 24, 1, 24, 0], [0, 1, 0, Math.random()>0.5?1:5, 0, 0, 1, 0], [0, 1, 1, 9, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 24, 1, 1, 24, 0], [0, 0, 0, 0, 0, 0, 0, 0]], tiles: '../common/js/skulpt_mixcar/pic/tiles_road.png',//地图路径图片 marker: '../common/js/skulpt_mixcar/pic/Start_final.png',//终点图标图片 background: '../common/js/skulpt_mixcar/pic/bg2.jpg',//地图背景图片 wall:'', award:'', barrier:'../common/js/skulpt_mixcar/pic/barrier.png', markers:['../common/js/skulpt_mixcar/pic/red.png','../common/js/skulpt_mixcar/pic/yellow.png','../common/js/skulpt_mixcar/pic/blue.png','../common/js/skulpt_mixcar/pic/green.png'], SquareType :{//迷宫中方块的类型 WALL: 0, OPEN: 1, BARRIER:5, MARKER4:13, S_F: 9,//既是起点又是终点 INVIMAKER: 24 }, //迷宫部分参数指定 MAZE_WIDTH : maze_SQUARE_SIZE * 8, MAZE_HEIGHT : maze_SQUARE_SIZE * 8, PATH_WIDTH : maze_SQUARE_SIZE / 3, result : ResultType.UNSET, finish : {x:0,y:0}, type:0,//类型为非用户自定义的 INVIMNUM : 4 }, //第四关 { mlevel:4, map:[ [0, 1, 1, 13, 24, 1, 24, 0], [20, 1, 0, Math.random()>0.5?1:5, 0, 0, 1, 0], [0, 1, 1, 9, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 24, 1, 1, 24, 0], [0, 0, 0, 0, 0, 0, 0, 0]], tiles: '../common/js/skulpt_mixcar/pic/tiles_road.png',//地图路径图片 marker: '../common/js/skulpt_mixcar/pic/Start_final.png',//终点图标图片 background: '../common/js/skulpt_mixcar/pic/bg3.jpg',//地图背景图片 wall:'', award:'', barrier:'../common/js/skulpt_mixcar/pic/barrier.png', markers:['../common/js/skulpt_mixcar/pic/red.png','../common/js/skulpt_mixcar/pic/yellow.png','../common/js/skulpt_mixcar/pic/blue.png','../common/js/skulpt_mixcar/pic/green.png'], SquareType :{//迷宫中方块的类型 WALL: 0, OPEN: 1, BARRIER:5, MARKER4:13, S_F: 9,//既是起点又是终点 OIL_STATION:20,//加油站 INVIMAKER:24 }, //迷宫部分参数指定 MAZE_WIDTH : maze_SQUARE_SIZE * 8, MAZE_HEIGHT : maze_SQUARE_SIZE * 8, PATH_WIDTH : maze_SQUARE_SIZE / 3, result : ResultType.UNSET, finish : {x:0,y:0}, type:0,//类型为非用户自定义的 INVIMNUM : 4 }, //第五关 { mlevel:5, map:[ [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 0, 0, 0, 0, 1, 0], [0, 1, 1, 2, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0]], tiles: '../common/js/skulpt_mixcar/pic/tiles_road.png',//地图路径图片 marker: '../common/js/skulpt_mixcar/pic/Start_final.png',//终点图标图片 background: '../common/js/skulpt_mixcar/pic/bg1.jpg',//地图背景图片 wall:'', award:'', barrier:'', markers:[], SquareType :{//迷宫中方块的类型 WALL: 0, OPEN: 1, START: 2, S_F: 9,//既是起点又是终点 TRAFFIC_LIGHT:21,//红绿灯 INVIMAKER:24 }, //迷宫部分参数指定 MAZE_WIDTH : maze_SQUARE_SIZE * 8, MAZE_HEIGHT : maze_SQUARE_SIZE * 8, PATH_WIDTH : maze_SQUARE_SIZE / 3, result : ResultType.UNSET, finish : {x:3,y:2}, type:0,//类型为非用户自定义的 INVIMNUM : 0 }, //第六关 { mlevel:6, map:[ [0, 1, 1, 13, 1, 1, 12, 0], [0, 1, 0, 1, 0, 0, 1, 0], [0, 1, 1, 2, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 10, 1, 1, 11, 0], [0, 0, 0, 0, 0, 0, 0, 0]], tiles: '../common/js/skulpt_mixcar/pic/tiles_road.png',//地图路径图片 marker: '../common/js/skulpt_mixcar/pic/Start_final.png',//终点图标图片 background: '../common/js/skulpt_mixcar/pic/bg1.jpg',//地图背景图片 wall:'', award:'', barrier:'', markers:['../common/js/skulpt_mixcar/pic/red.png','../common/js/skulpt_mixcar/pic/yellow.png','../common/js/skulpt_mixcar/pic/blue.png','../common/js/skulpt_mixcar/pic/green.png'], SquareType :{//迷宫中方块的类型 WALL: 0, OPEN: 1, START: 2, MARKER1:10, MARKER2:11, MARKER3:12, MARKER4:13, S_F: 9,//既是起点又是终点 INVIMAKER:24 }, //迷宫部分参数指定 MAZE_WIDTH : maze_SQUARE_SIZE * 8, MAZE_HEIGHT : maze_SQUARE_SIZE * 8, PATH_WIDTH : maze_SQUARE_SIZE / 3, result : ResultType.UNSET, finish : {x:0,y:0}, type:0,//类型为非用户自定义的 INVIMNUM : 0 }, //第七关 { mlevel:7, map:[ [0, 1, 1, 1, 1, 1, 1, 0], [0, 1, 0, 0, 0, 0, 1, 0], [0, 1, 1, 2, 22, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0], [0, 0, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0]], tiles: '../common/js/skulpt_mixcar/pic/tiles_road.png',//地图路径图片 marker: '../common/js/skulpt_mixcar/pic/Start_final.png',//终点图标图片 background: '../common/js/skulpt_mixcar/pic/bg4.jpg',//地图背景图片 wall:'', award:'', barrier:'', markers:[], SquareType :{//迷宫中方块的类型 WALL: 0, OPEN: 1, START: 2, S_F: 9,//既是起点又是终点 LIGHT_GREEN:22,//红绿灯中的绿灯 LIGHT_RED:23,//红绿灯中的红灯 INVIMAKER:24 }, //迷宫部分参数指定 MAZE_WIDTH : maze_SQUARE_SIZE * 8, MAZE_HEIGHT : maze_SQUARE_SIZE * 8, PATH_WIDTH : maze_SQUARE_SIZE / 3, result : ResultType.UNSET, finish : {x:3,y:2}, type:0,//类型为非用户自定义的 INVIMNUM : 0 } ] /** * Display Pegman at the specified location, facing the specified direction. * @param {number} x Horizontal grid (or fraction thereof). * @param {number} y Vertical grid (or fraction thereof). * @param {number} d Direction (0 - 15) or dance (16 - 17). * @param {number=} opt_angle Optional angle (in degrees) to rotate Pegman. */ var displayPegman = function(x, y, d, opt_angle) { var pegmanIcon = $(Sk.TurtleGraphics.target).find('#pegman'); if(actor.type=='animate'){ if(maze.type==0){ pegmanIcon.attr('x', x * maze_SQUARE_SIZE - d * actor.width+ 1); pegmanIcon.attr('y', maze_SQUARE_SIZE * (y + 0.5) - actor.height / 2 ); }else{ pegmanIcon.attr('x', x * maze_SQUARE_SIZE - d * actor.width + 1); pegmanIcon.attr('y', maze_SQUARE_SIZE * (y + 0.5) - actor.height / 2 - 8); } if (opt_angle) { pegmanIcon.attr('transform', 'rotate(' + opt_angle + ', ' + (x * maze_SQUARE_SIZE + maze_SQUARE_SIZE / 2) + ', ' + (y * maze_SQUARE_SIZE + maze_SQUARE_SIZE / 2) + ')'); } else { pegmanIcon.attr('transform', 'rotate(0, 0, 0)'); } }else{ pegmanIcon.attr('x', x * maze_SQUARE_SIZE + 1); pegmanIcon.attr('y', maze_SQUARE_SIZE * (y + 0.5) - actor.height / 2 ); } var clipRect = $(Sk.TurtleGraphics.target).find('#clipRect'); clipRect.attr('x', x * maze_SQUARE_SIZE + 1); clipRect.attr('y', pegmanIcon.attr('y')); }; var initPegman=function(){ // Pegman's clipPath element, whose (x, y) is reset by Maze.displayPegman svg.append('clipPath').attr('id','pegmanClipPath') const elem = Sk.TurtleGraphics.target.querySelector("#pegmanClipPath"); d3.select(elem).append('rect').attr('id','clipRect').attr('width', actor.width).attr('height', actor.height) if(actor.type=="animate"){ if(maze.type==0){ //绘制精灵. svg.append('image').attr('id','pegman').attr('width', actor.width * 16).attr('height', actor.height).attr('clip-path', 'url(#pegmanClipPath)') .attr('xlink:href',actor.img) }else{ //绘制精灵. svg.append('image').attr('id','pegman').attr('width', actor.width * 21).attr('height', actor.height).attr('clip-path', 'url(#pegmanClipPath)') .attr('xlink:href',actor.img) } }else{ //绘制精灵. svg.append('image').attr('id','pegman').attr('width', actor.width ).attr('height', actor.height).attr('clip-path', 'url(#pegmanClipPath)') .attr('xlink:href',actor.img) } displayPegman(actor.x , actor.y , actor.direction*4 ) } var drawMap=function(){ svg.attr('id','game_stage') var scale = Math.max(maze_ROWS, maze_COLS) * maze_SQUARE_SIZE; svg.attr('viewBox', '0 -10 ' + scale + ' ' + (scale+10)); // 绘制外框 svg.append('rect').attr('x', 0).attr('y', 0).attr('width', maze.MAZE_WIDTH).attr('height', maze.MAZE_HEIGHT) .style('fill','#F1EEE7').style('stroke','#CCB').style('stroke-width','1'); // for (var y = 0; y < maze_ROWS; y++) { // for (var x = 0; x < maze_COLS; x++) { // //绘制迷宫背景 // svg.append('image').attr('x', x*maze_SQUARE_SIZE).attr('y', y*maze_SQUARE_SIZE).attr('width', maze_SQUARE_SIZE).attr('height',maze_SQUARE_SIZE) // .attr('xlink:href',maze.background) // } // } svg.append('image').attr('x', 0).attr('y', 0).attr('width', maze_SQUARE_SIZE*maze_COLS).attr('height',maze_SQUARE_SIZE*maze_ROWS) .attr('xlink:href',maze.background) //初始化地图 var normalize = function(x, y) { if (x < 0 || x >= maze_COLS || y < 0 || y >= maze_ROWS) { return '0'; } return ((map[y][x] == maze.SquareType.WALL)||(map[y][x] == maze.SquareType.OIL_STATION)) ? '0' : '1'; }; // 依次判断格子的类型,并绘制相应格子内的图形 var tileId = 0; for (var y = 0; y < maze_ROWS; y++) { for (var x = 0; x < maze_COLS; x++) { // 标记每个格子的“弯曲状态”. var tileShape = normalize(x, y) + normalize(x, y - 1) + // North. normalize(x + 1, y) + // West. normalize(x, y + 1) + // South. normalize(x - 1, y); // East. // 绘制路径. if (!tile_SHAPES[tileShape]) { // Empty square. Use null0 for large areas, with null1-4 for borders. // Add some randomness to avoid large empty spaces. if (tileShape == '00000' && Math.random() > 0.3) { tileShape = 'null0'; } else { tileShape = 'null' + Math.floor(1 + Math.random() * 4); } } var left = tile_SHAPES[tileShape][0]; var top = tile_SHAPES[tileShape][1]; // Tile's clipPath element. svg.append('clipPath').attr('id','tileClipPath' + tileId) const elem = Sk.TurtleGraphics.target.querySelector("#tileClipPath" + tileId); d3.select(elem).append('rect').attr('x', x * maze_SQUARE_SIZE).attr('y', y * maze_SQUARE_SIZE).attr('width', maze_SQUARE_SIZE).attr('height', maze_SQUARE_SIZE) if(maze.type==0){//非用户自定义 // Tile sprite. if ((map[y][x] != maze.SquareType.WALL) && (map[y][x] != maze.SquareType.OIL_STATION) && (map[y][x] != maze.SquareType.TRAFFIC_LIGHT)&& (map[y][x] != maze.SquareType.LIGHT_GREEN)&& (map[y][x] != maze.SquareType.LIGHT_RED)) { svg.append('image').attr('x', x * maze_SQUARE_SIZE).attr('y', y * maze_SQUARE_SIZE).attr('width',maze_SQUARE_SIZE ).attr('height',maze_SQUARE_SIZE ) .attr('clip-path', 'url(#tileClipPath' + tileId + ')').attr('xlink:href',maze.tiles); tileId++; } }else{ // Tile sprite. svg.append('image').attr('x',(x - left) * maze_SQUARE_SIZE).attr('y',(y - top) * maze_SQUARE_SIZE).attr('width',maze_SQUARE_SIZE * 5).attr('height',maze_SQUARE_SIZE * 4) .attr('clip-path', 'url(#tileClipPath' + tileId + ')').attr('xlink:href',maze.tiles) tileId++; } if(map[y][x]==0){//当地图中此处标记为墙时 svg.append('image').attr('x',x * maze_SQUARE_SIZE + (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.8/2)).attr('y',y * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.8/2)).attr('width',maze_SQUARE_SIZE*0.8 ).attr('height',maze_SQUARE_SIZE*0.8) .attr('xlink:href',maze.wall) }else if(map[y][x]==4){//当地图中此处标记为金币时 svg.append('image').attr('id','coin'+y+x).attr('x',x * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.5/2)).attr('y',y * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.5/2)).attr('width',maze_SQUARE_SIZE*0.5).attr('height',maze_SQUARE_SIZE*0.5) .attr('xlink:href',maze.award) }else if(map[y][x]==5){//当地图中此处标记为障碍时 svg.append('image').attr('id','barrier'+y+x).attr('x',x * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('y',y * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('width',maze_SQUARE_SIZE*0.7).attr('height',maze_SQUARE_SIZE*0.7) .attr('xlink:href',maze.barrier) }else if(map[y][x]==10){//当地图中此处标记为符号1——红标时 svg.append('image').attr('id','marker1').attr('x',x * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('y',y * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('width',maze_SQUARE_SIZE*0.7).attr('height',maze_SQUARE_SIZE*0.7) .attr('xlink:href',maze.markers[0]) maze_marker_num+=1 }else if(map[y][x]==11){//当地图中此处标记为符号2——橘标时 svg.append('image').attr('id','marker2').attr('x',x * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('y',y * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('width',maze_SQUARE_SIZE*0.7).attr('height',maze_SQUARE_SIZE*0.7) .attr('xlink:href',maze.markers[1]) maze_marker_num+=1 }else if(map[y][x]==12){//当地图中此处标记为符号3——蓝标时 svg.append('image').attr('id','marker3').attr('x',x * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('y',y * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('width',maze_SQUARE_SIZE*0.7).attr('height',maze_SQUARE_SIZE*0.7) .attr('xlink:href',maze.markers[2]) maze_marker_num+=1 }else if(map[y][x]==13){//当地图中此处标记为符号4——绿标时 svg.append('image').attr('id','marker4').attr('x',x * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('y',y * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('width',maze_SQUARE_SIZE*0.7).attr('height',maze_SQUARE_SIZE*0.7) .attr('xlink:href',maze.markers[3]) maze_marker_num+=1 } } } if(maze.type==1){ // 绘制终点图标 svg.append('image').attr('id','finish').attr('width', 0.5 * maze_SQUARE_SIZE).attr('height', 0.5*maze_SQUARE_SIZE).attr('xlink:href',maze.marker) //定位:精灵与终点初始的位置 // Locate the start and finish squares. for (var y = 0; y < maze_ROWS; y++) { for (var x = 0; x < maze_COLS; x++) { if (map[y][x] == maze.SquareType.START) { actor.x= x; actor.y= y; } else if (map[y][x] == maze.SquareType.FINISH) { // Move the finish icon into position. var finishIcon = $(Sk.TurtleGraphics.target).find('#finish'); finishIcon.attr('x', maze_SQUARE_SIZE * (x + 0.5) - finishIcon.attr('width') / 2); finishIcon.attr('y', maze_SQUARE_SIZE * (y + 0.6) - finishIcon.attr('height')); maze.finish={x:x,y:y} } } } }else{ //绘制既是起点、又是终点的坐标 // Locate the start and finish squares. for (var y = 0; y < maze_ROWS; y++) { for (var x = 0; x < maze_COLS; x++) { if (map[y][x] == 9) {//既是起点又是终点 // 绘制终点图标 svg.append('image').attr('id','finish').attr('width', maze_SQUARE_SIZE*0.8).attr('height', maze_SQUARE_SIZE*0.8).attr('xlink:href',maze.marker) actor.x= x; actor.y= y; var finishIcon = $(Sk.TurtleGraphics.target).find('#finish'); finishIcon.attr('x', maze_SQUARE_SIZE * x+5 ); finishIcon.attr('y', maze_SQUARE_SIZE * y+5); maze.finish={x:x,y:y} }else if(map[y][x]==20){//当地图中此处标记为20——加油站时 svg.append('image').attr('id','station').attr('x',x * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.8/2)).attr('y',y * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.8/2)).attr('width',maze_SQUARE_SIZE*2*0.8).attr('height',maze_SQUARE_SIZE*0.8) .attr('xlink:href','../common/js/skulpt_mixcar/pic/oilstation.png') }else if(map[y][x]==21){//当地图中此处标记为21——红绿灯时 svg.append('image').attr('id','trafficlight').attr('x',x * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('y',y * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('width',maze_SQUARE_SIZE*0.7).attr('height',maze_SQUARE_SIZE*0.7) .attr('xlink:href','../common/js/skulpt_mixcar/pic/trafficlight.png') }else if(map[y][x]==22){//当地图中此处标记为22——红绿灯中的绿灯时 svg.append('image').attr('id','lightgreen').attr('x',x * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('y',y * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('width',maze_SQUARE_SIZE*0.7).attr('height',maze_SQUARE_SIZE*0.7) .attr('xlink:href','../common/js/skulpt_mixcar/pic/greenlight.png') }else if(map[y][x]==23){//当地图中此处标记为23——红绿灯中的红灯时 svg.append('image').attr('id','lightred').attr('x',x * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('y',y * maze_SQUARE_SIZE+ (maze_SQUARE_SIZE/2 - maze_SQUARE_SIZE*0.7/2)).attr('width',maze_SQUARE_SIZE*0.7).attr('height',maze_SQUARE_SIZE*0.7) .attr('xlink:href','../common/js/skulpt_mixcar/pic/redlight.png') }else if(map[y][x]==2){//当地图中此处标记为起点时,画上和“既是起点又是终点”一样的图标 actor.x= x; actor.y= y; svg.append('image').attr('id','start').attr('x', maze_SQUARE_SIZE * x).attr('y',maze_SQUARE_SIZE * y+5).attr('width',maze_SQUARE_SIZE).attr('height',maze_SQUARE_SIZE*0.8) .attr('xlink:href',maze.marker) } } } } } //检查是否已到终点 var checkFinish=function(){ maze.result = actor.x != maze.finish.x || actor.y != maze.finish.y ? ResultType.UNSET : ResultType.SUCCESS; if(maze.result==ResultType.SUCCESS){ if(maze.type==1){ return true }else{ if(maze.mlevel==5 || maze.mlevel==7 ||maze.mlevel==6){ return true }else{ if(actor.marker_num==maze_marker_num){ if(actor.invisible_mark>=maze.INVIMNUM){ return true }else{return "error3"} }else{return "error2"} } } }else{ return false } } /** * Is there a path next to pegman? * @param {number} direction Direction to look * (0 = forward, 1 = right, 2 = backward, 3 = left). * @param {?string} id ID of block that triggered this action. * Null if called as a helper function in Maze.move(). * @return {boolean} True if there is a path. */ var isPath=function(direction,id){ var effectiveDirection = actor.direction + direction; var square; var command; switch (constrainDirection4(effectiveDirection)) { case DirectionType.NORTH: square = map[actor.y - 1] && map[actor.y - 1][actor.x]; command = 'look_north'; break; case DirectionType.EAST: square = map[actor.y][actor.x + 1]; command = 'look_east'; break; case DirectionType.SOUTH: square = map[actor.y + 1] && map[actor.y + 1][actor.x]; command = 'look_south'; break; case DirectionType.WEST: square = map[actor.y][actor.x - 1]; command = 'look_west'; break; } if (id) { return [command , square !== maze.SquareType.WALL && square !== undefined && square !== maze.SquareType.BARRIER && square !== maze.SquareType.OIL_STATION && square !== maze.SquareType.TRAFFIC_LIGHT && square !== maze.SquareType.LIGHT_RED && square !== maze.SquareType.LIGHT_GREEN] } return square !== maze.SquareType.WALL && square !== undefined && square !== maze.SquareType.BARRIER && square !== maze.SquareType.OIL_STATION && square !== maze.SquareType.TRAFFIC_LIGHT && square !== maze.SquareType.LIGHT_RED && square !== maze.SquareType.LIGHT_GREEN; }; var constrainDirection4 = function(d) { d = Math.round(d) % 4; if (d < 0) { d += 4; } return d; }; var constrainDirection16 = function(d) { d = Math.round(d) % 16; if (d < 0) { d += 16; } return d; }; /** * Attempt to move pegman forward or backward. * @param {number} direction Direction to move . * @param {string} id ID of block that triggered this action. * @throws {true} If the end of the maze is reached. * @throws {false} If Pegman collides with a wall. */ var move = function(direction) { if (!isPath(0, null)) { return false } var command; switch (constrainDirection4(direction)) { case DirectionType.NORTH: command = 'north'; break; case DirectionType.EAST: command = 'east'; break; case DirectionType.SOUTH: command = 'south'; break; case DirectionType.WEST: command = 'west'; break; } return command }; /** * Turn pegman left or right. * @param {number} direction Direction to turn (0 = left, 1 = right). * @param {string} id ID of block that triggered this action. */ var turn = function(direction) { var command; if (direction=='right') { // Right turn (clockwise). command='right' } else { // Left turn (counterclockwise). command='left' } return command }; /** * Schedule the animations for a move or turn. * @param {!Array.} startPos X, Y starting points. * @param {!Array.} endPos X, Y ending points. */ var schedule = function(startPos, endPos) { var deltas = [(endPos[0] - startPos[0]) / 4, (endPos[1] - startPos[1]) / 4, (endPos[2] - startPos[2]) / 4]; displayPegman(startPos[0] + deltas[0], startPos[1] + deltas[1], constrainDirection16(startPos[2] + deltas[2])); setTimeout(function() { displayPegman(startPos[0] + deltas[0] * 2, startPos[1] + deltas[1] * 2, constrainDirection16(startPos[2] + deltas[2] * 2)); }, actor.stepSpeed); setTimeout(function() { displayPegman(startPos[0] + deltas[0] * 3, startPos[1] + deltas[1] * 3, constrainDirection16(startPos[2] + deltas[2] * 3)); }, actor.stepSpeed * 2) setTimeout(function() { displayPegman(endPos[0], endPos[1], constrainDirection16(endPos[2])); }, actor.stepSpeed * 3) }; /** * 检查精灵在移动的过程中是否吃到了金币 * @param {} x 当前精灵的横坐标. * @param {} y 当前精灵的纵坐标. */ var hasCoin=function(x , y) { if(map[y][x]==maze.SquareType.AWARD){//如果此处是金币 setTimeout(function() { $(Sk.TurtleGraphics.target).find('#coin'+y+x).remove() }, actor.stepSpeed * 3) map[y][x]=maze.SquareType.OPEN actor.coin_point+=1 } } /** * 检查精灵在移动的过程中是否走到了标记处 * @param {} x 当前精灵的横坐标. * @param {} y 当前精灵的纵坐标. */ var hasMarker=function(x , y) { if((map[y][x]==maze.SquareType.MARKER1)||(map[y][x]==maze.SquareType.MARKER2)||(map[y][x]==maze.SquareType.MARKER3)||(map[y][x]==maze.SquareType.MARKER4)){//如果此处是标记 actor.marker_num+=1 } } /** * 检查精灵在移动的过程中是否走到不可见的标记点(INVIMAKER)处 * @param {} x 当前精灵的横坐标. * @param {} y 当前精灵的纵坐标. */ var hasInviMarker=function(x , y) { if(map[y][x]==maze.SquareType.INVIMAKER){//如果此处是标记 actor.invisible_mark+=1 } } //高亮辅助函数 var highlight = function(id) { id=Sk.ffi.remapToJs(id) Mixly.Editor.blockEditor.highlightBlock(id); }; /** * 设置地图属性. * * @param {number} M_x为地图横向方格的数目(范围为3-10),初始默认为8 * @param {number} M_y为地图竖向方格的数目(范围为3-10),初始默认为8 * @param {string} startPos X, Y 起点位置的坐标. * @param {string} endPos X, Y 终点位置的坐标 * @param {string} bg_pic为地图背景的图片 */ var setMap_f=function( M_x , M_y , startPos , endPos , bg_pic) { Sk.builtin.pyCheckArgs("setMap", arguments, 5, 5); map=[] if(bg_pic=='无可用地图'){ bg_pic="" } if((M_x<3) || (M_x>20) || (M_y<3) || (M_y>20)){ throw new Sk.builtin.TypeError("错误!超出地图可设置范围,请设置横纵方格数大于等于3,小于等于20"); } M_x = Sk.ffi.remapToJs(M_x); M_y = Sk.ffi.remapToJs(M_y); maze_COLS=M_x; maze_ROWS=M_y; maze.MAZE_WIDTH= maze_SQUARE_SIZE * maze_COLS; maze.MAZE_HEIGHT=maze_SQUARE_SIZE * maze_ROWS; startPos =Sk.ffi.remapToJs(startPos) endPos =Sk.ffi.remapToJs(endPos) switch (Sk.ffi.remapToJs(bg_pic)){ case "bg_default": maze.background ='../common/js/skulpt_mixcar/pic/bg_default.png';//默认为方格 break; case "bg_astro": maze.background ='../common/js/skulpt_mixcar/pic/bg_astro.jpg';//设置为管道 break; case "bg_panda": maze.background ='../common/js/skulpt_mixcar/pic/bg_panda.jpg';//设置为竹子 break; } var re=/\((\d+),(\d+)\)/.exec(startPos); if(re!=null){ if((re[1]>M_x) || (re[1]<1) || (re[2]>M_y) || (re[2]<1)){ throw new Sk.builtin.TypeError("错误!起点坐标超出地图范围!"); } } var re=/\((\d+),(\d+)\)/.exec(endPos); if(re!=null){ if((re[1]>M_x) || (re[1]<1) || (re[2]>M_y) || (re[2]<1)){ throw new Sk.builtin.TypeError("错误!终点坐标超出地图范围!"); } } for (var i=0; i(map[0].length)) || (Pos_x< 0) || (Pos_y>(map.length)) || (Pos_y< 0)){ throw new Sk.builtin.TypeError("错误!放置物坐标超过地图范围"); } switch(type){ case "wall"://墙:障碍 map[Pos_y-1][Pos_x-1]=maze.SquareType.WALL; break; case "coin": map[Pos_y-1][Pos_x-1]=maze.SquareType.AWARD; break; } } mod.placeItem = new Sk.builtin.func(placeItem_f); /** * 初始化地图 */ var initMap_f=function() { drawMap() } mod.initMap = new Sk.builtin.func(initMap_f); var isDone = function(block_id) { return new Promise((resolve) => { // Do things setTimeout( () => { var re=/block_id=([\s\S]*)/.exec(block_id) if(re!=null){ block_id=re[1]; highlight(block_id) } highlight(block_id) var isdone= Sk.ffi.remapToPy(checkFinish()); resolve(isdone); }, 800); }) } var isPathCheck=function(direction,block_id) { return new Promise((resolve) => { // Do things setTimeout( () => { var state=""; var re=/block_id=([\s\S]*)/.exec(block_id) if(re!=null){ block_id=re[1]; highlight(block_id) } highlight(block_id); switch (direction) { case 'left': direction= 3 state=isPath(direction, null) break; case 'right': direction= 1 state=isPath(direction, null) break; }; resolve(Sk.ffi.remapToPy(state)); }, 800); }) } var isBarrierCheck=function(direction,block_id) { return new Promise((resolve) => { // Do things setTimeout( () => { var state=false; var square=0; var re=/block_id=([\s\S]*)/.exec(block_id) if(re!=null){ block_id=re[1]; highlight(block_id) } highlight(block_id); switch (direction) { case DirectionType.NORTH: if(map[actor.y - 1]){ square = map[actor.y - 1][actor.x]; }else{ square = 0 } break; case DirectionType.EAST: if(map[actor.y][actor.x + 1]){ square = map[actor.y][actor.x + 1]; }else{ square = 0 } break; case DirectionType.SOUTH: if(map[actor.y + 1]){ square = map[actor.y + 1][actor.x]; }else{ square = 0 } break; case DirectionType.WEST: if(map[actor.y][actor.x - 1]){ square = map[actor.y][actor.x - 1]; }else{ square = 0 } break; }; state= square == maze.SquareType.BARRIER; resolve(Sk.ffi.remapToPy(state)); }, 800); }) } var isOilFullCheck=function(block_id) { return new Promise((resolve) => { // Do things setTimeout( () => { var state=false; var re=/block_id=([\s\S]*)/.exec(block_id) if(re!=null){ block_id=re[1]; highlight(block_id) } highlight(block_id); if(actor.oil==0){//没油了,返回需要加油为True resolve(Sk.ffi.remapToPy(true)); }else if(actor.oil==1){//还有油,返回需要加油为False resolve(Sk.ffi.remapToPy(false)); } }, 800); }) } var getpoint= function(block_id){ return new Promise((resolve) => { // Do things setTimeout( () => { var re=/block_id=([\s\S]*)/.exec(block_id) if(re!=null){ block_id=re[1]; highlight(block_id) } highlight(block_id) var point= actor.coin_point; resolve(Sk.ffi.remapToPy(point)); }, 800); }) } var checkLightGreen=function(block_id){ return new Promise((resolve) => { // Do things setTimeout( () => { var re=/block_id=([\s\S]*)/.exec(block_id) if(re!=null){ block_id=re[1]; highlight(block_id) } highlight(block_id) if(actor.traffic_light==maze.SquareType.LIGHT_GREEN){//绿灯,返回 true resolve(Sk.ffi.remapToPy(true)); }else if(actor.traffic_light==maze.SquareType.LIGHT_RED){//红灯,返回false resolve(Sk.ffi.remapToPy(false)); } }, 800); }) } mod.Actor = Sk.misceval.buildClass(mod, function($gbl, $loc) { $loc.__init__ = new Sk.builtin.func(function(self,img , direction ,block_id) { return new Sk.misceval.promiseToSuspension(new Promise(function(resolve) { Sk.setTimeout(function() { img= Sk.ffi.remapToJs(img) || 'pegman'; if(img=='无可用角色'){ img='pegman'; } switch (img){ case "pegman": actor.img='../common/js/skulpt_mixcar/pic/pegman.png';//默认为方格 actor.type="animate" break; case "panda": actor.img='../common/js/skulpt_mixcar/pic/panda.png';//设置为管道 actor.type="animate" break; case "astro": actor.img='../common/js/skulpt_mixcar/pic/astro.png';//设置为竹子 actor.type="animate" break; case "robot": actor.img='../common/js/skulpt_mixcar/pic/robot.png';//设置为机器人 actor.type="still" break; case "car": actor.img='../common/js/skulpt_mixcar/pic/actor_car3.png';//设置为小车 actor.type="animate" break; } actor.direction = Sk.ffi.remapToJs(direction) || DirectionType.NORTH; size=[52,49]//[height,width]//size需要根据方格的数目来确定 actor.coin_point=0 //高亮效果 var re=/block_id=([\s\S]*)/.exec(block_id) if(re!=null){ block_id=re[1]; highlight(block_id) } initPegman() resolve(Sk.builtin.none.none$); }, 800); })); }); //向某个方向移动移动 //暂时只实现了移动一步 //func: Actor.moveDirection() $loc.moveDirection=new Sk.builtin.func(function(self,direction,block_id) { Sk.builtin.pyCheckArgs("moveDirection", arguments, 3,3); return new Sk.misceval.promiseToSuspension(new Promise(function(resolve) { Sk.setTimeout(function() { actor.direction = parseInt(Sk.ffi.remapToJs(direction)); var command= move(direction) //向某个方向移动 if(command==false){ maze.result=ResultType.FAILURE layer.alert("挑战失败!请修改后重新尝试", { shade: false }) throw new Sk.builtin.TypeError("挑战失败!请修改后重新尝试"); } if(maze.mlevel==4){//如果是第四关,则需要判断是否需要加油的问题 //如果左侧存在加油站 // if((map[actor.y - 1][actor.x])==maze.SquareType.OIL_STATION||(map[actor.y + 1][actor.x])==maze.SquareType.OIL_STATION||(map[actor.y ][actor.x-1])==maze.SquareType.OIL_STATION||(map[actor.y ][actor.x+1])==maze.SquareType.OIL_STATION){ if((map[actor.y][actor.x-1])==maze.SquareType.OIL_STATION){ if(actor.oil==0){//在加油站处,如果没有油还想继续往前面走 maze.result=ResultType.FAILURE svg.append('image').attr('id','caroil').attr('x',maze_SQUARE_SIZE).attr('y',3.5 * maze_SQUARE_SIZE).attr('width',maze_SQUARE_SIZE).attr('height',maze_SQUARE_SIZE) .attr('xlink:href','../common/js/skulpt_mixcar/pic/no_oil.png') layer.alert("挑战失败!小车没有油了", { shade: false }) throw new Sk.builtin.TypeError("挑战失败!小车没有油了"); } } }else if(maze.mlevel==5){//如果是第五关,则需要记录循环次数;每次经过起点处循环次数+1 if((map[actor.y][actor.x])==maze.SquareType.START){ actor.circulation_num+=1; } }else if(maze.mlevel==7){//如果是第七关,则需要判断红绿灯是否为绿灯的问题 if(actor.traffic_light==maze.SquareType.LIGHT_RED){ layer.alert("挑战失败:小车在红灯亮时还未停止!", { shade: false }); throw new Sk.builtin.TypeError("挑战失败:小车在红灯亮时还未停止!"); } } switch (command) { case 'north': schedule([actor.x, actor.y, actor.direction * 4], [actor.x, actor.y - 1, actor.direction * 4]); actor.y--; break; case 'east': schedule([actor.x, actor.y, actor.direction * 4], [actor.x + 1, actor.y, actor.direction * 4]); actor.x++; break; case 'south': schedule([actor.x, actor.y, actor.direction * 4], [actor.x, actor.y + 1, actor.direction * 4]); actor.y++; break; case 'west': schedule([actor.x, actor.y, actor.direction * 4], [actor.x - 1, actor.y, actor.direction * 4]); actor.x--; break; } //高亮效果 var re=/block_id=([\s\S]*)/.exec(block_id) if(re!=null){ block_id=re[1]; highlight(block_id) } hasCoin(actor.x,actor.y) hasMarker(actor.x,actor.y) hasInviMarker(actor.x,actor.y) if(maze.mlevel==7){//如果是第七关,则需要随机改变红绿灯的颜色 if((map[actor.y][actor.x+1])==maze.SquareType.LIGHT_RED || (map[actor.y][actor.x+1])==maze.SquareType.LIGHT_GREEN){ map[actor.y][actor.x+1]=Math.random()>0.5? maze.SquareType.LIGHT_RED:maze.SquareType.LIGHT_GREEN;//随机刷新红绿灯的状态 actor.traffic_light=map[actor.y][actor.x+1]; if(actor.traffic_light==maze.SquareType.LIGHT_RED){//图像变为红灯 const elem = Sk.TurtleGraphics.target.querySelector("#lightgreen"); d3.select(elem).remove(); svg.append('image').attr('id','lightred').attr('x',(actor.x+1) * maze_SQUARE_SIZE-5).attr('y',actor.y * maze_SQUARE_SIZE+5).attr('width',maze_SQUARE_SIZE).attr('height',maze_SQUARE_SIZE) .attr('xlink:href','../common/js/skulpt_mixcar/pic/redlight.png') } } } var state=checkFinish() if(state=="error2"){ maze.result=ResultType.FAILURE layer.alert("挑战失败,请检查是否通过所有标记点!", { shade: false }) throw new Sk.builtin.TypeError("挑战失败,请检查是否通过所有标记点!"); }else if(state=="error3"){ layer.alert("挑战失败,请修改后重新尝试!", { shade: false }) throw new Sk.builtin.TypeError("挑战失败!请修改后重新尝试"); } resolve(Sk.builtin.none.none$); }, 800); })); }); $loc.turn=new Sk.builtin.func(function(self,direction,block_id){ Sk.builtin.pyCheckArgs("turn", arguments, 3, 3); Sk.builtin.pyCheckType("direction", "string", Sk.builtin.checkString(direction)); return new Sk.misceval.promiseToSuspension(new Promise(function(resolve) { Sk.setTimeout(function() { direction=Sk.ffi.remapToJs(direction) var command=turn(direction) switch (command) { case 'left': schedule([actor.x, actor.y, actor.direction * 4], [actor.x, actor.y, actor.direction * 4 - 4]); actor.direction = constrainDirection4(actor.direction - 1); break; case 'right': schedule([actor.x, actor.y, actor.direction * 4], [actor.x, actor.y, actor.direction * 4 + 4]); actor.direction = constrainDirection4(actor.direction + 1); break; } var re=/block_id=([\s\S]*)/.exec(block_id) if(re!=null){ block_id=re[1]; highlight(block_id) } resolve(Sk.builtin.none.none$); }, 800); })); }); $loc.isDone=new Sk.builtin.func(function(self,block_id){ Sk.builtin.pyCheckArgs("isDone", arguments, 2, 2); return new Sk.misceval.promiseToSuspension(isDone(block_id).then((r) => Sk.ffi.remapToPy(r))); }); $loc.isPath=new Sk.builtin.func(function(self,direction){ Sk.builtin.pyCheckArgs("isPath", arguments, 2, 2); Sk.builtin.pyCheckType("direction", "string", Sk.builtin.checkString(direction)); direction=Sk.ffi.remapToJs(direction) return new Sk.misceval.promiseToSuspension(isPathCheck(direction,block_id).then((r) => Sk.ffi.remapToPy(r))); }); //判断某个方向是否存在障碍物 $loc.isBarrier=new Sk.builtin.func(function(self,direction,block_id){ Sk.builtin.pyCheckArgs("isBarrier", arguments, 3, 3); Sk.builtin.pyCheckType("direction", "number", Sk.builtin.checkNumber(direction)); direction=Sk.ffi.remapToJs(direction) return new Sk.misceval.promiseToSuspension(isBarrierCheck(direction,block_id).then((r) => Sk.ffi.remapToPy(r))); }); //随机生成小车油量 $loc.randomOil=new Sk.builtin.func(function(self,block_id){ Sk.builtin.pyCheckArgs("randomOil", arguments, 2, 2); return new Sk.misceval.promiseToSuspension(new Promise(function(resolve) { Sk.setTimeout(function() { actor.oil=Math.random()>0.5?1:0;//随机初始化汽车的油量 if(actor.oil==0){//没油(呈现少量油的图片) svg.append('image').attr('id','caroil').attr('x',maze_SQUARE_SIZE).attr('y',3.5 * maze_SQUARE_SIZE).attr('width',maze_SQUARE_SIZE).attr('height',maze_SQUARE_SIZE) .attr('xlink:href','../common/js/skulpt_mixcar/pic/none_oil.png') }else if(actor.oil==1){//油量充足(呈现油量充足的图片) svg.append('image').attr('id','caroil').attr('x',maze_SQUARE_SIZE).attr('y',3.5 * maze_SQUARE_SIZE).attr('width',maze_SQUARE_SIZE).attr('height',maze_SQUARE_SIZE) .attr('xlink:href','../common/js/skulpt_mixcar/pic/full_oil.png') } var re=/block_id=([\s\S]*)/.exec(block_id) if(re!=null){ block_id=re[1]; highlight(block_id) } resolve(Sk.builtin.none.none$); }, 800); })); }); //判断是否需要加油 $loc.isOilFull=new Sk.builtin.func(function(self,block_id){ Sk.builtin.pyCheckArgs("isOilFull", arguments, 2, 2); return new Sk.misceval.promiseToSuspension(isOilFullCheck(block_id).then((r) => Sk.ffi.remapToPy(r))); }); //进加油站加油 $loc.addOil=new Sk.builtin.func(function(self,block_id){ Sk.builtin.pyCheckArgs("addOil", arguments, 2, 2); return new Sk.misceval.promiseToSuspension(new Promise(function(resolve) { Sk.setTimeout(function() { svg.append('image').attr('id','caroil').attr('x',maze_SQUARE_SIZE).attr('y',3.5 * maze_SQUARE_SIZE).attr('width',maze_SQUARE_SIZE).attr('height',maze_SQUARE_SIZE) .attr('xlink:href','../common/js/skulpt_mixcar/pic/full_oil.png') actor.oil=1//油量充足 var re=/block_id=([\s\S]*)/.exec(block_id) if(re!=null){ block_id=re[1]; highlight(block_id) } resolve(Sk.builtin.none.none$); }, 800); })); }); //获取角色当前的分数 $loc.getPoint=new Sk.builtin.func(function(self,block_id){ Sk.builtin.pyCheckArgs("getPoint", arguments, 2, 2); return new Sk.misceval.promiseToSuspension(getpoint(block_id).then((r) => Sk.ffi.remapToPy(r))); }); //判断信号灯是否为绿灯? $loc.isLightGreen=new Sk.builtin.func(function(self,block_id){ Sk.builtin.pyCheckArgs("isLightGreen", arguments, 2, 2); return new Sk.misceval.promiseToSuspension(checkLightGreen(block_id).then((r) => Sk.ffi.remapToPy(r))); }); //检查循环的次数是否正确 $loc.isCirculationRight=new Sk.builtin.func(function(self){ Sk.builtin.pyCheckArgs("isCirculationRight", arguments, 1, 1); return new Sk.misceval.promiseToSuspension(new Promise(function(resolve) { Sk.setTimeout(function() { var mlevel=maze.mlevel;//获取当前关卡序数 var state=false; switch (mlevel){ case 5://第五关 state=actor.circulation_num==3?true:false; break; case 7://第七关 if(actor.traffic_light==maze.SquareType.LIGHT_GREEN){//如果是绿灯,则怎么都算失败 state=false; }else if(actor.traffic_light==maze.SquareType.LIGHT_RED){//如果是红灯 for (var y = 0; y < maze.map.length; y++) { for (var x = 0; x < maze.map[0].length; x++) { if(maze.map[y][x]==maze.SquareType.LIGHT_RED){ if((actor.x+1)==x|| (actor.y)==y){//如果小车停的位置在红绿灯的左边,则挑战成功 state=true; } } } } } break; } if(state==false){ maze.result=ResultType.FAILURE layer.alert("挑战失败,请检查循环次数是否正确!", { shade: false }) throw new Sk.builtin.TypeError("挑战失败,请检查循环次数是否正确!"); }else{ maze.result=ResultType.SUCCESS resolve(Sk.builtin.none.none$); } }, 800); })) }); //检查是否挑战成功 $loc.isSuccess=new Sk.builtin.func(function(self){ Sk.builtin.pyCheckArgs("isSuccess", arguments, 1,1); return new Sk.misceval.promiseToSuspension(new Promise(function(resolve) { var state=checkFinish() if(state==true){ setTimeout(function() { layer.alert("挑战成功!", { shade: false }); },1000) resolve(Sk.builtin.none.none$); }else if(state==false){//没有到达终点就游戏结束,或者超过了终点 maze.result=ResultType.FAILURE layer.alert("挑战失败,请检查是否到达终点!", { shade: false }) throw new Sk.builtin.TypeError("挑战失败,请检查是否到达终点!"); } })) }) }, "Actor") /** * 初始化为设定好的地图 * * @param {number} level 初始化地图,level为地图的等级. * @param {string} block_id 图形块ID. */ var settedMap_f=function(level,block_id) { return new Sk.misceval.promiseToSuspension(new Promise(function(resolve) { Sk.setTimeout(function() { //高亮效果 var re=/block_id=([\s\S]*)/.exec(block_id) if(re!=null){ block_id=re[1]; highlight(block_id) } level=Sk.ffi.remapToJs(level) maze=MAZE_setted[level] map=MAZE_setted[level].map drawMap() resolve(Sk.builtin.none.none$); }, 800); })); } mod.settedMap = new Sk.builtin.func(settedMap_f); return mod; }