예제 #1
0
    def __init__(self, world: 'World', level: int, start_pos: Tuple[int, int],
                 scroll: Vector = Vector(0.05, 0)):
        self.level = level
        self.start_pos = Vector(
            start_pos[0] * BLOCK_SIZE,
            (GRID_SIZE[1] - start_pos[1] - 1) * BLOCK_SIZE
        )

        self.offset = Vector(0, 0)
        self.scroll = scroll

        self.items: List[LevelItem] = []
        self.finished = False

        self.counter = 0
        self.world = world
        self.world.source.last_active_level = self

        self.window_size = world.window.get_size()

        # Just some initialisation stuff here; less to compute later.
        self.background_offset = self.window_size[0] / 2
        self.background_image = load_image(LEVEL_BACKGROUND_IMAGE)
        self.bg_size = (self.background_image.get_width(), self.background_image.get_height())
        self.bg_center = (self.bg_size[0] / 2, self.bg_size[1] / 2)
예제 #2
0
    def __init__(self, window: Window):
        super().__init__(window)

        from constants import BUTTON_SIZE

        window_size = window.get_size()
        window_center = (window_size[0] / 2, window_size[1] / 2)

        dpi_factor = window.hidpi_factor

        button_size = (BUTTON_SIZE[0] * dpi_factor,
                       BUTTON_SIZE[1] * dpi_factor)
        button_font = Font('sans-serif', 16, dpi_factor)

        self.bg_image = util.load_image('assets/background.png')

        back_btn = Button(window,
                          '[ Back ]',
                          Vector(window_center[0] - button_size[0] / 2,
                                 window_size[1] * 2 / 3),
                          Vector(*button_size),
                          Color(0, 102, 255),
                          Color(255, 255, 255),
                          Color(0, 80, 230),
                          Color(255, 255, 255),
                          font=button_font)
        back_btn.set_click_handler(self.back)
        self.children.append(back_btn)
예제 #3
0
 def get_bounds(self) -> BoundingBox:
     size = self.window.get_size()
     return BoundingBox(
         Vector(0, 0),
         Vector(size[0], 0),
         Vector(size[0], size[1]),
         Vector(0, size[1]),
     )
예제 #4
0
def spline_eval_based_on_y(spNodes, y_value):
    """
    Given a spline represented by a bezier and a
    y value of interest.  Return the (first) point on
    the spline matches that y value.
    """

    # Find bezier segment of interest
    seg = -1
    n_seg = len(spNodes) / 4
    for i in range(n_seg):
        lower = spNodes[i * 4 + 0].y
        upper = spNodes[i * 4 + 3].y
        if y_value >= lower and y_value <= upper:
            seg = i
            break

    if seg == -1:
        print 'Did not find y value in the spline interval'
        print 'y= ', y_value
        if y_value < spNodes[0].y:
            # We are below the minimum y
            return ('FAIL', spNodes[0].y, 'FAIL')
        else:
            # We are abov the maximum y_value
            return ('FAIL', spNodes[-1].y, 'FAIL')

    b0 = Vector(spNodes[seg * 4 + 0].x, spNodes[seg * 4 + 0].y,
                spNodes[seg * 4 + 0].z)
    b1 = Vector(spNodes[seg * 4 + 1].x, spNodes[seg * 4 + 1].y,
                spNodes[seg * 4 + 1].z)
    b2 = Vector(spNodes[seg * 4 + 2].x, spNodes[seg * 4 + 2].y,
                spNodes[seg * 4 + 2].z)
    b3 = Vector(spNodes[seg * 4 + 3].x, spNodes[seg * 4 + 3].y,
                spNodes[seg * 4 + 3].z)

    Bx = [b0.x, b1.x, b2.x, b3.x]
    By = [b0.y, b1.y, b2.y, b3.y]
    Bz = [b0.z, b1.z, b2.z, b3.z]

    B = mySpline(Bx, By, Bz)
    funData = myData(B, y_value)

    for guess in init_guesses:
        x0 = guess[0]
        x1 = guess[1]
        t = secant(zero_fun_y, x0, x1, funData, limits=[0.0, 1.0])
        if t != 'FAIL':
            break

    if t == 'FAIL':
        print 'There is a problem finding the t-parameter'
        sys.exit(-1)

    return bezier3D_eval(t, Bx, By, Bz)
예제 #5
0
def walk(steps):
    loc = Point(0, 0)
    direc = Vector(0, 1, 0)
    for turn, dist in moves(steps):
        if turn == 'R':
            direc = -Vector.k().cross(direc)
        else:
            direc = direc.cross(-Vector.k())
        loc += dist * direc

    return loc
예제 #6
0
    def __init__(self, window: Window):
        super().__init__(window)

        from constants import BUTTON_SIZE

        self.window_size = window.get_size()
        self.window_center = (self.window_size[0] / 2, self.window_size[1] / 2)

        dpi_factor = window.hidpi_factor

        button_size = (BUTTON_SIZE[0] * dpi_factor,
                       BUTTON_SIZE[1] * dpi_factor)
        button_font = Font('sans-serif', 16, dpi_factor)

        self.bg_image = util.load_image('assets/background.png')
        self.bg_size = (self.bg_image.get_width(), self.bg_image.get_height())
        self.bg_center = (self.bg_size[0] / 2, self.bg_size[1] / 2)

        self.logo = util.load_image('assets/logo.png')
        self.logo_size = (self.logo.get_width(), self.logo.get_height())
        self.logo_center = (self.logo_size[0] / 2, self.logo_size[1] / 2)

        self.max_score = 0
        self.last_active_level = None

        self.text_font = Font('monospace', 20, window.hidpi_factor)
        self.text_font_color = Color(255, 255, 255)

        # Template to create new button
        start_btn = Button(window,
                           '[ Start ]',
                           Vector(self.window_center[0] - button_size[0] / 2,
                                  self.window_center[1] - button_size[1]),
                           Vector(*button_size),
                           Color(0, 102, 255),
                           Color(255, 255, 255),
                           Color(0, 80, 230),
                           Color(255, 255, 255),
                           font=button_font)
        start_btn.set_click_handler(self.start)
        self.children.append(start_btn)

        help_btn = Button(window,
                          '[ Help ]',
                          Vector(self.window_center[0] - button_size[0] / 2,
                                 self.window_center[1] + button_size[1]),
                          Vector(*button_size),
                          Color(0, 102, 255),
                          Color(255, 255, 255),
                          Color(0, 80, 230),
                          Color(255, 255, 255),
                          font=button_font)
        help_btn.set_click_handler(self.help)
        self.children.append(help_btn)
예제 #7
0
    def _on_click(self, pos: Tuple[int, int]):
        """
        Called whenever the window receives a mouse click event.
        Passes the event to the handler.
        """
        if self.handler is not None:
            self.handler.on_click(Vector(*pos))

        if self._mouse_down:
            self._mouse_down = False

            if self.handler is not None:
                self.handler.on_mouse_up(Vector(*pos))
예제 #8
0
def walk2(steps):
    loc = Point(0, 0)
    visited = {loc}
    direc = Vector(0, 1, 0)
    for turn, dist in cycle(moves(steps)):
        if turn == 'R':
            direc = -Vector.k().cross(direc)
        else:
            direc = direc.cross(-Vector.k())
        for _ in range(dist):
            loc += direc
            if loc in visited:
                return loc
            else:
                visited.add(loc)
예제 #9
0
    def _on_drag(self, pos: Tuple[int, int]):
        """
        Called whenever the window receives a mouse drag event.
        Passes the event to the handler.
        """
        if not self._mouse_down:
            self._mouse_down = True
            self._last_mouse_pos = pos

            if self.handler is not None:
                self.handler.on_mouse_down(Vector(*pos))
        else:
            if self.handler is not None:
                self.handler.on_drag(Vector(*self._last_mouse_pos),
                                     Vector(*pos))
예제 #10
0
 def on_collide(self, player: 'Player'):
     # Perform a "hopping off" animation and disable collision
     player.on_ground = False
     player.is_dying = True
     player.vel = Vector(
         math.copysign(PLAYER_DEATH_VELOCITY[0], player.vel.x),
         -PLAYER_DEATH_VELOCITY[1])
예제 #11
0
def find_location(cp):
    right = Vector(1, 0, 0)
    down = Vector(0, 1, 0)

    loc = Point(0, 0)
    size = 100
    right_edge = Vector(size - 1, 0, 0)
    bottom_edge = Vector(0, size - 1, 0)

    while not (cp(loc + right_edge) and cp(loc + bottom_edge)):
        while not cp(loc + bottom_edge):
            loc += right
        while not cp(loc + right_edge):
            loc += down

    return loc
예제 #12
0
    def __init__(self,
                 window: Window,
                 text: str,
                 pos: Vector,
                 size: Vector = Vector(150, 50),
                 bg: Color = Color(200, 200, 200),
                 fg: Color = Color(20, 20, 20),
                 bg_over: Color = Color(220, 220, 220),
                 fg_over: Color = Color(20, 20, 20),
                 border_size: int = 0,
                 font: Font = Font('sans-serif', 15, HIDPI_FACTOR)):
        super().__init__(window)
        self._click_handler = None

        self.text = text
        self.pos = pos
        self.size = size

        # Initial colours
        self.bg = bg
        self.fg = fg
        self.bg_over = bg_over
        self.fg_over = fg_over

        # Extra
        self.font = font
        self.border_size = border_size

        # Center
        self.center = (self.pos[0] + self.size[0] / 2,
                       self.pos[1] + self.size[1] / 2)

        # Get corners
        self.bounds = BoundingBox(pos, pos + size)
예제 #13
0
def combine_chains(chain1: EpicycleChain1D,
                   chain2: EpicycleChain1D,
                   tag_name,
                   color='black'):
    assert chain1.canvas == chain2.canvas
    assert chain1.num_vectors == chain2.num_vectors
    rotation = (chain1.rotation + chain2.rotation) / 2
    result_chain = EpicycleChain1D(chain1.canvas,
                                   chain1.origin_point,
                                   rotation,
                                   tag_name=tag_name)

    N = chain1.num_vectors
    c = result_chain.canvas

    result_chain.vectors = [Vector(Point(0, 0), Point(0, 0)) for i in range(N)]
    result_chain.epicycles = [
        (
            c.create_line(0, 0, 0, 0, tag=tag_name,
                          fill=color),  # , arrow=tk.LAST),
            c.create_oval(0, 0, 0, 0, tag=tag_name, outline=color))
        for i in range(N)
    ]
    for i in range(N):
        result_chain.vectors[i] = chain1.vectors[i] + chain2.vectors[i]
    result_chain.num_vectors = N
    return result_chain
예제 #14
0
    def get_bounds(self) -> BoundingBox:
        pos = self.get_pos()
        size = self.get_size()

        pos = Vector(
            pos[0] * BLOCK_SIZE,
            (GRID_SIZE[1] - pos[1] - 1) * BLOCK_SIZE,
        )
        size = Vector(
            size[0] * BLOCK_SIZE,
            size[1] * BLOCK_SIZE,
        )

        pos = pos - self.world.level.offset
        size = size

        return BoundingBox(pos, pos + size)
예제 #15
0
def paint(codes, start=0):
    c = Computer(codes)

    loc = Point(0, 0)
    direc = Vector(0, 1, 0)
    panels = {loc: start}
    while c.running:
        c.run([panels.get(loc, 0)])
        turn = c.output.pop()
        color = c.output.pop()
        panels[loc] = color

        if turn == 0:  # Turn left
            direc = Vector.k().cross(direc)
        elif turn == 1:  # Turn right
            direc = direc.cross(Vector.k())

        loc += direc
    return panels
예제 #16
0
 def get_text_bounds(self, text: str) -> Vector:
     """
     Returns to bounds of the text in this font.
     """
     font_name = self.face
     if font_name in simplegui._SIMPLEGUIFONTFACE_TO_PYGAMEFONTNAME:
         font_name = simplegui._SIMPLEGUIFONTFACE_TO_PYGAMEFONTNAME[
             font_name]
     bounds = pygame.font.SysFont(font_name,
                                  int(self.size *
                                      self.hidpi_factor)).size(text)
     return Vector(bounds[0], bounds[1])
예제 #17
0
    def __init__(self, world: 'World'):
        super().__init__(world.window)
        self.world = world

        self.size = Vector(*PLAYER_SIZE)

        self.pos = world.level.start_pos
        self.last_pos = self.pos.copy()
        self.last_x = 0
        self.vel = Vector(0, 0)
        self.accel = Vector(0, 0)

        self.on_ground = False
        self.jumping = False
        self.moving_x = False
        self.is_dying = False
        self.desired_platform = None

        self.score = 0
        self.lives = 3

        self.sprite_cols = 8
        self.sprite = Sprite('assets/player.png', self.sprite_cols, 1)
        self.roll = 0
예제 #18
0
def merge_vectors(vectors1, vectors2):
    assert vectors1[0].p_from == vectors2[0].p_from
    assert len(vectors1) == len(vectors2)
    vectors = []
    x_prev, y_prev = list(vectors1[0].p_from.get_iter())
    for i in range(len(vectors1)):
        rel_vec1 = (vectors1[i].p_to[0] - vectors1[i].p_from[0],
                    vectors1[i].p_to[1] - vectors1[i].p_from[1])
        rel_vec2 = (vectors2[i].p_to[0] - vectors2[i].p_from[0],
                    vectors2[i].p_to[1] - vectors2[i].p_from[1])
        rel_vec = rel_vec1[0] + rel_vec2[0], rel_vec1[1] + rel_vec2[1]
        x_cur, y_cur = x_prev + rel_vec[0], y_prev + rel_vec[1]
        vectors.append(Vector(Point(x_prev, y_prev), Point(x_cur, y_cur)))
        x_prev, y_prev = x_cur, y_cur
    return vectors
예제 #19
0
 def _init_epicycles(self, color):
     c = self.canvas
     self.epicycles = [
         (
             c.create_line(0, 0, 0, 0, tag=self.tag_name, fill=color),
             # , activefill=color, arrow=tk.LAST, arrowshape="10 20 10"
             c.create_oval(0,
                           0,
                           0,
                           0,
                           tag=self.tag_name,
                           outline=color,
                           width=2)) for i in range(self.num_vectors)
     ]
     self.vectors = [
         Vector(Point(0, 0), Point(0, 0)) for i in range(self.num_vectors)
     ]
예제 #20
0
def walk_scaffold(layout, robot):
    direcs = {
        '>': Vector(1, 0, 0),
        '<': Vector(-1, 0, 0),
        '^': Vector(0, -1, 0),
        'V': Vector(0, 1, 0)
    }
    scaffold = '#'

    cur_loc = Point(*robot[:2])
    cur_dir = direcs[robot[-1]]
    cur_run = 0
    moves = []
    while True:
        #print(cur_loc, cur_dir)
        next_loc = cur_loc + cur_dir
        if valid_index(
                layout,
                next_loc) and layout[next_loc.y][next_loc.x] == scaffold:
            cur_loc = next_loc
            cur_run += 1
        else:
            if cur_run:
                moves.append(cur_run)
                cur_run = 0

            # All of the directions are kinda flipped from expected because we're in a coordinate system
            # where +y is down.
            if cur_dir.x == 1:
                left = cur_loc.down
                right = cur_loc.up
            elif cur_dir.x == -1:
                left = cur_loc.up
                right = cur_loc.down
            elif cur_dir.y == 1:
                left = cur_loc.right
                right = cur_loc.left
            elif cur_dir.y == -1:
                left = cur_loc.left
                right = cur_loc.right

            if valid_index(layout,
                           left) and layout[left.y][left.x] == scaffold:
                moves.append('L')
                cur_dir = cur_dir.cross(Vector.k())
            elif valid_index(layout,
                             right) and layout[right.y][right.x] == scaffold:
                moves.append('R')
                cur_dir = Vector.k().cross(cur_dir)
            else:
                break

    return ','.join(str(i) for i in moves)
예제 #21
0
 def draw(self,
          canvas: simplegui.Canvas,
          pos: Vector,
          size: Optional[Vector] = None,
          index: Tuple[int, int] = (0, 0)):
     """
     Draw the sprite on the canvas.
     """
     source_center = [
         self.sprite_size[i] * index[i] + self.sprite_center[i]
         for i in [0, 1]
     ]
     if size is not None:
         size = size.into_tuple()
     else:
         size = self.sprite_size
     canvas.draw_image(self.image, source_center, self.sprite_size,
                       pos.into_tuple(), size)
예제 #22
0
 def update_vectors_by_time(self, time):
     x_prev, y_prev = self.x0, self.y0
     j = 0
     self.fourier_vectors = sorted(self.fourier_vectors,
                                   key=lambda i: i.amp,
                                   reverse=True)
     for f_vec in self.fourier_vectors:
         # for f_vec in self.fourier_vectors:
         rad = f_vec.amp
         x_cur = x_prev + rad * math.cos(time * f_vec.freq + f_vec.phase +
                                         self.rotation)
         y_cur = y_prev + rad * math.sin(time * f_vec.freq + f_vec.phase +
                                         self.rotation)
         self.vectors[j] = Vector(Point(x_prev, y_prev),
                                  Point(x_cur, y_cur))
         x_prev, y_prev = x_cur, y_cur
         j += 1
     return Point(x_cur, y_cur)  # last point of chain
예제 #23
0
    def on_death(self):
        self.lives -= 1

        if self.lives == 0:
            self.world.window.handler = self.world.source
        else:
            self.vel.x = 0
            self.vel.y = 0
            if self.desired_platform is None:
                self.pos = Vector(PLAYER_RESPAWN_X_OFFSET, -self.size.y)
            else:
                bounds = self.desired_platform.get_bounds()

                if bounds.max.x <= 0:
                    self.pos = Vector(PLAYER_RESPAWN_X_OFFSET, -self.size.y)
                else:
                    # Place player on platform they last touched
                    self.pos = Vector(
                        bounds.max.x - self.size.x - PLAYER_RESPAWN_X_OFFSET,
                        bounds.min.y - self.size.y)

            self.is_dying = False
예제 #24
0
def bezier_3_spline(m, p):
    """
    Given m+1 interpolation points, determine the m-segment,
    Bezier polyline that interpolates these points.

    Unlike the C-function, this returns a list of the
    beizer control points used to represent the spline.

    Further comments are in the accompanying C-file.
    Coded in Python: 06-Dec-2004
    """

    assert len(p) >= (m + 1)

    if m <= 0:
        print 'Cannot attempt to find a Bezier representation'
        print 'with ', m, ' segments.'
        return 'FAIL'

    tolerance = 1.0e-10

    # Setup the initial guess for the weight points by using the
    # supplied points. This also sets the end points correctly.

    d = []
    for node in p:
        # Use a Vector object which will not be stored in the Node.nodeList.
        d.append(Vector(node.x, node.y, node.z))

    # Apply the Gauss-Seidel interation until the internal
    # weight points converge.

    for j in range(50):
        max_diff = 0.0
        for i in range(1, m):
            old_p = d[i]

            d[i].x = 0.25 * (6.0 * p[i].x - d[i - 1].x - d[i + 1].x)
            d[i].y = 0.25 * (6.0 * p[i].y - d[i - 1].y - d[i + 1].y)
            d[i].z = 0.25 * (6.0 * p[i].z - d[i - 1].z - d[i + 1].z)

            dx = fabs(d[i].x - old_p.x)
            dy = fabs(d[i].y - old_p.y)
            dz = fabs(d[i].z - old_p.z)

            diff = dx + dy + dz
            if (diff > max_diff):
                max_diff = diff
        # end for i
        if (max_diff < tolerance):
            break

    # end for j

    if j >= 50:
        print 'Iterations did not converge while using the Guass-Seidel technique'
        print 'to find a bezier representation of a spline.'
        return 'FAIL'

    # Finally, calculate the Bezier segments an pack them away.
    bcp = range(4 * m)

    for i in range(m):
        bcp[i * 4 + 0] = copy(p[i])

        bcp[i * 4 + 1] = Vector()
        bcp[i * 4 + 1].x = (2.0 * d[i].x + d[i + 1].x) / 3.0
        bcp[i * 4 + 1].y = (2.0 * d[i].y + d[i + 1].y) / 3.0
        bcp[i * 4 + 1].z = (2.0 * d[i].z + d[i + 1].z) / 3.0

        bcp[i * 4 + 2] = Vector()
        bcp[i * 4 + 2].x = (d[i].x + 2.0 * d[i + 1].x) / 3.0
        bcp[i * 4 + 2].y = (d[i].y + 2.0 * d[i + 1].y) / 3.0
        bcp[i * 4 + 2].z = (d[i].z + 2.0 * d[i + 1].z) / 3.0

        bcp[i * 4 + 3] = copy(p[i + 1])

    return bcp
예제 #25
0
 def test_vector(self):
     v1 = Vector(7, 4)
     v2 = Vector(-6, 3)
     self.assertEqual("%s" % v1, "Vector(7.0, 4.0)")
     self.assertEqual("%s" % v2, "Vector(-6.0, 3.0)")
     # length should be sqrt(7**2 + 4**2) = 8.062
     self.assertAlmostEqual(v1.norm(), 8.062, places=3)
     # Create a unit vector and test its length
     v1u = v1.unit_vector()
     self.assertAlmostEqual(v1u.norm(), 1.00, places=3)
     v3 = v1 * 6.4
     self.assertTrue(isinstance(v3, Vector))
     # v3 length = 8.062(6.4) = 51.597
     self.assertAlmostEqual(v3.norm(), 51.597, places=2)
     # v1 + v2 = (1, 7); length = 7.071
     v4 = v1 + v2
     self.assertAlmostEqual(v4.norm(), 7.071, places=3)
     # Dot product of v1, v2 = (7)(-6) + (4)(3) = -30
     self.assertAlmostEqual(v1.dot(v2), -30.0, places=3)
     self.assertAlmostEqual(v2.dot(v1), -30.0, places=3)
     # Cross product of v1 x v2 = (7)(3) - (-6)(4) = 45
     self.assertAlmostEqual(v1.cross(v2), 45.0, places=3)
     # Cross product of v2 x v1 = (-6)(4) - (7)(3) = -45
     self.assertAlmostEqual(v2.cross(v1), -45.0, places=3)
     v5 = v1.perp()
     self.assertAlmostEqual(v5[0], -4.0, places=3)
     self.assertAlmostEqual(v5[1], 7.0, places=3)
예제 #26
0
class Level(object):
    """
    A game level.
    """

    def __init__(self, world: 'World', level: int, start_pos: Tuple[int, int],
                 scroll: Vector = Vector(0.05, 0)):
        self.level = level
        self.start_pos = Vector(
            start_pos[0] * BLOCK_SIZE,
            (GRID_SIZE[1] - start_pos[1] - 1) * BLOCK_SIZE
        )

        self.offset = Vector(0, 0)
        self.scroll = scroll

        self.items: List[LevelItem] = []
        self.finished = False

        self.counter = 0
        self.world = world
        self.world.source.last_active_level = self

        self.window_size = world.window.get_size()

        # Just some initialisation stuff here; less to compute later.
        self.background_offset = self.window_size[0] / 2
        self.background_image = load_image(LEVEL_BACKGROUND_IMAGE)
        self.bg_size = (self.background_image.get_width(), self.background_image.get_height())
        self.bg_center = (self.bg_size[0] / 2, self.bg_size[1] / 2)

    def get_score(self):
        return self.world.player.score

    def add_item(self, item: LevelItem):
        """
        Adds the item to the level.
        """
        self.items.append(item)

    def finish(self):
        """
        Finishes the level.
        """
        self.finished = True

    def render(self, world: 'World', canvas: simplegui.Canvas):
        """
        Called on every game tick to render the level.
        """

        # Draw background
        if LEVEL_USE_BACKGROUND:
            center_dest1 = (
                -(self.offset.x % self.window_size[0]) + self.background_offset,
                self.window_size[1] / 2
            )
            center_dest2 = (
                center_dest1[0] + self.window_size[0],
                center_dest1[1]
            )
            canvas.draw_image(self.background_image, self.bg_center, self.bg_size,
                              center_dest1, self.window_size)
            canvas.draw_image(self.background_image, self.bg_center, self.bg_size,
                              center_dest2, self.window_size)

        self.counter += 1

        if self.counter % BLOCK_SIZE == 0:
            self.counter = 0
            world.player.score += 1

        dpi_factor = world.window.hidpi_factor

        font = world.text_font
        font_color = world.text_font_color
        score_text = "SCORE // {0:d}".format(world.player.score)
        lives_text = "LIVES // {0:d}".format(world.player.lives)

        canvas.draw_text(score_text, (10 * dpi_factor, 20 * dpi_factor), font.get_size(),
                         str(font_color),
                         font.get_face())
        canvas.draw_text(lives_text, (10 * dpi_factor, 40 * dpi_factor), font.get_size(),
                         str(font_color),
                         font.get_face())

        # Render items
        for item in self.items:
            bounds = item.get_bounds()
            if bounds.max.x > 0 and bounds.min.x < WINDOW_SIZE[0]:
                item.render(canvas)

        # Render player
        world.player.render(canvas)

        # Add the level scroll, mutating the current offset.
        self.offset.add(self.scroll * BLOCK_SIZE)

        # Load next level.
        if self.finished:
            levels = world.levels

            next_level = self.level + 1
            if len(levels) >= next_level:
                target_level = levels[next_level - 1]
                world.player.pos = target_level.start_pos
                world.level = target_level
            else:
                world.level = None
예제 #27
0
 def get_cursor_pos(self) -> Vector:
     x, y = pygame.mouse.get_pos()
     return Vector(x, y)
예제 #28
0
class Player(Renderable):
    def __init__(self, world: 'World'):
        super().__init__(world.window)
        self.world = world

        self.size = Vector(*PLAYER_SIZE)

        self.pos = world.level.start_pos
        self.last_pos = self.pos.copy()
        self.last_x = 0
        self.vel = Vector(0, 0)
        self.accel = Vector(0, 0)

        self.on_ground = False
        self.jumping = False
        self.moving_x = False
        self.is_dying = False
        self.desired_platform = None

        self.score = 0
        self.lives = 3

        self.sprite_cols = 8
        self.sprite = Sprite('assets/player.png', self.sprite_cols, 1)
        self.roll = 0

    def jump(self):
        self.on_ground = False
        self.vel.y = -PLAYER_VELOCITY[1]
        self.accel.y = -ACCEL_GRAVITY

    def get_bounds(self) -> BoundingBox:
        pos = self.pos
        size = self.size
        return BoundingBox(pos, pos + size)

    def get_render_bounds(self) -> BoundingBox:
        bounds = self.get_bounds()
        dpi_factor = self.window.hidpi_factor
        return BoundingBox(bounds.min * dpi_factor, bounds.max * dpi_factor)

    def on_key_down(self, key: int):
        if not self.is_dying:
            if key == Key.SPACE:
                self.jumping = True  # Allow holding jump button.
                if self.on_ground:
                    self.jump()

            elif key == Key.KEY_A:
                self.vel.x = -PLAYER_VELOCITY[0]

            elif key == Key.KEY_D:
                self.vel.x = PLAYER_VELOCITY[0]

    def on_key_up(self, key: int):
        if not self.is_dying:
            if key == Key.SPACE:
                self.jumping = False

            elif key == Key.KEY_A:
                if self.vel.x < 0:
                    self.vel.x = 0

            elif key == Key.KEY_D:
                if self.vel.x > 0:
                    self.vel.x = 0

    def on_death(self):
        self.lives -= 1

        if self.lives == 0:
            self.world.window.handler = self.world.source
        else:
            self.vel.x = 0
            self.vel.y = 0
            if self.desired_platform is None:
                self.pos = Vector(PLAYER_RESPAWN_X_OFFSET, -self.size.y)
            else:
                bounds = self.desired_platform.get_bounds()

                if bounds.max.x <= 0:
                    self.pos = Vector(PLAYER_RESPAWN_X_OFFSET, -self.size.y)
                else:
                    # Place player on platform they last touched
                    self.pos = Vector(
                        bounds.max.x - self.size.x - PLAYER_RESPAWN_X_OFFSET,
                        bounds.min.y - self.size.y)

            self.is_dying = False

    def render(self, canvas: simplegui.Canvas):
        bounds = self.get_bounds()
        dpi_factor = self.window.hidpi_factor

        # Draw player.
        if PLAYER_POTATO:
            dest_center = self.pos + self.size / 2
            index = (self.roll // self.sprite_cols) % self.sprite_cols
            self.sprite.draw(canvas, dest_center * dpi_factor,
                             self.size * dpi_factor, (index, 0))
        else:
            point_list = [p.multiply(dpi_factor).into_tuple() for p in bounds]
            color = Color(120, 120, 200)

            canvas.draw_polygon(point_list, 1, str(color), str(color))

        # Update position.
        self.last_pos = self.pos.copy()
        self.pos.add(self.vel)

        self.roll += self.vel.x * 2 / PLAYER_VELOCITY[0]
        self.roll += 1

        if abs(self.vel.x) > PLAYER_VELOCITY[0]:
            self.vel.x = math.copysign(PLAYER_VELOCITY[0], self.vel.x)

        # Check collisions position.
        self.on_ground = False

        bounds = self.get_bounds()
        if not self.is_dying:
            for item in self.world.level.items:
                if item.collides_with(bounds):
                    item.on_collide(self)

        self.vel.add(self.accel)

        # Do gravity and platform collision.
        if self.on_ground:
            self.vel.y = 0
            self.accel.y = 0
        else:
            self.accel.y = -ACCEL_GRAVITY

        if bounds.max.y >= WINDOW_SIZE[1] or bounds.min.x <= 0:
            self.on_death()