TankAIAimGuesser.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <tankai/TankAIAimGuesser.h>
00022 #include <tank/Tank.h>
00023 #include <tank/TankLib.h>
00024 #include <tank/TankPosition.h>
00025 #include <server/ScorchedServer.h>
00026 #include <common/Logger.h>
00027 #include <common/RandomGenerator.h>
00028 #include <math.h>
00029 
00030 TankAIAimGuesser::TankAIAimGuesser()
00031 {
00032 }
00033 
00034 TankAIAimGuesser::~TankAIAimGuesser()
00035 {
00036 }
00037 
00038 bool TankAIAimGuesser::guess(Tank *tank, Vector &target, 
00039         float angleYZDegs, float distance, 
00040         Vector &actualPosition)
00041 {
00042         tank->getPosition().rotateGunYZ(fixed::fromFloat(angleYZDegs), false);
00043 
00044         // Make an initial randomish shot up
00045         initialShot(tank, target);
00046 
00047         for (int i=0;;i++)
00048         {
00049                 // Find out where this may land
00050                 getCurrentGuess(tank);
00051                 if (!collision_)
00052                 {
00053                         // No collision
00054                         // A bad thing
00055                         return false; 
00056                 }
00057 
00058                 // Its landed
00059                 actualPosition = currentGuess_.getPosition().asVector();
00060                 Vector direction = currentGuess_.getPosition().asVector() - target;
00061                 float actualDistance = 
00062                         float(sqrt(direction[0]*direction[0] + direction[1]*direction[1]));
00063                 if (actualDistance < distance)
00064                 {
00065                         // Its close
00066                         // A good thing
00067                         return true;
00068                 }
00069 
00070                 if (i > 25)
00071                 {
00072                         // No soultion
00073                         // A bad thing
00074                         return false;
00075                 }
00076 
00077                 // Not close
00078                 refineShot(tank, currentGuess_.getPosition().asVector(), target);
00079         }
00080 
00081         // Never gets here
00082         return false;
00083 }
00084 
00085 void TankAIAimGuesser::initialShot(Tank *tank, Vector &target)
00086 {
00087         fixed angleXYDegs;
00088         fixed angleYZDegs;
00089         fixed power;
00090 
00091         // Makes a randow powered shot towards the target
00092         RandomGenerator random;
00093         random.seed(rand());
00094         TankLib::getShotTowardsPosition(
00095                 ScorchedServer::instance()->getContext(),
00096                 random,
00097                 tank->getPosition().getTankPosition(), 
00098                 FixedVector::fromVector(target), 
00099                 angleXYDegs, angleYZDegs, power);
00100 
00101         // Set the parameters
00102         // Sets the angle of the gun and the power
00103         tank->getPosition().rotateGunXY(angleXYDegs, false);
00104         tank->getPosition().changePower(power, false);
00105 }
00106 
00107 void TankAIAimGuesser::refineShot(Tank *tank,
00108         Vector &currentPos, Vector &wantedPos)
00109 {
00110         // Get the used velocity
00111         FixedVector shotVelocity = tank->getPosition().getVelocityVector() *
00112                 (tank->getPosition().getPower() + 1);
00113 
00114         // Figure out how much the last shot missed by
00115         Vector missedBy = wantedPos - currentPos;
00116         
00117         // Adjust velocity to take this into account
00118         shotVelocity[0] += fixed::fromFloat(missedBy[0]) * fixed(true, 400);
00119         shotVelocity[1] += fixed::fromFloat(missedBy[1]) * fixed(true, 400);
00120 
00121         // Figure out a new XY angle based on these
00122         fixed angleXYRads = atan2x(shotVelocity[1], shotVelocity[0]);
00123         fixed angleXYDegs = (angleXYRads / fixed::XPI) * 180 - 90;
00124 
00125         tank->getPosition().rotateGunXY(angleXYDegs, false);
00126 
00127         // And the new best power
00128         FixedVector resultingVelocity = tank->getPosition().getVelocityVector();
00129         fixed resultingDistance = (
00130                 resultingVelocity[0] * resultingVelocity[0] +
00131                 resultingVelocity[1] * resultingVelocity[1]).sqrt();
00132         fixed wantedDistance = (
00133                 shotVelocity[0] * shotVelocity[0] +
00134                 shotVelocity[1] * shotVelocity[1]).sqrt();
00135         fixed power = wantedDistance / resultingDistance - 1;
00136 
00137         tank->getPosition().changePower(power, false);
00138 }
00139 
00140 void TankAIAimGuesser::collision(PhysicsParticleObject &position, 
00141         ScorchedCollisionId collisionId)
00142 {
00143         currentGuess_ = position;
00144         collision_ = true;
00145 }
00146 
00147 void TankAIAimGuesser::wallCollision(PhysicsParticleObject &position,
00148         ScorchedCollisionId collisionId)
00149 {
00150         // For now the AIs cannot cope with bouncy and wrap walls.
00151         // So they will count the shot end where they hit the wall
00152         currentGuess_ = position;
00153         collision_ = true;
00154 }
00155 
00156 void TankAIAimGuesser::getCurrentGuess(Tank *tank)
00157 {
00158         FixedVector shotVelocity = tank->getPosition().getVelocityVector() *
00159                 (tank->getPosition().getPower() + 1);
00160         FixedVector shotPosition = tank->getPosition().getTankGunPosition();
00161 
00162         PhysicsParticleObject particleObject;
00163         PhysicsParticleInfo info(ParticleTypeShot, tank->getPlayerId(), 0);
00164         particleObject.setPhysics(info, ScorchedServer::instance()->getContext(),
00165                 shotPosition, shotVelocity);
00166         particleObject.setHandler(this);
00167 
00168         collision_ = false;
00169         for (int i=0; i<10000 && !collision_; i++)
00170         {
00171                 particleObject.simulate(1);
00172         }
00173 }

Generated on Mon Feb 16 15:14:53 2009 for Scorched3D by  doxygen 1.5.3