Add actuator model
This commit is contained in:
		
							parent
							
								
									873a2a8d0a
								
							
						
					
					
						commit
						c811b5b1e5
					
				@ -15,7 +15,7 @@ interface ICommandBarProps {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@useSetting
 | 
					@useSetting
 | 
				
			||||||
@useStatusWithEvent("mouseModChange")
 | 
					@useStatusWithEvent("mouseModChange", "actuatorStartChange")
 | 
				
			||||||
class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixinStatusProps> {
 | 
					class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixinStatusProps> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render(): ReactNode {
 | 
					    render(): ReactNode {
 | 
				
			||||||
@ -34,7 +34,13 @@ class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixi
 | 
				
			|||||||
        >
 | 
					        >
 | 
				
			||||||
            <div>
 | 
					            <div>
 | 
				
			||||||
                {this.getRenderButton({ iconName: "Save", i18NKey: "Command.Bar.Save.Info" })}
 | 
					                {this.getRenderButton({ iconName: "Save", i18NKey: "Command.Bar.Save.Info" })}
 | 
				
			||||||
                {this.getRenderButton({ iconName: "Play", i18NKey: "Command.Bar.Play.Info" })}
 | 
					                {this.getRenderButton({
 | 
				
			||||||
 | 
					                    iconName: this.props.status?.actuator.start() ? "Pause" : "Play",
 | 
				
			||||||
 | 
					                    i18NKey: "Command.Bar.Play.Info",
 | 
				
			||||||
 | 
					                    click: () => this.props.status ? this.props.status.actuator.start(
 | 
				
			||||||
 | 
					                        !this.props.status.actuator.start()
 | 
				
			||||||
 | 
					                    ) : undefined
 | 
				
			||||||
 | 
					                })}
 | 
				
			||||||
                {this.getRenderButton({
 | 
					                {this.getRenderButton({
 | 
				
			||||||
                    iconName: "HandsFree", i18NKey: "Command.Bar.Drag.Info", 
 | 
					                    iconName: "HandsFree", i18NKey: "Command.Bar.Drag.Info", 
 | 
				
			||||||
                    active: mouseMod === MouseMod.Drag,
 | 
					                    active: mouseMod === MouseMod.Drag,
 | 
				
			||||||
 | 
				
			|||||||
@ -42,7 +42,7 @@ class HeaderBar extends Component<
 | 
				
			|||||||
        return (t: number) => {
 | 
					        return (t: number) => {
 | 
				
			||||||
            let newState: HeaderBarState = {} as any;
 | 
					            let newState: HeaderBarState = {} as any;
 | 
				
			||||||
            newState[type] = 1 / t;
 | 
					            newState[type] = 1 / t;
 | 
				
			||||||
            if (this.updateTime > 60) {
 | 
					            if (this.updateTime > 20) {
 | 
				
			||||||
                this.updateTime = 0;
 | 
					                this.updateTime = 0;
 | 
				
			||||||
                this.setState(newState);
 | 
					                this.setState(newState);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,7 @@ import { I18N } from "@Component/Localization/Localization";
 | 
				
			|||||||
import { superConnectWithEvent, superConnect } from "./Context";
 | 
					import { superConnectWithEvent, superConnect } from "./Context";
 | 
				
			||||||
import { PopupController } from "./Popups";
 | 
					import { PopupController } from "./Popups";
 | 
				
			||||||
import { Behavior } from "@Model/Behavior";
 | 
					import { Behavior } from "@Model/Behavior";
 | 
				
			||||||
 | 
					import { Actuator } from "@Model/Actuator";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function randomColor(unNormal: boolean = false) {
 | 
					function randomColor(unNormal: boolean = false) {
 | 
				
			||||||
    const color = [
 | 
					    const color = [
 | 
				
			||||||
@ -44,6 +45,7 @@ interface IStatusEvent {
 | 
				
			|||||||
    individualChange: void;
 | 
					    individualChange: void;
 | 
				
			||||||
    behaviorChange: void;
 | 
					    behaviorChange: void;
 | 
				
			||||||
    popupChange: void;
 | 
					    popupChange: void;
 | 
				
			||||||
 | 
					    actuatorStartChange: void;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Status extends Emitter<IStatusEvent> {
 | 
					class Status extends Emitter<IStatusEvent> {
 | 
				
			||||||
@ -71,6 +73,11 @@ class Status extends Emitter<IStatusEvent> {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public model: Model = new Model();
 | 
					    public model: Model = new Model();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 执行器
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public actuator: Actuator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 弹窗
 | 
					     * 弹窗
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@ -104,8 +111,14 @@ class Status extends Emitter<IStatusEvent> {
 | 
				
			|||||||
    public constructor() {
 | 
					    public constructor() {
 | 
				
			||||||
        super();
 | 
					        super();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 初始化执行器
 | 
				
			||||||
 | 
					        this.actuator = new Actuator(this.model);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 执行器开启事件
 | 
				
			||||||
 | 
					        this.actuator.on("startChange", () => { this.emit("actuatorStartChange") });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 循环事件
 | 
					        // 循环事件
 | 
				
			||||||
        this.model.on("loop", (t) => { this.emit("physicsLoop", t) });
 | 
					        this.actuator.on("loop", (t) => { this.emit("physicsLoop", t) });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 对象变化事件
 | 
					        // 对象变化事件
 | 
				
			||||||
        this.model.on("objectChange", () => this.emit("objectChange"));
 | 
					        this.model.on("objectChange", () => this.emit("objectChange"));
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										125
									
								
								source/Model/Actuator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								source/Model/Actuator.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,125 @@
 | 
				
			|||||||
 | 
					import { Model } from "./Model";
 | 
				
			||||||
 | 
					import { Emitter } from "./Emitter"; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IActuatorEvent {
 | 
				
			||||||
 | 
						startChange: boolean;
 | 
				
			||||||
 | 
						loop: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 模型执行器
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class Actuator extends Emitter<IActuatorEvent> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 速度系数
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public speed: number = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 模拟帧率
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public fps: number = 24;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 仿真是否进行
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private startFlag: boolean = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 主时钟状态控制
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public start(start?: boolean): boolean {
 | 
				
			||||||
 | 
							if (start === undefined) {
 | 
				
			||||||
 | 
								return this.startFlag;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								this.startFlag = start;
 | 
				
			||||||
 | 
								this.lastTime = 0;
 | 
				
			||||||
 | 
								this.alignTimer = 0;
 | 
				
			||||||
 | 
								this.emit("startChange", start);
 | 
				
			||||||
 | 
								return start;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 绑定模型
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public model: Model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 上一帧的时间
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private lastTime: number = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 对其计时器
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private alignTimer: number = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public tickerType: 1 | 2 = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ticker(t: number) {
 | 
				
			||||||
 | 
							if (this.startFlag && t !== 0) {
 | 
				
			||||||
 | 
								if (this.lastTime === 0) {
 | 
				
			||||||
 | 
									this.lastTime = t;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									let durTime = (t - this.lastTime) / 1000;
 | 
				
			||||||
 | 
									this.lastTime = t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// 丢帧判定
 | 
				
			||||||
 | 
									if (durTime > 0.1) {
 | 
				
			||||||
 | 
										console.log("Actuator: Ticker dur time error. dropping...")
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									this.alignTimer += durTime;
 | 
				
			||||||
 | 
									if (this.alignTimer > (1 / this.fps)) {
 | 
				
			||||||
 | 
										this.model.update(this.alignTimer * this.speed);
 | 
				
			||||||
 | 
										this.emit("loop", this.alignTimer);
 | 
				
			||||||
 | 
										this.alignTimer = 0;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								this.emit("loop", Infinity);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 帧率对其时钟
 | 
				
			||||||
 | 
						 * 1、使用 requestAnimationFrame 保证最高的性能
 | 
				
			||||||
 | 
						 * 2、最大模拟帧率只能小于 60
 | 
				
			||||||
 | 
						 * 3、可能出现帧率对其问题
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private tickerAlign = (t: number) => {
 | 
				
			||||||
 | 
							this.ticker(t);
 | 
				
			||||||
 | 
							requestAnimationFrame(this.tickerAlign);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 精确时钟
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private tickerExp = () => {
 | 
				
			||||||
 | 
							this.ticker(window.performance.now());
 | 
				
			||||||
 | 
							setTimeout(this.tickerExp, (1 / this.fps) * 1000);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 执行器
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private runTicker = (t: number) => {
 | 
				
			||||||
 | 
							if (this.tickerType === 1) {
 | 
				
			||||||
 | 
								this.ticker(t);
 | 
				
			||||||
 | 
								requestAnimationFrame(this.runTicker);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								this.ticker(window.performance.now());
 | 
				
			||||||
 | 
								setTimeout(this.runTicker, (1 / this.fps) * 1000);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public constructor(model: Model) {
 | 
				
			||||||
 | 
							super();
 | 
				
			||||||
 | 
							this.model = model;
 | 
				
			||||||
 | 
							this.runTicker(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { Actuator }
 | 
				
			||||||
@ -8,7 +8,6 @@ import { Label } from "./Label";
 | 
				
			|||||||
import { Behavior, IAnyBehavior, IAnyBehaviorRecorder } from "./Behavior";
 | 
					import { Behavior, IAnyBehavior, IAnyBehaviorRecorder } from "./Behavior";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ModelEvent = {
 | 
					type ModelEvent = {
 | 
				
			||||||
    loop: number;
 | 
					 | 
				
			||||||
    labelChange: Label[];
 | 
					    labelChange: Label[];
 | 
				
			||||||
    objectChange: CtrlObject[];
 | 
					    objectChange: CtrlObject[];
 | 
				
			||||||
    individualChange: Group;
 | 
					    individualChange: Group;
 | 
				
			||||||
@ -280,8 +279,6 @@ class Model extends Emitter<ModelEvent> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.draw();
 | 
					        this.draw();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.emit("loop", t);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public draw() {
 | 
					    public draw() {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user