import { clamp, rand } from '@/utils'; const enum EyeState { Idle, Closing, Closed, Opening, } export class Live2DEyeBlink { leftParam: number; rightParam: number; blinkInterval: DOMHighResTimeStamp = 4000; closingDuration: DOMHighResTimeStamp = 100; closedDuration: DOMHighResTimeStamp = 50; openingDuration: DOMHighResTimeStamp = 150; eyeState = EyeState.Idle; eyeParamValue = 1; closedTimer = 0; nextBlinkTimeLeft = this.blinkInterval; constructor(readonly coreModel: Live2DModelWebGL) { this.leftParam = coreModel.getParamIndex('PARAM_EYE_L_OPEN'); this.rightParam = coreModel.getParamIndex('PARAM_EYE_R_OPEN'); } setEyeParams(value: number) { this.eyeParamValue = clamp(value, 0, 1); this.coreModel.setParamFloat(this.leftParam, this.eyeParamValue); this.coreModel.setParamFloat(this.rightParam, this.eyeParamValue); } update(dt: DOMHighResTimeStamp) { switch (this.eyeState) { case EyeState.Idle: this.nextBlinkTimeLeft -= dt; if (this.nextBlinkTimeLeft < 0) { this.eyeState = EyeState.Closing; this.nextBlinkTimeLeft = this.blinkInterval + this.closingDuration + this.closedDuration + this.openingDuration + rand(0, 2000); } break; case EyeState.Closing: this.setEyeParams(this.eyeParamValue + dt / this.closingDuration); if (this.eyeParamValue <= 0) { this.eyeState = EyeState.Closed; this.closedTimer = 0; } break; case EyeState.Closed: this.closedTimer += dt; if (this.closedTimer >= this.closedDuration) { this.eyeState = EyeState.Opening; } break; case EyeState.Opening: this.setEyeParams(this.eyeParamValue + dt / this.openingDuration); if (this.eyeParamValue >= 1) { this.eyeState = EyeState.Idle; } } } }