// -------------------------- Kick ---------------------------------------- // // applys a force to the ball in the direction of heading. Truncates // the new velocity to make sure it doesn't exceed the max allowable. // ------------------------------------------------------------------------ public void kick(Vector2D direction, double force) { // ensure direction is normalized Vector2D d = direction.cloneVec(); d.Normalize(); // calculate the acceleration Vector2D acceleration = d.multiply(force).divide(mass); // update the velocity velocity.cloneVec(acceleration); }
// ----------------------------- AddNoiseToKick -------------------------------- // // this can be used to vary the accuracy of a player's kick. Just call it // prior to kicking the ball using the ball's position and the ball target as // parameters. // ----------------------------------------------------------------------------- public static Vector2D addNoiseToKick(Vector2D BallPos, Vector2D BallTarget) { double Pi = Utils.Pi; double displacement = (Pi - Pi * Params.Instance().PlayerKickingAccuracy) * RandomClamped(); Vector2D toTarget = BallTarget.minus(BallPos); vec2DRotateAroundOrigin(toTarget, displacement); return toTarget.plus(BallPos); }
// ----------------------------- Update ----------------------------------- // // updates the ball physics, tests for any collisions and adjusts // the ball's velocity accordingly // ------------------------------------------------------------------------ public void update(float tpf) { // keep a record of the old position so the goal::scored method // can utilize it for goal testing if (position != null) { oldPos.cloneVec(position); } // Test for collisions testCollisionWithWalls(pitchBoundary); // Simulate Params.Instance().Friction. Make sure the speed is positive // first though double friction = Params.Instance().Friction; // println (velocity) // println("LengthSq" + velocity.LengthSq() +" friction " + friction) if (velocity.LengthSq() > friction * friction) { velocity = velocity.plus(Vec2DNormalize(velocity).multiply(friction)); // println (velocity) position = position.plus(velocity.multiply(tpf)); // println (position) // update heading heading = Vec2DNormalize(velocity); } super.update(tpf); }
// ----------------------- PlaceAtLocation ------------------------------------- // // positions the ball at the desired location and sets the ball's velocity to // zero // ----------------------------------------------------------------------------- public void placeAtPosition(Vector2D NewPos) { position = NewPos; oldPos.cloneVec(position); velocity.setZero(); }
// ----------------------- TestCollisionWithWalls ------------------------- // public void testCollisionWithWalls(List<Wall2D> walls) { // test ball against each wall, find out which is closest int idxClosest = -1; // println ("Colision " +velocity) Vector2D velNormal = Vec2DNormalize(velocity); Vector2D intersectionPoint = new Vector2D(); Vector2D collisionPoint = new Vector2D(); double distToIntersection = Double.MAX_VALUE; // iterate through each wall and calculate if the ball intersects. // If it does then store the index into the closest intersecting wall for (int w = 0; w < walls.size(); ++w) { // assuming a collision if the ball continued on its current heading // calculate the point on the ball that would hit the wall. This is // simply the wall's normal(inversed) multiplied by the ball's radius // and added to the balls center (its position) Wall2D wallSegment = walls.get(w); Vector2D thisCollisionPoint = getPos().minus(wallSegment.Normal().multiply(getBRadius())); // calculate exactly where the collision point will hit the plane if (Geometry2DFunctions.whereIsPoint( thisCollisionPoint, wallSegment.From(), wallSegment.Normal()) == Geometry2DFunctions.SpanType.plane_backside) { double distToWall = distanceToRayPlaneIntersection( thisCollisionPoint, wallSegment.Normal(), wallSegment.From(), wallSegment.Normal()); intersectionPoint = thisCollisionPoint.plus(wallSegment.Normal().multiply(distToWall)); } else { double distToWall = distanceToRayPlaneIntersection( thisCollisionPoint, velNormal, wallSegment.From(), wallSegment.Normal()); intersectionPoint = thisCollisionPoint.plus(velNormal.multiply(distToWall)); } // check to make sure the intersection point is actually on the line // segment boolean OnLineSegment = false; Vector2D wallNormal = wallSegment.Normal().multiply(20.0); if (LineIntersection2D( wallSegment.From(), wallSegment.To(), thisCollisionPoint.minus(wallNormal), thisCollisionPoint.plus(wallNormal))) { OnLineSegment = true; } // Note, there is no test for collision with the end of a line segment // now check to see if the collision point is within range of the // velocity vector. [work in distance squared to avoid Math.sqrt] and if it // is the closest hit found so far. // If it is that means the ball will collide with the wall sometime // between this time step and the next one. double distSq = vec2DDistanceSq(thisCollisionPoint, intersectionPoint); if ((distSq <= velocity.LengthSq()) && (distSq < distToIntersection) && OnLineSegment) { distToIntersection = distSq; idxClosest = w; collisionPoint = intersectionPoint; } } // next wall // to prevent having to calculate the exact time of collision we // can just check if the velocity is opposite to the wall normal // before reflecting it. This prevents the case where there is overshoot // and the ball gets reflected back over the line before it has completely // reentered the playing area. if ((idxClosest >= 0) && velNormal.dot(walls.get(idxClosest).Normal()) < 0) { velocity.Reflect(walls.get(idxClosest).Normal()); } }