Le niveau 4 est super dur mais le niveau 5 l’est 5x plus >:D
Flèches: se déplacer OK / flèche haut: sauter ALPHA: changer le thème EXE: recommencer le niveau
😁
## ENGINE from math import * from random import * from kandinsky import * from ion import * from time import sleep, monotonic W,H = 320,222 SIZE, WIN = (W,H), (0,0,W,H) FONTW, FONTH = 10,18 # Colors BLACK = (0, 0, 0) DARK_GRAY = (95, 87, 79) LIGHT_GRAY = (194, 195, 199) WHITE = (255, 241, 232) # 4-7 DARK_BLUE = (29, 43, 83) BLUE = (41, 173, 255) DARK_GREEN = (0, 135, 81) GREEN = (0, 228, 54) # 8-B YELLOW = (255, 236, 39) ORANGE = (255, 163, 0) RED = (255, 0, 77) BROWN = (171, 82, 54) # C-F PEACH = (255, 204, 170) PINK = (255, 119, 168) PURPLE = (126, 37, 83) LAVENDER = (131, 118, 156) COLORS = [BLACK, DARK_GRAY, LIGHT_GRAY, WHITE, DARK_BLUE, BLUE, DARK_GREEN, GREEN, YELLOW, ORANGE, RED, BROWN, PEACH, PINK, PURPLE, LAVENDER] # Utils def clamp(m,x,M): return max(m,min(x,M)) def proba(n): return randint(1,n)==1 def ints(list): return tuple(int(x) for x in list) def center_pos(rect): return rect[0]+rect[2]//2, rect[1]+rect[3]//2 # - collision def collide_x(r1,r2): return r1[0] < r2[0]+r2[2] and r2[0] < r1[0]+r1[2] def collide_y(r1,r2): return r1[1] < r2[1]+r2[3] and r2[1] < r1[1]+r1[3] def collide (r1,r2): return collide_x(r1,r2) and collide_y(r1,r2) # - rect def bottom(rect): return rect[1]+rect[3] def right(rect): return rect[0]+rect[2] def add(r1,r2): res = [] for i in range(min(4,max(len(r1),len(r2)))): x = r1[i] if i < len(r1) else 0 y = r2[i] if i < len(r2) else 0 res.append(x+y) return res # - drawing def draw_rect(rect, color): fill_rect(int(rect[0]),int(rect[1]),int(rect[2]),int(rect[3]),color) def draw_rect_mult(x,y,w,h, color): fill_rect(int(x),int(y),int(w),int(h),color) def fill(color=WHITE): draw_rect(WIN, color) def draw_rects(img,color=BLACK, X=0,Y=0): """( (x,y,w,h[,color]), ... )""" for r in img: draw_rect_mult(X+r[0],Y+r[1], r[2], r[3], (r[4] if len(r) > 4 else color)) def draw_text(text, x, y, side="topleft", color=BLACK, background=WHITE): if "right" in side: x -= len(text)*FONTW elif not "left" in side: x -= len(text)*FONTW/2 if "bottom" in side: y -= FONTH elif not "top" in side: y -= FONTH/2 draw_string(text, int(round(x)),int(round(y)), color, background) # - time (time: ne pas utiliser en dehors d'engine) _time,timers = 0,{} def every(dt): if dt not in timers: timers[dt] = _time return (_time - timers[dt]) >= dt def timer(t, dura): return (monotonic() - t) >= dura # - update just_pressed,_pressed = {},{} def update(keys=[KEY_OK]): """ keys: touches inscrites dans just_pressed. ATTENTION: ne JAMAIS utiliser just_pressed dans un "every" """ global _time for dt in timers: if _time-timers[dt] >= dt: timers[dt] = _time _time = monotonic() for key in keys: kd = keydown(key) just_pressed[key] = kd and not _pressed.get(key) _pressed[key] = kd return True ## JEU MAPW, MAPH = 320,200 ECART = H-MAPH in_bounds = lambda r: 0 <= r[0] and right(r) < MAPW and 0 <= r[1] and bottom(r) < MAPH TS = 20 MOVE_COOLDOWN = 0.05 SPEED = 10 COYOTE = .2 GRAVITY = 15 JUMP = 20 GRAVITY_ACCEL = 2 # Couleurs def apply_theme(theme): global BG, PLR_COLOR, BLOCKS, HEADER_COLOR, END_COLOR BG, PLR_COLOR, BLOCKS[0], HEADER_COLOR, BLOCKS[1], END_COLOR = themes[theme] themes = [ # Background, Player, Blocks, Header, Coin, End (BLUE, BLACK, DARK_GREEN, DARK_BLUE, YELLOW, BROWN), (WHITE, DARK_GRAY, LIGHT_GRAY, DARK_GRAY, ORANGE, GREEN), (PINK, PURPLE, LAVENDER, PURPLE, WHITE, BROWN), (DARK_GRAY, WHITE, BLACK, BLACK, YELLOW, GREEN), ] BG = BLUE PLR_COLOR = DARK_BLUE BLOCKS = [DARK_GREEN, YELLOW] END_COLOR = GREEN HEADER_COLOR = DARK_BLUE apply_theme(0) # Créer monde levels = [ [(2, 9, 0), (6, 7, 0), (10, 5, 0), (14, 8, 0), (14, 7, 0), (14, 6, 0), (14, 5, 0), (14, 4, 0), (14, 3, 0), (14, 2, 0), (14, 1, 'end'), (1, 9, 0), (1, 8, 'player'), (0, 9, 0), (15, 2, 0), (15, 3, 0), (15, 4, 0), (15, 5, 0), (15, 6, 0), (15, 7, 0), (15, 8, 0), (15, 9, 0), (14, 9, 0)], [(3, 2, 0), (3, 3, 0), (3, 4, 0), (3, 5, 0), (3, 8, 0), (3, 9, 0), (3, 7, 0), (7, 0, 0), (7, 1, 0), (7, 2, 0), (7, 7, 0), (11, 3, 0), (11, 4, 0), (11, 5, 0), (11, 6, 0), (15, 0, 'end'), (15, 7, 0), (0, 9, 0), (2, 6, 0), (0, 8, 'player'), (11, 9, 0), (11, 2, 1), (12, 4, 0), (3, 6, 0), (2, 7, 0), (2, 8, 0), (2, 9, 0), (2, 10, 0), (2, 11, 0), (8, 0, 0), (8, 1, 0), (8, 2, 0), (8, 11, 0), (15, 8, 0), (15, 9, 0), (15, 10, 0), (12, 5, 0), (12, 2, 0), (11, 1, 0), (12, 1, 0), (11, 0, 0), (6, 0, 0), (0, 0, 0), (0, 1, 0), (1, 0, 0), (7, 3, 0), (7, 4, 0), (0, 2, 0)], [(1, 9, 0), (6, 9, 0), (11, 9, 0), (15, 6, 0), (12, 5, 0), (11, 4, 0), (4, 0, 'end'), (1, 7, 'player'), (1, 3, 0), (0, 3, 0), (1, 2, 1), (4, 3, 0), (0, 4, 0), (0, 5, 0), (0, 6, 0), (0, 7, 0), (0, 8, 0), (0, 9, 0), (1, 4, 0), (1, 5, 0), (11, 5, 0), (15, 7, 0), (15, 8, 0), (15, 9, 0), (14, 9, 0), (13, 9, 0), (12, 9, 0), (3, 2, 0), (3, 3, 0), (2, 3, 0), (2, 4, 0), (3, 4, 0)], [(0, 1, 0), (0, 0, 'player'), (10, 6, 0), (10, 2, 0), (7, 9, 0), (7, 6, 0), (7, 5, 0), (7, 3, 0), (7, 0, 0), (3, 0, 0), (3, 1, 0), (3, 2, 0), (3, 3, 0), (3, 4, 0), (3, 5, 0), (3, 9, 0), (3, 7, 0), (3, 6, 0), (10, 5, 0), (10, 4, 0), (8, 2, 0), (9, 1, 0), (9, 7, 0), (8, 7, 0), (10, 7, 1), (7, 7, 0), (15, 0, 'end'), (12, 5, 0), (12, 4, 0), (12, 3, 0), (12, 2, 0), (12, 1, 0), (12, 0, 0), (14, 0, 0), (14, 1, 0), (14, 2, 0), (14, 9, 0), (14, 5, 0)], [(15, 0, 'end'), (0, 8, 'player'), (0, 9, 0), (1, 9, 0), (0, 6, 0), (1, 6, 0), (2, 6, 0), (4, 7, 0), (5, 9, 0), (6, 7, 0), (4, 5, 0), (6, 4, 0), (7, 5, 0), (4, 2, 0), (3, 3, 0), (10, 6, 0), (11, 7, 0), (1, 4, 0), (5, 6, 0), (9, 5, 0), (8, 7, 0), (7, 8, 0), (7, 7, 0), (4, 3, 0), (4, 6, 0), (9, 9, 0), (13, 9, 0), (13, 8, 0), (14, 6, 0), (15, 8, 0), (15, 4, 0), (13, 5, 0), (13, 3, 0), (15, 2, 0), (12, 3, 0), (9, 1, 0), (8, 4, 0), (6, 2, 0), (7, 0, 0), (5, 0, 0), (8, 2, 0), (12, 6, 0), (13, 6, 0), (6, 3, 0), (10, 2, 0), (12, 4, 0), (10, 3, 0), (11, 9, 0), (12, 1, 0), (12, 2, 0), (1, 7, 0), (3, 9, 0), (0, 0, 1), (0, 1, 0), (1, 2, 0), (2, 0, 0), (3, 1, 0), (3, 0, 0), (10, 1, 0), (9, 0, 0)], [(11, 3, 0), (4, 7, 0), (5, 8, 0), (6, 8, 0), (7, 8, 0), (8, 8, 0), (9, 8, 0), (10, 8, 0), (11, 7, 0), (11, 2, 0), (12, 2, 0), (3, 1, 'player'), (11, 4, 0), (12, 4, 0), (13, 4, 0), (13, 3, 0), (13, 2, 0), (12, 3, 'end'), (3, 3, 0), (3, 4, 0), (4, 4, 0), (4, 3, 0)], ] def create_world(level): world = [(0,-MAPH,MAPW,MAPH,0),(-MAPW,0,MAPW,MAPH,0),(MAPW,0,MAPW,MAPH,0)] blocks = [] for x,y,type in levels[level-1]: if type == "player": plr = (x*TS+TS//4,y*TS+TS//4) elif type == "end": end = (x*TS+TS//4,y*TS+TS//4) elif type == 1: blocks.append((x*TS+TS//4,y*TS+TS//4,TS//2,TS//2,1)) else: blocks.append((x*TS,y*TS,TS,TS,type)) world.extend(blocks) plr_rect = [plr[0], plr[1], TS//2,TS//2] end_rect = [end[0], end[1], TS//2,TS//2] return world, plr_rect, end_rect # Dessiner monde def draw_block(rect, color, offset): fill_rect(rect[0]-offset[0], ECART+rect[1]-offset[1], rect[2], rect[3], color) def draw_world(world, plr_rect, offset, end_rect, level, coins): fill(BG) draw_top(level, coins) for block in world[3:]: draw_block(block, BLOCKS[block[4]], offset) draw_block(plr_rect, PLR_COLOR, offset) draw_block(end_rect, END_COLOR, offset) def draw_top(level, coins): fill_rect(0,0,W,ECART,HEADER_COLOR) draw_text("LEVEL "+str(level)+"/"+str(len(levels)), 20, ECART//2, "midleft", WHITE, HEADER_COLOR) draw_text("coins "+str(coins), W-20, ECART//2, "midright", WHITE, HEADER_COLOR) def plr_collide(world, plr_rect): for rect in world: if collide(rect, plr_rect): return True def game(): # Setup level, coins = 1, 0 theme = 0 world, plr_rect, end_rect = create_world(level) plr_spawn = plr_rect[:] move_timer = 0 offset = [0,0] vy = GRAVITY grounded = -float('inf') # Dessiner au début draw_world(world, plr_rect, offset, end_rect, level, coins) # Update while update(keys=[KEY_ALPHA]): # Mouvement dx, dy = 0, 0 if (keydown(KEY_UP) or keydown(KEY_OK))and not timer(grounded, COYOTE): vy = -JUMP grounded = -float('inf') if timer(move_timer, MOVE_COOLDOWN): vy = min(GRAVITY, vy+GRAVITY_ACCEL) dy += vy dx -= (keydown(KEY_LEFT) and plr_rect[0] > 0) * SPEED dx += (keydown(KEY_RIGHT) and right(plr_rect) < MAPW) * SPEED has_moved = dx != 0 or dy != 0 # - collision if has_moved and not plr_collide(world, plr_rect): r_dx = add(plr_rect,(dx,0)) for block in world[:]: if collide(block, r_dx): if block[4] == 1: draw_block(block, BG, offset) world.remove(block) coins += 1 draw_top(level, coins) elif dx > 0: dx = block[0] - right(plr_rect) elif dx < 0: dx = right(block) - plr_rect[0] r_dx[0] = plr_rect[0] + dx r_dy = add(plr_rect,(dx,dy)) for block in world[:]: if collide(block, r_dy): if block[4] == 1: draw_block(block, BG, offset) world.remove(block) coins += 1 draw_top(level, coins) elif dy > 0: dy = block[1] - bottom(plr_rect) grounded = monotonic() elif dy < 0: dy = bottom(block) - plr_rect[1] vy = max(vy, 0) has_moved = dx != 0 or dy != 0 # - move old_rect = plr_rect[:] if has_moved: plr_rect[0] += dx; plr_rect[1] += dy move_timer = monotonic() # End if collide(end_rect, plr_rect): level = min(len(levels), level+1) world, plr_rect, end_rect = create_world(level) plr_spawn = plr_rect[:] draw_world(world, plr_rect, offset, end_rect, level, coins) continue # Reset if keydown(KEY_EXE) or plr_rect[1] >= H: draw_block(old_rect, BG, offset) plr_rect = plr_spawn[:] # Draw if has_moved: draw_block(old_rect, BG, offset) draw_block(plr_rect, PLR_COLOR, offset) # Theme if just_pressed[KEY_ALPHA]: theme = (theme+1)%len(themes) apply_theme(theme) draw_world(world, plr_rect, offset, end_rect, level, coins) # Game over draw_text("ok to retry", W/2,H*.7,"center",BLACK,BG) draw_text("esc to quit", W/2,H*.8,"center",BLACK,BG) while not (update() and just_pressed.get(KEY_OK)): pass game() # Start game()