Exemplo n.º 1
0
Arquivo: level.py Projeto: ikn/wvoas
 def init (self, ID = None, cp = None):
     self.paused = False
     self.dying = False
     self.first_dying = False
     self.winning = False
     self.fading = False
     self.particles = []
     self.particle_rects = []
     self.void_jitter = [conf.VOID_JITTER_X, conf.VOID_JITTER_Y, conf.VOID_JITTER_T]
     self.first = True
     # get level/current checkpoint
     if ID is None:
         # same level
         ID = self.ID
     if ID != self.ID:
         # new level
         self.ID = ID
         self.current_cp = cp if cp is not None else -1
         # clouds: randomise initial positions and velocities
         self.clouds = cs = []
         w, h = conf.RES
         imgs = self.imgs
         vx0 = conf.CLOUD_SPEED
         vy0 = vx0 * conf.CLOUD_VERT_SPEED_RATIO
         self.cloud_vel = [vx0 * random0(), vy0 * random0()]
         vx = conf.CLOUD_MOD_SPEED_RATIO
         vy = vx * conf.CLOUD_VERT_SPEED_RATIO
         for c in conf.CLOUDS:
             c_w, c_h = imgs[c].get_size()
             s = (c_w, c_h)
             c_w /= 2
             c_h /= 2
             pos = [randint(-c_w, w - c_w), randint(-c_h, h - c_h)]
             vel = [vx * random0(), vy * random0()]
             cs.append((pos, vel, s))
     elif cp is not None:
         self.current_cp = cp
     data = conf.LEVELS[ID]
     # background
     self.bgs = data.get('bgs', conf.DEFAULT_BGS)
     # player
     if self.current_cp >= 0:
         p = list(data['checkpoints'][self.current_cp][:2])
         s_p, s_c = conf.PLAYER_SIZE, conf.CHECKPOINT_SIZE
         for i in (0, 1):
             p[i] += float(s_c[i] - s_p[i]) / 2
     else:
         p = data['player_pos']
     self.player = Player(self, p)
     # window
     x, y = Rect(self.to_screen(self.player.rect)).center
     w, h = conf.HALF_WINDOW_SIZE
     self.window = Rect(x - w, y - h, 2 * w, 2 * h)
     self.old_window = self.window.copy()
     # checkpoints
     s = conf.CHECKPOINT_SIZE
     self.checkpoints = [Rect(p + s) for p in data.get('checkpoints', [])]
     # goal
     self.goal = Rect(data['goal'] + conf.GOAL_SIZE)
     self.goal_img = self.goal.move(conf.GOAL_OFFSET)
     self.goal_img.size = self.imgs['goal'].get_size()
     # stars
     self.stars = [Star(self, p, [ID, i] in conf.STARS)
                   for i, p in enumerate(data.get('stars', []))]
     if self.star_channel is not None and not all(s.got for s in self.stars):
         self.star_channel.unpause()
     # rects
     self.all_rects = [Rect(r) for r in data.get('rects', [])]
     self.all_vrects = [Rect(r) for r in data.get('vrects', [])]
     self.arects = [Rect(r) for r in data.get('arects', [])]
     self.update_rects()
Exemplo n.º 2
0
# Display object initialization (includes Power-On-Sequence)
disp = PmodOLEDrgb(spi, dc, rst)

# Analog-Digital converter input
adc = ADC(0)  # Caution ! ADC should not have more than 1 volt !

# Array which is storing next frame
dispArr = bytearray(SCREEN_WIDTH * SCREEN_HEIGHT * 2)
fbuf = framebuf.FrameBuffer(dispArr, SCREEN_WIDTH, SCREEN_HEIGHT,
                            framebuf.RGB565)

# Start conditions & positions
ball = Ball(32, 16, 3, 3, 1, -1, SCREEN_WIDTH,
            SCREEN_HEIGHT)  # vx = 2; vx = -2
player = Player(30, SCREEN_HEIGHT - 3, 15, 2, 0, 0)

# Required to calculate dt for first time
tick = time.ticks_ms()

# Execute loop as long as game isnt lost
while not ball.get_game_over():
    ntick = time.ticks_ms()
    ball.update(
        time.ticks_diff(ntick, tick) // 100, player
    )  # the floor division // rounds the result down to the nearest whole number
    tick = ntick
    player.x = adc.read_u16() * (SCREEN_WIDTH - 15) / 1023
    fbuf.fill(0)  # Fill entire framebuf with specific color (0 == black)
    ball.draw(fbuf)  # Inserts current ball position into frame
    player.draw(fbuf)  # Inserts current player platform position into frame
Exemplo n.º 3
0
Arquivo: level.py Projeto: ikn/wvoas
class Level (object):
    def __init__ (self, game, event_handler = None, ID = 0, cp = -1):
        self.game = game
        # input
        if event_handler is not None:
            event_handler.add_event_handlers({
                pg.KEYDOWN: self.skip,
                pg.MOUSEBUTTONDOWN: self.skip
            })
            event_handler.add_key_handlers([
                (conf.KEYS_BACK, self.pause, eh.MODE_ONDOWN),
                (conf.KEYS_RESET, self.reset, eh.MODE_ONDOWN),
                (conf.KEYS_JUMP, self.jump, eh.MODE_ONDOWN_REPEAT, 1, 1)
            ] + [
                (ks, [(self.move, (i,))], eh.MODE_HELD)
                for i, ks in enumerate((conf.KEYS_LEFT, conf.KEYS_RIGHT))
            ])
        w, h = conf.RES
        self.centre = (w / 2, h / 2)
        ww, wh = conf.WINDOW_SIZE
        border = (2 * (ww + 5), 2 * (wh + 5))
        self.window_bds = pg.Rect(0, 0, w, h).inflate(border)
        self.clouds = []
        self.load_graphics()
        if event_handler is not None:
            self.move_channel = game.move_channel
            self.star_channel = game.star_channel
        else:
            self.move_channel = None
            self.star_channel = None
        # load first level
        self.ID = None
        self.init(ID, cp)

    def init (self, ID = None, cp = None):
        self.paused = False
        self.dying = False
        self.first_dying = False
        self.winning = False
        self.fading = False
        self.particles = []
        self.particle_rects = []
        self.void_jitter = [conf.VOID_JITTER_X, conf.VOID_JITTER_Y, conf.VOID_JITTER_T]
        self.first = True
        # get level/current checkpoint
        if ID is None:
            # same level
            ID = self.ID
        if ID != self.ID:
            # new level
            self.ID = ID
            self.current_cp = cp if cp is not None else -1
            # clouds: randomise initial positions and velocities
            self.clouds = cs = []
            w, h = conf.RES
            imgs = self.imgs
            vx0 = conf.CLOUD_SPEED
            vy0 = vx0 * conf.CLOUD_VERT_SPEED_RATIO
            self.cloud_vel = [vx0 * random0(), vy0 * random0()]
            vx = conf.CLOUD_MOD_SPEED_RATIO
            vy = vx * conf.CLOUD_VERT_SPEED_RATIO
            for c in conf.CLOUDS:
                c_w, c_h = imgs[c].get_size()
                s = (c_w, c_h)
                c_w /= 2
                c_h /= 2
                pos = [randint(-c_w, w - c_w), randint(-c_h, h - c_h)]
                vel = [vx * random0(), vy * random0()]
                cs.append((pos, vel, s))
        elif cp is not None:
            self.current_cp = cp
        data = conf.LEVELS[ID]
        # background
        self.bgs = data.get('bgs', conf.DEFAULT_BGS)
        # player
        if self.current_cp >= 0:
            p = list(data['checkpoints'][self.current_cp][:2])
            s_p, s_c = conf.PLAYER_SIZE, conf.CHECKPOINT_SIZE
            for i in (0, 1):
                p[i] += float(s_c[i] - s_p[i]) / 2
        else:
            p = data['player_pos']
        self.player = Player(self, p)
        # window
        x, y = Rect(self.to_screen(self.player.rect)).center
        w, h = conf.HALF_WINDOW_SIZE
        self.window = Rect(x - w, y - h, 2 * w, 2 * h)
        self.old_window = self.window.copy()
        # checkpoints
        s = conf.CHECKPOINT_SIZE
        self.checkpoints = [Rect(p + s) for p in data.get('checkpoints', [])]
        # goal
        self.goal = Rect(data['goal'] + conf.GOAL_SIZE)
        self.goal_img = self.goal.move(conf.GOAL_OFFSET)
        self.goal_img.size = self.imgs['goal'].get_size()
        # stars
        self.stars = [Star(self, p, [ID, i] in conf.STARS)
                      for i, p in enumerate(data.get('stars', []))]
        if self.star_channel is not None and not all(s.got for s in self.stars):
            self.star_channel.unpause()
        # rects
        self.all_rects = [Rect(r) for r in data.get('rects', [])]
        self.all_vrects = [Rect(r) for r in data.get('vrects', [])]
        self.arects = [Rect(r) for r in data.get('arects', [])]
        self.update_rects()

    def skip (self, evt):
        if self.dying and self.dying_counter < conf.DIE_SKIP_THRESHOLD and \
           not (evt.type == pg.KEYDOWN and evt.key in conf.KEYS_BACK) and \
           not self.winning:
            self.init()
        elif conf.DEBUG and evt.type == pg.MOUSEBUTTONDOWN:
            r = self.player.rect
            c = self.window.center
            print 'moving to', c
            for i in (0, 1):
                r[i] = c[i] - (r[i + 2] / 2)
            self.player.old_rect = r

    def pause (self, *args):
        if self.move_channel is not None:
            self.move_channel.pause()
        if self.star_channel is not None:
            self.star_channel.pause()
        self.game.start_backend(ui.Paused, self)
        self.paused = True

    def reset (self, *args):
        if not self.winning:
            self.init()

    def jump (self, key, mode, mods):
        self.player.jump(mode == 0)

    def move (self, key, mode, mods, i):
        self.player.move(i)

    def update_window (self):
        w = self.window
        wp0 = w.topleft
        wp1 = w.bottomright
        s = conf.RES
        self.inverse_win = rs = []
        for px in (0, 1, 2):
            for py in (0, 1, 2):
                if px == py == 1:
                    continue
                r = [0, 0, 0, 0]
                for i, p in enumerate((px, py)):
                    if p == 0:
                        r[i + 2] = wp0[i]
                    if p == 1:
                        r[i] = wp0[i]
                        r[i + 2] = wp1[i] - wp0[i]
                    elif p == 2:
                        r[i] = wp1[i]
                        r[i + 2] = s[i] - wp1[i]
                if r[2] > 0 and r[3] > 0:
                    rs.append(Rect(r))

    def get_clip (self, r1, r2, err = 0):
        x01, y01, w, h = r1
        x11, y11 = x01 + w, y01 + h
        x02, y02, w, h = r2
        x12, y12 = x02 + w, y02 + h
        x0, y0 = max(x01, x02), max(y01, y02)
        x1, y1 = min(x11, x12), min(y11, y12)
        w, h = x1 - x0, y1 - y0
        if w > err and h > err:
            return (x0, y0, w, h)

    def update_rects (self):
        self.update_window()
        # rects
        self.rects = rects = []
        self.draw_rects = draw = []
        w = self.window
        for r in self.all_rects:
            c = w.clip(r)
            if c:
                rects.append(c)
                draw.append(r)
        # vrects
        self.vrects = rects = []
        ws = self.inverse_win
        for r in self.all_vrects:
            for w in ws:
                c = w.clip(r)
                if c:
                    rects.append(c)

    def handle_collisions (self):
        get_clip = self.get_clip
        p = self.player.rect
        p0 = list(p)
        for r in self.rects + self.vrects + self.arects:
            if get_clip(r, p):
                r_x0, r_y0, w, h = r
                r_x1, r_y1 = r_x0 + w, r_y0 + h
                p_x0, p_y0, w, h = p
                p_x1, p_y1 = p_x0 + w, p_y0 + h
                x, dirn = min((p_x1 - r_x0, 0), (p_y1 - r_y0, 1),
                              (r_x1 - p_x0, 2), (r_y1 - p_y0, 3))
                axis = dirn % 2
                p[axis] += (1 if dirn >= 2 else -1) * x
                self.player.impact(axis, 0)
                if axis == 1:
                    self.vert_dirn = dirn
        # screen left/right
        if p[0] < 0:
            p[0] = 0
            self.player.impact(0, 0)
        elif p[0] + p[2] > conf.RES[0]:
            p[0] = conf.RES[0] - p[2]
            self.player.impact(0, 0)
        # die if still colliding
        axes = set()
        e = conf.ERR
        colliding = [r for r in self.rects + self.vrects + self.arects \
                     if get_clip(r, p, e)]
        if colliding:
            for r in colliding:
                r_x0, r_y0, w, h = r
                r_x1, r_y1 = r_x0 + w, r_y0 + h
                p_x0, p_y0, w, h = p
                p_x1, p_y1 = p_x0 + w, p_y0 + h
                x, dirn = min((p_x1 - r_x0, 0), (p_y1 - r_y0, 1),
                              (r_x1 - p_x0, 2), (r_y1 - p_y0, 3))
                axes.add(dirn % 2)
            if len(axes) == 2:
                dirn = .5
            else:
                dirn = .95 if axes.pop() == 0 else .1
            self.die(dirn)

    def die (self, dirn = .5):
        self.first_dying = True
        self.dying = True
        self.dying_counter = conf.DIE_TIME
        # particles
        pos = list(Rect(self.to_screen(self.player.rect)).center)
        self.add_ptcls('die', pos, dirn)
        # sound
        if self.move_channel is not None:
            self.move_channel.pause()
        self.game.play_snd('die')

    def next_level (self, save = True, progress = True):
        if progress:
            if self.move_channel is not None:
                self.move_channel.pause()
            if self.star_channel is not None:
                self.star_channel.pause()
        i = self.ID
        if not conf.COMPLETED and i + 1 in conf.EXISTS:
            # there's a next level
            if save:
                conf.CURRENT_LEVEL = i + 1
            if progress:
                self.init(i + 1)
        else:
            if save:
                conf.COMPLETED = True
            if progress:
                self.game.switch_backend(ui.LevelSelect)

    def win (self):
        if self.winning:
            return
        self.winning = True
        self.next_level(progress = False)
        if self.ID not in conf.COMPLETED_LEVELS:
            conf.COMPLETED_LEVELS.append(self.ID)
        conf.dump()
        self.start_fading(lambda: self.next_level(False))

    def update (self):
        # fade counter
        if self.fading:
            self.fade_counter -= 1
            if self.fade_counter == 0:
                self.fading = False
                del self.fade_sfc
                self.fade_cb()
        # move player
        if not self.dying:
            pl = self.player
            pl.update()
        # get amount to move window by
        w = self.window
        self.old_window = w.copy()
        x0, y0 = self.centre
        if self.paused or self.first:
            dx = dy = 0
            self.first = False
        else:
            x, y = pg.mouse.get_pos()
            dx, dy = x - x0, y - y0
            # don't move too far outside the screen
            w_moved = w.move(dx, dy).clamp(self.window_bds)
            dx, dy = w_moved[0] - w[0], w_moved[1] - w[1]
        pg.mouse.set_pos(x0, y0)
        wx0, wy0, ww, wh = self.total_window = w.union(w.move(dx, dy))
        # move window
        if self.dying:
            # just move window
            w.move_ip(dx, dy)
            self.update_rects()
        else:
            self.vert_dirn = 3
            if dx == dy == 0:
                # just handle collisions
                self.handle_collisions()
            else:
                # check if player and window intersect
                wx1, wy1 = wx0 + ww, wy0 + wh
                r = pl.rect
                o_r = pl.old_rect
                px0, py0 = min(r[0], o_r[0]), min(r[1], o_r[1])
                px1 = max(r[0] + r[2], o_r[0] + o_r[2])
                py1 = max(r[1] + r[3], o_r[1] + o_r[3])
                if px1 > wx0 and py1 > wy0 and px0 < wx1 and py0 < wy1:
                    # if so, move window a few pixels at a time
                    c = conf.WINDOW_MOVE_AMOUNT
                    for axis, d in ((0, dx), (1, dy)):
                        dirn = 1 if d > 0 else -1
                        while d * dirn > 0:
                            d -= dirn * c
                            rel = [0, 0]
                            rel[axis] += c * dirn + (0 if d * dirn > 0 else d)
                            w.move_ip(rel)
                            self.update_rects()
                            if not self.dying:
                                self.handle_collisions()
                else:
                    # else move it the whole way
                    w.move_ip(dx, dy)
                    self.update_rects()
                    self.handle_collisions()
            if self.vert_dirn == 1:
                pl.on_ground = conf.ON_GROUND_TIME
        # clouds
        if self.clouds:
            # jitter
            jx = conf.CLOUD_JITTER
            jy = jx * conf.CLOUD_VERT_SPEED_RATIO
            v0 = self.cloud_vel
            v0[0] += jx * random0()
            v0[1] += jy * random0()
            r = conf.RES
            for p, v, s in self.clouds:
                for i, (i_w, r_w) in enumerate(zip(s, r)):
                    # move
                    x = p[i]
                    x += v0[i] + v[i]
                    # wrap
                    if x + i_w < 0:
                        x = r_w
                    elif x > r_w:
                        x = -i_w
                    p[i] = x
        # particles
        ptcls = []
        rects = []
        for k, j, group in self.particles:
            g = []
            x0, y0 = conf.RES
            x1 = y1 = 0
            for c, p, v, size, t in group:
                x, y = p
                # update boundary
                if x < x0:
                    x0 = x
                if y < y0:
                    y0 = y
                if x + size > x1:
                    x1 = x + size
                if y + size > y1:
                    y1 = y + size
                t -= 1
                if t != 0:
                    # move
                    vx, vy = v
                    x += vx
                    y += vy
                    # update boundary
                    if x < x0:
                        x0 = x
                    if y < y0:
                        y0 = y
                    if x + size > x1:
                        x1 = x + size
                    if y + size > y1:
                        y1 = y + size
                    # damp/jitter
                    vx *= k
                    vy *= k
                    vx += j * random0()
                    vy += j * random0()
                    g.append((c, (x, y), (vx, vy), size, t))
            if g:
                ptcls.append((k, j, g))
            if x1 > x0 and y1 > y0:
                rects.append((int(x0), int(y0), ceil(x1 - x0), ceil(y1 - y0)))
        self.particles = ptcls
        self.particle_rects = rects
        # death counter
        if self.dying:
            self.dying_counter -= 1
            if self.dying_counter == 0:
                self.init()
            return
        # player velocity
        pl.update_vel()
        # die if OoB
        if pl.rect[1] > conf.RES[1]:
            self.die()
        # win if at goal
        p = pl.rect
        c = w.clip(self.goal)
        if c and self.get_clip(p, c):
            self.win()
        # check if at checkpoints
        for c in self.checkpoints[self.current_cp + 1:]:
            if w.clip(c) and self.get_clip(p, c):
                self.current_cp += 1
        # check if at stars
        for i, s in enumerate(self.stars):
            if not s.got and w.clip(s.rect) and self.get_clip(p, s.rect):
                #self.game.play_snd('collectstar')
                if self.star_channel is not None and all(s.got for s in self.stars):
                    self.star_channel.pause()
                s.got = True
                conf.STARS.append([self.ID, i])
                conf.dump()

    def load_graphics (self):
        self.imgs = imgs = {}
        for img in ('void', 'window', 'rect', 'vrect', 'arect',
                    'checkpoint-current', 'checkpoint', 'goal') + \
                   conf.BGS + conf.CLOUDS:
            imgs[img] = self.game.img(img + '.png')
        self.window_sfc = pg.Surface(conf.WINDOW_SIZE).convert_alpha()

    def to_screen (self, rect):
        return [ir(x) for x in rect]

    def add_ptcls (self, key, pos, dirn = .5):
        particles = []
        data = conf.PARTICLES[key]
        max_speed = data['speed']
        max_size = data['size']
        k = data['damping']
        j = data['jitter']
        max_life = data['life']
        dirn *= pi / 2
        for c, amount in data['colours']:
            a, b = divmod(amount, 1)
            amount = int(a) + (1 if random() < b else 0)
            while amount > 0:
                size = randint(1, max_size)
                amount -= size
                angle = random() * 2 * pi
                speed = max_speed * expovariate(5)
                v = (speed * cos(dirn) * cos(angle), speed * sin(dirn) * sin(angle))
                life = int(random() * max_life)
                if life > 0:
                    particles.append((c, tuple(pos), v, size, life))
        self.particles.append((k, j, particles))

    def start_fading (self, cb):
        if not self.fading:
            self.fading = True
            self.fade_counter = conf.FADE_TIME
            self.fade_sfc = pg.Surface(conf.RES).convert_alpha()
            self.fade_cb = cb

    def update_jitter (self, jitter):
        if len(jitter) == 3:
            jx, jy, t0 = jitter
            t = t0
            ox, oy = randint(0, jx), randint(0, jy)
            jitter += [ox, oy, t]
        else:
            jx, jy, t0, ox, oy, t = jitter
            if t == 0:
                ox, oy = randint(0, jx), randint(0, jy)
                jitter[3] = ox
                jitter[4] = oy
                jitter[5] = t0
        jitter[5] -= 1

    def draw (self, screen):
        # don't draw on last frame
        #if not self.game.running:
            #return False
        imgs = self.imgs
        w = self.window
        pl = self.player
        pl.pre_draw()
        # background
        jitter = self.void_jitter
        self.update_jitter(jitter)
        ox, oy = jitter[3], jitter[4]
        img = imgs['void']
        draw_all = jitter[5] == conf.VOID_JITTER_T - 1 or self.fading or self.paused
        if self.paused:
            self.paused = False
        if draw_all:
            tile(screen, img, (0, 0) + screen.get_size(), ox, oy)
        else:
            draw_rects = self.particle_rects + [self.total_window, self.goal_img]
            if self.first_dying or not self.dying:
                draw_rects.append(pl.rect_img.union(pl.old_rect_img))
            for r in draw_rects:
                tile(screen, img, r, ox, oy, (0, 0))
        # vrects
        img = imgs['vrect']
        for r in self.all_vrects:
            tile(screen, img, r)
        # window
        offset = (-w[0], -w[1])
        w_sfc = self.window_sfc
        # window background: static images
        for img in self.bgs:
            if isinstance(img, str):
                pos = (0, 0)
            else:
                img, pos = img
            w_sfc.blit(imgs[img], Rect(pos + (0, 0)).move(offset))
        # clouds
        for c, (p, v, s) in zip(conf.CLOUDS, self.clouds):
            w_sfc.blit(imgs[c], Rect(self.to_screen(p + [0, 0])).move(offset))
        # rects in window
        img = imgs['rect']
        for r, r_full in zip(self.rects, self.draw_rects):
            tile(w_sfc, img, r.move(offset), full = r_full.move(offset))
        # checkpoints
        for i, r in enumerate(self.checkpoints):
            img = imgs['checkpoint' + ('-current' if i == self.current_cp else '')]
            w_sfc.blit(img, r.move(offset))
        # window border
        w_sfc.blit(imgs['window'], (0, 0), None, pg.BLEND_RGBA_MULT)
        # copy window area to screen
        screen.blit(w_sfc, w)
        # arects
        img = imgs['arect']
        for r in self.arects:
            tile(screen, img, r)
        # goal
        screen.blit(imgs['goal'], self.goal_img)
        # stars
        for s in self.stars:
            if not s.got:
                s.draw(screen, (0, 0))
        # player
        if not self.dying:
            pl.draw(screen)
        # particles
        for k, j, g in self.particles:
            for c, p, v, size, t in g:
                screen.fill(c, p + (size, size))
        # fadeout
        if self.fading:
            t = conf.FADE_TIME - self.fade_counter
            alpha = conf.FADE_RATE * float(t) / conf.FADE_TIME
            alpha = min(255, ir(alpha))
            self.fade_sfc.fill((0, 0, 0, alpha))
            screen.blit(self.fade_sfc, (0, 0))
            draw_all = True
        if self.first_dying:
            self.first_dying = False
        if draw_all:
            return True
        else:
            return draw_rects + self.arects