Vue實現(xiàn)圖形化積木式編程(一)

前言

前段時間想要做一個web端的圖形化積木式編程(類似少兒編程)的案例,網(wǎng)上沖浪了一圈又一圈,終于技術(shù)選型好,然后代碼一頓敲,終于出來了一個雛形。

TIPS:該案例設(shè)計主要參考iRobot Coding,只用做學(xué)習(xí)用途,侵刪。

https://code.irobot.com/#/

最終實現(xiàn)效果

最終實現(xiàn)效果

本文實現(xiàn)效果

  • 可移動相機視角查看3d模型


    可移動相機視角

技術(shù)選型

1.前端

  • vuetify - 基于vue的界面框架

  • babylon.js - 3d圖形引擎

  • ammo.js - 物理引擎庫

  • blockly - 模塊化編程工具

  1. 后端
  • ThinkJS - 基于Node.js的后端框架

完整代碼

  • 一個完整的vue文件
<template>
  <div style="height: 100%;width: 100%;">
    <div>
      <canvas id="renderCanvas"></canvas>
    </div>
  </div>
</template>

<script>
import * as BABYLON from 'babylonjs';
import * as BABYLON_MATERAIAL from "babylonjs-materials"

function loadScene() {
  //獲取到renderCanvas這個元素
  var canvas = document.getElementById("renderCanvas");
  //初始化引擎
  var engine = new BABYLON.Engine(canvas, true);
  //初始化場景
  var scene = new BABYLON.Scene(engine);
  //注冊一個渲染循環(huán)來重復(fù)渲染場景
  engine.runRenderLoop(function () {
    scene.render();
  });
  //瀏覽器窗口變化時監(jiān)聽
  window.addEventListener("resize", function () {
    engine.resize();
  });

  //相機初始化
  var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 5, new BABYLON.Vector3(0, 0, 10), scene);
  camera.setPosition(new BABYLON.Vector3(20, 200, 400));
  //相機角度限制
  camera.upperBetaLimit = 1.5;//最大z軸旋轉(zhuǎn)角度差不多45度俯瞰
  camera.lowerRadiusLimit = 50;//最小縮小比例
  camera.upperRadiusLimit = 1500;//最大放大比例
  //變焦速度
  camera.wheelPrecision = 1; //電腦滾輪速度 越小靈敏度越高
  camera.pinchPrecision = 20; //手機放大縮小速度 越小靈敏度越高
  scene.activeCamera.panningSensibility = 100;//右鍵平移靈敏度
  // 將相機和畫布關(guān)聯(lián)
  camera.attachControl(canvas, true);

  //燈光初始化
  var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 10, 0), scene);
  //設(shè)置高光顏色
  light.specular = new BABYLON.Color3(0, 0, 0);
  //設(shè)置燈光強度
  light.intensity = 1

  // 綠地初始化
  var materialPlane = new BABYLON.StandardMaterial("texturePlane", scene);
  materialPlane.diffuseColor = new BABYLON.Color3(152 / 255.0, 209 / 255.0, 115 / 255.0)
  materialPlane.backFaceCulling = false;
  materialPlane.freeze()
  var plane = BABYLON.MeshBuilder.CreateDisc("ground", {radius: 3000}, scene);
  plane.rotation.x = Math.PI / 2;
  plane.material = materialPlane;
  plane.position.y = -0.1;
  plane.freezeWorldMatrix()

  //網(wǎng)格地板初始化
  const groundSide = 144;
  var ground = BABYLON.Mesh.CreateGround("ground", groundSide, groundSide, 1, scene, true);
  var groundMaterial = new BABYLON_MATERAIAL.GridMaterial("grid", scene);
  groundMaterial.mainColor = BABYLON.Color3.White();//底板顏色
  groundMaterial.alpha = 1;//透明度
  const gridLineGray = 0.95;
  groundMaterial.lineColor = new BABYLON.Color3(gridLineGray, gridLineGray, gridLineGray);
  groundMaterial.backFaceCulling = true; // 可看到背面
  //大網(wǎng)格間距
  groundMaterial.majorUnitFrequency = 16;
  //小網(wǎng)格間距
  groundMaterial.minorUnitVisibility = 0;
  const gridOffset = 8; // 網(wǎng)格偏移量
  groundMaterial.gridOffset = new BABYLON.Vector3(gridOffset, 0, gridOffset);
  groundMaterial.freeze(); // 凍結(jié)材質(zhì),優(yōu)化渲染速度
  ground.material = groundMaterial
  ground.freezeWorldMatrix()

  //正方形物體初始化
  var blueBox = BABYLON.Mesh.CreateBox("blue", 10, scene);
  var blueMat = new BABYLON.StandardMaterial("ground", scene);
  blueMat.diffuseColor = new BABYLON.Color3(0.4, 0.4, 0.4);
  blueMat.specularColor = new BABYLON.Color3(0.4, 0.4, 0.4);
  blueMat.emissiveColor = BABYLON.Color3.Blue();
  // blueMat.wireframe = true;//網(wǎng)格狀
  blueBox.material = blueMat;
  //起始位置坐標(biāo)
  blueBox.position.x = 0;
  blueBox.position.y = 5;
  blueBox.position.z = 0;

  //天空盒初始化
  var skyMaterial = new BABYLON_MATERAIAL.SkyMaterial("skyMaterial", scene);
  skyMaterial.inclination = 0
  skyMaterial.backFaceCulling = false;
  var skybox = BABYLON.Mesh.CreateBox("skyBox", 5000.0, scene);
  skybox.material = skyMaterial;
}


export default {
  name: "test",
  data() {
    return {
    }
  },
  mounted() {
    //加載場景
    loadScene()
  },
}
</script>

<style scoped>
#renderCanvas {
  width: 680px;
  height: 680px;
  touch-action: none;
  z-index: 10000;
  border-radius: 10px;
}
</style>

babylonjs入門場景學(xué)習(xí)

0、npm安裝相關(guān)依賴
npm install babylonjs babylonjs-gui babylonjs-loaders babylonjs-materials --save
  • 安裝的模塊在package.json中生成
"dependencies": {
 {
    "babylonjs": "^4.2.0",//babylon核心庫
    "babylonjs-gui": "^4.2.0",//UI界面庫(按鈕等)
    "babylonjs-loaders": "^4.2.0",//開機加載庫(修改啟動動畫的)
    "babylonjs-materials": "^4.2.0"http://材質(zhì)庫,有些材質(zhì)像是SkyMaterial,babylonjs庫的默認(rèn)材質(zhì)中是沒有這個對象的
}
1、引入模塊
import * as BABYLON from 'babylonjs';
import * as BABYLON_MATERAIAL from "babylonjs-materials"
2、場景初始化
  • template中
<div>
     <canvas id="renderCanvas"></canvas>
</div>
  • css中
#renderCanvas {
  width: 680px;
  height: 680px;
  touch-action: none;
  z-index: 10000;
  border-radius: 10px;
}
  • js中
//獲取到renderCanvas這個元素
var canvas = document.getElementById("renderCanvas");
//初始化引擎
var engine = new BABYLON.Engine(canvas, true);
//初始化場景
var scene = new BABYLON.Scene(engine);
//注冊一個渲染循環(huán)來重復(fù)渲染場景
engine.runRenderLoop(function () {
  scene.render();
});
//瀏覽器窗口變化時監(jiān)聽
window.addEventListener("resize", function () {
  engine.resize();
});
3、ArcRotateCamera 相機初始化
var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 5, new BABYLON.Vector3(0,0,10), scene);
camera.setPosition(new BABYLON.Vector3(20, 200, 400));
//相機角度限制
 camera.upperBetaLimit = 1.5;//最大z軸旋轉(zhuǎn)角度差不多45度俯瞰
camera.lowerRadiusLimit = 50;//最小縮小比例
camera.upperRadiusLimit = 1500;//最大放大比例
//變焦速度
camera.wheelPrecision = 1; //電腦滾輪速度 越小靈敏度越高
camera.pinchPrecision = 20; //手機放大縮小速度 越小靈敏度越高
scene.activeCamera.panningSensibility = 100;//右鍵平移靈敏度
// 將相機和畫布關(guān)聯(lián)
camera.attachControl(canvas, true);
4、燈光初始化
//設(shè)置半球光
var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 10, 0), scene);
//設(shè)置高光顏色
light.specular = new BABYLON.Color3(0, 0, 0);
//設(shè)置燈光強度
light.intensity = 1
5、地面初始化
5.1、綠地
// 添加地面
var materialPlane = new BABYLON.StandardMaterial("texturePlane", scene);
materialPlane.diffuseColor = new BABYLON.Color3(152 / 255.0, 209 / 255.0, 115 / 255.0)
materialPlane.backFaceCulling = false;//Allways show the front and the back of an element
materialPlane.freeze()
var plane = BABYLON.MeshBuilder.CreateDisc("ground", {radius: 6000}, scene);
plane.rotation.x = Math.PI / 2;
plane.material = materialPlane;
plane.position.y = -0.01;
plane.freezeWorldMatrix()
5.2、網(wǎng)格地面
//地板
  const groundSide = 144;
  var ground = BABYLON.Mesh.CreateGround("ground", groundSide, groundSide, 1, scene, true);
  var groundMaterial = new BABYLON_MATERAIAL.GridMaterial("grid", scene);
  groundMaterial.freeze(); // Optimization.
  groundMaterial.mainColor = BABYLON.Color3.White();//底板顏色
  groundMaterial.alpha = 1;//透明度
  const gridLineGray = 0.95;
  groundMaterial.lineColor = new BABYLON.Color3(gridLineGray, gridLineGray, gridLineGray);
  groundMaterial.backFaceCulling = true; // Change this if the back of the pad needs to be visible.
  //大網(wǎng)格間距
  groundMaterial.majorUnitFrequency = 16;
  //小網(wǎng)格間距
  groundMaterial.minorUnitVisibility = 0;
  const gridOffset = 0; // This makes the grid cells to be aligned with the pad's borders.
  groundMaterial.gridOffset = new BABYLON.Vector3(gridOffset, 0, gridOffset);
  ground.material = groundMaterial
  ground.freezeWorldMatrix()
  • TIPS:很多同學(xué)會發(fā)現(xiàn),將兩個平面疊加時,移動相機視角,會出現(xiàn)蟲影現(xiàn)象
兩平面疊加蟲影
  • 優(yōu)化方案
//1、凍結(jié)材質(zhì)和模型
//綠地
//設(shè)置為靜態(tài)網(wǎng)格,freezeWorldMatrix之后,改變postion、rotation是無效的
plane.freezeWorldMatrix()
//將材質(zhì)凍結(jié)
plane.material.freeze()
//網(wǎng)格
ground.freezeWorldMatrix()
ground.material.freeze()
//2、增大兩個物體的y軸間距
plane.position.y = -0.1
6、正方體物體初始化
 //添加物體
var blueBox = BABYLON.Mesh.CreateBox("blue", 10, scene);
var blueMat = new BABYLON.StandardMaterial("ground", scene);
blueMat.diffuseColor = new BABYLON.Color3(0.4, 0.4, 0.4);
blueMat.specularColor = new BABYLON.Color3(0.4, 0.4, 0.4);
blueMat.emissiveColor = BABYLON.Color3.Blue();
// blueMat.wireframe = true;//網(wǎng)格狀
blueBox.material = blueMat;
//起始位置坐標(biāo)
blueBox.position.x = 0;
blueBox.position.y = 5;
blueBox.position.z = 0;
7、天空盒初始化
//天空盒初始化
var skyMaterial = new BABYLON_MATERAIAL.SkyMaterial("skyMaterial", scene);
skyMaterial.inclination = 0
skyMaterial.backFaceCulling = false;
var skybox = BABYLON.Mesh.CreateBox("skyBox", 5000.0, scene);
skybox.material = skyMaterial;

后續(xù)計劃

Babylon.js

  • 加載網(wǎng)絡(luò)模型
  • 點擊移動物體
  • 自定義啟動界面
  • 初始化攝像機動畫
  • 物體重力效果
  • babylonjs-gui 按鈕實現(xiàn)
  • babylonjs+ammojs 碰撞體實現(xiàn)
  • 將3d界面放入可拖動窗口中

Blockly

  • 入門使用blockly
  • 自定義block塊
  • blockly第三方組件使用
  • 接入js-interpreter,步驟運行block塊
  • ......(想到啥寫啥)

開源項目GitHub鏈接

https://github.com/Wenbile/Child-Programming-Web

你的點贊是我繼續(xù)編寫的動力

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 什么是blockly? blockly是google發(fā)布的可視化編程工具,是一個基于web技術(shù)構(gòu)建的庫;block...
    辣椒爸閱讀 7,042評論 0 2
  • 打個小廣告:如果你想獲取更多前端干貨、鵝廠工程師的前端面試指南,歡迎關(guān)注我的個人微信公眾號:前端夜談 Github...
    ssthouse閱讀 1,954評論 0 1
  • 16宿命:用概率思維提高你的勝算 以前的我是風(fēng)險厭惡者,不喜歡去冒險,但是人生放棄了冒險,也就放棄了無數(shù)的可能。 ...
    yichen大刀閱讀 7,816評論 0 4
  • 公元:2019年11月28日19時42分農(nóng)歷:二零一九年 十一月 初三日 戌時干支:己亥乙亥己巳甲戌當(dāng)月節(jié)氣:立冬...
    石放閱讀 7,447評論 0 2

友情鏈接更多精彩內(nèi)容