界面效果
思路
- bootstrap控制界面效果
- jquery动态修改界面内容
- [Add]增加一个box
- [Play]导出
play.html
,打开play.html
就可以看到程序运行效果
编辑器代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>编辑器</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<style>
body {
margin: 0;
width: 100%;
height: 100%;
}
#project {
position: absolute;
z-index: 100;
}
#propertyList {
position: absolute;
z-index: 100;
left: 80%;
right: 0px;
top: 25%;
}
#canvas {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
z-index: 0;
background: transparent;
touch-action: none;
object-fit: cover;
}
</style>
</head>
<body οnresize="resize_canvas()">
<div class="panel panel-default" id="project">
<button type="button" class="btn btn-default" onclick="addBox()">Add</button>
<button type="button" class="btn btn-default" onclick="startSimulate()">Play</button>
<br />
project
<div class="panel-body">
<ul class="list-group" id="projectUl">
</ul>
</div>
</div>
<div class="panel panel-default" id="propertyList">
property
<div class="panel-body" id="propertyListBody">
</div>
</div>
<canvas id="canvas"></canvas>
<script type="importmap">
{
"imports": {
"@orillusion/core": "https://unpkg.com/@orillusion/core/dist/orillusion.es.js",
"@orillusion/stats": "https://unpkg.com/@orillusion/stats/dist/stats.es.js",
"dat.gui": "https://npm.elemecdn.com/dat.gui@0.7.9/build/dat.gui.module.js"
}
}
</script>
<script type="module">
import { Engine3D, Scene3D, Object3D, Camera3D, ComponentBase, LitMaterial, BoxGeometry, MeshRenderer, DirectLight, PlaneGeometry, HoverCameraController, View3D, AtmosphericComponent } from '@orillusion/core'
import { Stats } from '@orillusion/stats'
import * as dat from 'dat.gui'
window.startGame = startGame
window.continueGame = continueGame
window.endGame = endGame
window.showMenu = showMenu
window.hideMenu = hideMenu
window.resize_canvas = resize_canvas
window.initGame = initGame
window.selectItem = selectItem
window.startSimulate = startSimulate
window.serializeGame = serializeGame
window.saveFile = saveFile
window.scene2Json = scene2Json
window.addBox = addBox
window.addCamera = addCamera
window.addLight = addLight
let gameState = 'none'
let GUIHelp
let gItemes = new Array()
let scene3D
let gCurrentItemIndex = -1
let gItemsSize = 0
let dataMap = []
function startGame() {
console.log("StartGame")
if (gameState == 'pause') {
continueGame()
return
}
hideMenu()
gameState = 'start'
initGame()
}
function continueGame() {
console.log("ContinueGame")
hideMenu()
if (gameState == 'none') {
startGame()
}
}
function endGame() {
console.log("EndGame")
}
function showMenu() {
console.log("showMenu")
if (gameState == 'start') {
gameState = 'pause'
Engine3D.pause()
}
}
function hideMenu() {
console.log("hideMenu")
let canvas = document.getElementById('canvas')
if (gameState == 'pause') {
gameState = 'start'
Engine3D.resume()
}
}
function resize_canvas() {
canvas = document.getElementById("canvas");
if (canvas.width < window.innerWidth) {
canvas.width = window.innerWidth;
}
if (canvas.height < window.innerHeight) {
canvas.height = window.innerHeight;
}
}
async function initGame() {
await Engine3D.init({
canvasConfig: { canvas }
})
scene3D = new Scene3D()
addSky()
let camera = addCamera()
addLight()
let view = new View3D()
view.scene = scene3D
view.camera = camera
Engine3D.startRenderView(view)
const GUIHelp = new dat.GUI()
GUIHelp.addFolder('Setting')
GUIHelp.add({ menu: () => showMenu() }, 'menu')
}
function addSky() {
let sky = scene3D.addComponent(AtmosphericComponent)
sky.sunY = 0.6
scene3D.name = 'scene3D'
gCurrentItemIndex = gItemes.length
$("#projectUl").append("<li class=\"list-group-item\"> <button type=\"button\" class=\"btn btn-default\" οnclick=\"selectItem(" + gCurrentItemIndex + ")\">" + "scene3D" + "</button> </li>")
gItemes.push({
"obj": scene3D,
"type": 'scene3D',
"scriptContent": "",
"scriptClassName": "",
})
return sky
}
function addBox() {
gCurrentItemIndex = gItemes.length
let name = 'box-' + gCurrentItemIndex
$("#projectUl").append("<li class=\"list-group-item\"> <button type=\"button\" class=\"btn btn-default\" οnclick=\"selectItem(" + gCurrentItemIndex + ")\">" + name + "</button> </li>")
const obj = new Object3D()
obj.name = name
let mr = obj.addComponent(MeshRenderer)
mr.geometry = new BoxGeometry(5, 5, 5)
mr.material = new LitMaterial()
scene3D.addChild(obj)
gItemes.push({
"obj": obj,
"type": 'box',
"scriptContent": "",
"scriptClassName": "",
})
}
function addCamera() {
let cameraObj = new Object3D()
cameraObj.name = "camera"
let camera = cameraObj.addComponent(Camera3D)
camera.perspective(60, Engine3D.aspect, 1, 5000.0)
let controller = cameraObj.addComponent(HoverCameraController)
controller.setCamera(0, 0, 15)
scene3D.addChild(cameraObj)
gCurrentItemIndex = gItemes.length
$("#projectUl").append("<li class=\"list-group-item\"> <button type=\"button\" class=\"btn btn-default\" οnclick=\"selectItem(" + gCurrentItemIndex + ")\">" + "camera" + "</button> </li>")
gItemes.push({
"obj": cameraObj,
"type": 'camera',
"scriptContent": "",
"scriptClassName": "",
})
return camera
}
function addLight() {
let light = new Object3D()
light.name = "light"
let component = light.addComponent(DirectLight)
light.rotationX = 45
light.rotationY = 30
component.intensity = 1
scene3D.addChild(light)
gCurrentItemIndex = gItemes.length
$("#projectUl").append("<li class=\"list-group-item\"> <button type=\"button\" class=\"btn btn-default\" οnclick=\"selectItem(" + gCurrentItemIndex + ")\">" + "light" + "</button> </li>")
gItemes.push({
"obj": light,
"type": 'light',
"scriptContent": "",
"scriptClassName": "",
})
return light
}
function selectItem(index) {
console.log("selectItemIndex: " + index)
gCurrentItemIndex = index
showItemProrperty(gItemes[index])
}
function showItemProrperty(item) {
let name = item['obj'].name
console.log("showItemProrperty: " + item)
$("#propertyListBody").empty()
let obj = item['obj']
if (!obj) {
console.warn("scene3D not find: " + name)
return
}
$("#propertyListBody").append("<div class=\"input-group\"> <span class=\"input-group-addon\">name</span><input type=\"text\" id=\"objName\" value=" + obj.name + "></input></div><br/>")
let trans = obj.transform
$("#propertyListBody").append("<p>transform</p>")
$("#propertyListBody").append("<p>position</p>")
$("#propertyListBody").append("<div class=\"input-group\"> <span class=\"input-group-addon\">x</span><input type=\"text\" id=\"transX\" value=" + trans.x + "></input></div>")
$("#propertyListBody").append("<div class=\"input-group\"> <span class=\"input-group-addon\">y</span><input type=\"text\" id=\"transY\" value=" + trans.y + "></input></div>")
$("#propertyListBody").append("<div class=\"input-group\"> <span class=\"input-group-addon\">z</span><input type=\"text\" id=\"transZ\" value=" + trans.z + "></input></div>")
$("#transX").change(function () { obj.x = $("#transX").val() })
$("#transY").change(function () { obj.y = $("#transY").val() })
$("#transZ").change(function () { obj.z = $("#transZ").val() })
$("#propertyListBody").append("<p>script</p>")
$("#propertyListBody").append("<textarea class=\"form-control\" rows=\"6\" id=\"textareaScript\">" + item.scriptContent + "</textarea>")
$("#textareaScript").change(function () {
let str = $("#textareaScript").val()
let className = str.split(/\s* extends/)[0].replace('class', '')
console.log("className = " + className + ";gCurrentItemIndex=" + gCurrentItemIndex + ";str=" + str)
if (gCurrentItemIndex > -1) {
gItemes[gCurrentItemIndex].scriptContent = str
gItemes[gCurrentItemIndex].scriptClassName = className.trim()
}
})
}
function startSimulate() {
serializeGame()
}
function serializeGame() {
saveFile('play.html')
}
async function getFile() {
const [fileHandle] = await window.showOpenFilePicker();
const file = await fileHandle.getFile();
return file;
}
async function saveFile(path) {
const newHandle = await window.showSaveFilePicker();
const writableStream = await newHandle.createWritable();
dataMap = []
let data = scene2Json()
console.log("scene2Json=" + data)
await writableStream.write("<!DOCTYPE html>");
await writableStream.write("<html>");
await writableStream.write("<head>\n");
await writableStream.write("<meta charset=\"utf-8\">\n");
await writableStream.write("<title>Play</title>\n");
await writableStream.write("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n");
await writableStream.write("<link rel=\"stylesheet\" href=\"https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css\">\n");
await writableStream.write("<script src=\"https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js\"><\/script>\n");
await writableStream.write("<script src=\"https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js\"><\/script>\n");
await writableStream.write("<style>body {margin: 0;width: 100%;height: 100%;}\n");
await writableStream.write("#canvas {position: absolute;top: 0px;left: 0px;width: 100%;height: 100%;z-index: 0;background: transparent;touch-action: none;object-fit: cover;}\n");
await writableStream.write("</style>\n");
await writableStream.write("</head>\n");
await writableStream.write("<body οnresize=\"resize_canvas()\">\n");
await writableStream.write("<canvas id=\"canvas\"></canvas>\n");
await writableStream.write("<script type=\"importmap\">{\n");
await writableStream.write(" \"imports\": {\n");
await writableStream.write("\"@orillusion/core\": \"https://unpkg.com/@orillusion/core/dist/orillusion.es.js\",\n");
await writableStream.write("\"@orillusion/stats\": \"https://unpkg.com/@orillusion/stats/dist/stats.es.js\",\n");
await writableStream.write("\"dat.gui\": \"https://npm.elemecdn.com/dat.gui@0.7.9/build/dat.gui.module.js\"}}\n");
await writableStream.write("<\/script>\n");
await writableStream.write("<script type=\"module\">\n");
await writableStream.write("import { Engine3D, Scene3D, Object3D, Camera3D, ComponentBase, LitMaterial, BoxGeometry, MeshRenderer, DirectLight, PlaneGeometry, HoverCameraController, View3D, AtmosphericComponent } from '@orillusion/core'\n");
await writableStream.write("import { Stats } from '@orillusion/stats'\n");
await writableStream.write("import * as dat from 'dat.gui'\n");
await writableStream.write("import * as localSprite from './localScript.mjs'\n");
for(var s = 0; s < dataMap.length; s++){
let strScript = dataMap[s].scriptContent
if(strScript == "") continue;
await writableStream.write(strScript);
await writableStream.write("\n");
}
await writableStream.write("async function initGame() {\n");
await writableStream.write("await Engine3D.init({ canvasConfig: { canvas } })\n");
await writableStream.write("let scene3D = new Scene3D()\n");
await writableStream.write("let view = new View3D()\n");
await writableStream.write("view.scene = scene3D\n");
await writableStream.write("localSprite.testlocalScript()\n");
await writableStream.write("localSprite.loadObj(scene3D, view, " + data + ")\n");
for(var s = 0; s < dataMap.length; s++){
if(dataMap[s].scriptClassName != ""){
await writableStream.write("{ let obj = scene3D.getObjectByName(\"" + dataMap[s].name + "\"); ");
await writableStream.write("obj.addComponent(" + dataMap[s].scriptClassName + ") }\n");
}
}
await writableStream.write("Engine3D.startRenderView(view) }\n");
await writableStream.write("initGame()\n");
await writableStream.write("<\/script>\n");
await writableStream.write("</body>\n");
await writableStream.write("</html>");
await writableStream.close();
}
function scene2Json() {
for (var i = 0; i < gItemes.length; i++) {
let item = gItemes[i]
console.log(item.obj.name)
let mapobj = {
name: item.obj.name,
type: item.type,
scriptContent: item.scriptContent,
scriptClassName: item.scriptClassName,
x: item.obj.x,
y: item.obj.y,
z: item.obj.z,
scaleX: item.obj.scaleX,
scaleY: item.obj.scaleY,
scaleZ: item.obj.scaleZ,
rotationX: item.obj.rotationX,
rotationY: item.obj.rotationY,
rotationZ: item.obj.rotationZ,
}
let mr = item.obj.getComponent(MeshRenderer)
if (mr) {
mapobj.MeshRenderer = {}
let geometry = mr.geometry
if (geometry) {
mapobj.MeshRenderer.geometry = {}
if (geometry.constructor === BoxGeometry) {
console.log("===========BoxGeometry======================")
mapobj.MeshRenderer.geometry.type = 'BoxGeometry'
mapobj.MeshRenderer.geometry.width = geometry.width
mapobj.MeshRenderer.geometry.height = geometry.height
mapobj.MeshRenderer.geometry.depth = geometry.depth
}
}
}
dataMap.push(mapobj)
}
return JSON.stringify(dataMap)
}
startGame()
</script>
</body>
</html>
play.html
是编辑器自动生成的不用修改
localScript.mjs
是方便play.html
动态创建加载Object3D
export function testlocalScript() {
console.log("testlocalScript~~~~~~~~~~~~~")
}
import { Engine3D, Scene3D, Object3D, Camera3D, LitMaterial, BoxGeometry, MeshRenderer, DirectLight, PlaneGeometry, HoverCameraController, View3D, AtmosphericComponent } from "https://unpkg.com/@orillusion/core/dist/orillusion.es.js"
export function loadObj(scene3D, view, content) {
console.log("loadObj~~~~~~~~~~~~~" + content)
for (var i = 0; i < content.length; i++) {
let item = content[i]
console.log("loadObj~~~~~~~~~~~~~" + i + item)
if (item.type == "scene3D") {
addSky(item, scene3D)
}
else if (item.type == "light") {
addLight(item, scene3D)
}
else if (item.type == "camera") {
let camera = addCamera(item, scene3D)
view.camera = camera
}
else if (item.type == "box") {
addBox(item, scene3D)
}
}
}
function addBox(item, scene3D) {
const obj = new Object3D()
obj.name = item.name
let mr = obj.addComponent(MeshRenderer)
if (item.MeshRenderer) {
if (item.MeshRenderer.geometry) {
mr.geometry = new BoxGeometry(item.MeshRenderer.geometry.width,
item.MeshRenderer.geometry.height,
item.MeshRenderer.geometry.depth)
}
}
mr.material = new LitMaterial()
setObjInfo(item, obj)
scene3D.addChild(obj)
}
function addCamera(item, scene3D) {
let cameraObj = new Object3D()
cameraObj.name = item.name
let camera = cameraObj.addComponent(Camera3D)
camera.perspective(60, Engine3D.aspect, 1, 5000.0)
let controller = cameraObj.addComponent(HoverCameraController)
controller.setCamera(0, 0, 15)
scene3D.addChild(cameraObj)
return camera
}
function addLight(item, scene3D) {
let light = new Object3D()
light.name = item.name
let component = light.addComponent(DirectLight)
light.rotationX = 45
light.rotationY = 30
component.intensity = 1
scene3D.addChild(light)
return light
}
function addSky(item, scene3D) {
let sky = scene3D.addComponent(AtmosphericComponent)
sky.sunY = 0.6
return sky
}
function setObjInfo(item, obj){
obj.x = item.x
obj.y = item.y
obj.z = item.z
obj.rotationX = item.rotationX
obj.rotationY = item.rotationY
obj.rotationZ = item.rotationZ
}
物体的脚本也会动态写入play.html
,所以支持物体脚本行为
play效果