//-------------------------------Update()-------------------------------- // // First we take sensor readings and feed these into the sweepers brain. // // The inputs are: // // A vector to the closest mine (x, y) // The sweepers 'look at' vector (x, y) // // We receive two outputs from the brain.. lTrack & rTrack. // So given a force for each track we calculate the resultant rotation // and acceleration and apply to current velocity vector. // //----------------------------------------------------------------------- bool CMinesweeper::Update(vector<SVector2D> &mines) { //this will store all the inputs for the NN vector<double> inputs; //get vector to closest mine SVector2D vClosestMine = GetClosestMine(mines); //normalise it Vec2DNormalize(vClosestMine); //add in vector to closest mine inputs.push_back(vClosestMine.x); inputs.push_back(vClosestMine.y); //add in sweepers look at vector inputs.push_back(m_vLookAt.x); inputs.push_back(m_vLookAt.y); //update the brain and get feedback vector<double> output = m_ItsBrain.Update(inputs); //make sure there were no errors in calculating the //output if (output.size() < CParams::iNumOutputs) { return false; } //assign the outputs to the sweepers left & right tracks m_lTrack = output[0]; m_rTrack = output[1]; //calculate steering forces double RotForce = m_lTrack - m_rTrack; //clamp rotation Clamp(RotForce, -CParams::dMaxTurnRate, CParams::dMaxTurnRate); m_dRotation += RotForce; m_dSpeed = (m_lTrack + m_rTrack); //update Look At m_vLookAt.x = -sin(m_dRotation); m_vLookAt.y = cos(m_dRotation); //update position m_vPosition += (m_vLookAt * m_dSpeed); //wrap around window limits if (m_vPosition.x > CParams::WindowWidth) m_vPosition.x = 0; if (m_vPosition.x < 0) m_vPosition.x = CParams::WindowWidth; if (m_vPosition.y > CParams::WindowHeight) m_vPosition.y = 0; if (m_vPosition.y < 0) m_vPosition.y = CParams::WindowHeight; return true; }
//-------------------------------Update()-------------------------------- // // First we take sensor readings. These are then fed into the learning algorithm // // The inputs are: // // A vector to the closest mine (x, y) // The sweepers 'look at' vector (x, y) // So given a force we calculate the resultant rotation // and acceleration. This is then applied to current velocity vector. // //----------------------------------------------------------------------- bool CMinesweeper::Update(vector<CCollisionObject> &objects, vector<CMinesweeper> &tanks, CMlp &mlp) { //get vector to closest mine SVector2D vClosestMine = GetClosestMine(objects); GetClosestSuperMine(objects); //normalise it Vec2DNormalize(vClosestMine); double angleToMine = Vec2DAngle(m_vLookAt, vClosestMine); double steering = 0.5; if(abs(angleToMine) > 0.5){ if(angleToMine <= 0) steering = 0.0; else steering = 1.0; } minesLeft = minesRight = false; // We want more than the closest mine. We want all mines within a certain radius to make a better decision // on which direction to turn. vector<int> nearbyObjects = GetNearbySupermines(objects, CParams::dMineScale + 9); Vec2DNormalize(m_vLookAt); // Shift the point we measure angles from to the back of the sweeper // in order to reduce the area where the sweeper doesn't see stuff in front of it. SVector2D fakePosition = m_vPosition - (m_vLookAt*100); for(int i=0; i < nearbyObjects.size(); i++){ if (objects[nearbyObjects[i]].getType() == CCollisionObject::ObjectType::SuperMine) { SVector2D direction = objects[nearbyObjects[i]].getPosition() - fakePosition; double angle = Vec2DAngle(m_vLookAt, direction) * 180 / CParams::dPi; // Which quadrant does the mine fall into if(angle >= -20.0 && angle < 0.0) minesLeft = true; else if(angle <= 20.0 && angle >= 0.0) minesRight = true; } } // Don't collide with other tanks either vector<int> nearbySweepers = GetNearbySweepers(tanks, CParams::iSweeperScale + 10); for(int i=0; i < nearbySweepers.size(); i++){ SVector2D direction = tanks[nearbySweepers[i]].Position() - fakePosition; double angle = Vec2DAngle(m_vLookAt, direction) * 180 / CParams::dPi; // Which quadrant does the mine fall into if(angle >= -20.0 && angle < 0.0) minesLeft = true; else if(angle <= 20.0 && angle >= 0.0) minesRight = true; } // Set the inputs to the MLP of where the mines are located. mlp.SetNodeInput(0, minesLeft); mlp.SetNodeInput(1, minesRight); mlp.CalculateOutput(); // Our MLP outputs steering directions in the range 0.1-0.9. First we standardize it to 0-1.0. double output = (mlp.GetOutput(0) - 0.1) / 0.8; if (output <= 0.499 || output >= 0.501) steering = output; // Next we need to use this output in the form -0.3-0.3. double convertedRotation = (steering * CParams::dMaxTurnRate * 2.0) - CParams::dMaxTurnRate; //TODO: calculate the steering forces here, it is set to 0 for now... double RotForce = convertedRotation; //clamp rotation Clamp(RotForce, -CParams::dMaxTurnRate, CParams::dMaxTurnRate); m_dRotation += RotForce; // Grab our calculated speed. m_dSpeed = (((mlp.GetOutput(1) - 0.1) / 0.8) * CParams::dMaxSpeed); //update Look At m_vLookAt.x = -sin(m_dRotation); m_vLookAt.y = cos(m_dRotation); //update position m_vPosition += (m_vLookAt * m_dSpeed); //wrap around window limits if (m_vPosition.x > CParams::WindowWidth) m_vPosition.x = 0; if (m_vPosition.x < 0) m_vPosition.x = CParams::WindowWidth; if (m_vPosition.y > CParams::WindowHeight) m_vPosition.y = 0; if (m_vPosition.y < 0) m_vPosition.y = CParams::WindowHeight; return true; }