Feature/physics and tilemap enhancement (#247)

* feat(behavior-tree,tilemap): 修复编辑器连线缩放问题并增强插件系统

* feat(node-editor,blueprint): 新增通用节点编辑器和蓝图可视化脚本系统

* feat(editor,tilemap): 优化编辑器UI样式和Tilemap编辑器功能

* fix: 修复CodeQL安全警告和CI类型检查错误

* fix: 修复CodeQL安全警告和CI类型检查错误

* fix: 修复CodeQL安全警告和CI类型检查错误
This commit is contained in:
YHH
2025-11-29 23:00:48 +08:00
committed by GitHub
parent f03b73b58e
commit 359886c72f
198 changed files with 33879 additions and 13121 deletions

View File

@@ -0,0 +1,91 @@
/**
* Print Node - Outputs a message for debugging
* 打印节点 - 输出调试消息
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
/**
* Print node template
* Print 节点模板
*/
export const PrintTemplate: BlueprintNodeTemplate = {
type: 'Print',
title: 'Print String',
category: 'debug',
color: '#785EF0',
description: 'Prints a message to the console for debugging (打印消息到控制台用于调试)',
keywords: ['log', 'debug', 'console', 'output', 'print'],
inputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
},
{
name: 'message',
type: 'string',
displayName: 'Message',
defaultValue: 'Hello Blueprint!'
},
{
name: 'printToScreen',
type: 'bool',
displayName: 'Print to Screen',
defaultValue: true
},
{
name: 'duration',
type: 'float',
displayName: 'Duration',
defaultValue: 2.0
}
],
outputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
}
]
};
/**
* Print node executor
* Print 节点执行器
*/
@RegisterNode(PrintTemplate)
export class PrintExecutor implements INodeExecutor {
execute(node: BlueprintNode, context: ExecutionContext): ExecutionResult {
const message = context.evaluateInput(node.id, 'message', 'Hello Blueprint!');
const printToScreen = context.evaluateInput(node.id, 'printToScreen', true);
const duration = context.evaluateInput(node.id, 'duration', 2.0);
// Console output
// 控制台输出
console.log(`[Blueprint] ${message}`);
// Screen output via event (handled by runtime)
// 通过事件输出到屏幕(由运行时处理)
if (printToScreen) {
const event = new CustomEvent('blueprint:print', {
detail: {
message: String(message),
duration: Number(duration),
entityId: context.entity.id,
entityName: context.entity.name
}
});
if (typeof window !== 'undefined') {
window.dispatchEvent(event);
}
}
return {
nextExec: 'exec'
};
}
}

View File

@@ -0,0 +1,6 @@
/**
* Debug Nodes - Tools for debugging blueprints
* 调试节点 - 蓝图调试工具
*/
export * from './Print';

View File

@@ -0,0 +1,44 @@
/**
* Event Begin Play Node - Triggered when the blueprint starts
* 开始播放事件节点 - 蓝图启动时触发
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
/**
* EventBeginPlay node template
* EventBeginPlay 节点模板
*/
export const EventBeginPlayTemplate: BlueprintNodeTemplate = {
type: 'EventBeginPlay',
title: 'Event Begin Play',
category: 'event',
color: '#CC0000',
description: 'Triggered once when the blueprint starts executing (蓝图开始执行时触发一次)',
keywords: ['start', 'begin', 'init', 'event'],
inputs: [],
outputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
}
]
};
/**
* EventBeginPlay node executor
* EventBeginPlay 节点执行器
*/
@RegisterNode(EventBeginPlayTemplate)
export class EventBeginPlayExecutor implements INodeExecutor {
execute(_node: BlueprintNode, _context: ExecutionContext): ExecutionResult {
// Event nodes just trigger execution flow
// 事件节点只触发执行流
return {
nextExec: 'exec'
};
}
}

View File

@@ -0,0 +1,42 @@
/**
* Event End Play Node - Triggered when the blueprint stops
* 结束播放事件节点 - 蓝图停止时触发
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
/**
* EventEndPlay node template
* EventEndPlay 节点模板
*/
export const EventEndPlayTemplate: BlueprintNodeTemplate = {
type: 'EventEndPlay',
title: 'Event End Play',
category: 'event',
color: '#CC0000',
description: 'Triggered once when the blueprint stops executing (蓝图停止执行时触发一次)',
keywords: ['stop', 'end', 'destroy', 'event'],
inputs: [],
outputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
}
]
};
/**
* EventEndPlay node executor
* EventEndPlay 节点执行器
*/
@RegisterNode(EventEndPlayTemplate)
export class EventEndPlayExecutor implements INodeExecutor {
execute(_node: BlueprintNode, _context: ExecutionContext): ExecutionResult {
return {
nextExec: 'exec'
};
}
}

View File

@@ -0,0 +1,50 @@
/**
* Event Tick Node - Triggered every frame
* 每帧事件节点 - 每帧触发
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
/**
* EventTick node template
* EventTick 节点模板
*/
export const EventTickTemplate: BlueprintNodeTemplate = {
type: 'EventTick',
title: 'Event Tick',
category: 'event',
color: '#CC0000',
description: 'Triggered every frame during execution (执行期间每帧触发)',
keywords: ['update', 'frame', 'tick', 'event'],
inputs: [],
outputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
},
{
name: 'deltaTime',
type: 'float',
displayName: 'Delta Seconds'
}
]
};
/**
* EventTick node executor
* EventTick 节点执行器
*/
@RegisterNode(EventTickTemplate)
export class EventTickExecutor implements INodeExecutor {
execute(_node: BlueprintNode, context: ExecutionContext): ExecutionResult {
return {
nextExec: 'exec',
outputs: {
deltaTime: context.deltaTime
}
};
}
}

View File

@@ -0,0 +1,8 @@
/**
* Event Nodes - Entry points for blueprint execution
* 事件节点 - 蓝图执行的入口点
*/
export * from './EventBeginPlay';
export * from './EventTick';
export * from './EventEndPlay';

View File

@@ -0,0 +1,11 @@
/**
* Blueprint Nodes - All node definitions and executors
* 蓝图节点 - 所有节点定义和执行器
*/
// Import all nodes to trigger registration
// 导入所有节点以触发注册
export * from './events';
export * from './debug';
export * from './time';
export * from './math';

View File

@@ -0,0 +1,122 @@
/**
* Math Operation Nodes - Basic arithmetic operations
* 数学运算节点 - 基础算术运算
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
// Add Node (加法节点)
export const AddTemplate: BlueprintNodeTemplate = {
type: 'Add',
title: 'Add',
category: 'math',
color: '#4CAF50',
description: 'Adds two numbers together (将两个数字相加)',
keywords: ['add', 'plus', 'sum', '+', 'math'],
isPure: true,
inputs: [
{ name: 'a', type: 'float', displayName: 'A', defaultValue: 0 },
{ name: 'b', type: 'float', displayName: 'B', defaultValue: 0 }
],
outputs: [
{ name: 'result', type: 'float', displayName: 'Result' }
]
};
@RegisterNode(AddTemplate)
export class AddExecutor implements INodeExecutor {
execute(node: BlueprintNode, context: ExecutionContext): ExecutionResult {
const a = Number(context.evaluateInput(node.id, 'a', 0));
const b = Number(context.evaluateInput(node.id, 'b', 0));
return { outputs: { result: a + b } };
}
}
// Subtract Node (减法节点)
export const SubtractTemplate: BlueprintNodeTemplate = {
type: 'Subtract',
title: 'Subtract',
category: 'math',
color: '#4CAF50',
description: 'Subtracts B from A (从 A 减去 B)',
keywords: ['subtract', 'minus', '-', 'math'],
isPure: true,
inputs: [
{ name: 'a', type: 'float', displayName: 'A', defaultValue: 0 },
{ name: 'b', type: 'float', displayName: 'B', defaultValue: 0 }
],
outputs: [
{ name: 'result', type: 'float', displayName: 'Result' }
]
};
@RegisterNode(SubtractTemplate)
export class SubtractExecutor implements INodeExecutor {
execute(node: BlueprintNode, context: ExecutionContext): ExecutionResult {
const a = Number(context.evaluateInput(node.id, 'a', 0));
const b = Number(context.evaluateInput(node.id, 'b', 0));
return { outputs: { result: a - b } };
}
}
// Multiply Node (乘法节点)
export const MultiplyTemplate: BlueprintNodeTemplate = {
type: 'Multiply',
title: 'Multiply',
category: 'math',
color: '#4CAF50',
description: 'Multiplies two numbers (将两个数字相乘)',
keywords: ['multiply', 'times', '*', 'math'],
isPure: true,
inputs: [
{ name: 'a', type: 'float', displayName: 'A', defaultValue: 0 },
{ name: 'b', type: 'float', displayName: 'B', defaultValue: 1 }
],
outputs: [
{ name: 'result', type: 'float', displayName: 'Result' }
]
};
@RegisterNode(MultiplyTemplate)
export class MultiplyExecutor implements INodeExecutor {
execute(node: BlueprintNode, context: ExecutionContext): ExecutionResult {
const a = Number(context.evaluateInput(node.id, 'a', 0));
const b = Number(context.evaluateInput(node.id, 'b', 1));
return { outputs: { result: a * b } };
}
}
// Divide Node (除法节点)
export const DivideTemplate: BlueprintNodeTemplate = {
type: 'Divide',
title: 'Divide',
category: 'math',
color: '#4CAF50',
description: 'Divides A by B (A 除以 B)',
keywords: ['divide', '/', 'math'],
isPure: true,
inputs: [
{ name: 'a', type: 'float', displayName: 'A', defaultValue: 0 },
{ name: 'b', type: 'float', displayName: 'B', defaultValue: 1 }
],
outputs: [
{ name: 'result', type: 'float', displayName: 'Result' }
]
};
@RegisterNode(DivideTemplate)
export class DivideExecutor implements INodeExecutor {
execute(node: BlueprintNode, context: ExecutionContext): ExecutionResult {
const a = Number(context.evaluateInput(node.id, 'a', 0));
const b = Number(context.evaluateInput(node.id, 'b', 1));
// Prevent division by zero (防止除零)
if (b === 0) {
return { outputs: { result: 0 } };
}
return { outputs: { result: a / b } };
}
}

View File

@@ -0,0 +1,6 @@
/**
* Math Nodes - Mathematical operation nodes
* 数学节点 - 数学运算节点
*/
export * from './MathOperations';

View File

@@ -0,0 +1,57 @@
/**
* Delay Node - Pauses execution for a specified duration
* 延迟节点 - 暂停执行指定的时长
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
/**
* Delay node template
* Delay 节点模板
*/
export const DelayTemplate: BlueprintNodeTemplate = {
type: 'Delay',
title: 'Delay',
category: 'flow',
color: '#FFFFFF',
description: 'Pauses execution for a specified number of seconds (暂停执行指定的秒数)',
keywords: ['wait', 'delay', 'pause', 'sleep', 'timer'],
inputs: [
{
name: 'exec',
type: 'exec',
displayName: ''
},
{
name: 'duration',
type: 'float',
displayName: 'Duration',
defaultValue: 1.0
}
],
outputs: [
{
name: 'exec',
type: 'exec',
displayName: 'Completed'
}
]
};
/**
* Delay node executor
* Delay 节点执行器
*/
@RegisterNode(DelayTemplate)
export class DelayExecutor implements INodeExecutor {
execute(node: BlueprintNode, context: ExecutionContext): ExecutionResult {
const duration = context.evaluateInput(node.id, 'duration', 1.0) as number;
return {
nextExec: 'exec',
delay: duration
};
}
}

View File

@@ -0,0 +1,45 @@
/**
* Get Delta Time Node - Returns the time since last frame
* 获取增量时间节点 - 返回上一帧以来的时间
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
/**
* GetDeltaTime node template
* GetDeltaTime 节点模板
*/
export const GetDeltaTimeTemplate: BlueprintNodeTemplate = {
type: 'GetDeltaTime',
title: 'Get Delta Time',
category: 'time',
color: '#4FC3F7',
description: 'Returns the time elapsed since the last frame in seconds (返回上一帧以来经过的时间,单位秒)',
keywords: ['delta', 'time', 'frame', 'dt'],
isPure: true,
inputs: [],
outputs: [
{
name: 'deltaTime',
type: 'float',
displayName: 'Delta Seconds'
}
]
};
/**
* GetDeltaTime node executor
* GetDeltaTime 节点执行器
*/
@RegisterNode(GetDeltaTimeTemplate)
export class GetDeltaTimeExecutor implements INodeExecutor {
execute(_node: BlueprintNode, context: ExecutionContext): ExecutionResult {
return {
outputs: {
deltaTime: context.deltaTime
}
};
}
}

View File

@@ -0,0 +1,45 @@
/**
* Get Time Node - Returns the total time since blueprint started
* 获取时间节点 - 返回蓝图启动以来的总时间
*/
import { BlueprintNodeTemplate, BlueprintNode } from '../../types/nodes';
import { ExecutionContext, ExecutionResult } from '../../runtime/ExecutionContext';
import { INodeExecutor, RegisterNode } from '../../runtime/NodeRegistry';
/**
* GetTime node template
* GetTime 节点模板
*/
export const GetTimeTemplate: BlueprintNodeTemplate = {
type: 'GetTime',
title: 'Get Game Time',
category: 'time',
color: '#4FC3F7',
description: 'Returns the total time since the blueprint started in seconds (返回蓝图启动以来的总时间,单位秒)',
keywords: ['time', 'total', 'elapsed', 'game'],
isPure: true,
inputs: [],
outputs: [
{
name: 'time',
type: 'float',
displayName: 'Seconds'
}
]
};
/**
* GetTime node executor
* GetTime 节点执行器
*/
@RegisterNode(GetTimeTemplate)
export class GetTimeExecutor implements INodeExecutor {
execute(_node: BlueprintNode, context: ExecutionContext): ExecutionResult {
return {
outputs: {
time: context.time
}
};
}
}

View File

@@ -0,0 +1,8 @@
/**
* Time Nodes - Time-related utility nodes
* 时间节点 - 时间相关的工具节点
*/
export * from './GetDeltaTime';
export * from './GetTime';
export * from './Delay';