public static bool HitInStride(Vector ballStart, Vector playerStart, Vector playerVelocity, out Vector throwVelocity, out Vector catchLocation) { var diff = playerStart.NewAdded(ballStart.NewMinus()); // don't try to hit yourself in stride if (diff.Length == 0) { throwVelocity = default; catchLocation = default; return(false); } var speedAWay = diff.NewUnitized().Dot(playerVelocity); var t1 = HowLongItTakesBallToGo(diff.Length, Constants.maxThrowPower); var t2 = HowLongItTakesBallToGo(diff.Length + speedAWay * t1, Constants.maxThrowPower); var t3 = HowLongItTakesBallToGo(diff.Length + speedAWay * t2, Constants.maxThrowPower); if (t3 == Double.MaxValue) { throwVelocity = default; catchLocation = default; return(false); } catchLocation = playerStart.NewAdded(playerVelocity.NewScaled(t3)); throwVelocity = diff.NewAdded(playerVelocity.NewScaled(t3)).NewUnitized().NewScaled(Constants.maxThrowPower); return(true); }
public static bool HitInStride(Vector ballStart, Vector playerStart, Vector playerVelocity, double time, out Vector throwVelocity, out Vector catchLocation) { var diff = playerStart.NewAdded(ballStart.NewMinus()); // don't try to hit yourself in stride if (diff.Length == 0) { throwVelocity = default; catchLocation = default; return(false); } catchLocation = playerStart.NewAdded(playerVelocity.NewScaled(time)); var v = HowHardToThrow(catchLocation.NewAdded(ballStart.NewMinus()).Length, time); if (v > Constants.maxThrowPower) { throwVelocity = default; catchLocation = default; return(false); } throwVelocity = catchLocation.NewAdded(ballStart.NewMinus()).NewUnitized().NewScaled(v); return(true); }
public static void Apply(this GameState state, Dictionary <Guid, PlayerInputs> inputs) { // TODO what about count down state? // if the ball is not being held apply friction to it if (state.GameBall.OwnerOrNull == null) { //if (state.GameBall.Velocity.Length > 0) //{ // var friction = state.GameBall.Velocity.NewUnitized().NewScaled(-state.GameBall.Velocity.Length * state.GameBall.Velocity.Length * state.GameBall.Mass / (175.0 * 175)); // state.GameBall.Velocity = state.GameBall.Velocity.NewAdded(friction); //} if (state.GameBall.Velocity.Length > 0) { var friction = state.GameBall.Velocity.NewUnitized().NewScaled(-state.GameBall.Velocity.Length * state.GameBall.Mass / Constants.FrictionDenom); state.GameBall.Velocity = state.GameBall.Velocity.NewAdded(friction); } } // loop over the players and update them foreach (var player in state.players.Values) { player.ExternalVelocity = player.ExternalVelocity.NewScaled(Constants.ExternalVelocityFriction); //if (state.Frame % 90 == 0) { player.Boosts = Math.Min(2, Math.Max(player.Boosts + 1.0 / 90.0, -1)); //} // handle inputs if (inputs.TryGetValue(player.Id, out var input)) { if (input.ControlScheme == ControlScheme.SipmleMouse) { var dx = input.BodyX - player.PlayerBody.Position.x; var dy = input.BodyY - player.PlayerBody.Position.y; if (dx != 0 || dy != 0) { // base velocity becomes the part of the velocity in the direction of the players movement var v = new Vector(player.PlayerBody.Velocity.x, player.PlayerBody.Velocity.y); var f = new Vector(dx, dy).NewUnitized(); var with = v.Dot(f); var baseValocity = with > 0 ? f.NewUnitized().NewScaled(with) : new Vector(0, 0); var engeryAdd = /*player.Id == state.GameBall.OwnerOrNull ? Constants.EnergyAdd / 2.0 :*/ Constants.EnergyAdd; // var finalE = VtoE(Math.Sqrt(Math.Pow(baseValocity.x, 2) + Math.Pow(baseValocity.y, 2))) + engeryAdd; var inputAmount = new Vector(input.BodyX, input.BodyY).Length; if (inputAmount < .1) { finalE = 0; } else if (inputAmount < 1) { finalE = Math.Min(finalE, (inputAmount - .1) * (inputAmount - .1) * engeryAdd * 100); } var finalSpeed = EtoV(finalE); var finalVelocity = f.NewScaled(finalSpeed); if (finalVelocity.Length > new Vector(dx, dy).Length) { finalVelocity = finalVelocity.NewUnitized().NewScaled(new Vector(dx, dy).Length); } player.PlayerBody.Velocity = finalVelocity;// / 2.0; } else { player.PlayerBody.Velocity = new Vector(0, 0); } } else if (input.BodyX != 0 || input.BodyY != 0) { if (input.ControlScheme == ControlScheme.MouseAndKeyboard) { var v = new Vector(player.PlayerBody.Velocity.x, player.PlayerBody.Velocity.y); if (v.Length > 0) { var f = new Vector(Math.Sign(input.BodyX), Math.Sign(input.BodyY)).NewUnitized(); var with = v.NewUnitized().Dot(f); if (with <= 0) { player.PlayerBody.Velocity = new Vector(0, 0); } else { var withVector = f.NewScaled(with * v.Length); //var notWith = v.Length - withVector.Length; var notWith = v.NewAdded(withVector.NewScaled(-1)); // dont' crush stuff with in 45 degrees var notWithScald = notWith.Length > withVector.Length ? notWith.NewScaled(with) : notWith; player.PlayerBody.Velocity = withVector.NewAdded(notWithScald); //player.PlayerBody.Velocity = f.NewScaled(withVector.Length + (notWith * Math.Sqrt(with)));//new Vector(withVector.x + notWithScald.x, withVector.y + notWithScald.y); } } var damp = .9;//.98; var engeryAdd = /*player.Id == state.GameBall.OwnerOrNull ? Constants.EnergyAdd / 2.0 :*/ Constants.EnergyAdd; var R0 = EtoV(VtoE(player.PlayerBody.Velocity.Length) + engeryAdd); var a = Math.Pow(Math.Sign(input.BodyX), 2) + Math.Pow(Math.Sign(input.BodyY), 2); var b = 2 * ((Math.Sign(input.BodyX) * player.PlayerBody.Velocity.x * damp) + (Math.Sign(input.BodyY) * player.PlayerBody.Velocity.y * damp)); var c = Math.Pow(player.PlayerBody.Velocity.x * damp, 2) + Math.Pow(player.PlayerBody.Velocity.y * damp, 2) - Math.Pow(R0, 2); var t = (-b + Math.Sqrt(Math.Pow(b, 2) - (4 * a * c))) / (2 * a); player.PlayerBody.Velocity = new Vector((damp * player.PlayerBody.Velocity.x) + (t * input.BodyX), (damp * player.PlayerBody.Velocity.y) + (t * input.BodyY));// / 2.0; } else if (input.ControlScheme == ControlScheme.Controller || input.ControlScheme == ControlScheme.AI) { // base velocity becomes the part of the velocity in the direction of the players movement var f = new Vector(input.BodyX, input.BodyY).NewUnitized(); var baseValocity = new Vector(0, 0); if (player.PlayerBody.Velocity.Length > 0) { var with = player.PlayerBody.Velocity.NewUnitized().Dot(f); if (with > 0) { var withVector = f.NewScaled(with * player.PlayerBody.Velocity.Length); var notWith = player.PlayerBody.Velocity.Length - withVector.Length; baseValocity = withVector.NewAdded(f.NewScaled(notWith * with)); } } var engeryAdd = Constants.EnergyAdd;// player.Id == state.GameBall.OwnerOrNull ? Constants.EnergyAdd / 2.0 : Constants.EnergyAdd; // var finalE = VtoE(baseValocity.Length) + engeryAdd; var inputAmount = new Vector(input.BodyX, input.BodyY).Length; if (inputAmount < .1) { player.PlayerBody.Velocity = new Vector(0, 0); } else if (inputAmount < 0.9) { var finalSpeed = ((inputAmount - .1) / .8) * Constants.bodyStartAt; var finalVelocity = f.NewScaled(finalSpeed); player.PlayerBody.Velocity = finalVelocity; } else { var finalSpeed = EtoV(finalE); var finalVelocity = f.NewScaled(finalSpeed); player.PlayerBody.Velocity = finalVelocity; } // //if (input.Boost && player.Boosts >= 0) //{ // var move = f.NewScaled(Constants.BoostPower); // player.BoostVelocity = move; // player.BoostCenter = player.BoostCenter.NewAdded(move); // player.Boosts -= Constants.BoostConsumption * move.Length * player.BoostCenter.Length; //} //else { // player.BoostCenter = new Vector(); // player.BoostVelocity = new Vector(0.0, 0.0); //} } } else { player.PlayerBody.Velocity = new Vector(0, 0); } player.BoostVelocity = player.BoostVelocity.NewScaled(0.90); if (input.ControlScheme == ControlScheme.Controller) { var currentOffset = player.PlayerFoot.Position.NewAdded(player.PlayerBody.Position.NewMinus()); var targetOffset = new Vector(input.FootX, input.FootY).NewScaled(Constants.footLen - Constants.PlayerRadius); var offsetDiff = targetOffset.NewAdded(currentOffset.NewMinus()); if (offsetDiff.Length < Constants.speedLimit && new Vector(input.BodyX, input.BodyY).Length > .98 && player.Boosts > 0 && input.Boost != Constants.NoMove) { player.PlayerFoot.Velocity = offsetDiff; player.BoostVelocity = player.BoostVelocity.NewScaled(0.2).NewAdded(new Vector(input.BodyX, input.BodyY).NewUnitized().NewScaled(Constants.speedLimit - offsetDiff.Length)); } else if (offsetDiff.Length > Constants.speedLimit) { offsetDiff.NewUnitized().NewScaled(Constants.speedLimit); player.PlayerFoot.Velocity = offsetDiff; } else { player.PlayerFoot.Velocity = offsetDiff; } } else if (input.ControlScheme == ControlScheme.AI) { var drag = mouseDrags.GetOrAdd(input.Id, new MouseDrag { Id = input.Boost, moves = new ConcurrentLinkedList <Vector>() }); if (input.Boost != Constants.NoMove && drag.Id != input.Boost) { drag.Id = input.Boost; drag.moves = new ConcurrentLinkedList <Vector>(); } var move = new Vector(input.FootX, input.FootY);//.NewScaled(1.0 / Constants.BoostSpread); var totallyToAdd = drag.residual.NewAdded(move); if (totallyToAdd.Length > Constants.speedLimit && input.Boost != Constants.NoMove) { while (totallyToAdd.Length > Constants.speedLimit) { var toAdd = totallyToAdd.NewUnitized().NewScaled(Constants.speedLimit); drag.moves.Add(toAdd); totallyToAdd = totallyToAdd.NewAdded(toAdd.NewMinus()); } drag.residual = totallyToAdd; } else { if (move.Length > Constants.speedLimit) { move = move.NewUnitized().NewScaled(Constants.speedLimit); } drag.moves.Add(move); drag.residual = new Vector(0, 0); } if (drag.moves.TryGetFirst(out var moveToApply)) { drag.moves.RemoveStart(); var targetPos = player.PlayerFoot.Position.NewAdded(moveToApply); var resultingOffest = targetPos.NewAdded(player.PlayerBody.Position.NewMinus()); if (resultingOffest.Length > Constants.footLen - Constants.PlayerRadius && moveToApply.Length > 0 && player.Boosts > 0 && input.Boost != Constants.NoMove) { var currentOffset = player.PlayerFoot.Position.NewAdded(player.PlayerBody.Position.NewMinus()); var targetOffest = resultingOffest.NewUnitized().NewScaled(Constants.footLen - Constants.PlayerRadius); var offsetDiff = targetOffest.NewAdded(currentOffset.NewMinus()); player.PlayerFoot.Velocity = offsetDiff; player.BoostVelocity = player.BoostVelocity.NewScaled(0.2).NewAdded(moveToApply.NewUnitized().NewScaled(Constants.speedLimit - offsetDiff.Length)); } else if (resultingOffest.Length > Constants.footLen - Constants.PlayerRadius && moveToApply.Length > 0) { var currentOffset = player.PlayerFoot.Position.NewAdded(player.PlayerBody.Position.NewMinus()); var targetOffest = resultingOffest.NewUnitized().NewScaled(Constants.footLen - Constants.PlayerRadius); var offsetDiff = targetOffest.NewAdded(currentOffset.NewMinus()); player.PlayerFoot.Velocity = offsetDiff; } else { player.PlayerFoot.Velocity = moveToApply; } } else if (drag.Id != Constants.NoMove) { drag.Id = Constants.NoMove; } } player.Boosts -= Constants.BoostConsumption * player.BoostVelocity.Length; // throwing 2 //if (!player.Throwing && input.Throw) //{ // player.ProposedThrow = new Vector(0, 0); //} //if (input.Boost == Constants.NoMove) //{ if (input.ControlScheme == ControlScheme.Controller) { player.ProposedThrow = new Vector(input.FootX, input.FootY).NewScaled(Constants.maxThrowPower); } else if (input.ControlScheme == ControlScheme.AI) { if (new Vector(input.FootX, input.FootY).Length > 1) { player.ProposedThrow = new Vector(0, 0); } else { player.ProposedThrow = new Vector(input.FootX, input.FootY).NewScaled(Constants.maxThrowPower);//.NewAdded(player.PlayerBody.Velocity.NewMinus()); } } else if (input.ControlScheme == ControlScheme.MouseAndKeyboard) { player.ProposedThrow = player.ProposedThrow.NewAdded(new Vector(input.FootX, input.FootY).NewScaled(.5)); if (player.ProposedThrow.Length > Constants.maxThrowPower) { player.ProposedThrow = player.ProposedThrow.NewUnitized().NewScaled(Constants.maxThrowPower); } } else if (input.ControlScheme == ControlScheme.SipmleMouse) { throw new NotImplementedException(); } //} if (input.Throw && state.GameBall.OwnerOrNull == player.Id) { state.GameBall.Velocity = player.ProposedThrow; //.NewAdded(player.PlayerBody.Velocity).NewAdded(player.ExternalVelocity).NewAdded(player.BoostVelocity); //player.PlayerBody.Velocity = player.PlayerBody.Velocity.NewScaled(2); state.players[state.GameBall.OwnerOrNull.Value].LastHadBall = state.Frame; state.GameBall.OwnerOrNull = null; //player.ProposedThrow = new Vector(); } //player.Throwing = input.Throw; // handle throwing //{ // if (player == state.ball.ownerOrNull) // { // state.ball.velocity = player.externalVelocity.NewAdded(player.body.velocity).NewAdded(player.foot.velocity); // } // var throwV = player.foot.velocity; // // I think force throw is making throwing harder // if (forceThrow && player == state.ball.ownerOrNull) // { // var newPart = 1;//Math.Max(1, throwV.Length); // var oldPart = 2;// Math.Max(1, ball.proposedThrow.Length); // player.proposedThrow = new Vector( // ((throwV.x * newPart) + (player.proposedThrow.x * oldPart)) / (newPart + oldPart), // ((throwV.y * newPart) + (player.proposedThrow.y * oldPart)) / (newPart + oldPart)); // // throw the ball! // // duplicate code // {C7BF7AF7-2C8E-4094-85F6-E7C19F6F71C9} // state.ball.velocity = player.proposedThrow.NewAdded(player.body.velocity).NewAdded(player.externalVelocity); // state.ball.ownerOrNull.lastHadBall = state.frame; // state.ball.ownerOrNull = null; // forceThrow = false; // player.proposedThrow = new Vector(); // } // else if (player.throwing) // { // if (player.proposedThrow.Length > Constants.MimimunThrowingSpped && (throwV.Length * 1.3 < player.proposedThrow.Length || throwV.Dot(player.proposedThrow) < 0) && player.throwing && player == state.ball.ownerOrNull) // { // // throw the ball! // // duplicate code // {C7BF7AF7-2C8E-4094-85F6-E7C19F6F71C9} // state.ball.velocity = player.proposedThrow.NewAdded(player.body.velocity).NewAdded(player.externalVelocity); // state.ball.ownerOrNull.lastHadBall = state.frame; // state.ball.ownerOrNull = null; // forceThrow = false; // player.proposedThrow = new Vector(); // } // else if (player.proposedThrow.Length == 0) // { // player.proposedThrow = throwV; // } // else // { // var newPart = 1;//Math.Max(1, throwV.Length); // var oldPart = 4;// Math.Max(1, ball.proposedThrow.Length); // player.proposedThrow = new Vector( // ((throwV.x * newPart) + (player.proposedThrow.x * oldPart)) / (newPart + oldPart), // ((throwV.y * newPart) + (player.proposedThrow.y * oldPart)) / (newPart + oldPart)); // } // } // else // { // player.proposedThrow = new Vector(); // } //} } state.Frame++; } }