Compare commits
	
		
			3 Commits
		
	
	
		
			647819dec6
			...
			d0b7935f12
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d0b7935f12 | |||
| 407e3061df | |||
| 3e9b60f598 | 
| @ -38,13 +38,32 @@ abstract class Behavior< | |||||||
|      */ |      */ | ||||||
|     abstract parameter?: P; |     abstract parameter?: P; | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * 全部影响作用前 | ||||||
|  |      * @param individual 影响个体 | ||||||
|  |      * @param group 影响组 | ||||||
|  |      * @param model 模型 | ||||||
|  |      * @param t 经过时间 | ||||||
|  |      */ | ||||||
|  |     public beforeEffect(individual: Individual, group: Group, model: Model, t: number): void {}; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * 作用影响于个体 |      * 作用影响于个体 | ||||||
|      * @param individual 影响个体 |      * @param individual 影响个体 | ||||||
|      * @param group 影响组 |      * @param group 影响组 | ||||||
|  |      * @param model 模型 | ||||||
|      * @param t 经过时间 |      * @param t 经过时间 | ||||||
|      */ |      */ | ||||||
|     abstract effect(individual: Individual, group: Group, model: Model, t: number): void; |     public effect(individual: Individual, group: Group, model: Model, t: number): void {}; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 全部影响作用后 | ||||||
|  |      * @param individual 影响个体 | ||||||
|  |      * @param group 影响组 | ||||||
|  |      * @param model 模型 | ||||||
|  |      * @param t 经过时间 | ||||||
|  |      */ | ||||||
|  |     public afterEffect(individual: Individual, group: Group, model: Model, t: number): void {}; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -7,6 +7,21 @@ import type { ObjectID } from "./Renderer"; | |||||||
|  */ |  */ | ||||||
| class CtrlObject extends LabelObject { | class CtrlObject extends LabelObject { | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * 颜色 | ||||||
|  |      */ | ||||||
|  |     public color: number[] = [.5, .5, .5]; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 是否显示 | ||||||
|  |      */ | ||||||
|  |     public display: boolean = true; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 是否更新 | ||||||
|  |      */ | ||||||
|  |     public update: boolean = true; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * 唯一标识符 |      * 唯一标识符 | ||||||
|      */ |      */ | ||||||
| @ -25,6 +40,13 @@ class CtrlObject extends LabelObject { | |||||||
|         this.model = model; |         this.model = model; | ||||||
|         this.id = id; |         this.id = id; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 移除 | ||||||
|  |      */ | ||||||
|  |     public delete() { | ||||||
|  |         this.model.deleteObject([this]); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default CtrlObject; | export default CtrlObject; | ||||||
|  | |||||||
| @ -37,9 +37,11 @@ class Group extends CtrlObject { | |||||||
|     public add(individual: Individual[] | Individual): this { |     public add(individual: Individual[] | Individual): this { | ||||||
|         if (Array.isArray(individual)) { |         if (Array.isArray(individual)) { | ||||||
|             for (let i = 0; i < individual.length; i++) { |             for (let i = 0; i < individual.length; i++) { | ||||||
|  |                 individual[i].group = this; | ||||||
|                 this.individuals.add(individual[i]); |                 this.individuals.add(individual[i]); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|  |             individual.group = this; | ||||||
|             this.individuals.add(individual); |             this.individuals.add(individual); | ||||||
|         } |         } | ||||||
|         return this; |         return this; | ||||||
| @ -112,13 +114,32 @@ class Group extends CtrlObject { | |||||||
|      * 执行行为影响 |      * 执行行为影响 | ||||||
| 	 * @param | 	 * @param | ||||||
|      */ |      */ | ||||||
| 	public runner(t: number): void { | 	public runner(t: number, effectType: "beforeEffect" | "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].effect(individual, this, this.model, t); | 				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 default Group; | ||||||
|  | |||||||
| @ -1,13 +1,17 @@ | |||||||
| 
 | 
 | ||||||
| import { Individual } from "./Individual"; | import { Individual } from "./Individual"; | ||||||
| import { Group } from "./Group"; | import { Group } from "./Group"; | ||||||
|  | import { Range } from "./Range"; | ||||||
| import { Emitter, EventType, EventMixin } from "./Emitter"; | import { Emitter, EventType, EventMixin } from "./Emitter"; | ||||||
| import { CtrlObject } from "./CtrlObject"; | import { CtrlObject } from "./CtrlObject"; | ||||||
| import { ObjectID } from "./Renderer"; | import { ObjectID, AbstractRenderer } from "./Renderer"; | ||||||
| 
 | 
 | ||||||
| type ModelEvent = { | type ModelEvent = { | ||||||
|     addGroup: Group; |     groupAdd: Group; | ||||||
|     deleteGroup: Group[]; |     rangeAdd: Range; | ||||||
|  |     objectAdd: CtrlObject; | ||||||
|  |     objectDelete: CtrlObject[]; | ||||||
|  |     objectChange: CtrlObject[]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -31,43 +35,127 @@ class Model extends Emitter<ModelEvent> { | |||||||
|     /** |     /** | ||||||
|      * 添加组 |      * 添加组 | ||||||
|      */ |      */ | ||||||
|     public addGroup(): void { |     public addGroup(): Group { | ||||||
|         console.log(`Model: Creat group with id ${this.idIndex}`); |         console.log(`Model: Creat group with id ${this.idIndex}`); | ||||||
|         let group = new Group(this, this.nextId); |         let group = new Group(this, this.nextId); | ||||||
|         this.objectPool.push(group); |         this.objectPool.push(group); | ||||||
|         this.emit("addGroup", group); |         this.emit("groupAdd", group); | ||||||
|  |         this.emit("objectAdd", group); | ||||||
|  |         this.emit("objectChange", this.objectPool); | ||||||
|  |         return group; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * 删除组 |      * 添加范围 | ||||||
|      */ |      */ | ||||||
|     public deleteGroup(groups: Group[] | ObjectID[]): void { |     public addRange(): Range { | ||||||
|         let deletedGroups: Group[] = []; |         console.log(`Model: Creat range with id ${this.idIndex}`); | ||||||
|         this.objectPool = this.objectPool.filter((object) => { |         let range = new Range(this, this.nextId); | ||||||
|             if (!(object instanceof Group)) return true; |         this.objectPool.push(range); | ||||||
|             let deletedGroup: Group | undefined; |         this.emit("rangeAdd", range); | ||||||
|  |         this.emit("objectAdd", range); | ||||||
|  |         this.emit("objectChange", this.objectPool); | ||||||
|  |         return range; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|             for (let i = 0; i < groups.length; i++) { |     /** | ||||||
|                 if (groups[i] instanceof Group) { |      * 删除对象 | ||||||
|                     if (groups[i] === object) { |      */ | ||||||
|                         deletedGroup = object; |     public deleteObject(object: CtrlObject[] | ObjectID[]): CtrlObject[] { | ||||||
|  |         let deletedObject: CtrlObject[] = []; | ||||||
|  |         this.objectPool = this.objectPool.filter((currentObject) => { | ||||||
|  |             let needDeleted: boolean = false; | ||||||
|  | 
 | ||||||
|  |             for (let i = 0; i < object.length; i++) { | ||||||
|  |                 if (object[i] instanceof CtrlObject) { | ||||||
|  |                     if (object[i] === currentObject) { | ||||||
|  |                         needDeleted = true; | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     if (groups[i] === object.id) { |                     if (object[i] == currentObject.id) { | ||||||
|                         deletedGroup = object; |                         needDeleted = true; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (deletedGroup) { |             if (needDeleted) { | ||||||
|                 deletedGroups.push(deletedGroup); |                 deletedObject.push(currentObject); | ||||||
|                 return false; |                 return false; | ||||||
|             } else { |             } else { | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         this.emit("deleteGroup", deletedGroups); |         if (deletedObject.length) { | ||||||
|  |             console.log(`Model: Delete object ${deletedObject.map((object) => object.id).join(", ")}`); | ||||||
|  |             this.emit("objectDelete", deletedObject); | ||||||
|  |             this.emit("objectChange", this.objectPool); | ||||||
|  |         } | ||||||
|  |         return deletedObject; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 渲染器 | ||||||
|  |      */ | ||||||
|  |     public renderer: AbstractRenderer = undefined as any; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 绑定渲染器 | ||||||
|  |      * @param renderer 渲染器 | ||||||
|  |      */ | ||||||
|  |     public bindRenderer(renderer: AbstractRenderer): this { | ||||||
|  |         this.renderer = renderer; | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * 更新渲染数据 | ||||||
|  |      */ | ||||||
|  |     public update(t: number) { | ||||||
|  | 
 | ||||||
|  |         // 清除全部渲染状态
 | ||||||
|  |         this.renderer.clean(); | ||||||
|  | 
 | ||||||
|  |         // 第一轮更新
 | ||||||
|  |         for (let i = 0; i < this.objectPool.length; i++) { | ||||||
|  |             let object = this.objectPool[i]; | ||||||
|  |             if (object instanceof Group && object.update) { | ||||||
|  |                 object.runner(t, "beforeEffect"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // 第二轮更新
 | ||||||
|  |         for (let i = 0; i < this.objectPool.length; i++) { | ||||||
|  |             let object = this.objectPool[i]; | ||||||
|  |             if (object instanceof Group && object.update) { | ||||||
|  |                 object.runner(t, "effect"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // 第三轮更新
 | ||||||
|  |         for (let i = 0; i < this.objectPool.length; i++) { | ||||||
|  |             let object = this.objectPool[i]; | ||||||
|  |             if (object instanceof Group && object.update) { | ||||||
|  |                 object.runner(t, "afterEffect"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // 渲染
 | ||||||
|  |         for (let i = 0; i < this.objectPool.length; i++) { | ||||||
|  |             let object = this.objectPool[i]; | ||||||
|  |             if (object.display && object instanceof Group) { | ||||||
|  |                 this.renderer.points(object.id, object.exportPositionData(), { | ||||||
|  |                     color: object.color, | ||||||
|  |                     size: object.size | ||||||
|  |                 } as any); | ||||||
|  |             } | ||||||
|  |             if (object.display && object instanceof Range) { | ||||||
|  |                 this.renderer.cube(object.id, object.position, { | ||||||
|  |                     color: object.color, | ||||||
|  |                     radius: object.radius | ||||||
|  |                 } as any); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -10,6 +10,11 @@ class Range extends CtrlObject { | |||||||
|      */ |      */ | ||||||
|     public position: number[] = []; |     public position: number[] = []; | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * 半径 | ||||||
|  |      */ | ||||||
|  |     public radius: number[] = [1, 1, 1]; | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default Range; | export default Range; | ||||||
|  | |||||||
| @ -24,15 +24,23 @@ class Laboratory extends Component { | |||||||
|         const canvas = document.createElement("canvas"); |         const canvas = document.createElement("canvas"); | ||||||
|         const renderer = new ClassicRenderer(canvas, { className: "canvas" }); |         const renderer = new ClassicRenderer(canvas, { className: "canvas" }); | ||||||
|         this.canvasContRef.current.appendChild(renderer.canvas.dom); |         this.canvasContRef.current.appendChild(renderer.canvas.dom); | ||||||
| 
 |  | ||||||
|         renderer.onLoad(); |         renderer.onLoad(); | ||||||
| 
 | 
 | ||||||
|         let model = new Model(); |         let model = new Model().bindRenderer(renderer); | ||||||
|         model.addGroup(); |         let group = model.addGroup(); | ||||||
|         model.addGroup(); |         let range = model.addRange(); | ||||||
|  |         range.color = [.1, .5, .9]; | ||||||
|  |         group.new(100); | ||||||
|  |         group.color = [.8, .1, .6]; | ||||||
|  |         group.individuals.forEach((individual) => { | ||||||
|  |             individual.position[0] = (Math.random() - .5) * 2; | ||||||
|  |             individual.position[1] = (Math.random() - .5) * 2; | ||||||
|  |             individual.position[2] = (Math.random() - .5) * 2; | ||||||
|  |         }) | ||||||
|  |         model.update(0); | ||||||
| 
 | 
 | ||||||
|         // 测试渲染器
 |         // 测试渲染器
 | ||||||
|         if (true) { |         if (false) { | ||||||
|             renderer.points("0"); |             renderer.points("0"); | ||||||
|             renderer.points("1", new Array(100 * 3).fill(0).map(() => (Math.random() - .5) * 2)); |             renderer.points("1", new Array(100 * 3).fill(0).map(() => (Math.random() - .5) * 2)); | ||||||
|             renderer.points("2", new Array(100 * 3).fill(0).map(() => (Math.random() - .5) * 2), { |             renderer.points("2", new Array(100 * 3).fill(0).map(() => (Math.random() - .5) * 2), { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user