diff --git a/source/Behavior/Behavior.ts b/source/Behavior/Behavior.ts index 123f8b3..dce8051 100644 --- a/source/Behavior/Behavior.ts +++ b/source/Behavior/Behavior.ts @@ -1,13 +1,10 @@ import { BehaviorRecorder, IAnyBehaviorRecorder } from "@Model/Behavior"; import { Template } from "./Template"; +import { Dynamics } from "./Dynamics"; -const AllBehaviors: IAnyBehaviorRecorder[] = new Array(4).fill(0).map((_, i) => { - let behavior = new BehaviorRecorder(Template); - behavior.behaviorId = behavior.behaviorId + i; - behavior.behaviorName = behavior.behaviorName + Math.random().toString(36).slice(-6); - behavior.category = "Category" + Math.floor(Math.random() * 3).toString(); - return behavior; -}); +const AllBehaviors: IAnyBehaviorRecorder[] = [ + new BehaviorRecorder(Dynamics) +] /** * 分类词条 @@ -52,4 +49,6 @@ function categoryBehaviors(behaviors: IAnyBehaviorRecorder[]): ICategory[] { return res; } +console.log(AllBehaviorsWithCategory) + export { AllBehaviors, AllBehaviorsWithCategory, ICategory as ICategoryBehavior }; \ No newline at end of file diff --git a/source/Behavior/Dynamics.ts b/source/Behavior/Dynamics.ts new file mode 100644 index 0000000..d944fc4 --- /dev/null +++ b/source/Behavior/Dynamics.ts @@ -0,0 +1,122 @@ +import { Behavior } from "@Model/Behavior"; +import Group from "@Model/Group"; +import Individual from "@Model/Individual"; +import { Model } from "@Model/Model"; + +type IDynamicsBehaviorParameter = { + mass: "number", + maxAcceleration: "number", + maxVelocity: "number", + resistance: "number" +} + +type IDynamicsBehaviorEvent = {} + +class Dynamics extends Behavior { + + public override behaviorId: string = "Dynamics"; + + public override behaviorName: string = "$Title"; + + public override iconName: string = "Running"; + + public override describe: string = "$Intro"; + + public override category: string = "$Physics"; + + public override parameterOption = { + mass: { + name: "$Mass", + type: "number", + defaultValue: 1, + numberStep: .01, + numberMin: .001 + }, + maxAcceleration: { + name: "$Max.Acceleration", + type: "number", + defaultValue: 0.5, + numberStep: .01, + numberMin: 0 + }, + maxVelocity: { + name: "$Max.Velocity", + type: "number", + defaultValue: 0.5, + numberStep: .01, + numberMin: 0 + }, + resistance: { + name: "$Resistance", + type: "number", + defaultValue: .01, + numberStep: .001, + numberMin: 0 + } + }; + + public override terms: Record> = { + "$Title": { + "ZH_CN": "动力学", + "EN_US": "Dynamics" + }, + "$Intro": { + "ZH_CN": "一切可以运动物体的必要行为,执行物理法则。", + "EN_US": "All necessary behaviors that can move objects and implement the laws of physics." + }, + "$Mass": { + "ZH_CN": "质量 (Kg)", + "EN_US": "Mass (Kg)" + }, + "$Max.Acceleration": { + "ZH_CN": "最大加速度 (m/s²)", + "EN_US": "Maximum acceleration (m/s²)" + }, + "$Max.Velocity": { + "ZH_CN": "最大速度 (m/s)", + "EN_US": "Maximum velocity (m/s)" + }, + "$Physics": { + "ZH_CN": "物理", + "EN_US": "Physics" + } + }; + + public override finalEffect(individual: Individual, group: Group, model: Model, t: number): void { + + // 计算当前速度 + const currentV = individual.vectorLength(individual.velocity); + + // 计算阻力 + const resistance = Math.max(1 - currentV * currentV * this.parameter.resistance, 0); + + // 计算加速度 + individual.acceleration[0] = individual.force[0] * resistance / this.parameter.mass; + individual.acceleration[1] = individual.force[1] * resistance / this.parameter.mass; + individual.acceleration[2] = individual.force[2] * resistance / this.parameter.mass; + + // 加速度约束 + const overA = Math.max(individual.vectorLength(individual.acceleration) - this.parameter.maxAcceleration, 0); + individual.acceleration[0] = individual.acceleration[0] - individual.acceleration[0] * overA; + individual.acceleration[1] = individual.acceleration[1] - individual.acceleration[1] * overA; + individual.acceleration[2] = individual.acceleration[2] - individual.acceleration[2] * overA; + + // 计算速度 + individual.velocity[0] = individual.velocity[0] + individual.acceleration[0] * t; + individual.velocity[1] = individual.velocity[1] + individual.acceleration[1] * t; + individual.velocity[2] = individual.velocity[2] + individual.acceleration[2] * t; + + // 速度约束 + const overV = Math.max(individual.vectorLength(individual.velocity) - this.parameter.maxVelocity, 0); + individual.velocity[0] = individual.velocity[0] - individual.velocity[0] * overV; + individual.velocity[1] = individual.velocity[1] - individual.velocity[1] * overV; + individual.velocity[2] = individual.velocity[2] - individual.velocity[2] * overV; + + // 应用速度 + individual.position[0] = individual.position[0] + individual.velocity[0] * t; + individual.position[1] = individual.position[1] + individual.velocity[1] * t; + individual.position[2] = individual.position[2] + individual.velocity[2] * t; + }; +} + +export { Dynamics }; \ No newline at end of file diff --git a/source/Component/BehaviorList/BehaviorList.tsx b/source/Component/BehaviorList/BehaviorList.tsx index e9624a7..5308c49 100644 --- a/source/Component/BehaviorList/BehaviorList.tsx +++ b/source/Component/BehaviorList/BehaviorList.tsx @@ -120,7 +120,7 @@ class BehaviorList extends Component {
{this.renderTerm(behavior, name, "title-view", needLocal)} - {this.renderTerm(behavior, info, "info-view", needLocal)} + {this.renderTerm(behavior, info, "info-view", true)}
{this.renderActionButton(behavior)} diff --git a/source/Model/Behavior.ts b/source/Model/Behavior.ts index dbc7d58..20f7acf 100644 --- a/source/Model/Behavior.ts +++ b/source/Model/Behavior.ts @@ -64,7 +64,7 @@ interface IBehaviorParameterOptionItem { /** * 参数类型 */ - type: T; + type: T | string; /** * 参数默认值 @@ -269,6 +269,7 @@ class BehaviorRecorder< this.behaviorId = this.behaviorInstance.behaviorId; this.behaviorName = this.behaviorInstance.behaviorName; this.describe = this.behaviorInstance.describe; + this.category = this.behaviorInstance.category; this.terms = this.behaviorInstance.terms; } } @@ -371,7 +372,7 @@ class Behavior< * @param model 模型 * @param t 经过时间 */ - public beforeEffect(individual: Individual, group: Group, model: Model, t: number): void {}; + public effect(individual: Individual, group: Group, model: Model, t: number): void {}; /** * 作用影响于个体 @@ -380,7 +381,7 @@ class Behavior< * @param model 模型 * @param t 经过时间 */ - public effect(individual: Individual, group: Group, model: Model, t: number): void {}; + public afterEffect(individual: Individual, group: Group, model: Model, t: number): void {}; /** * 全部影响作用后 @@ -389,7 +390,7 @@ class Behavior< * @param model 模型 * @param t 经过时间 */ - public afterEffect(individual: Individual, group: Group, model: Model, t: number): void {}; + public finalEffect(individual: Individual, group: Group, model: Model, t: number): void {}; } diff --git a/source/Model/Group.ts b/source/Model/Group.ts index 5e81e0f..21dcf27 100644 --- a/source/Model/Group.ts +++ b/source/Model/Group.ts @@ -330,7 +330,7 @@ class Group extends CtrlObject { * 执行行为影响 * @param */ - public runner(t: number, effectType: "beforeEffect" | "effect" | "afterEffect" ): void { + public runner(t: number, effectType: "finalEffect" | "effect" | "afterEffect" ): void { this.individuals.forEach((individual) => { for(let j = 0; j < this.behaviors.length; j++) { this.behaviors[j][effectType](individual, this, this.model, t); diff --git a/source/Model/Individual.ts b/source/Model/Individual.ts index 496a565..092edde 100644 --- a/source/Model/Individual.ts +++ b/source/Model/Individual.ts @@ -12,9 +12,9 @@ class Individual { * @param y y 坐标 * @param z z 坐标 */ - public static vectorLength(x: number[]): number; - public static vectorLength(x: number, y: number, z: number): number; - public static vectorLength(x: number | number[], y?: number, z?: number): number { + public vectorLength(x: number[]): number; + public vectorLength(x: number, y: number, z: number): number; + public vectorLength(x: number | number[], y?: number, z?: number): number { if (Array.isArray(x)) { return ((x[0] ?? 0)**2 + (x[1] ?? 0)**2 + (x[2] ?? 0)**2)**.5; } else { @@ -28,10 +28,10 @@ class Individual { * @param y y 坐标 * @param z z 坐标 */ - public static vectorNormalize(x: number[]): [number, number, number]; - public static vectorNormalize(x: number, y: number, z: number): [number, number, number]; - public static vectorNormalize(x: number | number[], y?: number, z?: number): [number, number, number] { - let length = Individual.vectorLength(x as number, y as number, z as number); + public vectorNormalize(x: number[]): [number, number, number]; + public vectorNormalize(x: number, y: number, z: number): [number, number, number]; + public vectorNormalize(x: number | number[], y?: number, z?: number): [number, number, number] { + let length = this.vectorLength(x as number, y as number, z as number); if (Array.isArray(x)) { return [ (x[0] ?? 0) / length, @@ -52,6 +52,39 @@ class Individual { */ public position: number[] = [0, 0, 0]; + /** + * 速度 + */ + public velocity: number[] = [0, 0, 0]; + + /** + * 加速度 + */ + public acceleration: number[] = [0, 0, 0]; + + /** + * 作用力 + */ + public force: number[] = [0, 0, 0]; + + /** + * 施加力 + */ + public applyForce(x: number[]): [number, number, number]; + public applyForce(x: number, y: number, z: number): [number, number, number]; + public applyForce(x: number | number[], y?: number, z?: number): [number, number, number] { + if (Array.isArray(x)) { + this.force[0] += x[0] ?? 0; + this.force[1] += x[1] ?? 0; + this.force[2] += x[2] ?? 0; + } else { + this.force[0] += x ?? 0; + this.force[1] += y ?? 0; + this.force[2] += z ?? 0; + } + return this.force as [number, number, number]; + } + /** * 所属群组 */ @@ -107,7 +140,7 @@ class Individual { * @param position 目标位置 */ public distanceTo(position: Individual | number[]): number { - return Individual.vectorLength(this.vectorTo(position)); + return this.vectorLength(this.vectorTo(position)); } /** diff --git a/source/Model/Model.ts b/source/Model/Model.ts index 23ad788..8c0b06c 100644 --- a/source/Model/Model.ts +++ b/source/Model/Model.ts @@ -258,7 +258,7 @@ class Model extends Emitter { for (let i = 0; i < this.objectPool.length; i++) { let object = this.objectPool[i]; if (object instanceof Group && object.update) { - object.runner(t, "beforeEffect"); + object.runner(t, "effect"); } } @@ -266,7 +266,7 @@ class Model extends Emitter { for (let i = 0; i < this.objectPool.length; i++) { let object = this.objectPool[i]; if (object instanceof Group && object.update) { - object.runner(t, "effect"); + object.runner(t, "afterEffect"); } } @@ -274,7 +274,7 @@ class Model extends Emitter { for (let i = 0; i < this.objectPool.length; i++) { let object = this.objectPool[i]; if (object instanceof Group && object.update) { - object.runner(t, "afterEffect"); + object.runner(t, "finalEffect"); } }