Example #1
0
    def closestItem(self, variant=Items.All):
        '''
        Get the closest item on the ground to this agent. Optionally specify additional modifiers for filtering
        items by an enumerated type. Returns None if no item was found nearby to this agent.
        '''
        # Check for override
        if self.__shouldPerformActionOverride(self.closestItem):
            self.__actionOverride.function(*self.__actionOverride.args)
            return None

        aPos = self.__position()
        nearbyEntities = self.nearbyEntities()
        if variant == Items.All:
            comparator = Items.All.isMember
        elif variant == Items.Food:
            comparator = Items.Food.isMember
        else:
            raise Exception("Closest item variant must be an enumerated type")

        closestDistance = 1000000.0
        closestItem = None
        for entity in nearbyEntities:
            if comparator(entity.type):
                ePos = entity.position
                distance = MathUtils.distanceBetweenPoints(aPos, ePos)
                if distance < closestDistance:
                    closestDistance = distance
                    closestItem = entity
        self.__logReports.append(LogUtils.ClosestItemReport(variant, closestItem))
        return closestItem
Example #2
0
    def __calculateTargetYawRate(self, targetPos):
        '''
        Calculate the rate at which to move the agent's POV left/right in order to face an (x,y,z) position.
        '''
        aJSON = self.toJSON()
        aPos = self.__position()
        currAngle = aJSON["Yaw"] if aJSON["Yaw"] >= 0 else 360.0 - abs(aJSON["Yaw"])
        vec = MathUtils.vectorFromPoints(aPos, targetPos)
        vec = MathUtils.normalizeVector(vec)

        # Convert target position to a target angle (360 degrees)
        if MathUtils.valuesAreEqual(vec.x, 0):
            if vec.z >= 0:
                targetAngle = -MathUtils.PI_OVER_TWO
            else:
                targetAngle = MathUtils.PI_OVER_TWO
        else:
            targetAngle = math.atan(vec.z / vec.x)

        # Modify target angle based on which quadrant the vector lies in
        if vec.x <= 0:   # quadrant 1 or 2
            targetAngle = MathUtils.PI_OVER_TWO + targetAngle
        else:
            targetAngle = MathUtils.THREE_PI_OVER_TWO + targetAngle
        targetAngle = math.degrees(targetAngle)
        if MathUtils.valuesAreEqual(targetAngle, 360.0):
            targetAngle = 0

        # Get difference between current and target angle
        if currAngle <= targetAngle:
            angleDiff = min(targetAngle - currAngle, 360 - targetAngle + currAngle)
        else:
            angleDiff = min(currAngle - targetAngle, 360 - currAngle + targetAngle)

        # Get the turning direction
        if currAngle > targetAngle and currAngle - targetAngle < 180:
            turnDirection = -1
        elif targetAngle > currAngle and targetAngle - currAngle > 180:
            turnDirection = -1
        else:
            turnDirection = 1

        # Calculate the turning rate
        rate = MathUtils.affineTransformation(angleDiff, 0.0, 180.0, 0, 1.0) * 4 * turnDirection
        rate = min(rate, 1) if rate >= 0 else max(rate, -1)
        return rate
Example #3
0
    def __isAt(self, targetPos, minTol=0.0, maxTol=STRIKING_DISTANCE):
        '''
        Returns true if the agent is currently at the given (x,y,z) position within tolerance.
        Tolerance values are as follows:

            minTol: Agent must be no closer than this value
            maxTol: Agent must be closer than this value
        '''
        aPos = self.__position()
        distance = MathUtils.distanceBetweenPointsXZ(aPos, targetPos)
        if distance >= minTol and distance <= maxTol:
            return True
        else:
            return False
Example #4
0
    def moveTo(self, entity):
        '''
        Begin moving the agent to the given entity. Returns true if the agent is at the entity,
        false otherwise.

            Preconditions:
                - The agent is looking at the entity
        '''
        # Check for override
        if self.__shouldPerformActionOverride(self.moveTo):
            return self.__actionOverride.function(*self.__actionOverride.args)

        minTol = 0.0
        maxTol = STRIKING_DISTANCE

        # If entity is an agent, represent it as an entity
        if isinstance(entity, Agent):
            entity = Entity(entity.id, "agent", entity.__position(), 1)
            minTol = 2.0
            maxTol = GIVING_DISTANCE

        # Preconditions
        if not self.__checkPreconditions(self.__isLookingAt(entity.position)):
            self.stopMoving()
            return False

        # Items are a special case since they can be picked up. Once close, lock down on the pickUpItem action.
        if Items.All.isMember(entity.type):
            distanceToItem = MathUtils.distanceBetweenPointsXZ(self.__position(), entity.position)
            if distanceToItem <= PICK_UP_ITEM_LOCKDOWN_DISTANCE:
                currentInventoryAmt = self.inventory.amountOfItem(entity.type)
                self.__actionOverride = Agent.ActionOverride(self.__pickUpItem, [entity, currentInventoryAmt])
                return self.__pickUpItem(entity, currentInventoryAmt)

        # Action
        if self.__moveToPosition(entity.position, minTol, maxTol):
            self.__stopWalking()
            self.__logReports.append(LogUtils.MoveToReport(entity))
            return True
        else:
            return False
Example #5
0
    def __moveToPosition(self, targetPos, minTol=0.0, maxTol=STRIKING_DISTANCE, hardStop=True):
        '''
        Command the agent to begin walking forwards or backwards in order to reach the given target
        (x,y,z) position within tolerance. Returns true if the agent is at the target, false otherwise.
        This function takes several optional arguments:

            minTol: Agent must be no closer than this value
            maxTol: Agent must be closer than this value
            hardStop: Once within tolerance, should the agent come to a complete stop, or slow down
        '''
        aPos = self.__position()
        distance = MathUtils.distanceBetweenPointsXZ(aPos, targetPos)
        if distance >= minTol and distance <= maxTol:
            if hardStop:
                self.stopMoving()
            else:
                self.__startWalking(0.4)
            return True
        elif distance > maxTol:
            self.__startWalking(1)
            return False
        else:
            self.__startWalking(-1)
            return False
Example #6
0
    def __isLookingAt(self, targetPos, pitchRate=None, yawRate=None):
        '''
        Returns true if the agent is currently looking at the given (x,y,z) position.
        Optionally provide the pitch and yaw turning rates if they were already previously calculated.
        '''
        pitchRate = pitchRate if pitchRate != None else self.__calculateTargetPitchRate(targetPos)
        yawRate = yawRate if yawRate != None else self.__calculateTargetYawRate(targetPos)

        # Tolerance depends on how close we are to the target
        aPos = self.__position()
        distance = MathUtils.distanceBetweenPoints(aPos, targetPos)

        # If we are close to target and yaw is 1, there is a chance we got stuck and are
        # circling the target. Step back and return false for this iteration..
        # if distance < 2 and yawRate > .9:
        #     self.__startWalking(-1)
        #     time.sleep(0.2)
        #     self.stopMoving()
        #     return False

        if distance < 2:
            return abs(pitchRate) <= .4 and abs(yawRate) <= .4
        else:
            return abs(pitchRate) <= .2 and abs(yawRate) <= .2
Example #7
0
    def __calculateTargetPitchRate(self, targetPos):
        '''
        Calculate the rate at which to move the agent's POV up/down in order to face an (x,y,z) position.
        '''
        aJSON = self.toJSON()
        aPos = self.__position()
        currAngle = aJSON["Pitch"]
        vec = MathUtils.vectorFromPoints(aPos, targetPos)
        vec = MathUtils.normalizeVector(vec)
        trimmedVec = Vector(vec.x, 0, vec.z)

        # Convert target position to a target angle (-90 to 90 degrees)
        if MathUtils.isZeroVector(trimmedVec):
            return 0.0
        cos = MathUtils.dotProduct(vec, trimmedVec) / (MathUtils.vectorMagnitude(vec) * MathUtils.vectorMagnitude(trimmedVec))
        if cos > 1:
            cos = 1
        elif cos < -1:
            cos = -1
        targetAngle = math.acos(cos)
        if vec.y > 0:
            targetAngle = -targetAngle
        targetAngle = math.degrees(targetAngle)

        # Get difference between current and target angle
        if currAngle <= targetAngle:
            angleDiff = targetAngle - currAngle
        else:
            angleDiff = currAngle - targetAngle

        # Get the turning direction
        if currAngle > targetAngle:
            turnDirection = -1
        else:
            turnDirection = 1

        # Calculate the turning rate
        rate = MathUtils.affineTransformation(angleDiff, 0.0, 180.0, 0, 1.0) * 4 * turnDirection
        rate = min(rate, 1) if rate >= 0 else max(rate, -1)
        return rate