living-together/source/Model/Group.ts
2022-03-14 21:11:28 +08:00

156 lines
3.8 KiB
TypeScript

import { Individual } from "./Individual";
import { CtrlObject } from "./CtrlObject";
import type { Behavior } from "./Behavior";
import type { Model } from "./Model";
enum GenMod {
Point = "p",
Range = "R"
}
/**
* 群体类型
*/
class Group extends CtrlObject {
/**
* 所有个体
*/
public individuals: Set<Individual> = new Set();
/**
* 个体生成方式
*/
public genMethod: GenMod = GenMod.Point;
/**
* 创建个体
* @param count 创建数量
*/
public new(count: number = 1): Individual {
let newIndividual: Individual | undefined;
for (let i = 0; i < count; i++) {
newIndividual = new Individual(this);
this.individuals.add(newIndividual);
}
if (newIndividual) {
return newIndividual;
} else {
return new Individual(this);
}
}
/**
* 添加个体
* @param individual 个体
*/
public add(individual: Individual[] | Individual): this {
if (Array.isArray(individual)) {
for (let i = 0; i < individual.length; i++) {
individual[i].group = this;
this.individuals.add(individual[i]);
}
} else {
individual.group = this;
this.individuals.add(individual);
}
return this;
}
/**
* 移除成员
* @param individual 需要移除的个体
*/
public remove(individual: Individual[] | Individual): this {
if (Array.isArray(individual)) {
for (let i = 0; i < individual.length; i++) {
this.individuals.delete(individual[i]);
}
} else {
this.individuals.delete(individual);
}
return this;
}
/**
* 通过距离获取个体
* 此函数将排除传入对象
* @param position 观测位置
* @param distance 距离
* @param excludeSelf 是否排除自身
*/
public getIndividualsByDistance(
position: Individual | number[], distance: number, excludeSelf?: boolean
): Individual[] {
const result: Individual[] = [];
this.individuals.forEach(((individual) => {
// 排除自身
if (individual === position && excludeSelf) {
return;
}
if (individual.distanceTo(position) < distance) {
result.push(individual);
}
}));
return result;
}
/**
* 行为列表
*/
public behaviors: Behavior[] = [];
/**
* 添加行为
* @param behavior 添加行为
*/
public addBehavior(behavior: Behavior | Behavior[]): this {
if (Array.isArray(behavior)) {
this.behaviors = this.behaviors.concat(behavior);
} else {
this.behaviors.push(behavior);
}
// 按照优先级
this.behaviors = this.behaviors.sort((b1, b2) => {
return (b1.priority ?? 0) - (b2.priority ?? 0)
});
return this;
}
/**
* 执行行为影响
* @param
*/
public runner(t: number, effectType: "beforeEffect" | "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);
}
});
}
/**
* 导出坐标数据
*/
public exportPositionData(): Float32Array {
let index = 0;
let dataBuffer = new Float32Array(this.individuals.size * 3);
this.individuals.forEach((individual) => {
dataBuffer[index ++] = individual.position[0];
dataBuffer[index ++] = individual.position[1];
dataBuffer[index ++] = individual.position[2];
});
return dataBuffer;
}
/**
* 绘制大小
*/
public size: number = 60;
}
export default Group;
export { Group, GenMod };