Add actuator & dynamics behavior & brownian behavior & boundary constraint behavior #30
@ -1,13 +1,10 @@
|
|||||||
import { BehaviorRecorder, IAnyBehaviorRecorder } from "@Model/Behavior";
|
import { BehaviorRecorder, IAnyBehaviorRecorder } from "@Model/Behavior";
|
||||||
import { Template } from "./Template";
|
import { Template } from "./Template";
|
||||||
|
import { Dynamics } from "./Dynamics";
|
||||||
|
|
||||||
const AllBehaviors: IAnyBehaviorRecorder[] = new Array(4).fill(0).map((_, i) => {
|
const AllBehaviors: IAnyBehaviorRecorder[] = [
|
||||||
let behavior = new BehaviorRecorder(Template);
|
new BehaviorRecorder(Dynamics)
|
||||||
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;
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分类词条
|
* 分类词条
|
||||||
@ -52,4 +49,6 @@ function categoryBehaviors(behaviors: IAnyBehaviorRecorder[]): ICategory[] {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(AllBehaviorsWithCategory)
|
||||||
|
|
||||||
export { AllBehaviors, AllBehaviorsWithCategory, ICategory as ICategoryBehavior };
|
export { AllBehaviors, AllBehaviorsWithCategory, ICategory as ICategoryBehavior };
|
122
source/Behavior/Dynamics.ts
Normal file
122
source/Behavior/Dynamics.ts
Normal file
@ -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<IDynamicsBehaviorParameter, IDynamicsBehaviorEvent> {
|
||||||
|
|
||||||
|
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<string, Record<string, string>> = {
|
||||||
|
"$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 };
|
@ -120,7 +120,7 @@ class BehaviorList extends Component<IBehaviorListProps & IMixinSettingProps> {
|
|||||||
</div>
|
</div>
|
||||||
<div className="behavior-content-view">
|
<div className="behavior-content-view">
|
||||||
{this.renderTerm(behavior, name, "title-view", needLocal)}
|
{this.renderTerm(behavior, name, "title-view", needLocal)}
|
||||||
{this.renderTerm(behavior, info, "info-view", needLocal)}
|
{this.renderTerm(behavior, info, "info-view", true)}
|
||||||
</div>
|
</div>
|
||||||
<div className="behavior-action-view">
|
<div className="behavior-action-view">
|
||||||
{this.renderActionButton(behavior)}
|
{this.renderActionButton(behavior)}
|
||||||
|
@ -64,7 +64,7 @@ interface IBehaviorParameterOptionItem<T extends IParamType = IParamType> {
|
|||||||
/**
|
/**
|
||||||
* 参数类型
|
* 参数类型
|
||||||
*/
|
*/
|
||||||
type: T;
|
type: T | string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 参数默认值
|
* 参数默认值
|
||||||
@ -269,6 +269,7 @@ class BehaviorRecorder<
|
|||||||
this.behaviorId = this.behaviorInstance.behaviorId;
|
this.behaviorId = this.behaviorInstance.behaviorId;
|
||||||
this.behaviorName = this.behaviorInstance.behaviorName;
|
this.behaviorName = this.behaviorInstance.behaviorName;
|
||||||
this.describe = this.behaviorInstance.describe;
|
this.describe = this.behaviorInstance.describe;
|
||||||
|
this.category = this.behaviorInstance.category;
|
||||||
this.terms = this.behaviorInstance.terms;
|
this.terms = this.behaviorInstance.terms;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -371,7 +372,7 @@ class Behavior<
|
|||||||
* @param model 模型
|
* @param model 模型
|
||||||
* @param t 经过时间
|
* @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 model 模型
|
||||||
* @param t 经过时间
|
* @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 model 模型
|
||||||
* @param t 经过时间
|
* @param t 经过时间
|
||||||
*/
|
*/
|
||||||
public afterEffect(individual: Individual, group: Group, model: Model, t: number): void {};
|
public finalEffect(individual: Individual, group: Group, model: Model, t: number): void {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,7 +330,7 @@ class Group extends CtrlObject {
|
|||||||
* 执行行为影响
|
* 执行行为影响
|
||||||
* @param
|
* @param
|
||||||
*/
|
*/
|
||||||
public runner(t: number, effectType: "beforeEffect" | "effect" | "afterEffect" ): void {
|
public runner(t: number, effectType: "finalEffect" | "effect" | "afterEffect" ): void {
|
||||||
this.individuals.forEach((individual) => {
|
this.individuals.forEach((individual) => {
|
||||||
for(let j = 0; j < this.behaviors.length; j++) {
|
for(let j = 0; j < this.behaviors.length; j++) {
|
||||||
this.behaviors[j][effectType](individual, this, this.model, t);
|
this.behaviors[j][effectType](individual, this, this.model, t);
|
||||||
|
@ -12,9 +12,9 @@ class Individual {
|
|||||||
* @param y y 坐标
|
* @param y y 坐标
|
||||||
* @param z z 坐标
|
* @param z z 坐标
|
||||||
*/
|
*/
|
||||||
public static vectorLength(x: number[]): number;
|
public vectorLength(x: number[]): number;
|
||||||
public static vectorLength(x: number, y: number, z: number): number;
|
public vectorLength(x: number, y: number, z: number): number;
|
||||||
public static vectorLength(x: number | number[], y?: number, z?: number): number {
|
public vectorLength(x: number | number[], y?: number, z?: number): number {
|
||||||
if (Array.isArray(x)) {
|
if (Array.isArray(x)) {
|
||||||
return ((x[0] ?? 0)**2 + (x[1] ?? 0)**2 + (x[2] ?? 0)**2)**.5;
|
return ((x[0] ?? 0)**2 + (x[1] ?? 0)**2 + (x[2] ?? 0)**2)**.5;
|
||||||
} else {
|
} else {
|
||||||
@ -28,10 +28,10 @@ class Individual {
|
|||||||
* @param y y 坐标
|
* @param y y 坐标
|
||||||
* @param z z 坐标
|
* @param z z 坐标
|
||||||
*/
|
*/
|
||||||
public static vectorNormalize(x: number[]): [number, number, number];
|
public vectorNormalize(x: number[]): [number, number, number];
|
||||||
public static vectorNormalize(x: number, y: number, z: number): [number, number, number];
|
public vectorNormalize(x: number, y: number, z: number): [number, number, number];
|
||||||
public static vectorNormalize(x: number | number[], y?: number, z?: number): [number, number, number] {
|
public vectorNormalize(x: number | number[], y?: number, z?: number): [number, number, number] {
|
||||||
let length = Individual.vectorLength(x as number, y as number, z as number);
|
let length = this.vectorLength(x as number, y as number, z as number);
|
||||||
if (Array.isArray(x)) {
|
if (Array.isArray(x)) {
|
||||||
return [
|
return [
|
||||||
(x[0] ?? 0) / length,
|
(x[0] ?? 0) / length,
|
||||||
@ -52,6 +52,39 @@ class Individual {
|
|||||||
*/
|
*/
|
||||||
public position: number[] = [0, 0, 0];
|
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 目标位置
|
* @param position 目标位置
|
||||||
*/
|
*/
|
||||||
public distanceTo(position: Individual | number[]): number {
|
public distanceTo(position: Individual | number[]): number {
|
||||||
return Individual.vectorLength(this.vectorTo(position));
|
return this.vectorLength(this.vectorTo(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -258,7 +258,7 @@ class Model extends Emitter<ModelEvent> {
|
|||||||
for (let i = 0; i < this.objectPool.length; i++) {
|
for (let i = 0; i < this.objectPool.length; i++) {
|
||||||
let object = this.objectPool[i];
|
let object = this.objectPool[i];
|
||||||
if (object instanceof Group && object.update) {
|
if (object instanceof Group && object.update) {
|
||||||
object.runner(t, "beforeEffect");
|
object.runner(t, "effect");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +266,7 @@ class Model extends Emitter<ModelEvent> {
|
|||||||
for (let i = 0; i < this.objectPool.length; i++) {
|
for (let i = 0; i < this.objectPool.length; i++) {
|
||||||
let object = this.objectPool[i];
|
let object = this.objectPool[i];
|
||||||
if (object instanceof Group && object.update) {
|
if (object instanceof Group && object.update) {
|
||||||
object.runner(t, "effect");
|
object.runner(t, "afterEffect");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +274,7 @@ class Model extends Emitter<ModelEvent> {
|
|||||||
for (let i = 0; i < this.objectPool.length; i++) {
|
for (let i = 0; i < this.objectPool.length; i++) {
|
||||||
let object = this.objectPool[i];
|
let object = this.objectPool[i];
|
||||||
if (object instanceof Group && object.update) {
|
if (object instanceof Group && object.update) {
|
||||||
object.runner(t, "afterEffect");
|
object.runner(t, "finalEffect");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user