代码编程教学_少儿编程教学环境开发之代码实战篇

本文介绍了少儿编程教学环境的前端实现,使用Vue.js构建SPA框架,集成Blockly进行代码编辑,并通过Phaser.js创建游戏窗口。详细展示了Blockly自定义block的代码以及Phaser游戏场景的配置和交互实现。通过这种方式,为少儿编程教学提供了互动式的编程和游戏体验。
摘要由CSDN通过智能技术生成
少儿编程教学环境开发之代码实战篇​mp.weixin.qq.com
688a1b4ee3bff261c0eca55b57358124.png

之前架构选型篇许诺要上自己原型demo的界面图,先把这个许诺给实现了,首先声明,这只是技术原型demo,比起http://code.org的产品来讲简陋很多:

06917bb53767abca51d134838fc09c29.png

首先对代码的整体架构做一下说明,首先我们采用的是Vue SPA框架为整个站点的前端框架,这样编辑器界面和游戏窗口界面各自被封装成Component。

下面先上右侧BlocklyEditor Component的的代码,代码解读就直接放到代码注释中了

<template>
    <div>
        <div id="blocklyDiv" style="position: absolute"></div>
        <!--上面的blockDvi主要是容器插槽用来放置编辑器-->
        <xml  id="toolbox" style="display: none">
            <block type="string_length"></block>
            <block type="controls_if"></block>
            <block type="logic_compare"></block>
            <block type="controls_repeat_ext"></block>
            <block type="math_number">
              <field name="NUM">123</field>
            </block>
            <block type="math_arithmetic"></block>
            <block type="text"></block>
            <block type="text_print"></block>
            

          </xml>
          <!--上面的xml主要是定制block工具栏列表-->

    </div>
</template>

<script>
    import Blockly from 'blockly'

    //下面这个代码块用来定制string_length block的形状
    Blockly.Blocks['string_length'] = {
      init: function() {
        this.jsonInit({
          "message0": '%1',
           "args0": [
                {
                  "type": "field_image",
                  "src": "/assets/logo.png",
                  "width": 100,
                  "height": 50,
                  "alt": "*"
                }
              ],
          "nextStatement": "Action",
          "fillPattern":"#",
          "colour": 160,
          "tooltip": "Returns number of letters in the provided text.",
          "helpUrl": "http://www.w3schools.com/jsref/jsref_length_string.asp"
        });
      }
    };
    //下面这个代码块用来定制string_length block的行为函数
    // eslint-disable-next-line    
    Blockly.JavaScript['string_length'] = function(block) {
      // String or array length.
      //var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE',
      //    Blockly.JavaScript.ORDER_FUNCTION_CALL) || '''';
      var argument0= "begin"
      return [argument0 + '.length', Blockly.JavaScript.ORDER_MEMBER];
    };


    export default {
        name: "BlocklyEditor",
        mounted() {
            //在component的这个生命周期事件上初始化整个编辑器
            this.$nextTick(
                function () {
                    var blocklyArea = document.getElementById("app");
                    var blocklyDiv = document.getElementById('blocklyDiv');
                    //往blocklyDiv容器插槽中插入blockly编辑器
                    var demoWorkspace = Blockly.inject(blocklyDiv,
                        {media: '/assets/blockly_media/',
                            trashcan:true,
                            grid:
                             {spacing: 20,

                              length: 20,
                              colour: '#ccc',
                              snap: true},
                         toolbox: document.getElementById('toolbox')});
                    //定义编辑器响应resize事件的函数,里面逻辑顺便完成了编辑器的形状设置
                    // eslint-disable-next-line
                    var onresize = function(e) {
                      // Compute the absolute coordinates and dimensions of blocklyArea.
                      var element = blocklyDiv;
                      // eslint-disable-next-line
                      var x = 0;
                      var y = 0;
                      do {
                        x += element.offsetLeft;
                        y += element.offsetTop;
                        element = element.offsetParent;
                      } while (element);
                      // Position blocklyDiv over blocklyArea.
                      blocklyDiv.style.left = 436 + 'px';
                      blocklyDiv.style.top = y + 'px';
                      blocklyDiv.style.width = blocklyArea.offsetWidth -470 + 'px';
                      blocklyDiv.style.height = blocklyArea.offsetHeight-125 + 'px';
                      Blockly.svgResize(demoWorkspace);
                    };
                    window.addEventListener('resize', onresize, false);
                    onresize();
                    Blockly.svgResize(demoWorkspace);
                
                }
            )
        }
    }
</script>

下面上左侧phaser.js游戏窗口的的代码

<template>
    <div>
        <!--下面这个div是游戏界面的插槽容器-->
        <div id="phaser-wraper"></div>
        <div><button type="button" class="btn btn-primary">运行 <i class="fas fa-play"></i></button></div>
    </div>
</template>

<script>
    import Phaser from "phaser"

    var player
    var platforms

    //这个函数中完成游戏资源的预加载
    function preload ()
{
        //this.load.setBaseURL('Phaser 3 Examples');
        //this.load.image('logo', 'assets/sprites/phaser3-logo.png');
        //this.load.image('red', 'assets/particles/red.png');

        this.load.setBaseURL('/');
        this.load.image('sky', 'assets/sky.png');
        this.load.image('ground', 'assets/platform.png');
        this.load.multiatlas('citizen', 'assets/side_walk.json', 'assets');
        this.load.multiatlas('front', 'assets/front.json', 'assets');
    }
    //这个函数完成游戏场景的初始化
    function create ()
{
        var that = this;
        this.add.image(200, 200, 'sky');
        platforms = this.physics.add.staticGroup();
        platforms.create(200, 400, 'ground').setScale(1).refreshBody();

        player = this.physics.add.sprite(215, 215, 'citizen', '0_Citizen_Walk_003.png');

        player.setBounce(0.2);
        player.setCollideWorldBounds(true);


        this.anims.create({
            key: 'turn',
            frames: that.anims.generateFrameNames('front', {
                         start: 1, end: 1, zeroPad: 2,
                         prefix: '0_Citizen_Walk_0', suffix: '.png'
                     }),
            frameRate: 20
        });
        this.anims.create({
            key: 'down',
            frames: that.anims.generateFrameNames('front', {
                         start: 1, end: 28, zeroPad: 2,
                         prefix: '0_Citizen_Walk_0', suffix: '.png'
                     }),
            frameRate: 20
        });

        this.anims.create({
            key: 'left',
            frames: that.anims.generateFrameNames('citizen', {
                         start: 1, end: 28, zeroPad: 2,
                         prefix: '0_Citizen_Walk_0', suffix: '.png'
                     }),
            frameRate: 10,
            repeat: -1
        });
        this.anims.create({
            key: 'right',
            frames: that.anims.generateFrameNames('citizen', {
                         start: 1, end: 28, zeroPad: 2,
                         prefix: '0_Citizen_Walk_0', suffix: '.png'
                     }),
            frameRate: 10,
            repeat: -1
        });

        this.physics.add.collider(player, platforms);



    }
    //这个函数完成游戏中事件行为函数的编写,完成游戏的操作交互功能
    // eslint-disable-next-line
    function update(time, delta) {
        var cursors = this.input.keyboard.createCursorKeys();
        if (cursors.left.isDown)
        {
            player.setVelocityX(-160);
            player.anims.play('left', true);
            player.setFlipX(false)
        }
        else if (cursors.right.isDown)
        {
            player.setVelocityX(160);
            player.anims.play('right', true);
            player.setFlipX(true)
        }
        else if (cursors.down.isDown)
        {
            player.setVelocityY(160);
            player.anims.play('down', true);
            player.setFlipX(false)
        }
        else if (cursors.up.isDown)
        {
            player.setVelocityY(-160);
            player.anims.play('down', true);
            player.setFlipX(false)
        }
        else
        {
            player.setVelocityX(0);
            player.setVelocityY(0);
            player.anims.play('turn');
        }
        //player.update(delta)

    }
    export default {
        name: "Phaser",
        mounted() {
            //在vue组件的这个生命周期中完成整体游戏场景的初始化和加载
            this.$nextTick(function () {
                var config = {
                    type: Phaser.AUTO,
                    parent:"phaser-wraper",
                    width: 400,
                    height: 400,
                    physics: {
                        default: 'arcade',
                        arcade: {
                            gravity: { y: 0 }
                        }
                    },
                    scene: {
                        preload: preload,
                        create: create,
                        update: update,
                    }
                };
                // eslint-disable-next-line
                var game = new Phaser.Game(config);

            })
        }
    }
</script>

架构选型篇之后许诺的代码实战篇憋了好久了都没放出来,主要是代码注解一直懒得搞,让大家久等了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值