// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 using System; using ClassicalSharp.Events; using ClassicalSharp.Model; using OpenTK; #if USE16_BIT using BlockID = System.UInt16; #else using BlockID = System.Byte; #endif namespace ClassicalSharp.Renderers { internal class HeldBlockAnimation { internal bool doAnim, digAnim, swingAnim; internal float angleY = 0; internal Vector3 pos; double time, period = 0.25, speed = Math.PI / 0.25; BlockID lastType; Game game; HeldBlockRenderer held; internal void Init(Game game, HeldBlockRenderer held) { this.game = game; this.held = held; lastType = game.Inventory.Selected; game.Events.HeldBlockChanged += DoSwitchBlockAnim; game.UserEvents.BlockChanged += BlockChanged; } internal void Dispose() { game.Events.HeldBlockChanged -= DoSwitchBlockAnim; game.UserEvents.BlockChanged -= BlockChanged; } /// Sets the current animation state of the held block.
/// true = left mouse pressed, false = right mouse pressed.
internal void SetClickAnim(bool dig) { // TODO: timing still not quite right, rotate2 still not quite right ResetAnimationState(true, dig ? 0.35 : 0.25); swingAnim = false; digAnim = dig; doAnim = true; // Start place animation at bottom of cycle if (!dig) time = period / 2; } void DoSwitchBlockAnim(object sender, EventArgs e) { if (swingAnim) { // Like graph -sin(x) : x=0.5 and x=2.5 have same y values // but increasing x causes y to change in opposite directions if (time > period * 0.5) time = period - time; } else { ResetAnimationState(false, 0.25); doAnim = true; swingAnim = true; } } void BlockChanged(object sender, BlockChangedEventArgs e) { if (e.Block == 0) return; SetClickAnim(false); } internal void Update(double delta, Vector3 last) { if (swingAnim || !digAnim) { pos.Y = -0.4f * (float)Math.Sin(time * speed); if (swingAnim) { // i.e. the block has gone to bottom of screen and is now returning back up // at this point we switch over to the new held block. if (pos.Y > last.Y) lastType = held.block; held.block = lastType; } } else { if (time >= period * 0.25) DigSecondCycle(); else DigFirstCycle(); } time += delta; if (time > period) ResetAnimationState(true, 0.25); } // Based off incredible gifs from (Thanks goodlyay!) // https://dl.dropboxusercontent.com/s/iuazpmpnr89zdgb/slowBreakTranslate.gif // https://dl.dropboxusercontent.com/s/z7z8bset914s0ij/slowBreakRotate1.gif // https://dl.dropboxusercontent.com/s/pdq79gkzntquld1/slowBreakRotate2.gif // https://dl.dropboxusercontent.com/s/w1ego7cy7e5nrk1/slowBreakFull.gif void DigFirstCycle() { double angle = time * speed; pos.X = -0.325f * (float)Math.Sin(angle * 2); pos.Y = 0.20f * (float)Math.Sin(angle * 2 * 2); pos.Z = -0.325f * (float)Math.Sin(angle * 2); angleY = -90 * (float)Math.Sin(angle * 2); } void DigSecondCycle() { // Need to adjust angle so it starts at same point and of first cycle // And finishes cycle at original position double endFirst = period * 0.25; double angle = (endFirst * 2 + (time - endFirst) * 0.66667) * speed; pos.X = -0.325f * (float)Math.Sin(angle); pos.Y = 0.25f * (float)Math.Sin(angle * 2); pos.Z = -0.325f * (float)Math.Sin(angle); // For second cycle, rotate the block from 0-->15 then back to 15-->0. float rotX = Math.Max(0, (float)angle - 90 * Utils.Deg2Rad); if (rotX >= 45 * Utils.Deg2Rad) rotX = 90 * Utils.Deg2Rad - rotX; held.held.RotX = (rotX * 0.33333f) * Utils.Rad2Deg; angleY = -90 * (float)Math.Sin(angle); } void ResetAnimationState(bool updateLastType, double period) { time = 0; doAnim = false; swingAnim = false; pos = Vector3.Zero; angleY = 0; this.period = period; speed = Math.PI / period; if (updateLastType) lastType = game.Inventory.Selected; pos = Vector3.Zero; } } }