Exemplo n.º 1
0
    def checkSkip(self, sim, newX, newY, newFacing):
        """check if this displacement skips any space
        """
        if abs(sim.posX - newX) - sim.width > 0 or abs(sim.posY -
                                                       newY) - sim.height > 0:
            #print "skipping %s from: (%.2f, %.2f) to: (%.2f, %.2f)" %( sim, sim.posX, sim.posY, newX, newY)
            # create a bounding box to fit in the skipped area
            skipBox = AABB()
            skipBox.computeFor(sim)

            # calculate skip box values
            dx = newX - sim.posX
            dy = newY - sim.posY

            if dx > 0:
                xMultiplier = 1
            else:
                xMultiplier = -1
            if dy > 0:
                yMultiplier = 1
            else:
                yMultiplier = -1

            if dy == 0:
                skipWidth = sim.width * xMultiplier
                skipHeight = 0
            elif dx == 0:
                skipWidth = 0
                skipHeight = sim.height * yMultiplier
            else:
                ratio = float(abs(dx)) / float(abs(dy))
                if ratio > (float(sim.width) / sim.height):
                    skipWidth = sim.width * xMultiplier
                    skipHeight = (sim.width / ratio) * yMultiplier
                else:
                    skipWidth = (sim.height * ratio) * xMultiplier
                    skipHeight = sim.height * yMultiplier

            #print "dx %.2f dy %.2f skipWidth %.2f skipHeight %.2f " % (dx, dy, skipWidth, skipHeight)
            # move the skipBox to the first position
            skipPosX = sim.posX + skipWidth
            skipPosY = sim.posY + skipHeight

            # move the skipbox along the path
            while 1:
                skipBox.transform(skipPosX, skipPosY, newFacing)
                result = self.checkCollideAABB(skipBox, sim, skipPosX,
                                               skipPosY, newFacing)
                if result:
                    return result
                if abs(newX - skipPosX) <= sim.width and abs(
                        newY - skipPosY) <= sim.height:
                    break
                skipPosX += skipWidth
                skipPosY += skipHeight

        return 0
Exemplo n.º 2
0
class SimObject:
    """ A Simulation object in a two-dimensional space. 
    """
    def __init__(self, category, drawCallback=None):
        self.category = category
        self.mobile = category.mobile  # is object mobile
        self.life = category.life  # lifetime (seconds)
        self.collide = category.collide  # collision flag
        self.threshold = category.threshold  # variable update frequency

        # create my graphics object
        self.graphicsObject = engine.GraphicsObject(category.source,
                                                    self.mobile,
                                                    category.image,
                                                    drawCallback)

        # find out the size of my graphics object
        result = self.graphicsObject.getSimData()
        (self.centerX, self.centerY, self.width, self.height) = result

        self.posX = 0  # current X position
        self.posY = 0  # current Y position
        self.velocityX = 0  # current X velocity
        self.velocityY = 0  # current Y velocity
        self.facing = 0  # current facing (degrees)
        self.turnRate = 0  # degrees / second
        self.accel = 0  # speed / second
        self.alive = 1  # flag for staying alive
        self.uDelay = 0  # update delay
        self.uTimer = 0  # update timer
        self.aabb = AABB()
        self.aabb.computeFor(self)
        self.removeCallback = None  # callback when removed from the world
        self.handle = 0

    def __del__(self):
        self.graphicsObject.destroy()

    def setState(self, posX, posY, facing, speed=0):
        """Set the simulation state of the object.
        """
        self.posX = posX
        self.posY = posY
        self.facing = facing
        self.calculateVelocity(speed, facing)
        self.graphicsObject.setState(posX, posY, facing)

    def calculateVelocity(self, speed, facing):
        radians = toRadians(self.facing)
        self.velocityX = math.cos(radians) * speed
        self.velocityY = math.sin(
            radians) * speed  # negative for anti-clockwise

    def update(self, interval, world):
        """update an object's physical state for an interval.
        """
        if self.threshold and self.uDelay:
            self.uTimer += interval
            if self.uTimer < self.uDelay:
                return
            else:
                interval = self.uTimer
                self.uTimer -= self.uDelay

        radians = toRadians(self.facing)
        if self.accel:
            dx = math.cos(radians) * self.accel * interval
            dy = math.sin(radians) * self.accel * interval
            ##print "dx:", dx
            self.velocityX += dx
            self.velocityY += dy

        newPosX = self.posX + (self.velocityX * interval)
        newPosY = self.posY + (self.velocityY * interval)

        if self.turnRate:
            newFacing = self.facing + self.turnRate * interval
            newFacing = newFacing % 360
        else:
            newFacing = self.facing

        if world.canMove(self, newPosX, newPosY, newFacing):
            self.posX = newPosX
            self.posY = newPosY
            self.facing = newFacing
            world.move(self, newPosX, newPosY, newFacing)
            self.graphicsObject.setState(newPosX, newPosY, newFacing)

        if self.life:
            self.life -= interval
            if self.life <= 0:
                self.alive = 0

        # calculate the variable delay
        if self.threshold:
            value = max(abs(self.velocityX), abs(self.velocityY),
                        abs(self.turnRate))
            if value < self.threshold:
                self.uDelay = 1.0 - (value / self.threshold)
            else:
                self.uDelay = 0

        return self.alive

    def hit(self, other, newPosX, newPosY, newFacing):
        """Called when I hit another object.
        """
        self.velocityX = -(self.velocityX * 0.9)
        self.velocityY = -(self.velocityY * 0.9)
        self.accel = 0
        self.turnRate = -(self.turnRate * 0.9)
        return 1

    def setImage(self, image):
        """Change the image of this object"""
        engine.removeObject(self.graphicsObject)
        self.graphicsObject.image = image
        engine.addObject(self.graphicsObject, self.posX, self.posY,
                         self.facing)

    def setRemoveCallback(self, callback):
        self.removeCallback = callback

    def findOffset(self, direction, distance):
        """find a position in a direction a distance from the center of the sim.
        """
        radians = toRadians(direction)
        dx = math.cos(radians) * distance
        dy = math.sin(radians) * distance
        return (self.posX + dx, self.posY + dy)

    def findHitDirections(self, other, newPosX, newPosY, newFacing):
        """Determine what direction(s) an object should bounce.
        This should only be called from within the "hit" method of
        this class.
        """
        hitX = 0
        hitY = 0

        # test for world extents first
        if not isinstance(other, SimObject):
            if other == collision.WEST or other == collision.EAST:
                hitX = 1
            if other == collision.NORTH or other == collision.SOUTH:
                hitY = 1
            return (hitX, hitY)

        aabb = copy.copy(self.aabb)

        # test if collide if just X is changed
        aabb.transform(newPosX, self.posY, newFacing)
        hitX = aabb.checkCollide(other.aabb)

        # test if collide if just Y is changed
        aabb.transform(self.posX, newPosY, newFacing)
        hitY = aabb.checkCollide(other.aabb)

        # set both if neither hits alone
        if not hitY and not hitX:
            hitY = 1
            hitX = 1
        return (hitX, hitY)

    def __del__(self):
        pass