Last active
July 22, 2019 09:30
-
-
Save bartwttewaall/a4f2b484ebff96b3bb04abed9f3d3f48 to your computer and use it in GitHub Desktop.
A ticker / stopwatch class that keeps track of the activation and cooldown of a player's ability, like a shield.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class AbstractTicker { | |
public delegate void TickerEvent (); | |
public delegate void TickerProgressEvent (float progress); | |
public abstract void Tick (float time, bool input); | |
} | |
// Example | |
// TriggeredInputTicker shieldTicker = new TriggeredInputTicker () { duration = 4, cooldown = 8 }; | |
// shieldTicker.onStarted += () => { SoundService.instance.PlayOneShot(SoundAssets.SHIELD_UP); }; | |
// shieldTicker.onProgress += (progress) => { someUIElement.SetProgress(progress); }; | |
// shieldTicker.onFinished += () => { SoundService.instance.PlayOneShot(SoundAssets.SHIELD_DOWN); }; | |
// | |
// Update() { | |
// shieldTicker.Tick (Time.time, Input.GetKeyDown (KeyCode.LeftShift)); | |
// } | |
public class TriggeredInputTicker : AbstractTicker { | |
public event TickerEvent OnStarted; | |
public event TickerProgressEvent OnActiveProgress; | |
public event TickerProgressEvent OnCooldownProgress; | |
public event TickerProgressEvent OnTotalProgress; | |
public event TickerEvent OnFinished; | |
public event TickerEvent OnComplete; | |
private bool triggered; | |
private bool released = true; | |
private float startTime; | |
public float activeDuration; | |
public float cooldownDuration; | |
private float activeProgress; | |
private float cooldownProgress; | |
private float totalProgress; | |
public TriggeredInputTicker2 (Action startCallback = null, Action finishCallback = null) { | |
if (startCallback != null) OnStarted += () => { startCallback (); }; | |
if (finishCallback != null) OnFinished += () => { finishCallback (); }; | |
} | |
public override void Tick (float time, bool input) { | |
if (input) { | |
if ((startTime == 0 || time >= startTime + activeDuration + cooldownDuration) && released) { | |
startTime = time; | |
activeProgress = 0; | |
cooldownProgress = 0; | |
totalProgress = 0; | |
triggered = true; | |
released = false; | |
if (OnStarted != null) OnStarted (); | |
} | |
} else if (!released && totalProgress >= 1) { | |
released = true; | |
} | |
if (triggered) { | |
if (activeProgress >= 1) { | |
activeProgress = 1; | |
if (OnFinished != null) OnFinished (); | |
} | |
if (cooldownProgress >= 1) { | |
cooldownProgress = 1; | |
triggered = false; | |
if (OnComplete != null) OnComplete (); | |
} | |
activeProgress = Mathf.Clamp01 ((time - startTime) / activeDuration); | |
if (OnActiveProgress != null) OnActiveProgress (activeProgress); | |
cooldownProgress = Mathf.Clamp01 ((time - (startTime + activeDuration)) / cooldownDuration); | |
if (cooldownProgress > 0 && OnCooldownProgress != null) OnCooldownProgress (cooldownProgress); | |
totalProgress = Mathf.Clamp01 ((time - startTime) / (activeDuration + cooldownDuration)); | |
if (OnTotalProgress != null) OnTotalProgress (totalProgress); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as signals from "signals"; | |
export interface ITicker { | |
tick(time: number, input: boolean): void; | |
} | |
export interface ITickerOptions { | |
cooldown?: number; | |
duration?: number; | |
delay?: number; | |
interval?: number; | |
} | |
/** | |
* Ticker that knows it is triggered and that it should be released before triggering again. | |
* As long as progress < 1 and no release was detected at the finish it should not accept getting triggered, until released | |
* | |
* @example | |
* const shieldTicker = new TriggeredInputTicker ({ duration: 4, cooldown: 8 }); | |
* shieldTicker.onStarted.add(() => { player.isShielding = true; }); | |
* shieldTicker.onProgress.add((progress) => { player.shieldTotalProgress = progress; }); | |
* shieldTicker.onFinished.add(() => { player.isShielding = false; }); | |
* | |
* onUpdate() => { shieldTicker.tick(clock.elapsedTime, inputState.shield); } | |
*/ | |
export class TriggeredInputTicker implements ITicker { | |
public onStarted: signals.Signal = new signals.Signal(); | |
public onActiveProgress: signals.Signal<number> = new signals.Signal(); | |
public onCooldownProgress: signals.Signal<number> = new signals.Signal(); | |
public onTotalProgress: signals.Signal<number> = new signals.Signal(); | |
public onFinished: signals.Signal = new signals.Signal(); | |
public onComplete: signals.Signal = new signals.Signal(); | |
private triggered: boolean = false; | |
private released: boolean = true; | |
private startTime: number = 0; | |
private readonly activeDuration: number = 0; | |
private readonly cooldownDuration: number = 0; | |
private activeProgress: number = 0; | |
private cooldownProgress: number = 0; | |
private totalProgress: number = 0; | |
constructor(options: ITickerOptions) { | |
if (options !== null) { | |
this.activeDuration = options.duration || 0; | |
this.cooldownDuration = options.cooldown || 0; | |
} | |
} | |
public reset() { | |
this.triggered = false; | |
this.released = true; | |
this.startTime = 0; | |
this.activeProgress = 0; | |
this.cooldownProgress = 0; | |
this.totalProgress = 0; | |
} | |
public tick(time: number, input: boolean): void { | |
if (input) { | |
if ((this.startTime === 0 || time >= this.startTime + this.activeDuration + this.cooldownDuration) && this.released) { | |
this.startTime = time; | |
this.activeProgress = 0; | |
this.cooldownProgress = 0; | |
this.triggered = true; | |
this.released = false; | |
this.onStarted.dispatch(); | |
} | |
} else if (!this.released && this.totalProgress >= 1) { | |
this.released = true; | |
} | |
if (this.triggered) { | |
if (this.activeProgress >= 1) { | |
this.activeProgress = 1; | |
this.onFinished.dispatch(); | |
} | |
if (this.cooldownProgress >= 1) { | |
this.cooldownProgress = 1; | |
this.triggered = false; | |
this.onComplete.dispatch(); | |
} | |
this.activeProgress = this.clamp01((time - this.startTime) / this.activeDuration); | |
this.onActiveProgress.dispatch(this.activeProgress); | |
this.cooldownProgress = this.clamp01((time - (this.startTime + this.activeDuration)) / this.cooldownDuration); | |
this.onCooldownProgress.dispatch(this.cooldownProgress); | |
this.totalProgress = this.clamp01((time - this.startTime) / (this.activeDuration + this.cooldownDuration)); | |
this.onTotalProgress.dispatch(this.totalProgress); | |
} | |
} | |
public clamp01(value: number): number { | |
return Math.max(0, Math.min(value, 1)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment