改版;适配creator3.5

This commit is contained in:
Next
2022-07-17 16:48:06 +08:00
parent 9589907747
commit 63bbf81d1a
49 changed files with 1735 additions and 42594 deletions

39
src/App.vue Normal file
View File

@@ -0,0 +1,39 @@
<script setup lang="ts">
import TreePanel from './components/TreePanel.vue';
import { ref } from 'vue';
let showTree = ref(false);
</script>
<template>
<div>
<vue-final-modal v-model="showTree" classes="modal-container" content-class="modal-content" :hide-overlay="true"
:click-to-close="false" :prevent-click="true" :drag="true" :fit-parent="true" drag-selector=".modal-drag">
<TreePanel :show="showTree"></TreePanel>
</vue-final-modal>
<el-button size="small" @click="showTree = !showTree">节点树</el-button>
<el-button size="small" @click="showTree = !showTree">自定义监听</el-button>
<el-button size="small" @click="showTree = !showTree">设置</el-button>
</div>
</template>
<style scoped>
:deep(.modal-container) {
display: flex;
justify-content: start;
align-items: center;
}
:deep(.modal-content) {
position: relative;
display: flex;
flex-direction: column;
margin: 0;
padding: 0;
border: 1px solid #e2e8f0;
border-radius: 0.25rem;
background: #171920;
min-width: 400px;
height: 80%;
}
</style>

View 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
View 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>

View 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>

View 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>

View 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>

12
src/env.d.ts vendored Normal file
View File

@@ -0,0 +1,12 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}
declare module "ccc" {
function hehe(): void;
}

6
src/main.ts Normal file
View File

@@ -0,0 +1,6 @@
import { createApp } from 'vue';
import App from './App.vue';
import 'element-plus/theme-chalk/dark/css-vars.css';
import vfmPlugin from 'vue-final-modal'
createApp(App).use(vfmPlugin).mount('#app');

View File

@@ -0,0 +1,100 @@
interface IComponentProp {
name: string;
key: string;
custom?: boolean;
}
interface IComponentViewModel {
props: IComponentProp[];
}
export class ComponentManager {
static getViewModel(name: string, componentGetter: any) {
switch (name) {
case 'cc.UITransform':
return new CCUITransformModel(componentGetter);
case 'cc.Label':
return new CCLabelModel();
case 'cc.Sprite':
return new CCSpriteModel();
default:
return null
}
}
}
class CCUITransformModel implements IComponentViewModel {
private componentGetter: any;
props: IComponentProp[] = [
{ name: 'Width', key: 'width', custom: true },
{ name: 'Height', key: 'height', custom: true },
{ name: 'Anchor X', key: 'anchorX', custom: true },
{ name: 'Anchor Y', key: 'anchorY', custom: true },
]
constructor(componentGetter: any) {
this.componentGetter = componentGetter;
}
get component(): any {
return this.componentGetter();
}
get width() {
return this.componentGetter().contentSize.width;
}
set width(value: number) {
const origin = this.component.contentSize;
this.component.setContentSize(value, origin.height);
}
get height() {
return this.component.contentSize.height;
}
set height(value: number) {
const origin = this.component.contentSize;
this.component.setContentSize(origin.width, value);
}
get anchorX() {
return this.component.anchorPoint.x;
}
set anchorX(value: number) {
const origin = this.component.anchorPoint;
this.component.setAnchorPoint(value, origin.y);
}
get anchorY() {
return this.component.anchorPoint.y;
}
set anchorY(value: number) {
const origin = this.component.anchorPoint;
this.component.setAnchorPoint(origin.x, value);
}
}
class CCLabelModel implements IComponentViewModel {
props: IComponentProp[] = [
{ name: 'String', key: 'string' },
{ name: 'Color', key: 'color' },
{ name: 'Font Size', key: 'fontSize' },
{ name: 'Line Height', key: 'lineHeight' },
];
}
class CCSpriteModel implements IComponentViewModel {
props: IComponentProp[] = [
{ name: 'Color', key: 'color' },
];
}

31
src/misc/Utils.ts Normal file
View File

@@ -0,0 +1,31 @@
export default class Utils {
static checkNodeValid(ccNode: any) {
// @ts-ignore
return ccNode && cc.isValid(ccNode)
}
static outputToConsole(target: any) {
let i = 1;
// @ts-ignore
while (window['temp' + i] !== undefined) {
i++;
}
// @ts-ignore
window['temp' + i] = target;
console.log('temp' + i);
// @ts-ignore
console.log(window['temp' + i]);
}
static getComponentName(component: any) {
return component.__classname__;
}
static getComponents(ccNode: any) {
return ccNode.components.map((component: any) => {
return { name: component.__classname__, target: component }
});
}
}