Add dynamics behavior
This commit is contained in:
parent
c811b5b1e5
commit
e5ae05e737
@ -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 };
|
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 className="behavior-content-view">
|
||||
{this.renderTerm(behavior, name, "title-view", needLocal)}
|
||||
{this.renderTerm(behavior, info, "info-view", needLocal)}
|
||||
{this.renderTerm(behavior, info, "info-view", true)}
|
||||
</div>
|
||||
<div className="behavior-action-view">
|
||||
{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.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 {};
|
||||
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,7 +258,7 @@ class Model extends Emitter<ModelEvent> {
|
||||
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<ModelEvent> {
|
||||
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<ModelEvent> {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user