class CollisionObject(object): def __init__(self, label="Default", pos: Vector2D = Vector2D(0, 0), scale: Vector2D = Vector2D(0, 0), center: Vector2D = Vector2D(0, 0), colour: Colour = (0, 0, 0)): self.label = label self.pos: Vector2D = pos self.scale: Vector2D = scale self.center: Vector2D = center self.colour: Colour = colour self.visible = False global_pos: Vector2D = self.pos + self.center self.rect = Rect(global_pos.x, global_pos.y, self.scale.x, self.scale.y) def update(self): global_pos: Vector2D = self.pos + self.center self.rect = Rect(global_pos.x, global_pos.y, self.scale.x, self.scale.y) def draw(self, screen): if self.visible: pygame.draw.rect(screen, self.colour, self.rect, 5) def is_colliding(self, other): return self.rect.colliderect(other.rect) def is_colliding_any(self, others: list): others = [o.rect for o in others] return self.rect.collidelist(others) def is_colliding_all(self, others: list): others = [o.rect for o in others] return self.rect.collidelistall(others)
def grid_select(state, start_pos, steps, end_pos_func=None, COLOR=LIGHT_BLUE): x, y = start_pos speed = steps pos_list = [] rect_list = [] for i in range((speed * 2) + 1): for n in range((speed * 2) + 1): p = ((x + i - speed), (y + n - speed)) pos_list.append(p) pixel_p = tuple(axis * state.map.unit for axis in p) rect_list.append(Rect(pixel_p, state.map.unit_t)) state.draw() end_pos_found = False for i in range(len(pos_list)): p = pos_list[i] r = rect_list[i] if end_pos_func: if end_pos_func(p): pygame.draw.rect(state.screen, COLOR, r, 1) end_pos_found = True else: pygame.draw.rect(state.screen, COLOR, r, 1) pygame.display.flip() if end_pos_func and not end_pos_found: state._print('End position not found, cannot perform action') return while 1: event = pygame.event.wait() if event.type == pygame.KEYUP: if event.key == 27: # esc return None if event.type == pygame.MOUSEBUTTONUP: r = Rect(event.pos, (1, 1)) index = r.collidelist(rect_list) if not index == -1: return state.map.grid_pos(event.pos)
def advance_frame(input_get=pygame.event.get): global PLATFORMS, HATS, SPIKES, SPRINGS, ENEMIES, _ENEMIES, FLAGS, CHEESE, BACK, SPAWN global X, Y, x_vel, y_vel, DOOR, HAT, STATE, CROUCH, mov, hub, DIR global counter, dframe, IGT, endcard plats = [] allplats = [] for pos, dim, idx in PLATFORMS: allplats.append(Rect(pos, (dim[0]*32, dim[1]*32))) if isnear(pos, dim): plats.append(Rect(pos, (dim[0]*32, dim[1]*32))) # update counters/clock counter += 1 dframe = (dframe + 1) % 12 IGT += CLOCK.tick(30) # draw update screen adjust_scroller() SCREEN.blit(get_screen(), (0, 0)) SCREEN.blit(get_HUD(), (0, 0)) pygame.display.update() # evaluate input jmp = 0 door = 0 for e in input_get(): if e.type == QUIT or e.type == KEYDOWN and e.key == K_ESCAPE: quit() if e.type == KEYDOWN: if e.key == K_LEFT: mov = max(mov - 1, -1) if e.key == K_RIGHT: mov = min(mov + 1, 1) if e.key == K_DOWN: CROUCH = min(CROUCH+1, 1) if e.key == K_SPACE: jmp += 1 if e.key == K_UP: door = True if e.type == KEYUP: if e.key == K_LEFT: mov = min(mov+1, 1) if e.key == K_RIGHT: mov = max(mov-1, -1) if e.key == K_DOWN: CROUCH = max(CROUCH-1, 0) # change state, update movement JUMP = _JUMP * 2 if HAT == "baseball" else _JUMP if STATE == "dmg": if counter == 1: sounds["death"].stop() sounds["death"].play() if counter < 10: return STATE = "stand" X, Y = SPAWN x_vel, y_vel = 0, 0 HAT = None ENEMIES = deepcopy(_ENEMIES) elif jmp and (STATE in ["stand", "run0", "run1", "slide", "wall"] or HAT == "propeller"): sounds["jump"].stop() sounds["jump"].play() if HAT == "propeller": y_vel = JUMP if STATE == "wall": y_vel = JUMP DIR *= -1 x_vel = max(SPEED * DIR, x_vel) if DIR > 0 else min(SPEED * DIR, x_vel) else: STATE = "squat" counter = 0 elif STATE == "squat": if counter >= 3: y_vel = JUMP elif CROUCH: STATE = "crouch" elif mov and STATE not in ['crouch']: if DIR == mov: x_vel = max(SPEED * DIR, x_vel) if DIR > 0 else min(SPEED * DIR, x_vel) elif not x_vel or abs(x_vel) <= 3: DIR = mov if (x_vel > 0 and mov < 0) or (x_vel < 0 and mov > 0): STATE == "slide" elif x_vel == 0: STATE = "stand" else: STATE = "slide" if mov and not STATE in ["run0", "run1", "crouch", "squat"]: if ((x_vel > 0 and mov < 0) or (x_vel < 0 and mov > 0)): STATE = "slide" else: STATE = "run0" counter = 0 if STATE.startswith("run") and counter >= 5: STATE = "run" + str((int(STATE[-1]) + 1) % 2) counter = 0 if y_vel < 0: STATE = "jump0" if y_vel > 0: STATE = "jump1" # friction and gravity if x_vel and not STATE.startswith("jump"): x_vel += friction if x_vel < 0 else -1 y_vel += grav if STATE in ["jump1", "run0", "run1", "stand", "slide"] and HAT == "sombraro" and not CROUCH: y_vel = 0 # animate relevent actors for spring in SPRINGS: if spring[3]: spring[3] -= 1 # enemy logic remove = [] for i in range(len(ENEMIES)): pos, name, d, f , c = ENEMIES[i] if not isnear(pos): continue c += 1 if name == "bone": if c % 2: f = (f + 1) % 2 pos = (pos[0] + BONESPEED, pos[1]) if d == 0 else (pos[0] - BONESPEED, pos[1]) if c > 50: remove.append(i) if name == "skeleton": if abs(pos[0] - X) < 410: if f == 0: d = 0 if X > pos[0] else 1 if c >= 8 and f == 0: f = 1 elif c >= 30 and f == 1: sounds["throw"].stop() sounds["throw"].play() f = 2 ENEMIES.append( [pos, 'bone', d, 0, 0] ) elif c > 40: f, c = 0, 0 else: f, c = 0, 0 if name == "zombie": if c % 4 == 0 and abs(pos[0] - X) < 512: hitbox = Rect((pos[0]+8, pos[1]), (32, 64)) if d == 0: footbox = Rect((pos[0] + 32 + ZOMBIESPEED, pos[1] + 64), (10, 10)) else: footbox = Rect((pos[0] - ZOMBIESPEED, pos[1]+64), (10, 10)) if hitbox.collidelist(allplats) == -1: d = 0 if X > pos[0] else 1 f = (f + 1) % 2 pos = (pos[0] + ZOMBIESPEED, pos[1]) if d == 0 else (pos[0] - ZOMBIESPEED, pos[1]) if hitbox.collidelist(allplats) != -1 or footbox.collidelist(allplats) == -1: pos = (pos[0] - ZOMBIESPEED*2, pos[1]) if d == 0 else (pos[0] + ZOMBIESPEED*2, pos[1]) if name == "snake": hitbox = Rect(pos, (64, 16)) if c % 4 == 0: f = (f + 1) % 2 pos = (pos[0] + SNAKESPEED, pos[1]) if d == 0 else (pos[0] - SNAKESPEED, pos[1]) if hitbox.collidelist(allplats) != -1: d = (d + 1) % 2 pos = (pos[0] + SNAKESPEED*2, pos[1]) if d == 0 else (pos[0] - SNAKESPEED*2, pos[1]) if name == "ghost": d = 0 if X > pos[0] else 1 if (d == 1 and DIR == 1) or (d == 0 and DIR == -1): f = 1 else: f = 0 if abs(pos[0] - X) + abs(pos[1] - Y) < 800 and f == 0: if abs(pos[0] - X) > 30: x = -1 if X < pos[0] else 1 else: x = 0 if abs(pos[1] - Y) > 30: y = -1 if Y < pos[1] else 1 else: y = 0 pos = (pos[0]+x, pos[1]+y) ENEMIES[i] = [pos, name, d, f, c] for i in remove[::-1]: ENEMIES.pop(i) # hit detection - platforms hitbox = Rect((X, Y), (32, 64)) if STATE != "crouch" else Rect((X, Y+32), (32, 32)) checklist = plats if hitbox.collidelist(checklist) != -1: STATE = "dmg" return if x_vel: while hitbox.move(x_vel, 0).collidelist(checklist) != -1: if STATE.startswith("jump"): STATE = "wall" x_vel += 1 if x_vel < 0 else -1 if y_vel: while hitbox.move(0, y_vel).collidelist(checklist) != -1: y_vel += 1 if y_vel < 0 else -1 if x_vel and y_vel: while hitbox.move(x_vel, y_vel).collidelist(checklist) != -1: y_vel += 1 if y_vel < 0 else -1 x_vel += 1 if x_vel < 0 else -1 # hats checklist = [Rect(pos, (46, 46)) for pos, hat in HATS] i = hitbox.collidelist(checklist) if i != -1: HAT = HATS[i][1] # flags checklist = [Rect(pos, (46, 64)) for pos in FLAGS] i = hitbox.collidelist(checklist) if i != -1: SPAWN = FLAGS[i] # spikes and enemies checklist = [] for pos, d in SPIKES: if not isnear(pos): continue if d == 0: checklist += [Rect((pos[0]+8, pos[1]), (16, 16)), Rect((pos[0], pos[1]+16), (32, 16))] elif d == 1: checklist += [Rect((pos[0], pos[1]+8), (16, 16)), Rect((pos[0]+16, pos[1]), (16, 32))] elif d == 2: checklist += [Rect((pos[0], pos[1]), (32, 16)), Rect((pos[0]+8, pos[1]+16), (16, 16))] elif d == 3: checklist += [Rect((pos[0], pos[1]), (16, 32)), Rect((pos[0]+16, pos[1]+8), (32, 16))] for pos, name, d, f, c in ENEMIES: if not isnear(pos): continue if name in ["bone", "ghost"]: checklist.append(Rect(pos, (32, 32))) elif name == "snake": checklist.append(Rect(pos, (64, 16))) else: checklist.append(Rect(pos, (32, 64))) i = hitbox.collidelist(checklist) if i != -1: STATE = "dmg" counter = 0 # springs checklist = [Rect(pos, (48, 48)) for pos, d, s, f in SPRINGS] i = hitbox.collidelist(checklist) if i != -1: if SPRINGS[i][3] != 10: sounds["spring"].stop() sounds["spring"].play() SPRINGS[i][3] = 10 if SPRINGS[i][1] == 0: y_vel = 0 - SPRINGS[i][2] elif SPRINGS[i][1] == 2: y_vel = SPRINGS[i][2] elif SPRINGS[i][1] == 3: DIR = 1 x_vel = SPRINGS[i][2] elif SPRINGS[i][1] == 1: DIR = -1 x_vel = -1 * SPRINGS[i][2] # cheese checklist = [] for pos, idx in CHEESE: if idx == 3: checklist.append(Rect(pos, (64, 64))) else: checklist.append(Rect(pos, (32, 32))) i = hitbox.collidelist(checklist) if i != -1: sounds["get"].stop() sounds["get"].play() if not CHEESE[i][1] == 3: INV.append(CHEESE.pop(i)) else: n = H end = True while end: CLOCK.tick(30) if n >= 0: n -= 10 SCREEN.blit(get_screen(), (0, 0)) SCREEN.blit(endcard, (0, n)) pygame.draw.rect(SCREEN, (200, 200, 200), Rect((380, n + 530), (256, 104))) SCREEN.blit(HEL64.render(str(IGT // 60000) +":"+ ("0" + str(IGT // 1000 % 60))[-2:], 0, (0, 0, 0)), (400, n + 550)) pygame.display.update() for e in pygame.event.get(): if e.type == QUIT or e.type == KEYDOWN and e.key == K_ESCAPE: quit() if e.type == KEYDOWN: if e.key == K_LEFT: mov += -1 if e.key == K_RIGHT: mov += 1 if e.key == K_DOWN: CROUCH += 1 if e.key == K_SPACE and n <= 0: end = False load_level(hublvl) hub=True if e.type == KEYUP: if e.key == K_LEFT: mov -= -1 if e.key == K_RIGHT: mov -= 1 if e.key == K_DOWN: CROUCH -= 1 # door if hub: doorlist = [Rect((256+(i*256), 64), (64, 64)) for i in range(len(LEVELS))] di = hitbox.collidelist(doorlist) # enter door if door and (hitbox.colliderect(Rect(DOOR, (64, 64))) or (hub and di != -1 and len(INV)>=needs[di] )): sounds["door"].stop() sounds["door"].play() n = 2 if not hub: X, Y = DOOR[0] + 16, DOOR[1] adjust_scroller() STATE = "jump1" while n < 980: surf = rotate(get_screen(), n) SCREEN.blit(surf, ((W-surf.get_width())//2, (H - surf.get_height())//2)) n += n // 2 CLOCK.tick(30) pygame.display.update() for e in pygame.event.get(): if e.type == QUIT or e.type == KEYDOWN and e.key == K_ESCAPE: quit() if e.type == KEYDOWN: if e.key == K_LEFT: mov += -1 if e.key == K_RIGHT: mov += 1 if e.key == K_DOWN: CROUCH += 1 if e.type == KEYUP: if e.key == K_LEFT: mov -= -1 if e.key == K_RIGHT: mov -= 1 if e.key == K_DOWN: CROUCH -= 1 if hub and di != -1: load_level(LEVELS[di]) hub = False else: load_level(hublvl) hub = True # apply final calculated movement X += x_vel Y += y_vel
if abs(pos[0] - X) < 410: if f == 0: d = 0 if X > pos[0] else 1 if c >= 8 and f == 0: f = 1 elif c >= 30 and f == 1: f = 2 ENEMIES.append( [pos, 'bone', d, 0, 0] ) elif c > 40: f, c = 0, 0 else: f, c = 0, 0 if name == "zombie": if c % 4 == 0 and abs(pos[0] - X) < 512: hitbox = Rect((pos[0]+8, pos[1]), (32, 64)) if d == 0: footbox = Rect((pos[0] + 32 + ZOMBIESPEED, pos[1] + 64), (10, 10)) else: footbox = Rect((pos[0] - ZOMBIESPEED, pos[1]+64), (10, 10)) if hitbox.collidelist(allplats) == -1: d = 0 if X > pos[0] else 1 f = (f + 1) % 2 pos = (pos[0] + ZOMBIESPEED, pos[1]) if d == 0 else (pos[0] - ZOMBIESPEED, pos[1]) if hitbox.collidelist(allplats) != -1 or footbox.collidelist(allplats) == -1: pos = (pos[0] - ZOMBIESPEED*2, pos[1]) if d == 0 else (pos[0] + ZOMBIESPEED*2, pos[1]) if name == "snake": hitbox = Rect(pos, (64, 16)) if c % 4 == 0: f = (f + 1) % 2 pos = (pos[0] + SNAKESPEED, pos[1]) if d == 0 else (pos[0] - SNAKESPEED, pos[1]) if hitbox.collidelist(allplats) != -1: d = (d + 1) % 2 pos = (pos[0] + SNAKESPEED*2, pos[1]) if d == 0 else (pos[0] - SNAKESPEED*2, pos[1])