How to use pingPong method in wpt

Best JavaScript code snippet using wpt

block_pingpong_multi.js

Source:block_pingpong_multi.js Github

copy

Full Screen

1'use strict';2const Buffer = require('buffer').Buffer;3const OPCODE = {4 SINGLE_STEPS: 0xc1,5 SCHEDULED_STEPS: 0xca,6 SCHEDULED_POINTS: 0xcb,7 CONTINUOUS_STEPS: 0xcc,8 AGGREGATE_STEPS: 0xcd,9 LEDMATRIX: 0xa2,10 SERVO: 0xe1,11 MUSIC: 0xe8,12};13const METHOD = {14 CONTINOUS: 0,15 RELATIVE_SINGLE: 1,16 ABSOLUTE_SINGLE: 2,17 SCHED_STEPS: 3,18 sCHED_POINT: 4,19};20const MODE = {21 MULTIROLE: 2,22 CHECKCRC: 3,23};24const PROPERTY = {25 PERI: 0x01,26 MULTI: 0x02,27 PORT: 0x80,28 ADDRESS: 0x70,29 PAUSE: 1,30 RESUME: 2,31 MUSIC_PLAY: 0,32};33const DEFAULT_TEMPO = 60;34class PingpongBase {35 constructor(cubecnt) {36 this.TILT_THRESHOLD = 20;37 this.MOVE_THRESHOLD = 30;38 this.delayTime = 100;39 this.send_cmd_id = 0;40 this.cubeCnt = cubecnt || 2;41 this.tempo = DEFAULT_TEMPO;42 this.communicationType = 'manual';43 this.prev_sensor_data = {44 c0_TILT_X: false,45 c0_TILT_Y: false,46 c0_BUTTON: 0,47 c1_TILT_X: false,48 c1_TILT_Y: false,49 c1_BUTTON: 0,50 c2_TILT_X: false,51 c2_TILT_Y: false,52 c2_BUTTON: 0,53 c3_TILT_X: false,54 c3_TILT_Y: false,55 c3_BUTTON: 0,56 };57 this.lang_defblock = {58 ko: {59 pingpong_right: '오른쪽',60 pingpong_left: '왼쪽',61 pingpong_rotate_cw: '시계',62 pingpong_rotate_ccw: '반시계',63 pingpong_sensor_proximity: '근접',64 pingpong_sensor_ain: '아날로그',65 pingpong_dot_on: '켜기',66 pingpong_dot_off: '끄기',67 pingpong_opts_cube_tiltDir: [68 ['동그라미', 'F_CIRCLE'],69 ['세모', 'B_TRIANGLE'],70 ['네모', 'L_RECTANGLE'],71 ['별', 'R_STAR'],72 ],73 pingpong_opts_cube_dir6: [74 ['네모', 'DF_RECTANGLE'],75 ['별', 'DB_STAR'],76 ['세모', 'DL_TRIANGLE'],77 ['동그라미', 'DR_CIRCLE'],78 ['하트', 'DU_HEART'],79 ['빈칸', 'DD_NONE'],80 ],81 pingpong_opts_music_notes: [82 ['라 (A3)', 45],83 ['라# (A3#)', 46],84 ['시 (B3)', 47],85 ['도 (C4)', 48],86 ['도# (C4#)', 49],87 ['레 (D4)', 50],88 ['레# (D4#)', 51],89 ['미 (E4)', 52],90 ['파 (F4)', 53],91 ['파# (F4#)', 54],92 ['솔 (G4)', 55],93 ['솔# (G4#)', 56],94 ['라 (A4)', 57],95 ['라# (A4#)', 58],96 ['시 (B4)', 59],97 ['도 (C5)', 60],98 ['도# (C5#)', 61],99 ['레 (D5)', 62],100 ['레# (D5#)', 63],101 ['미 (E5)', 64],102 ['파 (F5)', 65],103 ['파# (F5#)', 66],104 ['솔 (G5)', 67],105 ['솔# (G5#)', 68],106 ['라 (A5)', 69],107 ['라# (A5#)', 70],108 ['시 (B5)', 71],109 ['도 (C6)', 72],110 ],111 },112 en: {113 pingpong_right: 'right',114 pingpong_left: 'left',115 pingpong_rotate_cw: 'clockwise',116 pingpong_rotate_ccw: 'counter clockwise',117 pingpong_sensor_proximity: 'proximity',118 pingpong_sensor_ain: 'ain',119 pingpong_dot_on: 'ON',120 pingpong_dot_off: 'OFF',121 pingpong_opts_cube_tiltDir: [122 ['circle', 'F_CIRCLE'],123 ['triangle', 'B_TRIANGLE'],124 ['rectangle', 'L_RECTANGLE'],125 ['star', 'R_STAR'],126 ],127 pingpong_opts_cube_dir6: [128 ['rectangle', 'DF_RECTANGLE'],129 ['star', 'B_STAR'],130 ['triangle', 'L_TRIANGLE'],131 ['circle', 'R_CIRCLE'],132 ['heart', 'U_HEART'],133 ['none', 'D_NONE'],134 ],135 pingpong_opts_music_notes: [136 ['La (A3)', 45],137 ['La# (A3#)', 46],138 ['Ti (B3)', 47],139 ['Do (C4)', 48],140 ['Do# (C4#)', 49],141 ['Re (D4)', 50],142 ['Re# (D4#)', 51],143 ['Mi (E4)', 52],144 ['Fa (F4)', 53],145 ['Fa# (F4#)', 54],146 ['Sol (G4)', 55],147 ['Sol#(G4#)', 56],148 ['La (A4)', 57],149 ['La# (A4#)', 58],150 ['Ti (B4)', 59],151 ['Do (C5)', 60],152 ['Do# (C5#)', 61],153 ['Re (D5)', 62],154 ['Re# (D5#)', 63],155 ['Mi (E5)', 64],156 ['Fa (F5)', 65],157 ['Fa# (F5#)', 66],158 ['Sol (G5)', 67],159 ['Sol#(G5#)', 68],160 ['La (A5)', 69],161 ['La# (A5#)', 70],162 ['Ti (B5)', 71],163 ['Do (C6)', 72],164 ],165 },166 };167 }168 setZero() {169 this.tempo = DEFAULT_TEMPO;170 this.sendCommand(this.makePacket(OPCODE.LEDMATRIX, 0xe3, -1, [0x70, 1, 0, ' ']));171 setTimeout(() => {172 this.sendCommand(this.makePacket(OPCODE.CONTINUOUS_STEPS, 0, -1, [2, 0, 0, 1, 0, 0]));173 setTimeout(() => {174 RoCode.hw.sendQueue.COMMAND = {175 id: -1,176 };177 RoCode.hw.update();178 this.send_cmd_id = 0;179 }, this.delayTime);180 }, this.delayTime);181 }182 sendCommand(packet) {183 RoCode.hw.sendQueue.COMMAND = {184 id: ++this.send_cmd_id,185 data: packet,186 };187 RoCode.hw.update();188 }189 afterReceive(pd) {190 if (!RoCode.engine.isState('run')) {191 return;192 }193 if (194 this.prev_sensor_data.c0_BUTTON != pd.c0_BUTTON ||195 this.prev_sensor_data.c1_BUTTON != pd.c1_BUTTON ||196 this.prev_sensor_data.c2_BUTTON != pd.c2_BUTTON ||197 this.prev_sensor_data.c3_BUTTON != pd.c3_BUTTON198 ) {199 RoCode.engine.fireEvent('pp_when_button_pressed');200 this.prev_sensor_data.c0_BUTTON = pd.c0_BUTTON;201 this.prev_sensor_data.c1_BUTTON = pd.c1_BUTTON;202 this.prev_sensor_data.c2_BUTTON = pd.c2_BUTTON;203 this.prev_sensor_data.c3_BUTTON = pd.c3_BUTTON;204 }205 const tiltXc0 = Math.abs(pd.c0_TILT_X) >= this.TILT_THRESHOLD;206 const tiltYc0 = Math.abs(pd.c0_TILT_Y) >= this.TILT_THRESHOLD;207 const tiltXc1 = Math.abs(pd.c1_TILT_X) >= this.TILT_THRESHOLD;208 const tiltYc1 = Math.abs(pd.c1_TILT_Y) >= this.TILT_THRESHOLD;209 const tiltXc2 = Math.abs(pd.c2_TILT_X) >= this.TILT_THRESHOLD;210 const tiltYc2 = Math.abs(pd.c2_TILT_Y) >= this.TILT_THRESHOLD;211 const tiltXc3 = Math.abs(pd.c3_TILT_X) >= this.TILT_THRESHOLD;212 const tiltYc3 = Math.abs(pd.c3_TILT_Y) >= this.TILT_THRESHOLD;213 if (214 tiltXc0 != this.prev_sensor_data.c0_TILT_X ||215 tiltYc0 != this.prev_sensor_data.c0_TILT_Y ||216 tiltXc1 != this.prev_sensor_data.c1_TILT_X ||217 tiltYc1 != this.prev_sensor_data.c1_TILT_Y ||218 tiltXc2 != this.prev_sensor_data.c2_TILT_X ||219 tiltYc2 != this.prev_sensor_data.c2_TILT_Y ||220 tiltXc3 != this.prev_sensor_data.c3_TILT_X ||221 tiltYc3 != this.prev_sensor_data.c3_TILT_Y222 ) {223 RoCode.engine.fireEvent('pp_when_tilted');224 }225 this.prev_sensor_data.c0_TILT_X = tiltXc0;226 this.prev_sensor_data.c0_TILT_Y = tiltYc0;227 this.prev_sensor_data.c1_TILT_X = tiltXc1;228 this.prev_sensor_data.c1_TILT_Y = tiltYc1;229 this.prev_sensor_data.c2_TILT_X = tiltXc2;230 this.prev_sensor_data.c2_TILT_Y = tiltYc2;231 this.prev_sensor_data.c3_TILT_X = tiltXc3;232 this.prev_sensor_data.c3_TILT_Y = tiltYc3;233 }234 postCallReturn(script, myfunc) {235 if (myfunc == undefined) {236 return script.callReturn();237 }238 if (script.is_start == undefined) {239 script.is_start = true;240 const [packet, waitTime = this.delayTime] = myfunc();241 if (packet && packet.length > 0) {242 this.sendCommand(packet);243 }244 setTimeout(() => {245 script.is_start = false;246 }, waitTime);247 return script;248 } else if (script.is_start == true) {249 return script;250 } else {251 delete script.is_start;252 //RoCode.engine.isContinue = false;253 return script.callReturn();254 }255 }256 makePacket(opcode, taskid, cubeNo, opt) {257 // make heder ( cubeid, cubecnt, op, size, method258 const header = Buffer.from([0xff, 0xff, 0xff, 0xff, 0, 0, opcode, 0, 0]);259 const property = Buffer.from(opt);260 //header.writeUInt16BE(0xFFFF, 0);261 //header.writeUInt16BE(0xFFFF, 2); // cubdid262 if (cubeNo <= -1) {263 header[3] = 0xff;264 } else {265 header[3] = cubeNo;266 }267 header.writeUInt16BE(taskid, 4);268 header.writeUInt16BE(header.length + property.length, 7);269 return Buffer.concat([header, property]);270 }271 _fillPacketIntoArray(data, opcode, taskid, cubeNo, size) {272 data[0] = 0xff;273 data[1] = 0xff;274 data[2] = 0xff;275 if (cubeNo <= -1) {276 data[3] = 0xff;277 } else {278 data[3] = cubeNo;279 }280 data[4] = taskid / 256;281 data[5] = taskid % 256;282 data[6] = opcode;283 data[7] = size / 256;284 data[8] = size % 256;285 }286 makeSingleStepPacket(cubeNo, speed, degree) {287 const packet = new Uint8Array(9 + 10);288 this._fillPacketIntoArray(packet, OPCODE.SINGLE_STEPS, 0 /*cubeCnt*/, cubeNo, 19);289 const sps = this._calcSpsFromSpeed(speed);290 let step = Math.round(Math.min(Math.max(degree, 0), 5000) * 5.5);291 if (step > 32768) {292 step = 32768;293 }294 packet[9] = MODE.MULTIROLE;295 packet[10] = METHOD.RELATIVE_SINGLE;296 packet[11] = 0; //step_type; full=0, servo=4297 packet[12] = PROPERTY.RESUME;298 packet[13] = sps / 256;299 packet[14] = sps % 256;300 packet[15] = 0;301 packet[16] = 0;302 packet[17] = step / 256;303 packet[18] = step % 256;304 const waitTime = Math.round(((1000 - Math.abs(speed) * 9) / 99) * step) + 400;305 return [packet, waitTime];306 }307 makeContStepPacket(cubeNo, speed) {308 const packet = new Uint8Array(9 + 6);309 this._fillPacketIntoArray(packet, OPCODE.CONTINUOUS_STEPS, 0, cubeNo, 15);310 const sps = this._calcSpsFromSpeed(speed);311 packet[9] = MODE.MULTIROLE;312 packet[10] = METHOD.CONTINOUS;313 packet[11] = 0; //step_type; full=0, servo=4314 if (sps == 0) {315 packet[12] = PROPERTY.PAUSE;316 packet[13] = 0;317 packet[14] = 0;318 } else {319 packet[12] = PROPERTY.RESUME;320 packet[13] = sps / 256;321 packet[14] = sps % 256;322 }323 return packet;324 }325 makeMusicNotePacket(cubeNo, note, duration) {326 const packet = new Uint8Array(9 + 5);327 this._fillPacketIntoArray(packet, OPCODE.MUSIC, 0xa1, cubeNo, 9 + 5);328 packet[9] = 0;329 packet[10] = PROPERTY.MUSIC_PLAY;330 packet[11] = note - 8;331 // type == 1332 packet[12] = duration;333 packet[13] = 0;334 return packet;335 }336 makeAggregatePacket(opcode, taskid, packets, opt = []) {337 let size = 9 + opt.length;338 let options = opt;339 let usedCubeIds = [];340 packets.forEach((n) => {341 size += n.length;342 Array.prototype.push.apply(options, n);343 usedCubeIds.push(n[3]);344 });345 // aggregate command must have cubeCount commands. add dummy packet346 if (packets.length < this.cubeCnt) {347 for (let i = 0; i < this.cubeCnt; i++) {348 if (usedCubeIds.includes(i) == false) {349 let dummyPacket = packets[0].slice();350 dummyPacket[3] = i;351 dummyPacket[6] = 0; // set opcode to zero352 Array.prototype.push.apply(options, dummyPacket);353 }354 }355 }356 const cmd = this.makePacket(opcode, (packets.length << 12) | taskid, 0xaa, options);357 return cmd;358 }359 _getTiltValue(cubeNo, tiltDir) {360 const pd = RoCode.hw.portData;361 let tiltValue = 0;362 if (cubeNo == 0) {363 if (tiltDir == 'F_CIRCLE') {364 tiltValue = pd.c0_TILT_X * -1;365 } else if (tiltDir == 'B_TRIANGLE') {366 tiltValue = pd.c0_TILT_X;367 } else if (tiltDir == 'L_RECTANGLE') {368 tiltValue = pd.c0_TILT_Y * -1;369 } else if (tiltDir == 'R_STAR') {370 tiltValue = pd.c0_TILT_Y;371 }372 } else if (cubeNo == 1) {373 if (tiltDir == 'F_CIRCLE') {374 tiltValue = pd.c1_TILT_X * -1;375 } else if (tiltDir == 'B_TRIANGLE') {376 tiltValue = pd.c1_TILT_X;377 } else if (tiltDir == 'L_RECTANGLE') {378 tiltValue = pd.c1_TILT_Y * -1;379 } else if (tiltDir == 'R_STAR') {380 tiltValue = pd.c1_TILT_Y;381 }382 } else if (cubeNo == 2) {383 if (tiltDir == 'F_CIRCLE') {384 tiltValue = pd.c2_TILT_X * -1;385 } else if (tiltDir == 'B_TRIANGLE') {386 tiltValue = pd.c2_TILT_X;387 } else if (tiltDir == 'L_RECTANGLE') {388 tiltValue = pd.c2_TILT_Y * -1;389 } else if (tiltDir == 'R_STAR') {390 tiltValue = pd.c2_TILT_Y;391 }392 } else if (cubeNo == 3) {393 if (tiltDir == 'F_CIRCLE') {394 tiltValue = pd.c3_TILT_X * -1;395 } else if (tiltDir == 'B_TRIANGLE') {396 tiltValue = pd.c3_TILT_X;397 } else if (tiltDir == 'L_RECTANGLE') {398 tiltValue = pd.c3_TILT_Y * -1;399 } else if (tiltDir == 'R_STAR') {400 tiltValue = pd.c3_TILT_Y;401 }402 }403 return tiltValue;404 }405 _isUpperDir(cubeNo, tiltDir) {406 const pd = RoCode.hw.portData;407 if (cubeNo == 0) {408 if (tiltDir == 'DF_RECTANGLE' && pd.c0_TILT_Y > 70) return true;409 if (tiltDir == 'DB_STAR' && pd.c0_TILT_Y < -70) return true;410 if (tiltDir == 'DR_CIRCLE' && pd.c0_TILT_X > 70) return true;411 if (tiltDir == 'DL_TRIANGLE' && pd.c0_TILT_X < -70) return true;412 if (tiltDir == 'DD_NONE' && pd.c0_TILT_Z > 70) return true;413 if (tiltDir == 'DU_HEART' && pd.c0_TILT_Z < -70) return true;414 return false;415 } else if (cubeNo == 1) {416 if (tiltDir == 'DF_RECTANGLE' && pd.c1_TILT_Y > 70) return true;417 if (tiltDir == 'DB_STAR' && pd.c1_TILT_Y < -70) return true;418 if (tiltDir == 'DR_CIRCLE' && pd.c1_TILT_X > 70) return true;419 if (tiltDir == 'DL_TRIANGLE' && pd.c1_TILT_X < -70) return true;420 if (tiltDir == 'DD_NONE' && pd.c1_TILT_Z > 70) return true;421 if (tiltDir == 'DU_HEART' && pd.c1_TILT_Z < -70) return true;422 return false;423 } else if (cubeNo == 2) {424 if (tiltDir == 'DF_RECTANGLE' && pd.c2_TILT_Y > 70) return true;425 if (tiltDir == 'DB_STAR' && pd.c2_TILT_Y < -70) return true;426 if (tiltDir == 'DR_CIRCLE' && pd.c2_TILT_X > 70) return true;427 if (tiltDir == 'DL_TRIANGLE' && pd.c2_TILT_X < -70) return true;428 if (tiltDir == 'DD_NONE' && pd.c2_TILT_Z > 70) return true;429 if (tiltDir == 'DU_HEART' && pd.c2_TILT_Z < -70) return true;430 return false;431 } else if (cubeNo == 3) {432 if (tiltDir == 'DF_RECTANGLE' && pd.c3_TILT_Y > 70) return true;433 if (tiltDir == 'DB_STAR' && pd.c3_TILT_Y < -70) return true;434 if (tiltDir == 'DR_CIRCLE' && pd.c3_TILT_X > 70) return true;435 if (tiltDir == 'DL_TRIANGLE' && pd.c3_TILT_X < -70) return true;436 if (tiltDir == 'DD_NONE' && pd.c3_TILT_Z > 70) return true;437 if (tiltDir == 'DU_HEART' && pd.c3_TILT_Z < -70) return true;438 return false;439 }440 }441 _getCubeNoFromBlock(script) {442 let cubeNo = script.getNumberValue('cubeno') - 1;443 if (cubeNo < 0) {444 cubeNo = 0;445 }446 if (cubeNo >= this.cubeCnt) {447 cubeNo = this.cubeCnt - 1;448 }449 return cubeNo;450 }451 _clampBeats(beats) {452 return Math.min(Math.max(beats, 0), 40);453 }454 _clampTempo(tempo) {455 return Math.min(Math.max(tempo, 20), 500);456 }457 _beatsToDuration(beats) {458 let duration = Math.round((60 / this.tempo) * beats * 100);459 return duration;460 }461 _calcSpsFromSpeed(speed_) {462 let speed = speed_;463 if (speed > 100) {464 speed = 100;465 }466 if (speed < -100) {467 speed = -100;468 }469 let sps = 0;470 if (speed != 0) {471 if (speed < 0) {472 sps = 65536 + (speed * 9 - 100);473 } else {474 sps = speed * 9 + 100;475 }476 sps = Math.round(sps);477 }478 return sps;479 }480}481RoCode.PingpongG2 = new (class extends PingpongBase {482 constructor() {483 super(2);484 this.id = '35.2';485 this.name = 'PingpongG2';486 this.url = 'https://www.roborisen.com';487 this.imageName = 'pingpong_g2.png';488 this.title = {489 ko: '핑퐁 G2',490 en: 'Pingpong G2',491 };492 this.blockMenuBlocks = [493 'pingpong_g2_when_button_pressed',494 'pingpong_g2_when_tilted',495 'pingpong_g2_is_button_pressed',496 'pingpong_g2_is_tilted',497 'pingpong_g2_get_tilt_value',498 'pingpong_g2_is_top_shape',499 'pingpong_g2_get_sensor_value',500 'pingpong_g2_multi_motor_rotate',501 'pingpong_g2_motor_rotate',502 'pingpong_g2_start_multi_motor_rotate',503 'pingpong_g2_start_motor_rotate',504 'pingpong_g2_stop_motor_rotate',505 'pingpong_g2_rotate_servo_mortor',506 'pingpong_g2_set_dot_pixel',507 'pingpong_g2_set_dot_string',508 'pingpong_g2_set_dot_clear',509 'pingpong_g2_playNoteForBeats',510 'pingpong_g2_playChordForBeats',511 'pingpong_g2_restForBeats',512 'pingpong_g2_setTempo',513 'pingpong_g2_getTempo',514 ];515 }516 getBlocks() {517 return {518 pingpong_g2_when_button_pressed: {519 color: RoCodeStatic.colorSet.block.default.HARDWARE,520 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,521 skeleton: 'basic_event',522 statements: [],523 params: [524 {525 type: 'Indicator',526 img: 'block_icon/start_icon_hardware.svg',527 size: 14,528 position: { x: 0, y: -2 },529 },530 {531 type: 'Dropdown',532 options: Lang.Blocks.pingpong_g2_cube_id,533 value: 0,534 fontSize: 11,535 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,536 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,537 },538 ],539 events: {},540 def: {541 params: [null],542 type: 'pingpong_g2_when_button_pressed',543 },544 paramsKeyMap: {545 CUBEID: 1,546 },547 class: 'PingpongG2',548 isNotFor: ['PingpongG2'],549 event: 'pp_when_button_pressed',550 func(sprite, script) {551 const cubeId = script.getNumberField('CUBEID');552 const pd = RoCode.hw.portData;553 if ((cubeId == 0 && pd.c0_BUTTON == 1) || (cubeId == 1 && pd.c1_BUTTON == 1)) {554 return script.callReturn();555 }556 return this.die();557 },558 },559 pingpong_g2_when_tilted: {560 color: RoCodeStatic.colorSet.block.default.HARDWARE,561 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,562 skeleton: 'basic_event',563 statements: [],564 params: [565 {566 type: 'Indicator',567 img: 'block_icon/start_icon_hardware.svg',568 size: 14,569 position: { x: 0, y: -2 },570 },571 {572 type: 'Dropdown',573 options: Lang.Blocks.pingpong_g2_cube_id,574 value: 0,575 fontSize: 11,576 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,577 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,578 },579 {580 type: 'Dropdown',581 options: Lang.Blocks.pingpong_opts_cube_tiltDir,582 value: 'F_CIRCLE',583 fontSize: 11,584 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,585 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,586 },587 ],588 events: {},589 def: {590 params: [null, null],591 type: 'pingpong_g2_when_tilted',592 },593 paramsKeyMap: {594 CUBEID: 1,595 TILT_DIR: 2,596 },597 class: 'PingpongG2',598 isNotFor: ['PingpongG2'],599 event: 'pp_when_tilted',600 func(sprite, script) {601 const cubeId = script.getNumberField('CUBEID');602 const tiltDir = script.getStringField('TILT_DIR');603 const tiltValue = RoCode.PingpongG2._getTiltValue(cubeId, tiltDir);604 if (tiltValue >= RoCode.PingpongG2.TILT_THRESHOLD) {605 return script.callReturn();606 }607 return this.die();608 },609 },610 pingpong_g2_is_button_pressed: {611 color: RoCodeStatic.colorSet.block.default.HARDWARE,612 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,613 skeleton: 'basic_boolean_field',614 statements: [],615 params: [616 {617 type: 'Dropdown',618 options: Lang.Blocks.pingpong_g2_cube_id,619 value: 0,620 fontSize: 11,621 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,622 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,623 },624 ],625 def: {626 params: [null],627 type: 'pingpong_g2_is_button_pressed',628 },629 paramsKeyMap: {630 CUBEID: 0,631 },632 class: 'PingpongG2',633 isNotFor: ['PingpongG2'],634 func(sprite, script) {635 const cubeId = script.getNumberField('CUBEID');636 const pd = RoCode.hw.portData;637 return (cubeId == 0 && pd.c0_BUTTON == 1) || (cubeId == 1 && pd.c1_BUTTON == 1);638 },639 },640 pingpong_g2_is_tilted: {641 color: RoCodeStatic.colorSet.block.default.HARDWARE,642 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,643 skeleton: 'basic_boolean_field',644 statements: [],645 params: [646 {647 type: 'Dropdown',648 options: Lang.Blocks.pingpong_g2_cube_id,649 value: 0,650 fontSize: 11,651 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,652 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,653 },654 {655 type: 'Dropdown',656 options: Lang.Blocks.pingpong_opts_cube_tiltDir,657 value: 'F_CIRCLE',658 fontSize: 11,659 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,660 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,661 },662 ],663 events: {},664 def: { params: [], type: 'pingpong_g2_is_tilted' },665 paramsKeyMap: {666 CUBEID: 0,667 TILT_DIR: 1,668 },669 class: 'PingpongG2',670 isNotFor: ['PingpongG2'],671 func(sprite, script) {672 const cubeId = script.getNumberField('CUBEID');673 const tiltDir = script.getStringField('TILT_DIR', script);674 const tiltValue = RoCode.PingpongG2._getTiltValue(cubeId, tiltDir);675 return tiltValue >= RoCode.PingpongG2.TILT_THRESHOLD;676 },677 },678 pingpong_g2_get_tilt_value: {679 color: RoCodeStatic.colorSet.block.default.HARDWARE,680 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,681 skeleton: 'basic_string_field',682 params: [683 {684 type: 'Dropdown',685 options: Lang.Blocks.pingpong_g2_cube_id,686 value: 0,687 fontSize: 11,688 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,689 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,690 },691 {692 type: 'Dropdown',693 options: Lang.Blocks.pingpong_opts_cube_tiltDir,694 value: 'F_CIRCLE',695 fontSize: 11,696 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,697 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,698 },699 ],700 events: {},701 def: {702 params: [null],703 type: 'pingpong_g2_get_tilt_value',704 },705 paramsKeyMap: { CUBEID: 0, DIR: 1 },706 class: 'PingpongG2',707 isNotFor: ['PingpongG2'],708 func(sprite, script) {709 const cubeId = script.getNumberField('CUBEID');710 const tiltDir = script.getStringField('DIR', script);711 return RoCode.PingpongG2._getTiltValue(cubeId, tiltDir);712 },713 },714 pingpong_g2_get_sensor_value: {715 color: RoCodeStatic.colorSet.block.default.HARDWARE,716 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,717 skeleton: 'basic_string_field',718 params: [719 {720 type: 'Dropdown',721 options: Lang.Blocks.pingpong_g2_cube_id,722 value: 0,723 fontSize: 11,724 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,725 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,726 },727 {728 type: 'Dropdown',729 options: [730 [Lang.Blocks.pingpong_sensor_proximity, 'PROXIMITY'],731 [Lang.Blocks.pingpong_sensor_ain, 'AIN'],732 ],733 value: 'PROXIMITY',734 fontSize: 11,735 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,736 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,737 },738 ],739 def: { params: [], type: 'pingpong_g2_get_sensor_value' },740 paramsKeyMap: { CUBEID: 0, SENSOR: 1 },741 class: 'PingpongG2',742 isNotFor: ['PingpongG2'],743 func(sprite, script) {744 const cubeId = script.getNumberField('CUBEID');745 const sensorType = script.getStringField('SENSOR', script);746 const pd = RoCode.hw.portData;747 let value = 0;748 if (sensorType == 'PROXIMITY') {749 if (cubeId == 0) {750 value = pd.c0_PROXIMITY;751 } else if (cubeId == 1) {752 value = pd.c1_PROXIMITY;753 }754 } else if (sensorType == 'AIN') {755 if (cubeId == 0) {756 value = pd.c0_AIN;757 } else if (cubeId == 1) {758 value = pd.c1_AIN;759 }760 }761 return value;762 },763 },764 pingpong_g2_is_top_shape: {765 color: RoCodeStatic.colorSet.block.default.HARDWARE,766 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,767 skeleton: 'basic_boolean_field',768 statements: [],769 params: [770 {771 type: 'Dropdown',772 options: Lang.Blocks.pingpong_g2_cube_id,773 value: 0,774 fontSize: 11,775 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,776 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,777 },778 {779 type: 'Dropdown',780 options: Lang.Blocks.pingpong_opts_cube_dir6,781 value: 'DF_RECTANGLE',782 fontSize: 11,783 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,784 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,785 },786 ],787 events: {},788 def: { params: [], type: 'pingpong_g2_is_top_shape' },789 paramsKeyMap: { CUBEID: 0, TILT_DIR: 1 },790 class: 'PingpongG2',791 isNotFor: ['PingpongG2'],792 func(sprite, script) {793 const cubeId = script.getNumberField('CUBEID');794 const tiltDir = script.getStringField('TILT_DIR', script);795 return RoCode.PingpongG2._isUpperDir(cubeId, tiltDir);796 },797 },798 pingpong_g2_multi_motor_rotate: {799 color: RoCodeStatic.colorSet.block.default.HARDWARE,800 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,801 skeleton: 'basic',802 params: [803 {804 type: 'Dropdown',805 options: [806 [Lang.Blocks.pingpong_rotate_cw, 'RIGHT'],807 [Lang.Blocks.pingpong_rotate_ccw, 'LEFT'],808 ],809 value: 'RIGHT',810 fontSize: 11,811 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,812 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,813 },814 {815 type: 'Block',816 accept: 'string',817 defaultType: 'number',818 value: 10,819 },820 {821 type: 'Dropdown',822 options: [823 [Lang.Blocks.pingpong_rotate_cw, 'RIGHT'],824 [Lang.Blocks.pingpong_rotate_ccw, 'LEFT'],825 ],826 value: 'RIGHT',827 fontSize: 11,828 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,829 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,830 },831 {832 type: 'Block',833 accept: 'string',834 defaultType: 'number',835 value: 10,836 },837 { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12 },838 ],839 def: {840 params: [null],841 type: 'pingpong_g2_multi_motor_rotate',842 },843 paramsKeyMap: { DIR_1: 0, DEGREE_1: 1, DIR_2: 2, DEGREE_2: 3 },844 class: 'PingpongG2_motor',845 isNotFor: ['PingpongG2'],846 func(sprite, script) {847 return RoCode.PingpongG2.postCallReturn(script, () => {848 const dir1 = script.getStringField('DIR_1');849 const dir2 = script.getStringField('DIR_2');850 const degree1 = script.getNumberValue('DEGREE_1');851 const degree2 = script.getNumberValue('DEGREE_2');852 const speed1 = 80 * (dir1 === 'LEFT' ? -1 : 1);853 const speed2 = 80 * (dir2 === 'LEFT' ? -1 : 1);854 const [arr1, delay1] = RoCode.PingpongG2.makeSingleStepPacket(855 0,856 speed1,857 degree1858 );859 const [arr2, delay2] = RoCode.PingpongG2.makeSingleStepPacket(860 1,861 speed2,862 degree2863 );864 const opt = [2, 1, 0, 2];865 const packet = RoCode.PingpongG2.makeAggregatePacket(866 OPCODE.AGGREGATE_STEPS,867 0,868 [arr1, arr2],869 opt870 );871 const waitTime = Math.max(delay1, delay2);872 return [packet, waitTime];873 });874 },875 },876 pingpong_g2_motor_rotate: {877 color: RoCodeStatic.colorSet.block.default.HARDWARE,878 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,879 skeleton: 'basic',880 statements: [],881 params: [882 {883 type: 'Dropdown',884 options: Lang.Blocks.pingpong_g2_cube_all,885 value: 0,886 fontSize: 11,887 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,888 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,889 },890 {891 type: 'Dropdown',892 options: [893 [Lang.Blocks.pingpong_rotate_cw, 'RIGHT'],894 [Lang.Blocks.pingpong_rotate_ccw, 'LEFT'],895 ],896 value: 'RIGHT',897 fontSize: 11,898 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,899 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,900 },901 {902 type: 'Block',903 accept: 'string',904 defaultType: 'number',905 value: 10,906 },907 { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12 },908 ],909 events: {},910 def: {911 params: [null, null, null],912 type: 'pingpong_g2_motor_rotate',913 },914 paramsKeyMap: { CUBEID: 0, DIR: 1, DEGREE: 2 },915 class: 'PingpongG2_motor',916 isNotFor: ['PingpongG2'],917 func(sprite, script) {918 return RoCode.PingpongG2.postCallReturn(script, () => {919 const cubeId = script.getNumberField('CUBEID');920 const dir = script.getStringField('DIR');921 const degree = script.getNumberValue('DEGREE');922 const speed = 80 * (dir === 'LEFT' ? -1 : 1);923 const [arr, waitTime] = RoCode.PingpongG2.makeSingleStepPacket(924 cubeId,925 speed,926 degree927 );928 const packet = Buffer.from(arr);929 return [packet, waitTime];930 });931 },932 },933 pingpong_g2_start_multi_motor_rotate: {934 color: RoCodeStatic.colorSet.block.default.HARDWARE,935 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,936 skeleton: 'basic',937 params: [938 { type: 'Block', accept: 'string', defaultType: 'number', value: 100 },939 { type: 'Block', accept: 'string', defaultType: 'number', value: 100 },940 {941 type: 'Indicator',942 img: 'block_icon/hardware_icon.svg',943 size: 12,944 },945 ],946 def: {947 params: [],948 type: 'pingpong_g2_start_multi_motor_rotate',949 },950 paramsKeyMap: { SPEED_1: 0, SPEED_2: 1 },951 class: 'PingpongG2_motor',952 isNotFor: ['PingpongG2'],953 func(sprite, script) {954 return RoCode.PingpongG2.postCallReturn(script, () => {955 const speed1 = script.getNumberValue('SPEED_1');956 const speed2 = script.getNumberValue('SPEED_2');957 const arr1 = RoCode.PingpongG2.makeContStepPacket(0, speed1);958 const arr2 = RoCode.PingpongG2.makeContStepPacket(1, speed2);959 const opt = [MODE.MULTIROLE, 0, 0, 2];960 const packet = RoCode.PingpongG2.makeAggregatePacket(961 OPCODE.AGGREGATE_STEPS,962 0,963 [arr1, arr2],964 opt965 );966 return [packet];967 });968 },969 },970 pingpong_g2_start_motor_rotate: {971 color: RoCodeStatic.colorSet.block.default.HARDWARE,972 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,973 skeleton: 'basic',974 params: [975 {976 type: 'Dropdown',977 options: Lang.Blocks.pingpong_g2_cube_all,978 value: 0,979 fontSize: 11,980 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,981 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,982 },983 {984 type: 'Block',985 accept: 'string',986 defaultType: 'number',987 value: 100,988 },989 {990 type: 'Indicator',991 img: 'block_icon/hardware_icon.svg',992 size: 12,993 },994 ],995 def: {996 params: [null, null],997 type: 'pingpong_g2_start_motor_rotate',998 },999 paramsKeyMap: { CUBEID: 0, SPEED: 1 },1000 class: 'PingpongG2_motor',1001 isNotFor: ['PingpongG2'],1002 func(sprite, script) {1003 return RoCode.PingpongG2.postCallReturn(script, () => {1004 const cubeId = script.getNumberField('CUBEID');1005 const speed = script.getNumberValue('SPEED');1006 const arr = RoCode.PingpongG2.makeContStepPacket(cubeId, speed);1007 const packet = Buffer.from(arr);1008 const waitTime = Math.round(((1100 - Math.abs(speed)) / 99) * 10) + 400;1009 return [packet, waitTime];1010 });1011 },1012 },1013 pingpong_g2_stop_motor_rotate: {1014 color: RoCodeStatic.colorSet.block.default.HARDWARE,1015 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1016 skeleton: 'basic',1017 params: [1018 {1019 type: 'Dropdown',1020 options: Lang.Blocks.pingpong_g2_cube_all,1021 value: 0,1022 fontSize: 11,1023 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1024 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1025 },1026 {1027 type: 'Indicator',1028 img: 'block_icon/hardware_icon.svg',1029 size: 12,1030 },1031 ],1032 def: {1033 params: [],1034 type: 'pingpong_g2_stop_motor_rotate',1035 },1036 paramsKeyMap: { CUBEID: 0 },1037 class: 'PingpongG2_motor',1038 isNotFor: ['PingpongG2'],1039 func(sprite, script) {1040 return RoCode.PingpongG2.postCallReturn(script, () => {1041 const cubeId = script.getNumberField('CUBEID');1042 const arr = RoCode.PingpongG2.makeContStepPacket(cubeId, 0);1043 const packet = Buffer.from(arr);1044 return [packet];1045 });1046 },1047 },1048 pingpong_g2_rotate_servo_mortor: {1049 color: RoCodeStatic.colorSet.block.default.HARDWARE,1050 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1051 skeleton: 'basic',1052 statements: [],1053 params: [1054 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },1055 {1056 type: 'Block',1057 accept: 'string',1058 defaultType: 'number',1059 },1060 {1061 type: 'Indicator',1062 img: 'block_icon/hardware_icon.svg',1063 size: 12,1064 },1065 ],1066 events: {},1067 def: { params: [null, { type: 'angle' }], type: 'pingpong_g2_rotate_servo_mortor' },1068 paramsKeyMap: { cubeno: 0, DEGREE: 1 },1069 class: 'PingpongG2_motor',1070 isNotFor: ['PingpongG2'],1071 func(sprite, script) {1072 return RoCode.PingpongG2.postCallReturn(script, () => {1073 const cubeId = RoCode.PingpongG2._getCubeNoFromBlock(script);1074 let angle = script.getNumberValue('DEGREE', script);1075 angle = Math.min(Math.max(angle, 0), 180);1076 const opt = [2, 0, angle, 1];1077 const packet = RoCode.PingpongG2.makePacket(OPCODE.SERVO, 0x00, cubeId, opt);1078 return [packet];1079 });1080 },1081 },1082 pingpong_g2_set_dot_pixel: {1083 color: RoCodeStatic.colorSet.block.default.HARDWARE,1084 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1085 skeleton: 'basic',1086 statements: [],1087 params: [1088 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },1089 { type: 'Block', accept: 'string', defaultType: 'number', value: '0' },1090 { type: 'Block', accept: 'string', defaultType: 'number', value: '0' },1091 {1092 type: 'Dropdown',1093 options: [1094 [Lang.Blocks.pingpong_dot_on, 1],1095 [Lang.Blocks.pingpong_dot_off, 0],1096 ],1097 value: 1,1098 fontSize: 11,1099 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1100 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1101 },1102 {1103 type: 'Indicator',1104 img: 'block_icon/hardware_icon.svg',1105 size: 12,1106 },1107 ],1108 events: {},1109 def: {1110 params: [null, null, null],1111 type: 'pingpong_g2_set_dot_pixel',1112 },1113 paramsKeyMap: { cubeno: 0, X: 1, Y: 2, onoff: 3 },1114 class: 'PingpongG2_peripheral_LED',1115 isNotFor: ['PingpongG2'],1116 func(sprite, script) {1117 return RoCode.PingpongG2.postCallReturn(script, () => {1118 const cubeId = RoCode.PingpongG2._getCubeNoFromBlock(script);1119 let dotX = script.getNumberValue('X', script);1120 let dotY = script.getNumberValue('Y', script);1121 const onoff = script.getNumberField('onoff', script);1122 dotX = Math.min(Math.max(dotX, 0), 7);1123 dotY = Math.min(Math.max(dotY, 0), 7);1124 const opt = [0x70, dotY, dotX, onoff];1125 const packet = RoCode.PingpongG2.makePacket(1126 OPCODE.LEDMATRIX,1127 0xe1,1128 cubeId,1129 opt1130 );1131 return [packet];1132 });1133 },1134 },1135 pingpong_g2_set_dot_string: {1136 color: RoCodeStatic.colorSet.block.default.HARDWARE,1137 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1138 skeleton: 'basic',1139 statements: [],1140 params: [1141 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },1142 { type: 'Block', accept: 'string', value: 'Hello!' },1143 { type: 'Block', accept: 'string', defaultType: 'number', value: '2' },1144 {1145 type: 'Indicator',1146 img: 'block_icon/hardware_icon.svg',1147 size: 12,1148 },1149 ],1150 events: {},1151 def: { params: [null, null], type: 'pingpong_g2_set_dot_string' },1152 paramsKeyMap: { cubeno: 0, STR: 1, DURATION: 2 },1153 class: 'PingpongG2_peripheral_LED',1154 isNotFor: ['PingpongG2'],1155 func(sprite, script) {1156 return RoCode.PingpongG2.postCallReturn(script, () => {1157 const cubeId = RoCode.PingpongG2._getCubeNoFromBlock(script);1158 const str = script.getStringValue('STR', script);1159 const duration = script.getNumberValue('DURATION', script);1160 let period = Math.round((duration * 100) / (str.length * 8));1161 period = Math.min(Math.max(period, 1), 200);1162 const opt = Buffer.concat([1163 Buffer.from([0x70, period, 0]),1164 Buffer.from(str.substring(0, 20)),1165 ]);1166 const packet = RoCode.PingpongG2.makePacket(1167 OPCODE.LEDMATRIX,1168 0xe3,1169 cubeId,1170 opt1171 );1172 // add delay time for matrix stability (about 400ms)1173 const waitTime = period * (str.length + 1) * 8 * 10 + 400;1174 return [packet, waitTime];1175 });1176 },1177 },1178 pingpong_g2_set_dot_clear: {1179 color: RoCodeStatic.colorSet.block.default.HARDWARE,1180 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1181 skeleton: 'basic',1182 statements: [],1183 params: [1184 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },1185 {1186 type: 'Indicator',1187 img: 'block_icon/hardware_icon.svg',1188 size: 12,1189 },1190 ],1191 events: {},1192 def: { params: [], type: 'pingpong_g2_set_dot_clear' },1193 paramsKeyMap: { cubeno: 0 },1194 class: 'PingpongG2_peripheral_LED',1195 isNotFor: ['PingpongG2'],1196 func(sprite, script) {1197 return RoCode.PingpongG2.postCallReturn(script, () => {1198 const cubeId = RoCode.PingpongG2._getCubeNoFromBlock(script);1199 const opt = [0x70, 1, 0, ' '];1200 const packet = RoCode.PingpongG2.makePacket(1201 OPCODE.LEDMATRIX,1202 0xe3,1203 cubeId,1204 opt1205 );1206 return [packet, 400];1207 });1208 },1209 },1210 pingpong_g2_playNoteForBeats: {1211 //'%1 큐브의 %2 번 음을 %3 박자로 연주하기 %4',1212 color: RoCodeStatic.colorSet.block.default.HARDWARE,1213 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1214 skeleton: 'basic',1215 statements: [],1216 params: [1217 {1218 type: 'Dropdown',1219 options: Lang.Blocks.pingpong_g2_cube_id,1220 value: 0,1221 fontSize: 11,1222 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1223 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1224 },1225 {1226 type: 'Dropdown',1227 options: Lang.Blocks.pingpong_opts_music_notes,1228 value: 48,1229 fontSize: 11,1230 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1231 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1232 },1233 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },1234 {1235 type: 'Indicator',1236 img: 'block_icon/hardware_icon.svg',1237 size: 12,1238 },1239 ],1240 events: {},1241 def: { params: [], type: 'pingpong_g2_playNoteForBeats' },1242 paramsKeyMap: { CUBEID: 0, NOTE: 1, BEATS: 2 },1243 class: 'PingpongG2_Music',1244 isNotFor: ['PingpongG2'],1245 func(sprite, script) {1246 return RoCode.PingpongG2.postCallReturn(script, () => {1247 const cubeId = script.getNumberField('CUBEID');1248 const NOTE = script.getNumberField('NOTE', script);1249 const BEATS = script.getNumberValue('BEATS', script);1250 const cBeats = RoCode.PingpongG2._clampBeats(BEATS);1251 const durationSec = RoCode.PingpongG2._beatsToDuration(cBeats);1252 const waitTime = durationSec * 10 + 30; //XXX1253 const arr = RoCode.PingpongG2.makeMusicNotePacket(cubeId, NOTE, durationSec);1254 const packet = Buffer.from(arr);1255 return [packet, waitTime];1256 });1257 },1258 },1259 pingpong_g2_playChordForBeats: {1260 color: RoCodeStatic.colorSet.block.default.HARDWARE,1261 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1262 skeleton: 'basic',1263 statements: [],1264 params: [1265 {1266 type: 'Dropdown',1267 options: Lang.Blocks.pingpong_g2_cube_id,1268 value: 0,1269 fontSize: 11,1270 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1271 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1272 },1273 {1274 type: 'Dropdown',1275 options: Lang.Blocks.pingpong_opts_music_notes,1276 value: 48,1277 fontSize: 11,1278 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1279 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1280 },1281 {1282 type: 'Dropdown',1283 options: Lang.Blocks.pingpong_g2_cube_id,1284 value: 1,1285 fontSize: 11,1286 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1287 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1288 },1289 {1290 type: 'Dropdown',1291 options: Lang.Blocks.pingpong_opts_music_notes,1292 value: 48,1293 fontSize: 11,1294 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1295 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1296 },1297 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },1298 {1299 type: 'Indicator',1300 img: 'block_icon/hardware_icon.svg',1301 size: 12,1302 },1303 ],1304 events: {},1305 def: { params: [], type: 'pingpong_g2_playChordForBeats' },1306 paramsKeyMap: {1307 CUBEID_1: 0,1308 NOTE_1: 1,1309 CUBEID_2: 2,1310 NOTE_2: 3,1311 BEATS: 4,1312 },1313 class: 'PingpongG2_Music',1314 isNotFor: ['PingpongG2'],1315 func(sprite, script) {1316 return RoCode.PingpongG2.postCallReturn(script, () => {1317 const cubeId1 = script.getNumberField('CUBEID_1');1318 const cubeId2 = script.getNumberField('CUBEID_2');1319 const NOTE1 = script.getNumberField('NOTE_1', script);1320 const NOTE2 = script.getNumberField('NOTE_2', script);1321 const BEATS = script.getNumberValue('BEATS', script);1322 const cBeats = RoCode.PingpongG2._clampBeats(BEATS);1323 const durationSec = RoCode.PingpongG2._beatsToDuration(cBeats);1324 const waitTime = durationSec * 10 + 30;1325 const arr1 = RoCode.PingpongG2.makeMusicNotePacket(1326 cubeId1,1327 NOTE1,1328 durationSec1329 );1330 const arr2 = RoCode.PingpongG2.makeMusicNotePacket(1331 cubeId2,1332 NOTE2,1333 durationSec1334 );1335 const packet = RoCode.PingpongG2.makeAggregatePacket(1336 OPCODE.MUSIC,1337 0xa2,1338 [arr1, arr2],1339 [0, 0]1340 );1341 return [packet, waitTime];1342 });1343 },1344 },1345 pingpong_g2_restForBeats: {1346 color: RoCodeStatic.colorSet.block.default.HARDWARE,1347 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1348 skeleton: 'basic',1349 params: [1350 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },1351 {1352 type: 'Indicator',1353 img: 'block_icon/hardware_icon.svg',1354 size: 12,1355 },1356 ],1357 def: { params: [], type: 'pingpong_g2_restForBeats' },1358 paramsKeyMap: { BEATS: 0 },1359 class: 'PingpongG2_Music',1360 isNotFor: ['PingpongG2'],1361 func(sprite, script) {1362 return RoCode.PingpongG2.postCallReturn(script, () => {1363 const BEATS = script.getNumberValue('BEATS', script);1364 const cBeats = RoCode.PingpongG2._clampBeats(BEATS);1365 const durationSec = RoCode.PingpongG2._beatsToDuration(cBeats);1366 const waitTime = durationSec * 10 + 30;1367 //XXX1368 return [null, waitTime];1369 });1370 },1371 },1372 pingpong_g2_setTempo: {1373 color: RoCodeStatic.colorSet.block.default.HARDWARE,1374 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1375 skeleton: 'basic',1376 params: [1377 { type: 'Block', accept: 'string', defaultType: 'number', value: '60' },1378 {1379 type: 'Indicator',1380 img: 'block_icon/hardware_icon.svg',1381 size: 12,1382 },1383 ],1384 def: { params: [], type: 'pingpong_g2_setTempo' },1385 paramsKeyMap: { TEMPO: 0 },1386 class: 'PingpongG2_Music',1387 isNotFor: ['PingpongG2'],1388 func(sprite, script) {1389 let tempo = script.getNumberValue('TEMPO', script);1390 RoCode.PingpongG2.tempo = RoCode.PingpongG2._clampTempo(tempo);1391 return script.callReturn();1392 },1393 },1394 pingpong_g2_getTempo: {1395 color: RoCodeStatic.colorSet.block.default.HARDWARE,1396 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1397 skeleton: 'basic_string_field',1398 params: [],1399 def: { params: [], type: 'pingpong_g2_getTempo' },1400 paramsKeyMap: {},1401 class: 'PingpongG2_Music',1402 isNotFor: ['PingpongG2'],1403 func(sprite, script) {1404 return RoCode.PingpongG2.tempo;1405 },1406 },1407 };1408 }1409 setLanguage() {1410 return {1411 ko: {1412 template: {1413 pingpong_g2_when_button_pressed: '%1 %2 큐브 버튼을 눌렀을 때',1414 pingpong_g2_when_tilted: '%1 %2 큐브를 %3로 기울였을 때',1415 pingpong_g2_is_button_pressed: '%1 큐브 버튼이 눌렸는가?',1416 pingpong_g2_is_tilted: '%1 큐브가 %2로 기울어졌는가?',1417 pingpong_g2_is_top_shape: '%1 큐브의 윗면에 %2 모양이 있는가?',1418 pingpong_g2_get_tilt_value: '%1 큐브의 %2 방향 기울기',1419 pingpong_g2_get_sensor_value: '%1 큐브의 %2 센서값',1420 pingpong_g2_multi_motor_rotate:1421 '모터1을 %1 방향 %2 도, 모터2를 %3 방향 %4 도 회전하기 %5',1422 pingpong_g2_motor_rotate: '%1 모터를 %2 방향으로 %3 도 회전하기 %4',1423 pingpong_g2_start_multi_motor_rotate:1424 '모터1 속도를 %1, 모터2 속도를 %2으로 계속 회전하기 %3',1425 pingpong_g2_start_motor_rotate: '%1 모터의 속도를 %2으로 계속 회전하기 %3',1426 pingpong_g2_stop_motor_rotate: '%1 모터 멈추기 %2',1427 pingpong_g2_set_dot_pixel: '%1 번째 큐브의 도트 X:%2 Y:%3 %4 %5',1428 pingpong_g2_set_dot_string:1429 '%1 번째 큐브에 도트 문자열 %2 %3초동안 보여주기 %4',1430 pingpong_g2_set_dot_clear: '%1 번째 큐브의 화면 지우기 %2',1431 pingpong_g2_rotate_servo_mortor: '%1 번째 큐브의 서보모터 %2도로 설정하기 %3',1432 pingpong_g2_playNoteForBeats: '%1 큐브의 %2 음을 %3 박자로 연주하기 %4',1433 pingpong_g2_playChordForBeats: '%1 큐브 %2, %3 큐브 %4, %5 박자로 연주하기 %6',1434 pingpong_g2_restForBeats: '%1 박자 쉬기 %2',1435 pingpong_g2_setTempo: '악보 빠르기를 %1 으로 정하기 %2',1436 pingpong_g2_getTempo: '악보 빠르기',1437 },1438 Blocks: {1439 ...this.lang_defblock.ko,1440 pingpong_g2_cube_id: [1441 ['1번', 0],1442 ['2번', 1],1443 ],1444 pingpong_g2_cube_all: [1445 ['1번', 0],1446 ['2번', 1],1447 ['모든', -1],1448 ],1449 },1450 },1451 en: {1452 template: {1453 pingpong_g2_when_button_pressed: '%1 %2 cube button pressed',1454 pingpong_g2_when_tilted: '%1 %2 cube tilted to %3',1455 pingpong_g2_is_button_pressed: '%1 cube button pressed?',1456 pingpong_g2_is_tilted: '%1 cube tilted to %2',1457 pingpong_g2_is_top_shape: '%1 cube shown %2 in top view?',1458 pingpong_g2_get_tilt_value: '%1 cube tilt angle to %2',1459 pingpong_g2_get_sensor_value: '%1 cube read sensor %2',1460 pingpong_g2_multi_motor_rotate:1461 'rotate motor1 %2 degrees %1, motor2 %4 degrees %3 %5',1462 pingpong_g2_motor_rotate: 'rotate %2 degrees %1 %3',1463 pingpong_g2_start_multi_motor_rotate:1464 'set motor1 speed to %1, motor2 speed to %2 %3',1465 pingpong_g2_start_motor_rotate: 'set motor speed to %1 %2',1466 pingpong_g2_stop_motor_rotate: 'stop motor rotate %1',1467 pingpong_g2_rotate_servo_mortor: 'set servo mortor to %1 degrees %2',1468 pingpong_g2_set_dot_pixel: '%1 cube set DOT X:%2 Y:%3 %4 %5',1469 pingpong_g2_set_dot_string:1470 'print %1 cube string %2 during %3 seconds to DOT %4',1471 pingpong_g2_set_dot_clear: '%1 cube clear DOT %2',1472 pingpong_g2_playNoteForBeats: '%1 cube play note %2 for %3 beats %4',1473 pingpong_g2_playChordForBeats: '%1 cube %2, %3 cube %4 for %5 beats %6',1474 pingpong_g2_restForBeats: 'rest for %1 beats %2',1475 pingpong_g2_setTempo: 'set tempo to %1 %2',1476 pingpong_g2_getTempo: 'tempo',1477 },1478 Blocks: {1479 ...this.lang_defblock.en,1480 pingpong_g2_cube_id: [1481 ['1st', 0],1482 ['2nd', 1],1483 ],1484 pingpong_g2_cube_all: [1485 ['1st', 0],1486 ['2nd', 1],1487 ['All', -1],1488 ],1489 },1490 },1491 };1492 }1493})();1494RoCode.PingpongG3 = new (class extends PingpongBase {1495 constructor() {1496 super(3);1497 this.id = '35.3';1498 this.name = 'PingpongG3';1499 this.url = 'https://www.roborisen.com';1500 this.imageName = 'pingpong_g3.png';1501 this.title = {1502 ko: '핑퐁 G3',1503 en: 'Pingpong G3',1504 };1505 this.blockMenuBlocks = [1506 'pingpong_g3_when_button_pressed',1507 'pingpong_g3_when_tilted',1508 'pingpong_g3_is_button_pressed',1509 'pingpong_g3_is_tilted',1510 'pingpong_g3_get_tilt_value',1511 'pingpong_g3_is_top_shape',1512 'pingpong_g3_get_sensor_value',1513 'pingpong_g3_multi_motor_rotate',1514 'pingpong_g3_motor_rotate',1515 'pingpong_g3_start_multi_motor_rotate',1516 'pingpong_g3_start_motor_rotate',1517 'pingpong_g3_stop_motor_rotate',1518 'pingpong_g3_rotate_servo_mortor',1519 'pingpong_g3_set_dot_pixel',1520 'pingpong_g3_set_dot_string',1521 'pingpong_g3_set_dot_clear',1522 'pingpong_g3_playNoteForBeats',1523 'pingpong_g3_playChordForBeats',1524 'pingpong_g3_restForBeats',1525 'pingpong_g3_setTempo',1526 'pingpong_g3_getTempo',1527 ];1528 }1529 getBlocks() {1530 return {1531 pingpong_g3_when_button_pressed: {1532 color: RoCodeStatic.colorSet.block.default.HARDWARE,1533 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1534 skeleton: 'basic_event',1535 statements: [],1536 params: [1537 {1538 type: 'Indicator',1539 img: 'block_icon/start_icon_hardware.svg',1540 size: 14,1541 position: { x: 0, y: -2 },1542 },1543 {1544 type: 'Dropdown',1545 options: Lang.Blocks.pingpong_g3_cube_id,1546 value: 0,1547 fontSize: 11,1548 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1549 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1550 },1551 ],1552 events: {},1553 def: {1554 params: [null],1555 type: 'pingpong_g3_when_button_pressed',1556 },1557 paramsKeyMap: {1558 CUBEID: 1,1559 },1560 class: 'PingpongG3',1561 isNotFor: ['PingpongG3'],1562 event: 'pp_when_button_pressed',1563 func(sprite, script) {1564 const cubeId = script.getNumberField('CUBEID');1565 const pd = RoCode.hw.portData;1566 if (1567 (cubeId == 0 && pd.c0_BUTTON == 1) ||1568 (cubeId == 1 && pd.c1_BUTTON == 1) ||1569 (cubeId == 2 && pd.c2_BUTTON == 1)1570 ) {1571 return script.callReturn();1572 }1573 return this.die();1574 },1575 },1576 pingpong_g3_when_tilted: {1577 color: RoCodeStatic.colorSet.block.default.HARDWARE,1578 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1579 skeleton: 'basic_event',1580 statements: [],1581 params: [1582 {1583 type: 'Indicator',1584 img: 'block_icon/start_icon_hardware.svg',1585 size: 14,1586 position: { x: 0, y: -2 },1587 },1588 {1589 type: 'Dropdown',1590 options: Lang.Blocks.pingpong_g3_cube_id,1591 value: 0,1592 fontSize: 11,1593 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1594 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1595 },1596 {1597 type: 'Dropdown',1598 options: Lang.Blocks.pingpong_opts_cube_tiltDir,1599 value: 'F_CIRCLE',1600 fontSize: 11,1601 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1602 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1603 },1604 ],1605 events: {},1606 def: {1607 params: [null, null],1608 type: 'pingpong_g3_when_tilted',1609 },1610 paramsKeyMap: {1611 CUBEID: 1,1612 TILT_DIR: 2,1613 },1614 class: 'PingpongG3',1615 isNotFor: ['PingpongG3'],1616 event: 'pp_when_tilted',1617 func(sprite, script) {1618 const cubeId = script.getNumberField('CUBEID');1619 const tiltDir = script.getStringField('TILT_DIR');1620 const tiltValue = RoCode.PingpongG3._getTiltValue(cubeId, tiltDir);1621 if (tiltValue >= RoCode.PingpongG3.TILT_THRESHOLD) {1622 return script.callReturn();1623 }1624 return this.die();1625 },1626 },1627 pingpong_g3_is_button_pressed: {1628 color: RoCodeStatic.colorSet.block.default.HARDWARE,1629 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1630 skeleton: 'basic_boolean_field',1631 statements: [],1632 params: [1633 {1634 type: 'Dropdown',1635 options: Lang.Blocks.pingpong_g3_cube_id,1636 value: 0,1637 fontSize: 11,1638 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1639 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1640 },1641 ],1642 def: {1643 params: [null],1644 type: 'pingpong_g3_is_button_pressed',1645 },1646 paramsKeyMap: {1647 CUBEID: 0,1648 },1649 class: 'PingpongG3',1650 isNotFor: ['PingpongG3'],1651 func(sprite, script) {1652 const cubeId = script.getNumberField('CUBEID');1653 const pd = RoCode.hw.portData;1654 return (1655 (cubeId == 0 && pd.c0_BUTTON == 1) ||1656 (cubeId == 1 && pd.c1_BUTTON == 1) ||1657 (cubeId == 2 && pd.c2_BUTTON == 1)1658 );1659 },1660 },1661 pingpong_g3_is_tilted: {1662 color: RoCodeStatic.colorSet.block.default.HARDWARE,1663 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1664 skeleton: 'basic_boolean_field',1665 statements: [],1666 params: [1667 {1668 type: 'Dropdown',1669 options: Lang.Blocks.pingpong_g3_cube_id,1670 value: 0,1671 fontSize: 11,1672 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1673 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1674 },1675 {1676 type: 'Dropdown',1677 options: Lang.Blocks.pingpong_opts_cube_tiltDir,1678 value: 'F_CIRCLE',1679 fontSize: 11,1680 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1681 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1682 },1683 ],1684 events: {},1685 def: { params: [], type: 'pingpong_g3_is_tilted' },1686 paramsKeyMap: {1687 CUBEID: 0,1688 TILT_DIR: 1,1689 },1690 class: 'PingpongG3',1691 isNotFor: ['PingpongG3'],1692 func(sprite, script) {1693 const cubeId = script.getNumberField('CUBEID');1694 const tiltDir = script.getStringField('TILT_DIR', script);1695 const tiltValue = RoCode.PingpongG3._getTiltValue(cubeId, tiltDir);1696 return tiltValue >= RoCode.PingpongG3.TILT_THRESHOLD;1697 },1698 },1699 pingpong_g3_get_tilt_value: {1700 color: RoCodeStatic.colorSet.block.default.HARDWARE,1701 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1702 skeleton: 'basic_string_field',1703 params: [1704 {1705 type: 'Dropdown',1706 options: Lang.Blocks.pingpong_g3_cube_id,1707 value: 0,1708 fontSize: 11,1709 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1710 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1711 },1712 {1713 type: 'Dropdown',1714 options: Lang.Blocks.pingpong_opts_cube_tiltDir,1715 value: 'F_CIRCLE',1716 fontSize: 11,1717 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1718 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1719 },1720 ],1721 events: {},1722 def: {1723 params: [null],1724 type: 'pingpong_g3_get_tilt_value',1725 },1726 paramsKeyMap: { CUBEID: 0, DIR: 1 },1727 class: 'PingpongG3',1728 isNotFor: ['PingpongG3'],1729 func(sprite, script) {1730 const cubeId = script.getNumberField('CUBEID');1731 const tiltDir = script.getStringField('DIR', script);1732 return RoCode.PingpongG3._getTiltValue(cubeId, tiltDir);1733 },1734 },1735 pingpong_g3_get_sensor_value: {1736 color: RoCodeStatic.colorSet.block.default.HARDWARE,1737 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1738 skeleton: 'basic_string_field',1739 params: [1740 {1741 type: 'Dropdown',1742 options: Lang.Blocks.pingpong_g3_cube_id,1743 value: 0,1744 fontSize: 11,1745 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1746 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1747 },1748 {1749 type: 'Dropdown',1750 options: [1751 [Lang.Blocks.pingpong_sensor_proximity, 'PROXIMITY'],1752 [Lang.Blocks.pingpong_sensor_ain, 'AIN'],1753 ],1754 value: 'PROXIMITY',1755 fontSize: 11,1756 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1757 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1758 },1759 ],1760 def: { params: [], type: 'pingpong_g3_get_sensor_value' },1761 paramsKeyMap: { CUBEID: 0, SENSOR: 1 },1762 class: 'PingpongG3',1763 isNotFor: ['PingpongG3'],1764 func(sprite, script) {1765 const cubeId = script.getNumberField('CUBEID');1766 const sensorType = script.getStringField('SENSOR', script);1767 const pd = RoCode.hw.portData;1768 let value = 0;1769 if (sensorType == 'PROXIMITY') {1770 if (cubeId == 0) {1771 value = pd.c0_PROXIMITY;1772 } else if (cubeId == 1) {1773 value = pd.c1_PROXIMITY;1774 } else if (cubeId == 2) {1775 value = pd.c2_PROXIMITY;1776 }1777 } else if (sensorType == 'AIN') {1778 if (cubeId == 0) {1779 value = pd.c0_AIN;1780 } else if (cubeId == 1) {1781 value = pd.c1_AIN;1782 } else if (cubeId == 2) {1783 value = pd.c2_AIN;1784 }1785 }1786 return value;1787 },1788 },1789 pingpong_g3_is_top_shape: {1790 color: RoCodeStatic.colorSet.block.default.HARDWARE,1791 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1792 skeleton: 'basic_boolean_field',1793 statements: [],1794 params: [1795 {1796 type: 'Dropdown',1797 options: Lang.Blocks.pingpong_g3_cube_id,1798 value: 0,1799 fontSize: 11,1800 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1801 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1802 },1803 {1804 type: 'Dropdown',1805 options: Lang.Blocks.pingpong_opts_cube_dir6,1806 value: 'DF_RECTANGLE',1807 fontSize: 11,1808 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1809 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1810 },1811 ],1812 events: {},1813 def: { params: [], type: 'pingpong_g3_is_top_shape' },1814 paramsKeyMap: { CUBEID: 0, TILT_DIR: 1 },1815 class: 'PingpongG3',1816 isNotFor: ['PingpongG3'],1817 func(sprite, script) {1818 const cubeId = script.getNumberField('CUBEID');1819 const tiltDir = script.getStringField('TILT_DIR', script);1820 return RoCode.PingpongG3._isUpperDir(cubeId, tiltDir);1821 },1822 },1823 pingpong_g3_multi_motor_rotate: {1824 color: RoCodeStatic.colorSet.block.default.HARDWARE,1825 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1826 skeleton: 'basic',1827 params: [1828 {1829 type: 'Dropdown',1830 options: [1831 [Lang.Blocks.pingpong_rotate_cw, 'RIGHT'],1832 [Lang.Blocks.pingpong_rotate_ccw, 'LEFT'],1833 ],1834 value: 'RIGHT',1835 fontSize: 11,1836 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1837 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1838 },1839 { type: 'Block', accept: 'string', defaultType: 'number', value: 10 },1840 {1841 type: 'Dropdown',1842 options: [1843 [Lang.Blocks.pingpong_rotate_cw, 'RIGHT'],1844 [Lang.Blocks.pingpong_rotate_ccw, 'LEFT'],1845 ],1846 value: 'RIGHT',1847 fontSize: 11,1848 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1849 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1850 },1851 {1852 type: 'Block',1853 accept: 'string',1854 defaultType: 'number',1855 value: 10,1856 },1857 {1858 type: 'Dropdown',1859 options: [1860 [Lang.Blocks.pingpong_rotate_cw, 'RIGHT'],1861 [Lang.Blocks.pingpong_rotate_ccw, 'LEFT'],1862 ],1863 value: 'RIGHT',1864 fontSize: 11,1865 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1866 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1867 },1868 { type: 'Block', accept: 'string', defaultType: 'number', value: 10 },1869 { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12 },1870 ],1871 def: {1872 params: [],1873 type: 'pingpong_g3_multi_motor_rotate',1874 },1875 paramsKeyMap: {1876 DIR_1: 0,1877 DEGREE_1: 1,1878 DIR_2: 2,1879 DEGREE_2: 3,1880 DIR_3: 4,1881 DEGREE_3: 5,1882 },1883 class: 'PingpongG3_motor',1884 isNotFor: ['PingpongG3'],1885 func(sprite, script) {1886 return RoCode.PingpongG3.postCallReturn(script, () => {1887 const dir1 = script.getStringField('DIR_1');1888 const dir2 = script.getStringField('DIR_2');1889 const dir3 = script.getStringField('DIR_3');1890 const degree1 = script.getNumberValue('DEGREE_1');1891 const degree2 = script.getNumberValue('DEGREE_2');1892 const degree3 = script.getNumberValue('DEGREE_3');1893 const speed1 = 80 * (dir1 === 'LEFT' ? -1 : 1);1894 const speed2 = 80 * (dir2 === 'LEFT' ? -1 : 1);1895 const speed3 = 80 * (dir3 === 'LEFT' ? -1 : 1);1896 const [arr1, delay1] = RoCode.PingpongG3.makeSingleStepPacket(1897 0,1898 speed1,1899 degree11900 );1901 const [arr2, delay2] = RoCode.PingpongG3.makeSingleStepPacket(1902 1,1903 speed2,1904 degree21905 );1906 const [arr3, delay3] = RoCode.PingpongG3.makeSingleStepPacket(1907 2,1908 speed3,1909 degree31910 );1911 const opt = [2, 1, 0, 2];1912 const packet = RoCode.PingpongG3.makeAggregatePacket(1913 OPCODE.AGGREGATE_STEPS,1914 0,1915 [arr1, arr2, arr3],1916 opt1917 );1918 const waitTime = Math.max(delay1, delay2, delay3);1919 return [packet, waitTime];1920 });1921 },1922 },1923 pingpong_g3_motor_rotate: {1924 color: RoCodeStatic.colorSet.block.default.HARDWARE,1925 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1926 skeleton: 'basic',1927 statements: [],1928 params: [1929 {1930 type: 'Dropdown',1931 options: Lang.Blocks.pingpong_g3_cube_all,1932 value: 0,1933 fontSize: 11,1934 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1935 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1936 },1937 {1938 type: 'Dropdown',1939 options: [1940 [Lang.Blocks.pingpong_rotate_cw, 'RIGHT'],1941 [Lang.Blocks.pingpong_rotate_ccw, 'LEFT'],1942 ],1943 value: 'RIGHT',1944 fontSize: 11,1945 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,1946 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,1947 },1948 { type: 'Block', accept: 'string', defaultType: 'number', value: 10 },1949 { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12 },1950 ],1951 events: {},1952 def: {1953 params: [],1954 type: 'pingpong_g3_motor_rotate',1955 },1956 paramsKeyMap: { CUBEID: 0, DIR: 1, DEGREE: 2 },1957 class: 'PingpongG3_motor',1958 isNotFor: ['PingpongG3'],1959 func(sprite, script) {1960 return RoCode.PingpongG3.postCallReturn(script, () => {1961 const cubeId = script.getNumberField('CUBEID');1962 const dir = script.getStringField('DIR');1963 const degree = script.getNumberValue('DEGREE');1964 const speed = 80 * (dir === 'LEFT' ? -1 : 1);1965 const [arr, waitTime] = RoCode.PingpongG3.makeSingleStepPacket(1966 cubeId,1967 speed,1968 degree1969 );1970 const packet = Buffer.from(arr);1971 return [packet, waitTime];1972 });1973 },1974 },1975 pingpong_g3_start_multi_motor_rotate: {1976 color: RoCodeStatic.colorSet.block.default.HARDWARE,1977 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,1978 skeleton: 'basic',1979 params: [1980 { type: 'Block', accept: 'string', defaultType: 'number', value: 100 },1981 { type: 'Block', accept: 'string', defaultType: 'number', value: 100 },1982 { type: 'Block', accept: 'string', defaultType: 'number', value: 100 },1983 {1984 type: 'Indicator',1985 img: 'block_icon/hardware_icon.svg',1986 size: 12,1987 },1988 ],1989 def: {1990 params: [],1991 type: 'pingpong_g3_start_multi_motor_rotate',1992 },1993 paramsKeyMap: { SPEED_1: 0, SPEED_2: 1, SPEED_3: 2 },1994 class: 'PingpongG3_motor',1995 isNotFor: ['PingpongG3'],1996 func(sprite, script) {1997 return RoCode.PingpongG3.postCallReturn(script, () => {1998 const speed1 = script.getNumberValue('SPEED_1');1999 const speed2 = script.getNumberValue('SPEED_2');2000 const speed3 = script.getNumberValue('SPEED_3');2001 const arr1 = RoCode.PingpongG3.makeContStepPacket(0, speed1);2002 const arr2 = RoCode.PingpongG3.makeContStepPacket(1, speed2);2003 const arr3 = RoCode.PingpongG3.makeContStepPacket(2, speed3);2004 const opt = [2, 0, 0, 2];2005 const packet = RoCode.PingpongG3.makeAggregatePacket(2006 OPCODE.AGGREGATE_STEPS,2007 0,2008 [arr1, arr2, arr3],2009 opt2010 );2011 return [packet];2012 });2013 },2014 },2015 pingpong_g3_start_motor_rotate: {2016 color: RoCodeStatic.colorSet.block.default.HARDWARE,2017 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2018 skeleton: 'basic',2019 params: [2020 {2021 type: 'Dropdown',2022 options: Lang.Blocks.pingpong_g3_cube_all,2023 value: 0,2024 fontSize: 11,2025 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2026 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2027 },2028 {2029 type: 'Block',2030 accept: 'string',2031 defaultType: 'number',2032 value: 100,2033 },2034 {2035 type: 'Indicator',2036 img: 'block_icon/hardware_icon.svg',2037 size: 12,2038 },2039 ],2040 def: {2041 params: [null, null],2042 type: 'pingpong_g3_start_motor_rotate',2043 },2044 paramsKeyMap: { CUBEID: 0, SPEED: 1 },2045 class: 'PingpongG3_motor',2046 isNotFor: ['PingpongG3'],2047 func(sprite, script) {2048 return RoCode.PingpongG3.postCallReturn(script, () => {2049 const cubeId = script.getNumberField('CUBEID');2050 const speed = script.getNumberValue('SPEED');2051 const arr = RoCode.PingpongG3.makeContStepPacket(cubeId, speed);2052 const packet = Buffer.from(arr);2053 return [packet];2054 });2055 },2056 },2057 pingpong_g3_stop_motor_rotate: {2058 color: RoCodeStatic.colorSet.block.default.HARDWARE,2059 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2060 skeleton: 'basic',2061 params: [2062 {2063 type: 'Dropdown',2064 options: Lang.Blocks.pingpong_g3_cube_all,2065 value: 0,2066 fontSize: 11,2067 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2068 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2069 },2070 {2071 type: 'Indicator',2072 img: 'block_icon/hardware_icon.svg',2073 size: 12,2074 },2075 ],2076 def: {2077 params: [],2078 type: 'pingpong_g3_stop_motor_rotate',2079 },2080 paramsKeyMap: { CUBEID: 0 },2081 class: 'PingpongG3_motor',2082 isNotFor: ['PingpongG3'],2083 func(sprite, script) {2084 return RoCode.PingpongG3.postCallReturn(script, () => {2085 const cubeId = script.getNumberField('CUBEID');2086 const arr = RoCode.PingpongG3.makeContStepPacket(cubeId, 0);2087 const packet = Buffer.from(arr);2088 return [packet];2089 });2090 },2091 },2092 pingpong_g3_rotate_servo_mortor: {2093 color: RoCodeStatic.colorSet.block.default.HARDWARE,2094 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2095 skeleton: 'basic',2096 statements: [],2097 params: [2098 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },2099 { type: 'Block', accept: 'string', defaultType: 'number' },2100 {2101 type: 'Indicator',2102 img: 'block_icon/hardware_icon.svg',2103 size: 12,2104 },2105 ],2106 events: {},2107 def: { params: [null, { type: 'angle' }], type: 'pingpong_g3_rotate_servo_mortor' },2108 paramsKeyMap: { cubeno: 0, DEGREE: 1 },2109 class: 'PingpongG3_motor',2110 isNotFor: ['PingpongG3'],2111 func(sprite, script) {2112 return RoCode.PingpongG3.postCallReturn(script, () => {2113 const cubeId = RoCode.PingpongG3._getCubeNoFromBlock(script);2114 let angle = script.getNumberValue('DEGREE', script);2115 angle = Math.min(Math.max(angle, 0), 180);2116 const opt = [2, 0, angle, 1];2117 const packet = RoCode.PingpongG3.makePacket(OPCODE.SERVO, 0x00, cubeId, opt);2118 return [packet];2119 });2120 },2121 },2122 pingpong_g3_set_dot_pixel: {2123 color: RoCodeStatic.colorSet.block.default.HARDWARE,2124 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2125 skeleton: 'basic',2126 statements: [],2127 params: [2128 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },2129 { type: 'Block', accept: 'string', defaultType: 'number', value: '0' },2130 { type: 'Block', accept: 'string', defaultType: 'number', value: '0' },2131 {2132 type: 'Dropdown',2133 options: [2134 [Lang.Blocks.pingpong_dot_on, 1],2135 [Lang.Blocks.pingpong_dot_off, 0],2136 ],2137 value: 1,2138 fontSize: 11,2139 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2140 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2141 },2142 {2143 type: 'Indicator',2144 img: 'block_icon/hardware_icon.svg',2145 size: 12,2146 },2147 ],2148 events: {},2149 def: {2150 params: [null, null, null],2151 type: 'pingpong_g3_set_dot_pixel',2152 },2153 paramsKeyMap: { cubeno: 0, X: 1, Y: 2, onoff: 3 },2154 class: 'PingpongG3_peripheral_LED',2155 isNotFor: ['PingpongG3'],2156 func(sprite, script) {2157 return RoCode.PingpongG3.postCallReturn(script, () => {2158 const cubeId = RoCode.PingpongG3._getCubeNoFromBlock(script);2159 let dotX = script.getNumberValue('X', script);2160 let dotY = script.getNumberValue('Y', script);2161 const onoff = script.getNumberField('onoff', script);2162 dotX = Math.min(Math.max(dotX, 0), 7);2163 dotY = Math.min(Math.max(dotY, 0), 7);2164 const opt = [0x70, dotY, dotX, onoff];2165 const packet = RoCode.PingpongG3.makePacket(2166 OPCODE.LEDMATRIX,2167 0xe1,2168 cubeId,2169 opt2170 );2171 return [packet];2172 });2173 },2174 },2175 pingpong_g3_set_dot_string: {2176 color: RoCodeStatic.colorSet.block.default.HARDWARE,2177 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2178 skeleton: 'basic',2179 statements: [],2180 params: [2181 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },2182 { type: 'Block', accept: 'string', value: 'Hello!' },2183 { type: 'Block', accept: 'string', defaultType: 'number', value: '2' },2184 {2185 type: 'Indicator',2186 img: 'block_icon/hardware_icon.svg',2187 size: 12,2188 },2189 ],2190 events: {},2191 def: { params: [null, null], type: 'pingpong_g3_set_dot_string' },2192 paramsKeyMap: { cubeno: 0, STR: 1, DURATION: 2 },2193 class: 'PingpongG3_peripheral_LED',2194 isNotFor: ['PingpongG3'],2195 func(sprite, script) {2196 return RoCode.PingpongG3.postCallReturn(script, () => {2197 const cubeId = RoCode.PingpongG3._getCubeNoFromBlock(script);2198 const str = script.getStringValue('STR', script);2199 const duration = script.getNumberValue('DURATION', script);2200 let period = Math.round((duration * 100) / (str.length * 8));2201 period = Math.min(Math.max(period, 1), 200);2202 const opt = Buffer.concat([2203 Buffer.from([0x70, period, 0]),2204 Buffer.from(str.substring(0, 20)),2205 ]);2206 const packet = RoCode.PingpongG3.makePacket(2207 OPCODE.LEDMATRIX,2208 0xe3,2209 cubeId,2210 opt2211 );2212 const waitTime = period * str.length * 8 * 10 + 400; // add wait for 400ms2213 return [packet, waitTime];2214 });2215 },2216 },2217 pingpong_g3_set_dot_clear: {2218 color: RoCodeStatic.colorSet.block.default.HARDWARE,2219 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2220 skeleton: 'basic',2221 statements: [],2222 params: [2223 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },2224 {2225 type: 'Indicator',2226 img: 'block_icon/hardware_icon.svg',2227 size: 12,2228 },2229 ],2230 events: {},2231 def: { params: [], type: 'pingpong_g3_set_dot_clear' },2232 paramsKeyMap: { cubeno: 0 },2233 class: 'PingpongG3_peripheral_LED',2234 isNotFor: ['PingpongG3'],2235 func(sprite, script) {2236 return RoCode.PingpongG3.postCallReturn(script, () => {2237 const cubeId = RoCode.PingpongG3._getCubeNoFromBlock(script);2238 const opt = [0x70, 1, 0, ' '];2239 const packet = RoCode.PingpongG3.makePacket(2240 OPCODE.LEDMATRIX,2241 0xe3,2242 cubeId,2243 opt2244 );2245 return [packet, 400];2246 });2247 },2248 },2249 pingpong_g3_playNoteForBeats: {2250 //'%1 큐브의 %2 번 음을 %3 박자로 연주하기 %4',2251 color: RoCodeStatic.colorSet.block.default.HARDWARE,2252 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2253 skeleton: 'basic',2254 statements: [],2255 params: [2256 {2257 type: 'Dropdown',2258 options: Lang.Blocks.pingpong_g3_cube_id,2259 value: 0,2260 fontSize: 11,2261 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2262 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2263 },2264 {2265 type: 'Dropdown',2266 options: Lang.Blocks.pingpong_opts_music_notes,2267 value: 48,2268 fontSize: 11,2269 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2270 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2271 },2272 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },2273 {2274 type: 'Indicator',2275 img: 'block_icon/hardware_icon.svg',2276 size: 12,2277 },2278 ],2279 events: {},2280 def: { params: [], type: 'pingpong_g3_playNoteForBeats' },2281 paramsKeyMap: { CUBEID: 0, NOTE: 1, BEATS: 2 },2282 class: 'PingpongG3_Music',2283 isNotFor: ['PingpongG3'],2284 func(sprite, script) {2285 return RoCode.PingpongG3.postCallReturn(script, () => {2286 const cubeId = script.getNumberField('CUBEID');2287 const NOTE = script.getNumberField('NOTE', script);2288 const BEATS = script.getNumberValue('BEATS', script);2289 const cBeats = RoCode.PingpongG3._clampBeats(BEATS);2290 const durationSec = RoCode.PingpongG3._beatsToDuration(cBeats);2291 const waitTime = durationSec * 10 + 30; //XXX2292 const arr = RoCode.PingpongG3.makeMusicNotePacket(cubeId, NOTE, durationSec);2293 const packet = Buffer.from(arr);2294 return [packet, waitTime];2295 });2296 },2297 },2298 pingpong_g3_playChordForBeats: {2299 //'%1 큐브 %2, %3 큐브 %4, %5 큐브 %6 %7 박자로 연주하기 %8',2300 color: RoCodeStatic.colorSet.block.default.HARDWARE,2301 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2302 skeleton: 'basic',2303 statements: [],2304 params: [2305 {2306 type: 'Dropdown',2307 options: Lang.Blocks.pingpong_g3_cube_id,2308 value: 0,2309 fontSize: 11,2310 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2311 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2312 },2313 {2314 type: 'Dropdown',2315 options: Lang.Blocks.pingpong_opts_music_notes,2316 value: 48,2317 fontSize: 11,2318 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2319 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2320 },2321 {2322 type: 'Dropdown',2323 options: Lang.Blocks.pingpong_g3_cube_id,2324 value: 1,2325 fontSize: 11,2326 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2327 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2328 },2329 {2330 type: 'Dropdown',2331 options: Lang.Blocks.pingpong_opts_music_notes,2332 value: 48,2333 fontSize: 11,2334 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2335 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2336 },2337 {2338 type: 'Dropdown',2339 options: Lang.Blocks.pingpong_g3_cube_id,2340 value: 2,2341 fontSize: 11,2342 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2343 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2344 },2345 {2346 type: 'Dropdown',2347 options: Lang.Blocks.pingpong_opts_music_notes,2348 value: 48,2349 fontSize: 11,2350 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2351 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2352 },2353 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },2354 {2355 type: 'Indicator',2356 img: 'block_icon/hardware_icon.svg',2357 size: 12,2358 },2359 ],2360 events: {},2361 def: { params: [], type: 'pingpong_g3_playChordForBeats' },2362 paramsKeyMap: {2363 CUBEID_1: 0,2364 NOTE_1: 1,2365 CUBEID_2: 2,2366 NOTE_2: 3,2367 CUBEID_3: 4,2368 NOTE_3: 5,2369 BEATS: 6,2370 },2371 class: 'PingpongG3_Music',2372 isNotFor: ['PingpongG3'],2373 func(sprite, script) {2374 return RoCode.PingpongG3.postCallReturn(script, () => {2375 const cubeId1 = script.getNumberField('CUBEID_1');2376 const cubeId2 = script.getNumberField('CUBEID_2');2377 const cubeId3 = script.getNumberField('CUBEID_3');2378 const NOTE1 = script.getNumberField('NOTE_1', script);2379 const NOTE2 = script.getNumberField('NOTE_2', script);2380 const NOTE3 = script.getNumberField('NOTE_3', script);2381 const BEATS = script.getNumberValue('BEATS', script);2382 const cBeats = RoCode.PingpongG3._clampBeats(BEATS);2383 const durationSec = RoCode.PingpongG3._beatsToDuration(cBeats);2384 const waitTime = durationSec * 10 + 30;2385 const arr1 = RoCode.PingpongG3.makeMusicNotePacket(2386 cubeId1,2387 NOTE1,2388 durationSec2389 );2390 const arr2 = RoCode.PingpongG3.makeMusicNotePacket(2391 cubeId2,2392 NOTE2,2393 durationSec2394 );2395 const arr3 = RoCode.PingpongG3.makeMusicNotePacket(2396 cubeId3,2397 NOTE3,2398 durationSec2399 );2400 const packet = RoCode.PingpongG3.makeAggregatePacket(2401 OPCODE.MUSIC,2402 0xa2,2403 [arr1, arr2, arr3],2404 [0, 0]2405 );2406 return [packet, waitTime];2407 });2408 },2409 },2410 pingpong_g3_restForBeats: {2411 color: RoCodeStatic.colorSet.block.default.HARDWARE,2412 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2413 skeleton: 'basic',2414 params: [2415 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },2416 {2417 type: 'Indicator',2418 img: 'block_icon/hardware_icon.svg',2419 size: 12,2420 },2421 ],2422 def: { params: [], type: 'pingpong_g3_restForBeats' },2423 paramsKeyMap: { BEATS: 0 },2424 class: 'PingpongG3_Music',2425 isNotFor: ['PingpongG3'],2426 func(sprite, script) {2427 return RoCode.PingpongG3.postCallReturn(script, () => {2428 const BEATS = script.getNumberValue('BEATS', script);2429 const cBeats = RoCode.PingpongG3._clampBeats(BEATS);2430 const durationSec = RoCode.PingpongG3._beatsToDuration(cBeats);2431 const waitTime = durationSec * 10 + 30;2432 //XXX2433 return [null, waitTime];2434 });2435 },2436 },2437 pingpong_g3_setTempo: {2438 color: RoCodeStatic.colorSet.block.default.HARDWARE,2439 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2440 skeleton: 'basic',2441 params: [2442 { type: 'Block', accept: 'string', defaultType: 'number', value: '60' },2443 {2444 type: 'Indicator',2445 img: 'block_icon/hardware_icon.svg',2446 size: 12,2447 },2448 ],2449 def: { params: [], type: 'pingpong_g3_setTempo' },2450 paramsKeyMap: { TEMPO: 0 },2451 class: 'PingpongG3_Music',2452 isNotFor: ['PingpongG3'],2453 func(sprite, script) {2454 let tempo = script.getNumberValue('TEMPO', script);2455 RoCode.PingpongG3.tempo = RoCode.PingpongG3._clampTempo(tempo);2456 return script.callReturn();2457 },2458 },2459 pingpong_g3_getTempo: {2460 color: RoCodeStatic.colorSet.block.default.HARDWARE,2461 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2462 skeleton: 'basic_string_field',2463 params: [],2464 def: { params: [], type: 'pingpong_g3_getTempo' },2465 paramsKeyMap: {},2466 class: 'PingpongG3_Music',2467 isNotFor: ['PingpongG3'],2468 func(sprite, script) {2469 return RoCode.PingpongG3.tempo;2470 },2471 },2472 };2473 }2474 setLanguage() {2475 return {2476 ko: {2477 template: {2478 pingpong_g3_when_button_pressed: '%1 %2 큐브 버튼을 눌렀을 때',2479 pingpong_g3_when_tilted: '%1 %2 큐브를 %3로 기울였을 때',2480 pingpong_g3_is_button_pressed: '%1 큐브 버튼이 눌렸는가?',2481 pingpong_g3_is_tilted: '%1 큐브가 %2로 기울어졌는가?',2482 pingpong_g3_is_top_shape: '%1 큐브의 윗면에 %2 모양이 있는가?',2483 pingpong_g3_get_tilt_value: '%1 큐브의 %2 방향 기울기',2484 pingpong_g3_get_sensor_value: '%1 큐브의 %2 센서값',2485 pingpong_g3_multi_motor_rotate:2486 '모터1을 %1 방향 %2 도, 모터2를 %3 방향 %4 도, 모터3을 %5방향 %6도 회전하기 %7',2487 pingpong_g3_motor_rotate: '%1 모터를 %2 방향으로 %3 도 회전하기 %4',2488 pingpong_g3_start_multi_motor_rotate:2489 '모터1 속도를 %1, 모터2 속도를 %2, 모터3 속도를 %3으로 계속 회전하기 %4',2490 pingpong_g3_start_motor_rotate: '%1 모터의 속도를 %2으로 계속 회전하기 %3',2491 pingpong_g3_stop_motor_rotate: '%1 모터 멈추기 %2',2492 pingpong_g3_set_dot_pixel: '%1 번째 큐브의 도트 X:%2 Y:%3 %4 %5',2493 pingpong_g3_set_dot_string:2494 '%1 번째 큐브에 도트 문자열 %2 %3초동안 보여주기 %4',2495 pingpong_g3_set_dot_clear: '%1 번째 큐브의 화면 지우기 %2',2496 pingpong_g3_rotate_servo_mortor: '%1 번째 큐브의 서보모터 %2도로 설정하기 %3',2497 pingpong_g3_playNoteForBeats: '%1 큐브의 %2 음을 %3 박자로 연주하기 %4',2498 pingpong_g3_playChordForBeats:2499 '%1 큐브 %2, %3 큐브 %4, %5 큐브 %6 %7 박자로 연주하기 %8',2500 pingpong_g3_restForBeats: '%1 박자 쉬기 %2',2501 pingpong_g3_setTempo: '악보 빠르기를 %1 으로 정하기 %2',2502 pingpong_g3_getTempo: '악보 빠르기',2503 },2504 Blocks: {2505 ...this.lang_defblock.ko,2506 pingpong_g3_cube_id: [2507 ['1번', 0],2508 ['2번', 1],2509 ['3번', 2],2510 ],2511 pingpong_g3_cube_all: [2512 ['1번', 0],2513 ['2번', 1],2514 ['3번', 2],2515 ['모든', -1],2516 ],2517 },2518 },2519 en: {2520 template: {2521 pingpong_g3_when_button_pressed: '%1 %2 cube button pressed',2522 pingpong_g3_when_tilted: '%1 %2 cube tilted to %3',2523 pingpong_g3_is_button_pressed: '%1 cube button pressed?',2524 pingpong_g3_is_tilted: '%1 cube tilted to %2',2525 pingpong_g3_is_top_shape: '%1 cube shown %2 in top view?',2526 pingpong_g3_get_tilt_value: '%1 cube tilt angle to %2',2527 pingpong_g3_get_sensor_value: '%1 cube read sensor %2',2528 pingpong_g3_multi_motor_rotate:2529 'rotate motor1 %2 degrees %1, ' +2530 'motor2 %4 degrees %3, motor3 %6 degrees %5 %7',2531 pingpong_g3_motor_rotate: 'rotate %2 degrees %1 %3',2532 pingpong_g3_start_multi_motor_rotate:2533 'set motor1 speed to %1, motor2 speed to %2, motor3 speed to %3 %4',2534 pingpong_g3_start_motor_rotate: 'set motor speed to %1 %2',2535 pingpong_g3_stop_motor_rotate: 'stop motor rotate %1',2536 pingpong_g3_rotate_servo_mortor: 'set servo mortor to %1 degrees %2',2537 pingpong_g3_set_dot_pixel: '%1 cube set DOT X:%2 Y:%3 %4 %5',2538 pingpong_g3_set_dot_string:2539 'print %1 cube string %2 during %3 seconds to DOT %4',2540 pingpong_g3_set_dot_clear: '%1 cube clear DOT %2',2541 pingpong_g3_playNoteForBeats: '%1 cube play note %2 for %3 beats %4',2542 pingpong_g3_playChordForBeats:2543 '%1 cube %2, %3 cube %4, %5 cube %6 for %7 beats %8',2544 pingpong_g3_restForBeats: 'rest for %1 beats %2',2545 pingpong_g3_setTempo: 'set tempo to %1 %2',2546 pingpong_g3_getTempo: 'tempo',2547 },2548 Blocks: {2549 ...this.lang_defblock.en,2550 pingpong_g3_cube_id: [2551 ['1st', 0],2552 ['2nd', 1],2553 ['3rd', 2],2554 ],2555 pingpong_g3_cube_all: [2556 ['1st', 0],2557 ['2nd', 1],2558 ['3rd', 2],2559 ['All', -1],2560 ],2561 },2562 },2563 };2564 }2565})();2566RoCode.PingpongG4 = new (class extends PingpongBase {2567 constructor() {2568 super(4);2569 this.id = '35.4';2570 this.name = 'PingpongG4';2571 this.url = 'https://www.roborisen.com';2572 this.imageName = 'pingpong_g4.png';2573 this.title = {2574 ko: '핑퐁 G4',2575 en: 'Pingpong G4',2576 };2577 this.blockMenuBlocks = [2578 'pingpong_g4_when_button_pressed',2579 'pingpong_g4_when_tilted',2580 'pingpong_g4_is_button_pressed',2581 'pingpong_g4_is_tilted',2582 'pingpong_g4_get_tilt_value',2583 'pingpong_g4_is_top_shape',2584 'pingpong_g4_get_sensor_value',2585 'pingpong_g4_multi_motor_rotate',2586 'pingpong_g4_motor_rotate',2587 'pingpong_g4_start_multi_motor_rotate',2588 'pingpong_g4_start_motor_rotate',2589 'pingpong_g4_stop_motor_rotate',2590 'pingpong_g4_rotate_servo_mortor',2591 'pingpong_g4_set_dot_pixel',2592 'pingpong_g4_set_dot_string',2593 'pingpong_g4_set_dot_clear',2594 'pingpong_g4_playNoteForBeats',2595 'pingpong_g4_playChordForBeats',2596 'pingpong_g4_restForBeats',2597 'pingpong_g4_setTempo',2598 'pingpong_g4_getTempo',2599 ];2600 }2601 getBlocks() {2602 return {2603 pingpong_g4_when_button_pressed: {2604 color: RoCodeStatic.colorSet.block.default.HARDWARE,2605 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2606 skeleton: 'basic_event',2607 statements: [],2608 params: [2609 {2610 type: 'Indicator',2611 img: 'block_icon/start_icon_hardware.svg',2612 size: 14,2613 position: { x: 0, y: -2 },2614 },2615 {2616 type: 'Dropdown',2617 options: Lang.Blocks.pingpong_g4_cube_id,2618 value: 0,2619 fontSize: 11,2620 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2621 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2622 },2623 ],2624 events: {},2625 def: {2626 params: [null],2627 type: 'pingpong_g4_when_button_pressed',2628 },2629 paramsKeyMap: {2630 CUBEID: 1,2631 },2632 class: 'PingpongG4',2633 isNotFor: ['PingpongG4'],2634 event: 'pp_when_button_pressed',2635 func(sprite, script) {2636 const cubeId = script.getNumberField('CUBEID');2637 const pd = RoCode.hw.portData;2638 if (2639 (cubeId == 0 && pd.c0_BUTTON == 1) ||2640 (cubeId == 1 && pd.c1_BUTTON == 1) ||2641 (cubeId == 2 && pd.c2_BUTTON == 1) ||2642 (cubeId == 3 && pd.c3_BUTTON == 1)2643 ) {2644 return script.callReturn();2645 }2646 return this.die();2647 },2648 },2649 pingpong_g4_when_tilted: {2650 color: RoCodeStatic.colorSet.block.default.HARDWARE,2651 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2652 skeleton: 'basic_event',2653 statements: [],2654 params: [2655 {2656 type: 'Indicator',2657 img: 'block_icon/start_icon_hardware.svg',2658 size: 14,2659 position: { x: 0, y: -2 },2660 },2661 {2662 type: 'Dropdown',2663 options: Lang.Blocks.pingpong_g4_cube_id,2664 value: 0,2665 fontSize: 11,2666 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2667 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2668 },2669 {2670 type: 'Dropdown',2671 options: Lang.Blocks.pingpong_opts_cube_tiltDir,2672 value: 'F_CIRCLE',2673 fontSize: 11,2674 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2675 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2676 },2677 ],2678 events: {},2679 def: {2680 params: [null, null],2681 type: 'pingpong_g4_when_tilted',2682 },2683 paramsKeyMap: {2684 CUBEID: 1,2685 TILT_DIR: 2,2686 },2687 class: 'PingpongG4',2688 isNotFor: ['PingpongG4'],2689 event: 'pp_when_tilted',2690 func(sprite, script) {2691 const cubeId = script.getNumberField('CUBEID');2692 const tiltDir = script.getStringField('TILT_DIR');2693 const tiltValue = RoCode.PingpongG4._getTiltValue(cubeId, tiltDir);2694 if (tiltValue >= RoCode.PingpongG4.TILT_THRESHOLD) {2695 return script.callReturn();2696 }2697 return this.die();2698 },2699 },2700 pingpong_g4_is_button_pressed: {2701 color: RoCodeStatic.colorSet.block.default.HARDWARE,2702 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2703 skeleton: 'basic_boolean_field',2704 statements: [],2705 params: [2706 {2707 type: 'Dropdown',2708 options: Lang.Blocks.pingpong_g4_cube_id,2709 value: 0,2710 fontSize: 11,2711 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2712 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2713 },2714 ],2715 def: {2716 params: [null],2717 type: 'pingpong_g4_is_button_pressed',2718 },2719 paramsKeyMap: {2720 CUBEID: 0,2721 },2722 class: 'PingpongG4',2723 isNotFor: ['PingpongG4'],2724 func(sprite, script) {2725 const cubeId = script.getNumberField('CUBEID');2726 const pd = RoCode.hw.portData;2727 return (2728 (cubeId == 0 && pd.c0_BUTTON == 1) ||2729 (cubeId == 1 && pd.c1_BUTTON == 1) ||2730 (cubeId == 2 && pd.c2_BUTTON == 1) ||2731 (cubeId == 3 && pd.c3_BUTTON == 1)2732 );2733 },2734 },2735 pingpong_g4_is_tilted: {2736 color: RoCodeStatic.colorSet.block.default.HARDWARE,2737 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2738 skeleton: 'basic_boolean_field',2739 statements: [],2740 params: [2741 {2742 type: 'Dropdown',2743 options: Lang.Blocks.pingpong_g4_cube_id,2744 value: 0,2745 fontSize: 11,2746 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2747 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2748 },2749 {2750 type: 'Dropdown',2751 options: Lang.Blocks.pingpong_opts_cube_tiltDir,2752 value: 'F_CIRCLE',2753 fontSize: 11,2754 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2755 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2756 },2757 ],2758 events: {},2759 def: { params: [], type: 'pingpong_g4_is_tilted' },2760 paramsKeyMap: {2761 CUBEID: 0,2762 TILT_DIR: 1,2763 },2764 class: 'PingpongG4',2765 isNotFor: ['PingpongG4'],2766 func(sprite, script) {2767 const cubeId = script.getNumberField('CUBEID');2768 const tiltDir = script.getStringField('TILT_DIR', script);2769 const tiltValue = RoCode.PingpongG4._getTiltValue(cubeId, tiltDir);2770 return tiltValue >= RoCode.PingpongG4.TILT_THRESHOLD;2771 },2772 },2773 pingpong_g4_get_tilt_value: {2774 color: RoCodeStatic.colorSet.block.default.HARDWARE,2775 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2776 skeleton: 'basic_string_field',2777 params: [2778 {2779 type: 'Dropdown',2780 options: Lang.Blocks.pingpong_g4_cube_id,2781 value: 0,2782 fontSize: 11,2783 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2784 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2785 },2786 {2787 type: 'Dropdown',2788 options: Lang.Blocks.pingpong_opts_cube_tiltDir,2789 value: 'F_CIRCLE',2790 fontSize: 11,2791 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2792 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2793 },2794 ],2795 events: {},2796 def: {2797 params: [null],2798 type: 'pingpong_g4_get_tilt_value',2799 },2800 paramsKeyMap: { CUBEID: 0, DIR: 1 },2801 class: 'PingpongG4',2802 isNotFor: ['PingpongG4'],2803 func(sprite, script) {2804 const cubeId = script.getNumberField('CUBEID');2805 const tiltDir = script.getStringField('DIR', script);2806 return RoCode.PingpongG4._getTiltValue(cubeId, tiltDir);2807 },2808 },2809 pingpong_g4_get_sensor_value: {2810 color: RoCodeStatic.colorSet.block.default.HARDWARE,2811 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2812 skeleton: 'basic_string_field',2813 params: [2814 {2815 type: 'Dropdown',2816 options: Lang.Blocks.pingpong_g4_cube_id,2817 value: 0,2818 fontSize: 11,2819 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2820 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2821 },2822 {2823 type: 'Dropdown',2824 options: [2825 [Lang.Blocks.pingpong_sensor_proximity, 'PROXIMITY'],2826 [Lang.Blocks.pingpong_sensor_ain, 'AIN'],2827 ],2828 value: 'PROXIMITY',2829 fontSize: 11,2830 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2831 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2832 },2833 ],2834 def: { params: [], type: 'pingpong_g4_get_sensor_value' },2835 paramsKeyMap: { CUBEID: 0, SENSOR: 1 },2836 class: 'PingpongG4',2837 isNotFor: ['PingpongG4'],2838 func(sprite, script) {2839 const cubeId = script.getNumberField('CUBEID');2840 const sensorType = script.getStringField('SENSOR', script);2841 const pd = RoCode.hw.portData;2842 let value = 0;2843 if (sensorType == 'PROXIMITY') {2844 if (cubeId == 0) {2845 value = pd.c0_PROXIMITY;2846 } else if (cubeId == 1) {2847 value = pd.c1_PROXIMITY;2848 } else if (cubeId == 2) {2849 value = pd.c2_PROXIMITY;2850 } else if (cubeId == 3) {2851 value = pd.c3_PROXIMITY;2852 }2853 } else if (sensorType == 'AIN') {2854 if (cubeId == 0) {2855 value = pd.c0_AIN;2856 } else if (cubeId == 1) {2857 value = pd.c1_AIN;2858 } else if (cubeId == 2) {2859 value = pd.c2_AIN;2860 } else if (cubeId == 3) {2861 value = pd.c3_AIN;2862 }2863 }2864 return value;2865 },2866 },2867 pingpong_g4_is_top_shape: {2868 color: RoCodeStatic.colorSet.block.default.HARDWARE,2869 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2870 skeleton: 'basic_boolean_field',2871 statements: [],2872 params: [2873 {2874 type: 'Dropdown',2875 options: Lang.Blocks.pingpong_g4_cube_id,2876 value: 0,2877 fontSize: 11,2878 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2879 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2880 },2881 {2882 type: 'Dropdown',2883 options: Lang.Blocks.pingpong_opts_cube_dir6,2884 value: 'DF_RECTANGLE',2885 fontSize: 11,2886 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2887 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2888 },2889 ],2890 events: {},2891 def: { params: [], type: 'pingpong_g4_is_top_shape' },2892 paramsKeyMap: { CUBEID: 0, TILT_DIR: 1 },2893 class: 'PingpongG4',2894 isNotFor: ['PingpongG4'],2895 func(sprite, script) {2896 const cubeId = script.getNumberField('CUBEID');2897 const tiltDir = script.getStringField('TILT_DIR', script);2898 return RoCode.PingpongG4._isUpperDir(cubeId, tiltDir);2899 },2900 },2901 pingpong_g4_multi_motor_rotate: {2902 color: RoCodeStatic.colorSet.block.default.HARDWARE,2903 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,2904 skeleton: 'basic',2905 params: [2906 {2907 type: 'Dropdown',2908 options: [2909 [Lang.Blocks.pingpong_rotate_cw, 'RIGHT'],2910 [Lang.Blocks.pingpong_rotate_ccw, 'LEFT'],2911 ],2912 value: 'RIGHT',2913 fontSize: 11,2914 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2915 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2916 },2917 { type: 'Block', accept: 'string', defaultType: 'number', value: 10 },2918 {2919 type: 'Dropdown',2920 options: [2921 [Lang.Blocks.pingpong_rotate_cw, 'RIGHT'],2922 [Lang.Blocks.pingpong_rotate_ccw, 'LEFT'],2923 ],2924 value: 'RIGHT',2925 fontSize: 11,2926 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2927 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2928 },2929 { type: 'Block', accept: 'string', defaultType: 'number', value: 10 },2930 {2931 type: 'Dropdown',2932 options: [2933 [Lang.Blocks.pingpong_rotate_cw, 'RIGHT'],2934 [Lang.Blocks.pingpong_rotate_ccw, 'LEFT'],2935 ],2936 value: 'RIGHT',2937 fontSize: 11,2938 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2939 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2940 },2941 { type: 'Block', accept: 'string', defaultType: 'number', value: 10 },2942 {2943 type: 'Dropdown',2944 options: [2945 [Lang.Blocks.pingpong_rotate_cw, 'RIGHT'],2946 [Lang.Blocks.pingpong_rotate_ccw, 'LEFT'],2947 ],2948 value: 'RIGHT',2949 fontSize: 11,2950 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,2951 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,2952 },2953 { type: 'Block', accept: 'string', defaultType: 'number', value: 10 },2954 { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12 },2955 ],2956 def: {2957 params: [],2958 type: 'pingpong_g4_multi_motor_rotate',2959 },2960 paramsKeyMap: {2961 DIR_1: 0,2962 DEGREE_1: 1,2963 DIR_2: 2,2964 DEGREE_2: 3,2965 DIR_3: 4,2966 DEGREE_3: 5,2967 DIR_4: 6,2968 DEGREE_4: 7,2969 },2970 class: 'PingpongG4_motor',2971 isNotFor: ['PingpongG4'],2972 func(sprite, script) {2973 return RoCode.PingpongG4.postCallReturn(script, () => {2974 const dir1 = script.getStringField('DIR_1');2975 const dir2 = script.getStringField('DIR_2');2976 const dir3 = script.getStringField('DIR_3');2977 const dir4 = script.getStringField('DIR_4');2978 const degree1 = script.getNumberValue('DEGREE_1');2979 const degree2 = script.getNumberValue('DEGREE_2');2980 const degree3 = script.getNumberValue('DEGREE_3');2981 const degree4 = script.getNumberValue('DEGREE_4');2982 const speed1 = 80 * (dir1 === 'LEFT' ? -1 : 1);2983 const speed2 = 80 * (dir2 === 'LEFT' ? -1 : 1);2984 const speed3 = 80 * (dir3 === 'LEFT' ? -1 : 1);2985 const speed4 = 80 * (dir4 === 'LEFT' ? -1 : 1);2986 const [arr1, delay1] = RoCode.PingpongG4.makeSingleStepPacket(2987 0,2988 speed1,2989 degree12990 );2991 const [arr2, delay2] = RoCode.PingpongG4.makeSingleStepPacket(2992 1,2993 speed2,2994 degree22995 );2996 const [arr3, delay3] = RoCode.PingpongG4.makeSingleStepPacket(2997 2,2998 speed3,2999 degree33000 );3001 const [arr4, delay4] = RoCode.PingpongG4.makeSingleStepPacket(3002 3,3003 speed4,3004 degree43005 );3006 const opt = [MODE.MULTIROLE, 1, 0, 2];3007 const packet = RoCode.PingpongG4.makeAggregatePacket(3008 OPCODE.AGGREGATE_STEPS,3009 0,3010 [arr1, arr2, arr3, arr4],3011 opt3012 );3013 const waitTime = Math.max(delay1, delay2, delay3, delay4);3014 return [packet, waitTime];3015 });3016 },3017 },3018 pingpong_g4_motor_rotate: {3019 color: RoCodeStatic.colorSet.block.default.HARDWARE,3020 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3021 skeleton: 'basic',3022 statements: [],3023 params: [3024 {3025 type: 'Dropdown',3026 options: Lang.Blocks.pingpong_g4_cube_all,3027 value: 0,3028 fontSize: 11,3029 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3030 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3031 },3032 {3033 type: 'Dropdown',3034 options: [3035 [Lang.Blocks.pingpong_rotate_cw, 'RIGHT'],3036 [Lang.Blocks.pingpong_rotate_ccw, 'LEFT'],3037 ],3038 value: 'RIGHT',3039 fontSize: 11,3040 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3041 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3042 },3043 { type: 'Block', accept: 'string', defaultType: 'number', value: 10 },3044 { type: 'Indicator', img: 'block_icon/hardware_icon.svg', size: 12 },3045 ],3046 events: {},3047 def: {3048 params: [],3049 type: 'pingpong_g4_motor_rotate',3050 },3051 paramsKeyMap: { CUBEID: 0, DIR: 1, DEGREE: 2 },3052 class: 'PingpongG4_motor',3053 isNotFor: ['PingpongG4'],3054 func(sprite, script) {3055 return RoCode.PingpongG4.postCallReturn(script, () => {3056 const cubeId = script.getNumberField('CUBEID');3057 const dir = script.getStringField('DIR');3058 const degree = script.getNumberValue('DEGREE');3059 const speed = 80 * (dir === 'LEFT' ? -1 : 1);3060 const [arr, waitTime] = RoCode.PingpongG4.makeSingleStepPacket(3061 cubeId,3062 speed,3063 degree3064 );3065 const packet = Buffer.from(arr);3066 return [packet, waitTime];3067 });3068 },3069 },3070 pingpong_g4_start_multi_motor_rotate: {3071 color: RoCodeStatic.colorSet.block.default.HARDWARE,3072 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3073 skeleton: 'basic',3074 params: [3075 { type: 'Block', accept: 'string', defaultType: 'number', value: 100 },3076 { type: 'Block', accept: 'string', defaultType: 'number', value: 100 },3077 { type: 'Block', accept: 'string', defaultType: 'number', value: 100 },3078 { type: 'Block', accept: 'string', defaultType: 'number', value: 100 },3079 {3080 type: 'Indicator',3081 img: 'block_icon/hardware_icon.svg',3082 size: 12,3083 },3084 ],3085 def: {3086 params: [],3087 type: 'pingpong_g4_start_multi_motor_rotate',3088 },3089 paramsKeyMap: { SPEED_1: 0, SPEED_2: 1, SPEED_3: 2, SPEED_4: 3 },3090 class: 'PingpongG4_motor',3091 isNotFor: ['PingpongG4'],3092 func(sprite, script) {3093 return RoCode.PingpongG4.postCallReturn(script, () => {3094 const speed1 = script.getNumberValue('SPEED_1');3095 const speed2 = script.getNumberValue('SPEED_2');3096 const speed3 = script.getNumberValue('SPEED_3');3097 const speed4 = script.getNumberValue('SPEED_4');3098 const arr1 = RoCode.PingpongG4.makeContStepPacket(0, speed1);3099 const arr2 = RoCode.PingpongG4.makeContStepPacket(1, speed2);3100 const arr3 = RoCode.PingpongG4.makeContStepPacket(2, speed3);3101 const arr4 = RoCode.PingpongG4.makeContStepPacket(3, speed4);3102 const opt = [MODE.MULTIROLE, 0, 0, 2];3103 const packet = RoCode.PingpongG4.makeAggregatePacket(3104 OPCODE.AGGREGATE_STEPS,3105 0,3106 [arr1, arr2, arr3, arr4],3107 opt3108 );3109 return [packet];3110 });3111 },3112 },3113 pingpong_g4_start_motor_rotate: {3114 color: RoCodeStatic.colorSet.block.default.HARDWARE,3115 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3116 skeleton: 'basic',3117 params: [3118 {3119 type: 'Dropdown',3120 options: Lang.Blocks.pingpong_g4_cube_all,3121 value: 0,3122 fontSize: 11,3123 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3124 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3125 },3126 {3127 type: 'Block',3128 accept: 'string',3129 defaultType: 'number',3130 value: 100,3131 },3132 {3133 type: 'Indicator',3134 img: 'block_icon/hardware_icon.svg',3135 size: 12,3136 },3137 ],3138 def: {3139 params: [null, null],3140 type: 'pingpong_g4_start_motor_rotate',3141 },3142 paramsKeyMap: { CUBEID: 0, SPEED: 1 },3143 class: 'PingpongG4_motor',3144 isNotFor: ['PingpongG4'],3145 func(sprite, script) {3146 return RoCode.PingpongG4.postCallReturn(script, () => {3147 const cubeId = script.getNumberField('CUBEID');3148 const speed = script.getNumberValue('SPEED');3149 const arr = RoCode.PingpongG4.makeContStepPacket(cubeId, speed);3150 const packet = Buffer.from(arr);3151 return [packet];3152 });3153 },3154 },3155 pingpong_g4_stop_motor_rotate: {3156 color: RoCodeStatic.colorSet.block.default.HARDWARE,3157 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3158 skeleton: 'basic',3159 params: [3160 {3161 type: 'Dropdown',3162 options: Lang.Blocks.pingpong_g4_cube_all,3163 value: 0,3164 fontSize: 11,3165 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3166 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3167 },3168 {3169 type: 'Indicator',3170 img: 'block_icon/hardware_icon.svg',3171 size: 12,3172 },3173 ],3174 def: {3175 params: [],3176 type: 'pingpong_g4_stop_motor_rotate',3177 },3178 paramsKeyMap: { CUBEID: 0 },3179 class: 'PingpongG4_motor',3180 isNotFor: ['PingpongG4'],3181 func(sprite, script) {3182 return RoCode.PingpongG4.postCallReturn(script, () => {3183 const cubeId = script.getNumberField('CUBEID');3184 const arr = RoCode.PingpongG4.makeContStepPacket(cubeId, 0);3185 const packet = Buffer.from(arr);3186 return [packet];3187 });3188 },3189 },3190 pingpong_g4_rotate_servo_mortor: {3191 color: RoCodeStatic.colorSet.block.default.HARDWARE,3192 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3193 skeleton: 'basic',3194 statements: [],3195 params: [3196 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },3197 { type: 'Block', accept: 'string', defaultType: 'number' },3198 {3199 type: 'Indicator',3200 img: 'block_icon/hardware_icon.svg',3201 size: 12,3202 },3203 ],3204 events: {},3205 def: { params: [null, { type: 'angle' }], type: 'pingpong_g4_rotate_servo_mortor' },3206 paramsKeyMap: { cubeno: 0, DEGREE: 1 },3207 class: 'PingpongG4_motor',3208 isNotFor: ['PingpongG4'],3209 func(sprite, script) {3210 return RoCode.PingpongG4.postCallReturn(script, () => {3211 const cubeId = RoCode.PingpongG4._getCubeNoFromBlock(script);3212 let angle = script.getNumberValue('DEGREE', script);3213 angle = Math.min(Math.max(angle, 0), 180);3214 const opt = [2, 0, angle, 1];3215 const packet = RoCode.PingpongG4.makePacket(OPCODE.SERVO, 0x00, cubeId, opt);3216 return [packet];3217 });3218 },3219 },3220 pingpong_g4_set_dot_pixel: {3221 color: RoCodeStatic.colorSet.block.default.HARDWARE,3222 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3223 skeleton: 'basic',3224 statements: [],3225 params: [3226 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },3227 { type: 'Block', accept: 'string', defaultType: 'number', value: '0' },3228 { type: 'Block', accept: 'string', defaultType: 'number', value: '0' },3229 {3230 type: 'Dropdown',3231 options: [3232 [Lang.Blocks.pingpong_dot_on, 1],3233 [Lang.Blocks.pingpong_dot_off, 0],3234 ],3235 value: 1,3236 fontSize: 11,3237 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3238 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3239 },3240 {3241 type: 'Indicator',3242 img: 'block_icon/hardware_icon.svg',3243 size: 12,3244 },3245 ],3246 events: {},3247 def: {3248 params: [null, null, null],3249 type: 'pingpong_g4_set_dot_pixel',3250 },3251 paramsKeyMap: { cubeno: 0, X: 1, Y: 2, onoff: 3 },3252 class: 'PingpongG4_peripheral_LED',3253 isNotFor: ['PingpongG4'],3254 func(sprite, script) {3255 return RoCode.PingpongG4.postCallReturn(script, () => {3256 const cubeId = RoCode.PingpongG4._getCubeNoFromBlock(script);3257 let dotX = script.getNumberValue('X', script);3258 let dotY = script.getNumberValue('Y', script);3259 const onoff = script.getNumberField('onoff', script);3260 dotX = Math.min(Math.max(dotX, 0), 7);3261 dotY = Math.min(Math.max(dotY, 0), 7);3262 const opt = [0x70, dotY, dotX, onoff];3263 const packet = RoCode.PingpongG4.makePacket(3264 OPCODE.LEDMATRIX,3265 0xe1,3266 cubeId,3267 opt3268 );3269 return [packet];3270 });3271 },3272 },3273 pingpong_g4_set_dot_string: {3274 color: RoCodeStatic.colorSet.block.default.HARDWARE,3275 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3276 skeleton: 'basic',3277 statements: [],3278 params: [3279 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },3280 { type: 'Block', accept: 'string', value: 'Hello!' },3281 { type: 'Block', accept: 'string', defaultType: 'number', value: '2' },3282 {3283 type: 'Indicator',3284 img: 'block_icon/hardware_icon.svg',3285 size: 12,3286 },3287 ],3288 events: {},3289 def: { params: [null, null], type: 'pingpong_g4_set_dot_string' },3290 paramsKeyMap: { cubeno: 0, STR: 1, DURATION: 2 },3291 class: 'PingpongG4_peripheral_LED',3292 isNotFor: ['PingpongG4'],3293 func(sprite, script) {3294 return RoCode.PingpongG4.postCallReturn(script, () => {3295 const cubeId = RoCode.PingpongG4._getCubeNoFromBlock(script);3296 const str = script.getStringValue('STR', script);3297 const duration = script.getNumberValue('DURATION', script);3298 let period = Math.round((duration * 100) / (str.length * 8));3299 period = Math.min(Math.max(period, 1), 200);3300 const opt = Buffer.concat([3301 Buffer.from([0x70, period, 0]),3302 Buffer.from(str.substring(0, 20)),3303 ]);3304 const packet = RoCode.PingpongG4.makePacket(3305 OPCODE.LEDMATRIX,3306 0xe3,3307 cubeId,3308 opt3309 );3310 const waitTime = period * str.length * 8 * 10 + 400; // add wait for 400ms3311 return [packet, waitTime];3312 });3313 },3314 },3315 pingpong_g4_set_dot_clear: {3316 color: RoCodeStatic.colorSet.block.default.HARDWARE,3317 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3318 skeleton: 'basic',3319 statements: [],3320 params: [3321 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },3322 {3323 type: 'Indicator',3324 img: 'block_icon/hardware_icon.svg',3325 size: 12,3326 },3327 ],3328 events: {},3329 def: { params: [], type: 'pingpong_g4_set_dot_clear' },3330 paramsKeyMap: { cubeno: 0 },3331 class: 'PingpongG4_peripheral_LED',3332 isNotFor: ['PingpongG4'],3333 func(sprite, script) {3334 return RoCode.PingpongG4.postCallReturn(script, () => {3335 const cubeId = RoCode.PingpongG4._getCubeNoFromBlock(script);3336 const opt = [0x70, 1, 0, ' '];3337 const packet = RoCode.PingpongG4.makePacket(3338 OPCODE.LEDMATRIX,3339 0xe3,3340 cubeId,3341 opt3342 );3343 return [packet, 400];3344 });3345 },3346 },3347 pingpong_g4_playNoteForBeats: {3348 //'%1 큐브의 %2 번 음을 %3 박자로 연주하기 %4',3349 color: RoCodeStatic.colorSet.block.default.HARDWARE,3350 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3351 skeleton: 'basic',3352 statements: [],3353 params: [3354 {3355 type: 'Dropdown',3356 options: Lang.Blocks.pingpong_g4_cube_id,3357 value: 0,3358 fontSize: 11,3359 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3360 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3361 },3362 {3363 type: 'Dropdown',3364 options: Lang.Blocks.pingpong_opts_music_notes,3365 value: 48,3366 fontSize: 11,3367 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3368 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3369 },3370 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },3371 {3372 type: 'Indicator',3373 img: 'block_icon/hardware_icon.svg',3374 size: 12,3375 },3376 ],3377 events: {},3378 def: { params: [], type: 'pingpong_g4_playNoteForBeats' },3379 paramsKeyMap: { CUBEID: 0, NOTE: 1, BEATS: 2 },3380 class: 'PingpongG4_Music',3381 isNotFor: ['PingpongG4'],3382 func(sprite, script) {3383 return RoCode.PingpongG4.postCallReturn(script, () => {3384 const cubeId = script.getNumberField('CUBEID');3385 const NOTE = script.getNumberField('NOTE', script);3386 const BEATS = script.getNumberValue('BEATS', script);3387 const cBeats = RoCode.PingpongG4._clampBeats(BEATS);3388 const durationSec = RoCode.PingpongG4._beatsToDuration(cBeats);3389 const waitTime = durationSec * 10 + 30; //XXX3390 const arr = RoCode.PingpongG4.makeMusicNotePacket(cubeId, NOTE, durationSec);3391 const packet = Buffer.from(arr);3392 return [packet, waitTime];3393 });3394 },3395 },3396 pingpong_g4_playChordForBeats: {3397 //'%1 큐브 %2, %3 큐브 %4, %5 큐브 %6 %7 박자로 연주하기 %8',3398 color: RoCodeStatic.colorSet.block.default.HARDWARE,3399 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3400 skeleton: 'basic',3401 statements: [],3402 params: [3403 {3404 type: 'Dropdown',3405 options: Lang.Blocks.pingpong_g4_cube_id,3406 value: 0,3407 fontSize: 11,3408 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3409 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3410 },3411 {3412 type: 'Dropdown',3413 options: Lang.Blocks.pingpong_opts_music_notes,3414 value: 48,3415 fontSize: 11,3416 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3417 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3418 },3419 {3420 type: 'Dropdown',3421 options: Lang.Blocks.pingpong_g4_cube_id,3422 value: 1,3423 fontSize: 11,3424 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3425 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3426 },3427 {3428 type: 'Dropdown',3429 options: Lang.Blocks.pingpong_opts_music_notes,3430 value: 48,3431 fontSize: 11,3432 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3433 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3434 },3435 {3436 type: 'Dropdown',3437 options: Lang.Blocks.pingpong_g4_cube_id,3438 value: 2,3439 fontSize: 11,3440 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3441 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3442 },3443 {3444 type: 'Dropdown',3445 options: Lang.Blocks.pingpong_opts_music_notes,3446 value: 48,3447 fontSize: 11,3448 bgColor: RoCodeStatic.colorSet.block.darken.HARDWARE,3449 arrowColor: RoCodeStatic.colorSet.arrow.default.HARDWARE,3450 },3451 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },3452 {3453 type: 'Indicator',3454 img: 'block_icon/hardware_icon.svg',3455 size: 12,3456 },3457 ],3458 events: {},3459 def: { params: [], type: 'pingpong_g4_playChordForBeats' },3460 paramsKeyMap: {3461 CUBEID_1: 0,3462 NOTE_1: 1,3463 CUBEID_2: 2,3464 NOTE_2: 3,3465 CUBEID_3: 4,3466 NOTE_3: 5,3467 BEATS: 6,3468 },3469 class: 'PingpongG4_Music',3470 isNotFor: ['PingpongG4'],3471 func(sprite, script) {3472 return RoCode.PingpongG4.postCallReturn(script, () => {3473 const cubeId1 = script.getNumberField('CUBEID_1');3474 const cubeId2 = script.getNumberField('CUBEID_2');3475 const cubeId3 = script.getNumberField('CUBEID_3');3476 const NOTE1 = script.getNumberField('NOTE_1', script);3477 const NOTE2 = script.getNumberField('NOTE_2', script);3478 const NOTE3 = script.getNumberField('NOTE_3', script);3479 const BEATS = script.getNumberValue('BEATS', script);3480 const cBeats = RoCode.PingpongG4._clampBeats(BEATS);3481 const durationSec = RoCode.PingpongG4._beatsToDuration(cBeats);3482 const waitTime = durationSec * 10 + 30;3483 const arr1 = RoCode.PingpongG4.makeMusicNotePacket(3484 cubeId1,3485 NOTE1,3486 durationSec3487 );3488 const arr2 = RoCode.PingpongG4.makeMusicNotePacket(3489 cubeId2,3490 NOTE2,3491 durationSec3492 );3493 const arr3 = RoCode.PingpongG4.makeMusicNotePacket(3494 cubeId3,3495 NOTE3,3496 durationSec3497 );3498 const packet = RoCode.PingpongG4.makeAggregatePacket(3499 OPCODE.MUSIC,3500 0xa2,3501 [arr1, arr2, arr3],3502 [0, 0]3503 );3504 return [packet, waitTime];3505 });3506 },3507 },3508 pingpong_g4_restForBeats: {3509 color: RoCodeStatic.colorSet.block.default.HARDWARE,3510 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3511 skeleton: 'basic',3512 params: [3513 { type: 'Block', accept: 'string', defaultType: 'number', value: '1' },3514 {3515 type: 'Indicator',3516 img: 'block_icon/hardware_icon.svg',3517 size: 12,3518 },3519 ],3520 def: { params: [], type: 'pingpong_g4_restForBeats' },3521 paramsKeyMap: { BEATS: 0 },3522 class: 'PingpongG4_Music',3523 isNotFor: ['PingpongG4'],3524 func(sprite, script) {3525 return RoCode.PingpongG4.postCallReturn(script, () => {3526 const BEATS = script.getNumberValue('BEATS', script);3527 const cBeats = RoCode.PingpongG4._clampBeats(BEATS);3528 const durationSec = RoCode.PingpongG4._beatsToDuration(cBeats);3529 const waitTime = durationSec * 10 + 30;3530 //XXX3531 return [null, waitTime];3532 });3533 },3534 },3535 pingpong_g4_setTempo: {3536 color: RoCodeStatic.colorSet.block.default.HARDWARE,3537 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3538 skeleton: 'basic',3539 params: [3540 { type: 'Block', accept: 'string', defaultType: 'number', value: '60' },3541 {3542 type: 'Indicator',3543 img: 'block_icon/hardware_icon.svg',3544 size: 12,3545 },3546 ],3547 def: { params: [], type: 'pingpong_g4_setTempo' },3548 paramsKeyMap: { TEMPO: 0 },3549 class: 'PingpongG4_Music',3550 isNotFor: ['PingpongG4'],3551 func(sprite, script) {3552 let tempo = script.getNumberValue('TEMPO', script);3553 RoCode.PingpongG4.tempo = RoCode.PingpongG4._clampTempo(tempo);3554 return script.callReturn();3555 },3556 },3557 pingpong_g4_getTempo: {3558 color: RoCodeStatic.colorSet.block.default.HARDWARE,3559 outerLine: RoCodeStatic.colorSet.block.darken.HARDWARE,3560 skeleton: 'basic_string_field',3561 params: [],3562 def: { params: [], type: 'pingpong_g4_getTempo' },3563 paramsKeyMap: {},3564 class: 'PingpongG4_Music',3565 isNotFor: ['PingpongG4'],3566 func(sprite, script) {3567 return RoCode.PingpongG4.tempo;3568 },3569 },3570 };3571 }3572 setLanguage() {3573 return {3574 ko: {3575 template: {3576 pingpong_g4_when_button_pressed: '%1 %2 큐브 버튼을 눌렀을 때',3577 pingpong_g4_when_tilted: '%1 %2 큐브를 %3로 기울였을 때',3578 pingpong_g4_is_button_pressed: '%1 큐브 버튼이 눌렸는가?',3579 pingpong_g4_is_tilted: '%1 큐브가 %2로 기울어졌는가?',3580 pingpong_g4_is_top_shape: '%1 큐브의 윗면에 %2 모양이 있는가?',3581 pingpong_g4_get_tilt_value: '%1 큐브의 %2 방향 기울기',3582 pingpong_g4_get_sensor_value: '%1 큐브의 %2 센서값',3583 pingpong_g4_multi_motor_rotate:3584 '모터1은 %1방향 %2도, 모터2는 %3방향 %4도, ' +3585 '모터3은 %5방향 %6도, 모터4는 %7방향 %8도 회전하기 %9',3586 pingpong_g4_motor_rotate: '%1 모터를 %2 방향으로 %3 도 회전하기 %4',3587 pingpong_g4_start_multi_motor_rotate:3588 '모터1 속도를 %1, 모터2 속도를 %2, 모터3 속도를 %3, 모터4 속도를 %4으로 계속 회전하기 %5',3589 pingpong_g4_start_motor_rotate: '%1 모터의 속도를 %2으로 계속 회전하기 %3',3590 pingpong_g4_stop_motor_rotate: '%1 모터 멈추기 %2',3591 pingpong_g4_set_dot_pixel: '%1 번째 큐브의 도트 X:%2 Y:%3 %4 %5',3592 pingpong_g4_set_dot_string:3593 '%1 번째 큐브에 도트 문자열 %2 %3초동안 보여주기 %4',3594 pingpong_g4_set_dot_clear: '%1 번째 큐브의 화면 지우기 %2',3595 pingpong_g4_rotate_servo_mortor: '%1 번째 큐브의 서보모터 %2도로 설정하기 %3',3596 pingpong_g4_playNoteForBeats: '%1 큐브의 %2 음을 %3 박자로 연주하기 %4',3597 pingpong_g4_playChordForBeats:3598 '%1 큐브 %2, %3 큐브 %4, %5 큐브 %6 %7 박자로 연주하기 %8',3599 pingpong_g4_restForBeats: '%1 박자 쉬기 %2',3600 pingpong_g4_setTempo: '악보 빠르기를 %1 으로 정하기 %2',3601 pingpong_g4_getTempo: '악보 빠르기',3602 },3603 Blocks: {3604 ...this.lang_defblock.ko,3605 pingpong_g4_cube_id: [3606 ['1번', 0],3607 ['2번', 1],3608 ['3번', 2],3609 ['4번', 3],3610 ],3611 pingpong_g4_cube_all: [3612 ['1번', 0],3613 ['2번', 1],3614 ['3번', 2],3615 ['4번', 3],3616 ['모든', -1],3617 ],3618 },3619 },3620 en: {3621 template: {3622 pingpong_g4_when_button_pressed: '%1 %2 cube button pressed',3623 pingpong_g4_when_tilted: '%1 %2 cube tilted to %3',3624 pingpong_g4_is_button_pressed: '%1 cube button pressed?',3625 pingpong_g4_is_tilted: '%1 cube tilted to %2',3626 pingpong_g4_is_top_shape: '%1 cube shown %2 in top view?',3627 pingpong_g4_get_tilt_value: '%1 cube tilt angle to %2',3628 pingpong_g4_get_sensor_value: '%1 cube read sensor %2',3629 pingpong_g4_multi_motor_rotate:3630 'rotate motor1 %2 degrees %1, motor2 %4 degrees %3, ' +3631 'motor3 %6 degrees %5, motor4 %8 degrees %7 %9',3632 pingpong_g4_motor_rotate: 'rotate %2 degrees %1 %3',3633 pingpong_g4_start_multi_motor_rotate:3634 'set motor1 speed to %1, motor2 speed to %2, ' +3635 'motor3 speed to %3, motor3 speed to %4, motor4 speed to %5 %6',3636 pingpong_g4_start_motor_rotate: 'set motor speed to %1 %2',3637 pingpong_g4_stop_motor_rotate: 'stop motor rotate %1',3638 pingpong_g4_rotate_servo_mortor: 'set servo mortor to %1 degrees %2',3639 pingpong_g4_set_dot_pixel: '%1 cube set DOT X:%2 Y:%3 %4 %5',3640 pingpong_g4_set_dot_string:3641 'print %1 cube string %2 during %3 seconds to DOT %4',3642 pingpong_g4_set_dot_clear: '%1 cube clear DOT %2',3643 pingpong_g4_playNoteForBeats: '%1 cube play note %2 for %3 beats %4',3644 pingpong_g4_playChordForBeats:3645 '%1 cube %2, %3 cube %4, %5 cube %6 for %7 beats %8',3646 pingpong_g4_restForBeats: 'rest for %1 beats %2',3647 pingpong_g4_setTempo: 'set tempo to %1 %2',3648 pingpong_g4_getTempo: 'tempo',3649 },3650 Blocks: {3651 ...this.lang_defblock.en,3652 pingpong_g4_cube_id: [3653 ['1st', 0],3654 ['2nd', 1],3655 ['3rd', 2],3656 ['4th', 3],3657 ],3658 pingpong_g4_cube_all: [3659 ['1st', 0],3660 ['2nd', 1],3661 ['3rd', 2],3662 ['4th', 3],3663 ['All', -1],3664 ],3665 },3666 },3667 };3668 }3669})();...

Full Screen

Full Screen

DefaultPingPong.test.ts

Source:DefaultPingPong.test.ts Github

copy

Full Screen

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.2// SPDX-License-Identifier: Apache-2.03import * as chai from 'chai';4import * as sinon from 'sinon';5import LogLevel from '../../src/logger/LogLevel';6import NoOpLogger from '../../src/logger/NoOpLogger';7import DefaultPingPong from '../../src/pingpong/DefaultPingPong';8import PingPongObserver from '../../src/pingpongobserver/PingPongObserver';9import TimeoutScheduler from '../../src/scheduler/TimeoutScheduler';10import DefaultSignalingClient from '../../src/signalingclient/DefaultSignalingClient';11import SignalingClientEvent from '../../src/signalingclient/SignalingClientEvent';12import SignalingClientEventType from '../../src/signalingclient/SignalingClientEventType';13import {14 SdkPingPongFrame,15 SdkPingPongType,16 SdkSignalFrame,17} from '../../src/signalingprotocol/SignalingProtocol.js';18import { Maybe } from '../../src/utils/Types';19import { wait as delay } from '../../src/utils/Utils';20import DefaultWebSocketAdapter from '../../src/websocketadapter/DefaultWebSocketAdapter';21import DOMMockBuilder from '../dommock/DOMMockBuilder';22describe('DefaultPingPong', () => {23 let expect: Chai.ExpectStatic;24 const defaultIntervalMs = 10000;25 const logger = new NoOpLogger(LogLevel.DEBUG);26 let domMockBuilder: DOMMockBuilder | null = null;27 before(() => {28 expect = chai.expect;29 });30 beforeEach(() => {31 domMockBuilder = new DOMMockBuilder();32 });33 afterEach(() => {34 if (domMockBuilder) {35 domMockBuilder.cleanup();36 domMockBuilder = null;37 }38 });39 describe('construction', () => {40 it('can be constructed', () => {41 const webSocketAdapter = new DefaultWebSocketAdapter(logger);42 const signalingClient = new DefaultSignalingClient(webSocketAdapter, logger);43 const pingPong = new DefaultPingPong(signalingClient, defaultIntervalMs, logger);44 expect(pingPong).to.not.equal(null);45 });46 });47 describe('start and stop', () => {48 it('can be started and stopped', () => {49 class TestSignalingClient extends DefaultSignalingClient {50 ready(): boolean {51 return true;52 }53 }54 const webSocketAdapter = new DefaultWebSocketAdapter(logger);55 const signalingClient = new TestSignalingClient(webSocketAdapter, logger);56 const deregisterSpy = sinon.spy(signalingClient, 'removeObserver');57 const registerSpy = sinon.spy(signalingClient, 'registerObserver');58 const pingPongSpy = sinon.spy(signalingClient, 'pingPong');59 const pingPong = new DefaultPingPong(signalingClient, defaultIntervalMs, logger);60 pingPong.start();61 expect(deregisterSpy.calledOnce).to.be.true;62 expect(registerSpy.calledOnce).to.be.true;63 expect(pingPong.pingId).to.equal(1);64 expect(pingPong.consecutivePongsUnaccountedFor).to.equal(1);65 expect(pingPongSpy.calledOnce).to.be.true;66 pingPong.stop();67 expect(pingPong.pingId).to.equal(0);68 expect(pingPong.consecutivePongsUnaccountedFor).to.equal(0);69 });70 it('can keep pinging once gets started', done => {71 class TestSignalingClient extends DefaultSignalingClient {72 ready(): boolean {73 return true;74 }75 }76 let called = false;77 class TestObserver implements PingPongObserver {78 didMissPongs?(_consecutiveMissed: number): void {79 called = true;80 }81 }82 const observer = new TestObserver();83 const webSocketAdapter = new DefaultWebSocketAdapter(logger);84 const signalingClient = new TestSignalingClient(webSocketAdapter, logger);85 const intervalMs = 100;86 const pingPong = new DefaultPingPong(signalingClient, intervalMs, logger);87 pingPong.addObserver(observer);88 pingPong.start();89 new TimeoutScheduler(intervalMs * 2.5).start(() => {90 expect(pingPong.consecutivePongsUnaccountedFor).to.equal(3);91 expect(called).to.be.true;92 pingPong.stop();93 pingPong.removeObserver(observer);94 done();95 });96 });97 it('cannot start if the signaling client is not ready', () => {98 class TestSignalingClient extends DefaultSignalingClient {99 ready(): boolean {100 return false;101 }102 }103 const webSocketAdapter = new DefaultWebSocketAdapter(logger);104 const signalingClient = new TestSignalingClient(webSocketAdapter, logger);105 const pingPong = new DefaultPingPong(signalingClient, defaultIntervalMs, logger);106 pingPong.start();107 expect(pingPong.pingId).to.equal(0);108 pingPong.stop();109 });110 it('can be started by the WebSocketOpen event', done => {111 class TestSignalingClient extends DefaultSignalingClient {112 ready(): boolean {113 return false;114 }115 }116 const webSocketAdapter = new DefaultWebSocketAdapter(logger);117 const signalingClient = new TestSignalingClient(webSocketAdapter, logger);118 const intervalMs = 100;119 const pingPong = new DefaultPingPong(signalingClient, intervalMs, logger);120 pingPong.start();121 pingPong.handleSignalingClientEvent(122 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketOpen, null)123 );124 new TimeoutScheduler(intervalMs * 2.5).start(() => {125 expect(pingPong.pingId).to.equal(3);126 pingPong.stop();127 done();128 });129 });130 it('can add and remove observers', () => {131 class TestObserver implements PingPongObserver {132 didMissPongs?(_consecutiveMissed: number): void {}133 }134 const observer = new TestObserver();135 const webSocketAdapter = new DefaultWebSocketAdapter(logger);136 const signalingClient = new DefaultSignalingClient(webSocketAdapter, logger);137 const pingPong = new DefaultPingPong(signalingClient, defaultIntervalMs, logger);138 pingPong.addObserver(observer);139 pingPong.forEachObserver(observer => {140 Maybe.of(observer.didMissPongs).map(f => f.bind(observer)());141 });142 pingPong.removeObserver(observer);143 });144 it('can stop pinging when the WebSocket is closed and restart when connected', async () => {145 class TestSignalingClient extends DefaultSignalingClient {146 ready(): boolean {147 return false;148 }149 }150 const webSocketAdapter = new DefaultWebSocketAdapter(logger);151 const signalingClient = new TestSignalingClient(webSocketAdapter, logger);152 const intervalMs = 100;153 const pingPong = new DefaultPingPong(signalingClient, intervalMs, logger);154 pingPong.start();155 pingPong.handleSignalingClientEvent(156 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketOpen, null)157 );158 await delay(intervalMs * 2.5);159 expect(pingPong.pingId).to.equal(3);160 pingPong.handleSignalingClientEvent(161 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketClosed, null)162 );163 await delay(intervalMs * 2.5);164 expect(pingPong.pingId).to.equal(0);165 pingPong.handleSignalingClientEvent(166 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketOpen, null)167 );168 await delay(intervalMs * 2.5);169 expect(pingPong.pingId).to.equal(3);170 pingPong.stop();171 });172 });173 describe('handleSignalingClientEvent', () => {174 let webSocketAdapter: DefaultWebSocketAdapter;175 let signalingClient: DefaultSignalingClient;176 let pingPong: DefaultPingPong;177 beforeEach(() => {178 webSocketAdapter = new DefaultWebSocketAdapter(logger);179 signalingClient = new DefaultSignalingClient(webSocketAdapter, logger);180 pingPong = new DefaultPingPong(signalingClient, defaultIntervalMs, logger);181 });182 it('can start pinging once receive WebSocketOpen event', () => {183 pingPong.handleSignalingClientEvent(184 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketOpen, null)185 );186 expect(pingPong.pingId).to.equal(1);187 pingPong.handleSignalingClientEvent(188 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketClosed, null)189 );190 });191 it('can stop pinging once receive WebSocketFailed event', () => {192 pingPong.handleSignalingClientEvent(193 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketOpen, null)194 );195 expect(pingPong.pingId).to.equal(1);196 pingPong.handleSignalingClientEvent(197 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketFailed, null)198 );199 });200 it('can stop pinging once receive WebSocketError event', () => {201 pingPong.handleSignalingClientEvent(202 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketOpen, null)203 );204 expect(pingPong.pingId).to.equal(1);205 pingPong.handleSignalingClientEvent(206 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketError, null)207 );208 });209 it('can stop pinging once receive WebSocketClosing event', () => {210 pingPong.handleSignalingClientEvent(211 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketOpen, null)212 );213 expect(pingPong.pingId).to.equal(1);214 pingPong.handleSignalingClientEvent(215 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketClosing, null)216 );217 });218 it('should PONG back when receive Signal PING frame', () => {219 const signalingClient = new DefaultSignalingClient(webSocketAdapter, logger);220 const clientSpy = sinon.spy(signalingClient, 'pingPong');221 const pingPong = new DefaultPingPong(signalingClient, defaultIntervalMs, logger);222 const ping = SdkSignalFrame.create();223 ping.type = SdkSignalFrame.Type.PING_PONG;224 ping.pingPong = SdkPingPongFrame.create();225 ping.pingPong.type = SdkPingPongType.PING;226 ping.pingPong.pingId = 1;227 ping.timestampMs = 10000;228 pingPong.handleSignalingClientEvent(229 new SignalingClientEvent(230 signalingClient,231 SignalingClientEventType.ReceivedSignalFrame,232 ping233 )234 );235 expect(clientSpy.calledOnce).to.be.true;236 clientSpy.restore();237 });238 it('should ignore other Signal frame', () => {239 const signalingClient = new DefaultSignalingClient(webSocketAdapter, logger);240 const clientSpy = sinon.spy(signalingClient, 'pingPong');241 const pingPong = new DefaultPingPong(signalingClient, defaultIntervalMs, logger);242 const frame = SdkSignalFrame.create();243 frame.type = -1;244 pingPong.handleSignalingClientEvent(245 new SignalingClientEvent(246 signalingClient,247 SignalingClientEventType.ReceivedSignalFrame,248 frame249 )250 );251 expect(clientSpy.calledOnce).to.not.be.true;252 expect(pingPong.pingId).to.equal(0);253 clientSpy.restore();254 });255 it('should process the PONG frame when receive Signal PONG frame after ping', done => {256 const pingTimestampLocalMs = 10000;257 const pingPong = new DefaultPingPong(signalingClient, defaultIntervalMs, logger);258 class TestObserver implements PingPongObserver {259 didReceivePong(id: number, latencyMs: number, clockSkewMs: number): void {260 expect(id).to.equal(1);261 expect(latencyMs).to.equal(0);262 expect(clockSkewMs).to.equal(2000);263 pingPong.stop();264 done();265 }266 }267 pingPong.addObserver(new TestObserver());268 pingPong.handleSignalingClientEvent(269 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketOpen, null)270 );271 expect(pingPong.pingId).to.equal(1);272 // override the ping local timestamp273 pingPong.pingTimestampLocalMs = pingTimestampLocalMs;274 // create PONG event275 const pong = SdkSignalFrame.create();276 pong.type = SdkSignalFrame.Type.PING_PONG;277 pong.pingPong = SdkPingPongFrame.create();278 pong.pingPong.type = SdkPingPongType.PONG;279 pong.pingPong.pingId = 1;280 pong.timestampMs = pingTimestampLocalMs + 1000;281 const pongEvent = new SignalingClientEvent(282 signalingClient,283 SignalingClientEventType.ReceivedSignalFrame,284 pong285 );286 pongEvent.timestampMs = pingTimestampLocalMs + 2000;287 pingPong.handleSignalingClientEvent(pongEvent);288 expect(pingPong.consecutivePongsUnaccountedFor).to.equal(0);289 });290 it('should ignore the PONG frame when receive Signal PONG frame but pingId does not match', done => {291 class TestObserver implements PingPongObserver {292 didReceivePong(_id: number, _latencyMs: number, _clockSkewMs: number): void {293 done();294 }295 }296 const pingPong = new DefaultPingPong(signalingClient, defaultIntervalMs, logger);297 pingPong.addObserver(new TestObserver());298 pingPong.handleSignalingClientEvent(299 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketOpen, null)300 );301 expect(pingPong.pingId).to.equal(1);302 const pong = SdkSignalFrame.create();303 pong.type = SdkSignalFrame.Type.PING_PONG;304 pong.pingPong = SdkPingPongFrame.create();305 pong.pingPong.type = SdkPingPongType.PONG;306 pong.pingPong.pingId = 0;307 pong.timestampMs = 10000;308 pingPong.handleSignalingClientEvent(309 new SignalingClientEvent(310 signalingClient,311 SignalingClientEventType.ReceivedSignalFrame,312 pong313 )314 );315 expect(pingPong.consecutivePongsUnaccountedFor).to.equal(1);316 pingPong.stop();317 done();318 });319 it('should ignore Signal PONG frame with null timestampMs', done => {320 class TestObserver implements PingPongObserver {321 didReceivePong(_id: number, _latencyMs: number, _clockSkewMs: number): void {322 done();323 }324 }325 const pingPong = new DefaultPingPong(signalingClient, defaultIntervalMs, logger);326 pingPong.addObserver(new TestObserver());327 pingPong.handleSignalingClientEvent(328 new SignalingClientEvent(signalingClient, SignalingClientEventType.WebSocketOpen, null)329 );330 expect(pingPong.pingId).to.equal(1);331 const pong = SdkSignalFrame.create();332 pong.type = SdkSignalFrame.Type.PING_PONG;333 pong.pingPong = SdkPingPongFrame.create();334 pong.pingPong.type = SdkPingPongType.PONG;335 pong.pingPong.pingId = 1;336 pong.timestampMs = undefined;337 pingPong.handleSignalingClientEvent(338 new SignalingClientEvent(339 signalingClient,340 SignalingClientEventType.ReceivedSignalFrame,341 pong342 )343 );344 expect(pingPong.consecutivePongsUnaccountedFor).to.equal(0);345 pingPong.stop();346 done();347 });348 });...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1var wpt = require('./wpt.js');2wpt.pingPong();3module.exports = {4 pingPong: function() {5 console.log("ping pong");6 }7}

Full Screen

Using AI Code Generation

copy

Full Screen

1var wpt = require('wpt.js');2var wpt = new wpt('API_KEY');3wpt.pingPong(function(err, data) {4 if (err) {5 console.log(err);6 } else {7 console.log(data);8 }9});10[Shubham Sharma](

Full Screen

Using AI Code Generation

copy

Full Screen

1var wpt = require('wpt');2var wpt = new WebPageTest('www.webpagetest.org', 'A.1b1d4d4e4c4b4c4d4e4f4g4h4i4j4k4l4m4n4o4p4q4r4s4t4u4v4w4x4y4z4');3wpt.pingPong(function(err, data) {4 if (err) {5 console.log(err);6 } else {7 console.log(data);8 }9});10var wpt = require('wpt');11var wpt = new WebPageTest('www.webpagetest.org', 'A.1b1d4d4e4c4b4c4d4e4f4g4h4i4j4k4l4m4n4o4p4q4r4s4t4u4v4w4x4y4z4');12 if (err) {13 console.log(err);14 } else {15 console.log(data);16 }17});18var wpt = require('wpt');19var wpt = new WebPageTest('www.webpagetest.org', 'A.1b1d4d4e4c4b4c4d4e4f4g4h4i4j4k4l4m4n4o4p4q4r4s4t4u4v4w4x4y4z4');20 if (err) {21 console.log(err);22 } else {23 console.log(data);24 }25});26var wpt = require('wpt');27var wpt = new WebPageTest('www.webpagetest

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run wpt automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful