From c5720e7925a446040fca5f91130baf51a45dac23 Mon Sep 17 00:00:00 2001 From: hikerstk Date: Tue, 23 Oct 2012 21:13:17 +0000 Subject: [PATCH] Fixed sing a skidding probability (before the random number was tested each frame, making it mostly certain that skidding was done). git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@11748 178a84e3-b1eb-0310-8ba1-8eac791a3b58 --- src/karts/controller/skidding_ai.cpp | 30 +++++++++++++++------------- src/karts/controller/skidding_ai.hpp | 15 +++++++++----- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/karts/controller/skidding_ai.cpp b/src/karts/controller/skidding_ai.cpp index 93ace0130..537056037 100644 --- a/src/karts/controller/skidding_ai.cpp +++ b/src/karts/controller/skidding_ai.cpp @@ -185,6 +185,7 @@ void SkiddingAI::reset() m_current_track_direction = GraphNode::DIR_STRAIGHT; m_item_to_collect = NULL; m_avoid_item_close = false; + m_skid_probability_state = SKID_PROBAB_NOT_YET; AIBaseController::reset(); m_track_node = QuadGraph::UNKNOWN_SECTOR; @@ -2172,35 +2173,36 @@ bool SkiddingAI::doSkid(float steer_fraction) void SkiddingAI::setSteering(float angle, float dt) { float steer_fraction = angle / m_kart->getMaxSteerAngle(); + + // Use a simple finite state machine to make sure to randomly decide + // whether to skid or not only once per skid section. See docs for + // m_skid_probability_state for more details. if(!doSkid(steer_fraction)) { - m_tried_skid_last_frame = false; - m_controls->m_skid = KartControl::SC_NONE; + m_skid_probability_state = SKID_PROBAB_NOT_YET; + m_controls->m_skid = KartControl::SC_NONE; } else { KartControl::SkidControl sc = steer_fraction > 0 ? KartControl::SC_RIGHT : KartControl::SC_LEFT; - if(!m_tried_skid_last_frame) + if(m_skid_probability_state==SKID_PROBAB_NOT_YET) { - float distance = - m_world->getOverallDistance(m_kart->getWorldKartId()) - - m_distance_to_player; - int prob = (int) - (100.0f*m_ai_properties->getSkiddingProbability(distance)); - - if(m_random_skid.get(100)>=prob) - sc = KartControl::SC_NONE; + int prob = (int)(100.0f*m_ai_properties + ->getSkiddingProbability(m_distance_to_player)); + m_skid_probability_state = (m_random_skid.get(100)>=prob) + ? SKID_PROBAB_SKID + : SKID_PROBAB_NO_SKID; #undef PRINT_SKID_STATS #ifdef PRINT_SKID_STATS printf("%s distance %f prob %d skidding %s\n", m_kart->getIdent().c_str(), distance, prob, - sc==0 ? "no" : sc==KartControl::SC_LEFT ? "left" : "right"); + sc= ? "no" : sc==KartControl::SC_LEFT ? "left" : "right"); #endif } - m_controls->m_skid = sc; - m_tried_skid_last_frame = true; + m_controls->m_skid = m_skid_probability_state == SKID_PROBAB_SKID + ? sc : KartControl::SC_NONE; } // Adjust steer fraction in case to be in [-1,1] diff --git a/src/karts/controller/skidding_ai.hpp b/src/karts/controller/skidding_ai.hpp index 9d6ddfda5..a92d34bc0 100644 --- a/src/karts/controller/skidding_ai.hpp +++ b/src/karts/controller/skidding_ai.hpp @@ -115,11 +115,16 @@ private: /** A random number generator to decide if the AI should skid or not. */ RandomGenerator m_random_skid; - /** True if the AI decided to skid in the previous frame. At the - * beginning of each skid it is randomly decided if the skid is - * to be done or not (to rubber-band the AI). This flag is used - * to decide if a new skid is happening. */ - bool m_tried_skid_last_frame; + /** This implements a simple finite state machine: it starts in + * NOT_YET. The first time the AI decides to skid, the state is changed + * randomly (dependeng on skid probability) to N_SKID or SKID. + * As long as the AI keeps on deciding the skid, the state remains + * unchanged (so no new random decision is made) till it decides + * not to skid. In which case the state is set to NOT_YET again. + * This guarantees that for each 'skidable' section of the track + * the random decision is only done once. */ + enum {SKID_PROBAB_NOT_YET, SKID_PROBAB_NO_SKID, SKID_PROBAB_SKID} + m_skid_probability_state; /** Which of the three Point Selection Algorithms (i.e. * findNoNCrashingPoint* functions) to use: