mirror of
https://github.com/potato47/ccc-devtools.git
synced 2025-10-13 18:45:53 +00:00
改版;适配creator3.5
This commit is contained in:
24
src/components/CCComponent.vue
Normal file
24
src/components/CCComponent.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<el-checkbox v-model="component!.enabled" size="small" style="margin-right: 10px;" />
|
||||
<span style="flex: 1;">{{ name }}</span>
|
||||
<el-button size="small" @click="Utils.outputToConsole(component)">></el-button>
|
||||
</div>
|
||||
<PropItem v-if="model" v-for="prop in model.props" :key="prop.key" :model="prop.custom ? model : component" :prop-name="prop.name" :prop-key="prop.key"
|
||||
:update-key="updateKey!"></PropItem>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import PropItem from './PropItem.vue';
|
||||
import Utils from '../misc/Utils';
|
||||
import { ComponentManager } from '../misc/ComponentManager';
|
||||
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
component: Object,
|
||||
updateKey: Number,
|
||||
});
|
||||
|
||||
const model = ComponentManager.getViewModel(props.name!, () => props.component)!;
|
||||
|
||||
</script>
|
101
src/components/CCNode.vue
Normal file
101
src/components/CCNode.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<el-checkbox v-model="ccNode!.active" size="small" style="margin-right: 10px;" />
|
||||
<span class="header-title" style="flex: 1;">Node</span>
|
||||
<el-button size="small">+</el-button>
|
||||
<el-button size="small" @click="Utils.outputToConsole(ccNode)">></el-button>
|
||||
</div>
|
||||
<PropItem v-for="prop in NodeModel.props" :key="prop.key" :model="NodeModel" :prop-name="prop.name"
|
||||
:prop-key="prop.key" :update-key="updateKey!"></PropItem>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import PropItem from './PropItem.vue';
|
||||
import Utils from '../misc/Utils';
|
||||
|
||||
const props = defineProps({
|
||||
ccNode: Object,
|
||||
updateKey: Number,
|
||||
});
|
||||
|
||||
class NodeModel {
|
||||
|
||||
static props = [
|
||||
{ name: 'Name', key: 'nodeName' },
|
||||
{ name: 'X', key: 'x' },
|
||||
{ name: 'Y', key: 'y' },
|
||||
{ name: 'Z', key: 'z' },
|
||||
{ name: 'Scale X', key: 'scaleX' },
|
||||
{ name: 'Scale Y', key: 'scaleY' },
|
||||
{ name: 'Scale Z', key: 'scaleZ' },
|
||||
]
|
||||
|
||||
static get ccNode(): any {
|
||||
return props.ccNode;
|
||||
}
|
||||
|
||||
static get nodeName() {
|
||||
return this.ccNode.name;
|
||||
}
|
||||
|
||||
static set nodeName(value: number) {
|
||||
this.ccNode.name = value;
|
||||
}
|
||||
|
||||
static get x() {
|
||||
return this.ccNode.getPosition().x;
|
||||
}
|
||||
|
||||
static set x(value: number) {
|
||||
const originPos = this.ccNode.getPosition();
|
||||
this.ccNode.setPosition(value, originPos.y, originPos.z);
|
||||
}
|
||||
|
||||
static get y() {
|
||||
return this.ccNode.getPosition().y;
|
||||
}
|
||||
|
||||
static set y(value: number) {
|
||||
const originPos = this.ccNode.getPosition();
|
||||
this.ccNode.setPosition(originPos.x, value, originPos.z);
|
||||
}
|
||||
|
||||
static get z() {
|
||||
return this.ccNode.getPosition().z;
|
||||
}
|
||||
|
||||
static set z(value: number) {
|
||||
const originPos = this.ccNode.getPosition();
|
||||
this.ccNode.setPosition(originPos.x, originPos.y, value);
|
||||
}
|
||||
|
||||
static get scaleX() {
|
||||
return this.ccNode.getScale().x;
|
||||
}
|
||||
|
||||
static set scaleX(value: number) {
|
||||
const originScale = this.ccNode.getScale();
|
||||
this.ccNode.setScale(value, originScale.y, originScale.z);
|
||||
}
|
||||
|
||||
static get scaleY() {
|
||||
return this.ccNode.getScale().y;
|
||||
}
|
||||
|
||||
static set scaleY(value: number) {
|
||||
const originScale = this.ccNode.getScale();
|
||||
this.ccNode.setScale(originScale.x, value, originScale.z);
|
||||
}
|
||||
|
||||
static get scaleZ() {
|
||||
return this.ccNode.getScale().z;
|
||||
}
|
||||
|
||||
static set scaleZ(value: number) {
|
||||
const originScale = this.ccNode.getScale();
|
||||
this.ccNode.setScale(originScale.x, originScale.y, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</script>
|
43
src/components/PropItem.vue
Normal file
43
src/components/PropItem.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<span style="flex: 1">{{ propName }}</span>
|
||||
<el-input-number v-model="model[propKey]" :precision="2" size="small" controls-position="right" style="flex: 1"
|
||||
v-if="getPropType() == 'number'" />
|
||||
<el-input size="small" v-model="model[propKey]" style="flex: 1" v-else-if="getPropType() == 'string'" />
|
||||
<el-checkbox v-model="model[propKey]" size="small" style="margin-left: 10px"
|
||||
v-else-if="getPropType() == 'boolean'" />
|
||||
<el-color-picker v-model="CustomModel.color" size="small" style="flex: 1" color-format="hex" show-alpha
|
||||
v-else-if="getPropType() == 'cc.Color'" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
model: any;
|
||||
propName: string;
|
||||
propKey: string;
|
||||
updateKey: number;
|
||||
}>();
|
||||
|
||||
function getPropType() {
|
||||
const data = props.model[props.propKey];
|
||||
const dataType = typeof data;
|
||||
if (dataType === "object" && data.__classname__) {
|
||||
return data.__classname__;
|
||||
}
|
||||
return dataType;
|
||||
}
|
||||
|
||||
class CustomModel {
|
||||
static get color() {
|
||||
const origin = props.model[props.propKey];
|
||||
const hexA = origin.a.toString(16);
|
||||
return `#${origin.toHEX()}${hexA.length === 1 ? "0" + hexA : hexA}`;
|
||||
}
|
||||
|
||||
static set color(v: string) {
|
||||
// @ts-ignore
|
||||
props.model[props.propKey] = new cc.Color().fromHEX(v);
|
||||
}
|
||||
}
|
||||
</script>
|
169
src/components/TreePanel.vue
Normal file
169
src/components/TreePanel.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div style="width: 100%;height: 30px;background-color: #26282f;display: flex;align-items: center;justify-content: center;color: white;" class="modal-drag">
|
||||
节点树
|
||||
</div>
|
||||
<div style="width: 100%;overflow: auto;" :style="{ height: treeViewHeight }">
|
||||
<el-tree-v2 ref="treeView" :props="defaultProps" empty-text="正在加载场景" :highlight-current="true"
|
||||
:expand-on-click-node="false" :default-expanded-keys="expandedKeys" @current-change="handleCurrentNodeChange"
|
||||
@node-expand="handleNodeExpand" @node-collapse="handleNodeCollapse" :height="treeViewHeight">
|
||||
<template #default="{ node }">
|
||||
<span :class="{ 'node-hide': !node.data.active }">{{ node.label }}</span>
|
||||
</template>
|
||||
</el-tree-v2>
|
||||
</div>
|
||||
<div style="width: 100%;border-top: 2px solid #1d1e21;overflow: auto;flex: 1;">
|
||||
<template v-if="updateKey !== 0 && Utils.checkNodeValid(currentNode)">
|
||||
<el-scrollbar>
|
||||
<CCNode :cc-node="currentNode" :update-key="updateKey"></CCNode>
|
||||
<div class="row" style="height: 2px;background-color: #1d1e21"></div>
|
||||
<template v-for="component in Utils.getComponents(currentNode)" :key="component.name">
|
||||
<CCComponent v-if="component.name.startsWith('cc.')" :component="component.target" :name="component.name"
|
||||
:update-key="updateKey"></CCComponent>
|
||||
<UserComponent v-else :component="component.target" :name="component.name" :update-key="updateKey">
|
||||
</UserComponent>
|
||||
<div class="row" style="height: 2px;background-color: #1d1e21"></div>
|
||||
</template>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue';
|
||||
import { ref } from 'vue-demi';
|
||||
import CCNode from './CCNode.vue';
|
||||
import Utils from '../misc/Utils';
|
||||
import CCComponent from './CCComponent.vue';
|
||||
import UserComponent from './UserComponent.vue';
|
||||
|
||||
const props = defineProps({
|
||||
show: Boolean,
|
||||
});
|
||||
|
||||
interface TreeNode {
|
||||
name: string;
|
||||
uuid: string;
|
||||
active: boolean;
|
||||
children?: TreeNode[];
|
||||
path: string[];
|
||||
}
|
||||
|
||||
let updateKey = ref(1);
|
||||
let currentNode: any;
|
||||
const expandedNodeMap = new Map();
|
||||
let expandedKeys: string[] = [];
|
||||
const defaultProps = {
|
||||
value: 'uuid',
|
||||
label: 'name',
|
||||
children: 'children',
|
||||
};
|
||||
|
||||
const treeViewHeight = window.innerHeight * 0.4;
|
||||
const treeView = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
console.log('ccc-devtools init');
|
||||
});
|
||||
|
||||
function getChildByUuidPath(node: any, path: string[], index: number): any {
|
||||
if (index >= path.length) {
|
||||
return node;
|
||||
}
|
||||
node = node.getChildByUuid(path[index]);
|
||||
return getChildByUuidPath(node, path, index + 1);
|
||||
}
|
||||
|
||||
function handleCurrentNodeChange(data: TreeNode) {
|
||||
console.log(data);
|
||||
// @ts-ignore
|
||||
const ccNode = getChildByUuidPath(cc.director.getScene(), data.path, 0);
|
||||
if (data) {
|
||||
currentNode = ccNode;
|
||||
} else {
|
||||
currentNode = null;
|
||||
}
|
||||
}
|
||||
|
||||
function handleNodeExpand(data: TreeNode) {
|
||||
expandedNodeMap.set(data.uuid, true);
|
||||
expandedKeys = [...expandedNodeMap.keys()];
|
||||
}
|
||||
|
||||
function handleNodeCollapse(data: TreeNode) {
|
||||
expandedNodeMap.delete(data.uuid);
|
||||
expandedKeys = [...expandedNodeMap.keys()];
|
||||
}
|
||||
|
||||
function setChildren(container: TreeNode[], children: any[], path: string[]) {
|
||||
children.forEach(ccNode => {
|
||||
const childPath = path.concat(ccNode.uuid);
|
||||
const node = {
|
||||
uuid: ccNode.uuid,
|
||||
name: ccNode.name,
|
||||
active: ccNode.activeInHierarchy,
|
||||
children: [],
|
||||
path: childPath,
|
||||
};
|
||||
if (ccNode.children && ccNode.children.length > 0) {
|
||||
setChildren(node.children, ccNode.children, childPath);
|
||||
}
|
||||
container.push(node);
|
||||
});
|
||||
}
|
||||
|
||||
function refreshTree() {
|
||||
if (props.show) {
|
||||
let value: TreeNode[] = [];
|
||||
//@ts-ignore
|
||||
setChildren(value, cc.director.getScene().children, []);
|
||||
(treeView.value as any).setData(value);
|
||||
updateKey.value = -updateKey.value;
|
||||
}
|
||||
window.requestAnimationFrame(refreshTree);
|
||||
}
|
||||
|
||||
function init() {
|
||||
refreshTree();
|
||||
}
|
||||
|
||||
const intervalId = setInterval(() => {
|
||||
// @ts-ignore
|
||||
if (window['cc'] && cc.director.getScene()) {
|
||||
init();
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.el-input__wrapper {
|
||||
padding-left: 10px !important;
|
||||
}
|
||||
|
||||
.el-color-picker {
|
||||
flex: 1 !important;
|
||||
}
|
||||
|
||||
.el-color-picker__trigger {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #cfd3dc;
|
||||
}
|
||||
|
||||
.node-hide {
|
||||
opacity: 0.3;
|
||||
}
|
||||
</style>
|
18
src/components/UserComponent.vue
Normal file
18
src/components/UserComponent.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<el-checkbox v-model="component!.enabled" size="small" style="margin-right: 10px;" />
|
||||
<span class="header-title" style="flex: 1;">{{ name }}</span>
|
||||
<el-button size="small" @click="Utils.outputToConsole(component)">></el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Utils from '../misc/Utils';
|
||||
|
||||
defineProps({
|
||||
name: String,
|
||||
component: Object,
|
||||
updateKey: Number,
|
||||
});
|
||||
|
||||
</script>
|
Reference in New Issue
Block a user