public void InputLogic(AdvancerConfigBasic2d config, InputBasic2d action, SnapHistory <NentBasic2d, NentStaticBasic2d> h, ref NentBasic2d snap, byte pid, float delta) { // process the inputs for this action snap.XVel = RMathF.Clamp(action.Horizontal, -1f, 1f) * config.PlayerSpeed; snap.YVel = RMathF.Clamp(action.Vertical, -1f, 1f) * config.PlayerSpeed; // set our rotation, but only if we're not mid-dash if (snap.Free1 <= 0) { snap.Rot = action.Rotation; } // dash action if ((action.Inputs & InputBasic2d.INPUT_A) != 0 && snap.Free1 == 0) { // if input A is pressed, dash forward according to rotation // we use Free1 to store the dash timer. We can only begin a // dash if Free1 is equal to 0 (e.g. dash is over). snap.Free1 = config.DashTimerMax; // we don't need to set XVel/YVel here because this is done // in AdvanceLogic } // finally, do AdvanceLogic over the delta window AdvanceLogic(config, h, ref snap, delta); }
private void InputLogic(InputBasic2d action, SnapHistory <NentBasic2d, NentStaticBasic2d> h, byte pid, float delta) { // process the inputs for this action h.Shots[h.CurrentIndex].XVel = RMathF.Clamp(action.Horizontal, -1f, 1f) * PlayerSpeed; h.Shots[h.CurrentIndex].YVel = RMathF.Clamp(action.Vertical, -1f, 1f) * PlayerSpeed; // set our rotation, but only if we're not mid-dash if (h.Shots[h.CurrentIndex].Free1 <= 0) { h.Shots[h.CurrentIndex].Rot = action.Rotation; } // dash action if ((action.Inputs & InputBasic2d.INPUT_A) != 0 && h.Shots[h.CurrentIndex].Free1 == 0) { // if input A is pressed, dash forward according to rotation // we use Free1 to store the dash timer. We can only begin a // dash if Free1 is equal to 0 (e.g. dash is over). h.Shots[h.CurrentIndex].Free1 = DashTimerMax; // we don't need to set XVel/YVel here because this is done // in AdvanceLogic } // finally, do AdvanceLogic over the delta window AdvanceLogic(h, delta); }
public void AngleBlendTest() { void test(float dega, float degb, float degresult, float percent) { // check extrema AssertFloatEqualsRadians(RMathF.ToRad(dega), RMathF.AngleBlend(RMathF.ToRad(dega), RMathF.ToRad(degb), 0)); AssertFloatEqualsRadians(RMathF.ToRad(degb), RMathF.AngleBlend(RMathF.ToRad(dega), RMathF.ToRad(degb), 1f)); // check midpoint AssertFloatEqualsRadians( RMathF.AngleMidpoint(RMathF.ToRad(dega), RMathF.ToRad(degb)), RMathF.AngleBlend(RMathF.ToRad(dega), RMathF.ToRad(degb), 0.5f)); AssertFloatEqualsRadians(RMathF.ToRad(degresult), RMathF.AngleBlend(RMathF.ToRad(dega), RMathF.ToRad(degb), percent)); } test(100f, 200f, 125f, 0.25f); test(200f, 100f, 125f, 0.75f); test(100f, 200f, 175f, 0.75f); test(200f, 100f, 175f, 0.25f); test(350f, 10f, 355f, 0.25f); test(10f, 350f, 355f, 0.75f); test(350f, 10f, 5f, 0.75f); test(10f, 350f, 5f, 0.25f); }
private void AdvanceLogic(SnapHistory <NentBasic2d, NentStaticBasic2d> h, float delta) { if (h.StaticData.Id2 == NENT_PLAYEROBJ) { // some special considerations for the playerobject if (h.Shots[h.CurrentIndex].Free1 > 0) { // if Free1 is over 0, we're in the middle of a dash // this means we're moving quickly in the direction // of our rotation // we're expecting the client to provide rotation in // radians, for the record h.Shots[h.CurrentIndex].XVel = DashSpeed * RMathF.Cos(h.Shots[h.CurrentIndex].Rot); h.Shots[h.CurrentIndex].YVel = DashSpeed * RMathF.Sin(h.Shots[h.CurrentIndex].Rot); // reduce the dash timer h.Shots[h.CurrentIndex].Free1 -= delta; // if we cross 0, set up the cooldown timer if (h.Shots[h.CurrentIndex].Free1 <= 0) { h.Shots[h.CurrentIndex].Free1 = -DashCooldownMax; } // note: something we're not really handling here // is that on the tick that the dash ends, we may // get a few ms of "extra" dash b/c if it has say // 10ms remaining and we have 16ms in the tick, // you're dashing for the full 16ms even though // you should only have 10ms of dash. // you could probably fix this issue if precision // matters in your use case. but for this demo // I think it's outside the scope } else if (h.Shots[h.CurrentIndex].Free1 < 0) { // if we're negative, we're on cooldown // count back up to 0, when we get to 0 // the dash is available again. h.Shots[h.CurrentIndex].Free1 += delta; if (h.Shots[h.CurrentIndex].Free1 >= 0) { h.Shots[h.CurrentIndex].Free1 = 0; } } } h.Shots[h.CurrentIndex].X += h.Shots[h.CurrentIndex].XVel * delta; h.Shots[h.CurrentIndex].Y += h.Shots[h.CurrentIndex].YVel * delta; }
public void AngleMidpointTest() { void test(float dega, float degb, float degresult) { AssertFloatEqualsRadians(RMathF.ToRad(degresult), RMathF.AngleMidpoint(RMathF.ToRad(dega), RMathF.ToRad(degb))); AssertFloatEqualsRadians(RMathF.ToRad(degresult), RMathF.AngleMidpoint(RMathF.ToRad(degb), RMathF.ToRad(dega))); } test(45f, 135f, 90f); test(30f, 340f, 5f); test(200f, 100f, 150f); test(10f, 200f, 285f); }
private void InterpolateLogic(SnapHistory <NentBasic2d, NentStaticBasic2d> h, float delta) { // interpolate from Current forward delta ms float tickpercent = delta / NetSnapper.TickMSTarget; float invtickpercent = 1.0f - tickpercent; // we don't adjust IDs at all // pos/vel is simple, just blend h.Shots[h.CurrentIndex].X = (h.Shots[h.CurrentIndex].X * invtickpercent) + (h.Shots[h.NextIndex].X * tickpercent); h.Shots[h.CurrentIndex].Y = (h.Shots[h.CurrentIndex].Y * invtickpercent) + (h.Shots[h.NextIndex].Y * tickpercent); h.Shots[h.CurrentIndex].XVel = (h.Shots[h.CurrentIndex].XVel * invtickpercent) + (h.Shots[h.NextIndex].XVel * tickpercent); h.Shots[h.CurrentIndex].YVel = (h.Shots[h.CurrentIndex].YVel * invtickpercent) + (h.Shots[h.NextIndex].YVel * tickpercent); // it makes sense to blend Free1 as well since we just // use it as a timer, but in other cases this might not // be appropriate h.Shots[h.CurrentIndex].Free1 = (h.Shots[h.CurrentIndex].Free1 * invtickpercent) + (h.Shots[h.NextIndex].Free1 * tickpercent); // rotation is more complicated to blend h.Shots[h.CurrentIndex].Rot = RMathF.AngleBlend(h.Shots[h.CurrentIndex].Rot, h.Shots[h.NextIndex].Rot, tickpercent); }
public void BlendLogic(SnapHistory <NentBasic2d, NentStaticBasic2d> h, ref NentBasic2d shot, NentBasic2d blendTarget, float factor) { // interpolate from Current forward delta ms float invfactor = 1.0f - factor; // we don't adjust IDs at all // pos/vel is simple, just blend shot.X = (shot.X * invfactor) + (blendTarget.X * factor); shot.Y = (shot.Y * invfactor) + (blendTarget.Y * factor); shot.XVel = (shot.XVel * invfactor) + (blendTarget.XVel * factor); shot.YVel = (shot.YVel * invfactor) + (blendTarget.YVel * factor); // it makes sense to blend Free1 as well since we just // use it as a timer, but in other cases this might not // be appropriate shot.Free1 = (shot.Free1 * invfactor) + (blendTarget.Free1 * factor); // rotation is more complicated to blend shot.Rot = RMathF.AngleBlend(shot.Rot, blendTarget.Rot, factor); }
private void InterpolateSnapLogic(SnapHistory <NentBasic2d, NentStaticBasic2d> h) { // interpolates from Prev to Next to create Current h.Shots[h.CurrentIndex] = h.Shots[h.PrevIndex]; // always inherit ids from previous //h.Prev.Id1 = h.Prev.Id1; //h.Prev.Id2 = h.Prev.Id2; // pos/vel is easy, just average them h.Shots[h.CurrentIndex].X = (h.Shots[h.NextIndex].X + h.Shots[h.CurrentIndex].X) / 2f; h.Shots[h.CurrentIndex].Y = (h.Shots[h.NextIndex].Y + h.Shots[h.CurrentIndex].Y) / 2f; h.Shots[h.CurrentIndex].XVel = (h.Shots[h.NextIndex].XVel + h.Shots[h.CurrentIndex].XVel) / 2f; h.Shots[h.CurrentIndex].YVel = (h.Shots[h.NextIndex].YVel + h.Shots[h.CurrentIndex].YVel) / 2f; // in our case, we use Free1 as a timer, so it makes // sense to average this as well. May not be the case // if Free1 is used for a different kind of value h.Shots[h.CurrentIndex].Free1 = (h.Shots[h.NextIndex].Free1 + h.Shots[h.CurrentIndex].Free1) / 2f; // rotation is more complicated to find the midpoint h.Shots[h.CurrentIndex].Rot = RMathF.AngleMidpoint(h.Shots[h.CurrentIndex].Rot, h.Shots[h.NextIndex].Rot); }
public void ClampTest() { Assert.AreEqual(30f, RMathF.Clamp(20f, 30f, 50f)); Assert.AreEqual(50f, RMathF.Clamp(90f, 30f, 50f)); Assert.AreEqual(40f, RMathF.Clamp(40f, 30f, 50f)); }