def calcAction(self): # TODO: make this settable soonThreshold = 50.0 # TODO: consider re-factoring using BrainConditional (or something like it) # TODO: this is hardwired to only avoid static obstacles if soonThreshold < self.percepts.myTimeToCollision() or (self.percepts.myNextCollider() and Inf != self.percepts.nextCollider.mass): # No collision danger time = self.percepts.getTime() # How many milliseconds to wait after a potential collision was detected before # resuming with the default controller. TODO: consider making a settable class variable. delay = 0.5 if self.timeLastCollisionDetected < 0 or delay < time - self.timeLastCollisionDetected: self.defaultBrain.calcAction() self.action = self.defaultBrain.action else: # Just continue with last action. # TODO: consider some time discounted blend of default controller and # avoidance vector. pass return self.timeLastCollisionDetected = self.percepts.getTime() # Collision danger present so need to take evasive action. self.rp = vec.normalize(self.percepts.myNextCollisionPoint() - self.percepts.myPosition(), self.rp) self.tmp = util2D.perpendicularTo(self.rp, self.percepts.myNextCollider().normalTo(self.percepts.getMe(), self.tmp), self.tmp)[0] assert util.isAlmostZero(vec.dot(self.rp, self.tmp)) self.action.setDirection(self.tmp) # TODO: modulate the speed based on time until collision and whatever the defaultControler # set it to. self.action.setSpeed(1.0)
def resolveCollisions(self): e = 0.75 # coefficient of restitution minTagInterval = 3.0 # minimum time allowed between re-tagging now = timer.getTime() loopCount = 0 while True: isCollision = False for i in self.gs.characters: for j in self.gs.characters: if i == j: continue if not i.isColliding(j): continue isCollision = True # We have to keep computing these in case they changed in a previous collision uc = i.getVelocity() mc = i.mass self.t = i.normalTo(j, self.t) self.n = util2D.perpendicularTo(self.t, self.n, self.nTmp)[0] uct = dot(uc, self.t) ucn = dot(uc, self.n) mo = j.mass uo = j.getVelocity() uot = dot(uo, self.t) uon = dot(uo, self.n) k = (uct - uot)/(mc + mo) vct = uct - (1 + e) * mo * k vot = uot + (1 + e) * mc * k i.setVelocity(vec.scale(self.t, vct, self.vt) + vec.scale(self.n, ucn, self.vn)) j.setVelocity(vec.scale(self.t, vot, self.vt) + vec.scale(self.n, uon, self.vn)) # TODO: limit re-tagging restriction to previously tagged character only if j.tagged and minTagInterval < now - self.gs.lastTagTime: self.gs.setTagged(i, j, now) elif i.tagged and minTagInterval < now - self.gs.lastTagTime: self.gs.setTagged(j, i, now) for j in self.gs.nonCharacterObstacles: if not i.isColliding(j): continue isCollision = True uc = i.getVelocity() self.t = i.normalTo(j, self.t) self.n = util2D.perpendicularTo(self.t, self.n, self.nTmp)[0] uct = dot(uc, self.t) ucn = dot(uc, self.n) vct = -e * uct i.setVelocity(vec.scale(self.t, vct, self.vt) + vec.scale(self.n, ucn, self.vn)) if not isCollision: break assert loopCount < 1000, "something probably went wrong" loopCount += 1