Skip to content

Instantly share code, notes, and snippets.

@bartwttewaall
Last active July 22, 2019 09:30
Show Gist options
  • Save bartwttewaall/a4f2b484ebff96b3bb04abed9f3d3f48 to your computer and use it in GitHub Desktop.
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.
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);
}
}
}
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