Exemple #1
0
def _distToWall(pos, angle, sWidth, w, h):
    "Calculate the distance to the sketch walls in the specified direction"
    walls = Polygon([(0,0), (w,0), (w,h), (0,h)])
    w += h
    pts = []
    for n in (-1, 0, 1):
        v = vec2d(w, angle + n * sWidth)
        line = Line(pos, vector=v)
        pts.extend(walls.intersect(line))
    return min(dist(pos, pt) for pt in pts) if len(pts) else None
Exemple #2
0
def _distToWall(pos, angle, sWidth, w, h):
    "Calculate the distance to the sketch walls in the specified direction"
    walls = Polygon([(0, 0), (w, 0), (w, h), (0, h)])
    w += h
    pts = []
    for n in (-1, 0, 1):
        v = vec2d(w, angle + n * sWidth)
        line = Line(pos, vector=v)
        pts.extend(walls.intersect(line))
    return min(dist(pos, pt) for pt in pts) if len(pts) else None
Exemple #3
0
    def frameStep(self):
        "Update robot sprite each frame"

        # Target wheel speed...
        v = self.maxSpeed
        v1, v2 = self._motors
        v1 *= v
        v2 *= v

        # Angular speed and turning radius...
        w = (v1 - v2) / (2 * self.radius)
        self.spin = w / DEG
        if w:
            R = (v1 + v2) / (2 * w)
            v = w * R
        else:
            v = v1

        # Acceleration...
        v = vec2d(v, self.angle * DEG)
        self.accel = times(sub(v, self.velocity), 0.05)

        # Update...
        super().frameStep()

        # Draw penColor on background...
        if self.penColor:  # and self._penPosn:
            srf = self.sketch.scaledBgImage.surface
            x, y = self.posn
            xy = (round(x), round(y)) if self.centerPen else self._penPosn
            circle(srf, self.penColor, xy, self.penRadius)

        # Check sensors...
        stall = not self.motorsOff and (self.edgeAdjust or self.collideUpdate)
        if stall:
            if self._stallTime is None:
                self._stallTime = self.sketch.time if stall else None
        else:
            self._stallTime = None
        self.downColor = self._downColor()
        self._closest_obstacle()
        if self._starting: self._starting = False

        # Adjust wheel speed...
        self.costumeTime = 0 if self.motorsOff else round(
            36 / (1 + 5 * self.averagePower))

        # Log destruction of robot...
        if self._thread is not None and self._thread.log and self in self.sketch.sprites._toRemove:
            print("{} has been destroyed... there goes a billion dollars!".
                  format(self._thread))
Exemple #4
0
 def _checkDown(self):
     "Update the down color sensor"
     x, y = self.rect.center
     r = 0.8 * self.radius
     dx, dy = vec2d(r, self.angle)
     r = max(1, round(0.25 * r))
     d = 2 * r
     sk = self.sketch
     r = pygame.Rect(x + dx - r, y + dy - r, d, d).clip(sk.rect)
     if r.width:
         if isinstance(sk.bg, Image):
             c = pygame.transform.average_color(sk.bg.image.subsurface(r))
         else: c = sk.bg
     else: c = 0, 0, 0
     self.sensorDown = noise(c, self.sensorNoise, 255)
Exemple #5
0
    def ondraw(self):
        "Update robot sprite each frame"

        if not self.active: raise InactiveError()

        # Target wheel speed...
        sk = self.sketch
        v = self.maxSpeed * sk.width
        v1, v2 = self._motors
        v1 *= v
        v2 *= v

        # Angular speed and turning radius...
        w = (v1 - v2) / (2 * self.radius)
        self.spin = w / DEG
        if w:
            R = (v1 + v2) / (2 * w)
            v = w * R
        else:
            v = v1

        # Acceleration...
        v = vec2d(v, self.angle)
        a = delta(v, self.vel)
        if hypot(*a) > 0.05:
            self.acc = delta(a, mag=0.05)
        else:
            self.vel = v
            self.acc = 0, 0

        # Adjust wheel speed...
        p = self.power
        self.costumeTime = 0 if p == 0 else round(36 / (1 + 5 * p))

        # Update position and angle...
        super().ondraw()

        # Update sensors if requested...
        if self._updateSensors:
            try:
                self._checkDown()
                self._checkFront()
                self._drawLEDs()
                self._updateSensors = False
            except:
                logError()
        self._startup = False
Exemple #6
0
    def __init__(self, ship):
        "Fire a new missile from the ship"
        super().__init__(self.original)

        # Initial position of missile
        u = vec2d(1.3 * ship.radius, ship.angle)
        pos = ship.pos[0] + u[0], ship.pos[1] + u[1]

        # Initial velocity of missile
        u = delta(u, mag=ship.sketch.height / 135)
        vel = ship.vel[0] + u[0], ship.vel[1] + u[1]

        self.config(width=ship.width / 4,
                    pos=pos,
                    vel=vel,
                    spin=ship.spin,
                    angle=ship.angle)
Exemple #7
0
 def _checkDown(self):
     "Update the down color sensor"
     x, y = self.rect.center
     r = 0.8 * self.radius
     dx, dy = vec2d(r, self.angle)
     r = max(1, round(0.25 * r))
     d = 2 * r
     sk = self.sketch
     r = pygame.Rect(x + dx - r, y + dy - r, d, d).clip(sk.rect)
     if r.width:
         if isinstance(sk.bg, Image):
             c = pygame.transform.average_color(sk.bg.image.subsurface(r))
         else:
             c = sk.bg
     else:
         c = 0, 0, 0
     self.sensorDown = noise(c, self.sensorNoise, 255)
Exemple #8
0
    def ondraw(self):
        "Update robot sprite each frame"

        if not self.active: raise InactiveError()

        # Target wheel speed...
        sk = self.sketch
        v = self.maxSpeed * sk.width
        v1, v2 = self._motors
        v1 *= v
        v2 *= v

        # Angular speed and turning radius...
        w = (v1 - v2) / (2 * self.radius)
        self.spin = w / DEG
        if w:
            R = (v1 + v2) / (2 * w)
            v = w * R
        else: v = v1

        # Acceleration...
        v = vec2d(v, self.angle)
        a = delta(v, self.vel)
        if hypot(*a) > 0.05:
            self.acc = delta(a, mag=0.05)
        else:
            self.vel = v
            self.acc = 0, 0

        # Adjust wheel speed...
        p = self.power
        self.costumeTime = 0 if p == 0 else round(36 / (1 + 5 * p))

        # Update position and angle...
        super().ondraw()

        # Update sensors if requested...
        if self._updateSensors:
            try:
                self._checkDown()
                self._checkFront()
                self._drawLEDs()
                self._updateSensors = False
            except: logError()
        self._startup = False
Exemple #9
0
    def _checkFront(self):
        "Update the front color sensor"

        # Sensor info
        sw = self.sensorWidth
        res = 0.5 * self.sensorResolution
        pos = delta(self.pos, vec2d(-self.radius, self.angle))

        # Distance from sensor to edge of sketch
        obj = prox = None
        sk = self.sketch
        if sk.weight:
            prox = _distToWall(pos, self.angle, self.sensorWidth, *sk.size)
            if prox: obj = sk

        # Find closest object within "sensor cone"
        for gr in self.sensorObjects(sk):
            if gr is not self and gr.avgColor and hasattr(gr, "rect"):
                r = gr.radius
                view = subtend(pos, gr.rect.center, r,
                               None if prox is None else prox + r)
                if view:
                    # Object may be closer than the current closest object
                    sep, direct, half = view
                    if not res or half > res:
                        # Object size meets sensor resolution threshold
                        beta = abs(angleDifference(self.angle, direct)) - sw
                        if beta < half or sep < r:
                            # Object is in sensor cone
                            pr = sep - r
                            if beta > 0:
                                # CLOSEST point is NOT in sensor cone
                                dr = r + sep * (cos(half * DEG) - 1)
                                pr += dr * (beta / half)**2
                            if prox is None or pr < prox:
                                # Object is closest (so far)
                                prox = pr
                                obj = gr

        # Save data
        self.closestObject = obj
        c = rgba(sk.border if obj is sk else obj.avgColor if obj else (0, 0,
                                                                       0))
        self.sensorFront = noise(divAlpha(c), self.sensorNoise, 255)
        self.proximity = None if prox is None else max(0, round(prox))
Exemple #10
0
    def scroll(self, pix=None, rel=True):
        # Calculate scroll when not specified
        a = self.angle
        if pix is None: pix = self.focussed and a in (0, 90)
        if pix is False: pix, rel = 0, False
        elif pix is True: pix, rel = self._scrollCalc(a)

        # Set scrolling attributes
        if pix or not rel:
            if rel: self._scrollX += pix
            else:
                tmp = pix
                pix -= self._scrollX
                self._scrollX = tmp
            if pix:
                if a == 90: self.pos = self.pos[0], self.pos[1] + pix
                else: self.pos = sigma(self.pos, vec2d(pix, a))
        return self
Exemple #11
0
    def __init__(self, sk):
        "Create a new asteroid"
        super().__init__(self.original)

        # Random size and mass
        m = uniform(1, 100)
        w = pow(m, 1 / 3) / 100 * sk.width

        # Random position and velocity
        pos = randint(0, sk.width - 1), -w
        vel = uniform(0.25, 1) * sk.asteroidSpeed
        vel = vec2d(vel, uniform(10, 170))

        self.config(width=w,
                    wrap=BOTH,
                    pos=pos,
                    vel=vel,
                    spin=uniform(-2, 2),
                    mass=m)
Exemple #12
0
    def _checkFront(self):
        "Update the front color sensor"

        # Sensor info
        sw = self.sensorWidth
        res = 0.5 * self.sensorResolution
        pos = delta(self.pos, vec2d(-self.radius, self.angle))
    
        # Distance from sensor to edge of sketch
        obj = prox = None
        sk = self.sketch
        if sk.weight:
            prox = _distToWall(pos, self.angle, self.sensorWidth, *sk.size)
            if prox: obj = sk

        # Find closest object within "sensor cone"
        for gr in self.sensorObjects(sk):
            if gr is not self and gr.avgColor and hasattr(gr, "rect"):
                r = gr.radius
                view = subtend(pos, gr.rect.center, r, None if prox is None else prox + r)
                if view:
                    # Object may be closer than the current closest object
                    sep, direct, half = view
                    if not res or half > res:
                        # Object size meets sensor resolution threshold
                        beta = abs(angleDifference(self.angle, direct)) - sw
                        if beta < half or sep < r:
                            # Object is in sensor cone
                            pr = sep - r
                            if beta > 0:
                                # CLOSEST point is NOT in sensor cone
                                dr = r + sep * (cos(half * DEG) - 1)
                                pr += dr * (beta / half) ** 2
                            if prox is None or pr < prox:
                                # Object is closest (so far)
                                prox = pr
                                obj = gr

        # Save data
        self.closestObject = obj
        c = rgba(sk.border if obj is sk else obj.avgColor if obj else (0,0,0))
        self.sensorFront = noise(divAlpha(c), self.sensorNoise, 255)
        self.proximity = None if prox is None else max(0, round(prox))
Exemple #13
0
 def _downColor(self):
     "Calculate downward colour-sensor value"
     d = self.radius // 8
     r = 2 * d
     size = r, r
     r = 0.75 * self.radius
     posn = vsum(vec2d(r, self.angle * DEG), self.posn, (-d, -d))
     sk = self.sketch
     self._downRect = Rect(posn + size)
     if sk.sprites._debugCollide:
         Image(size, self.downColor).blitTo(posn=posn)
     try:
         if sk.bgImage:
             srf = sk.scaledBgImage.surface.subsurface(posn + size)
         else:
             srf = None
         if sk.bgColor:
             img = Image(size, sk.bgColor)
             if srf: img.surface.blit(srf, (0, 0))
         else:
             img = Image(srf)
         return noise(img.averageColor(), self.sensorNoise, alpha=255)
     except:
         return None
Exemple #14
0
    def _detectObstacles(self, cone=0, steps=None, group=None):
        "Detect obstacles in front of the robot"
        sk = self.sketch
        if steps is None: steps = max(1, cone)
        if group is None:
            #            group = self.spriteList.search(status=VISIBLE)
            group = [s for s in self.spriteList if s.status == VISIBLE]
        if sk.wall:
            group = set(group) | set(self.sketch._wallPoly.segments)

        obst = {}
        r = sum(sk.size)
        stepAngle = cone / steps
        angle = -cone / 2
        while steps >= 0:
            a = (self.angle + angle) * DEG
            seg = Segment(self.posn, add(self.posn, vec2d(r, a)))
            if sk.sprites._debugCollide:
                line(sk.surface, (0, 0, 0), self.posn, seg.eval())
            for s in group:
                if s is not self:
                    shape = s.shape if isinstance(s, Sprite) else s
                    pts = shape.intersect2d(seg)
                    minSep = None
                    for pt in pts:
                        r2 = distSq(pt, self.posn)
                        if minSep is None or r2 < minSep:
                            minSep = r2
                    if minSep:
                        obst[None if s is shape else s] = sqrt(minSep)
            if cone:
                angle += stepAngle
                steps -= 1
            else:
                steps = -1
        return obst
Exemple #15
0
 def onbounce(self, wall):
     v, a = polar2d(*self.vel)
     self.vel = vec2d(v, a + uniform(-5, 5))
     self.oncollide()
Exemple #16
0
 def onbounce(self, wall):
     v, a = polar2d(*self.vel)
     self.vel = vec2d(v, a + uniform(-5, 5))
     self.oncollide()