Un jeu Pong codé par Aizeir > youtube.com/@aizeir
from math import * from random import * from kandinsky import * from ion import * from time import sleep, monotonic # Window W,H = 320,222 SIZE, WIN = (W,H), (0,0,W,H) FONTW, FONTH = 10,18 # 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 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) # - 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] # Image module def draw_rect(rect, color): fill_rect(int(rect[0]),int(rect[1]),int(rect[2]),int(rect[3]),color) def fill(color=WHITE): draw_rect(WIN, color) def draw_image(img,color=BLACK, X=0,Y=0): "( (x,y,w,h[,color]), ... )" for r in img: draw_rect((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: temps de la FRAME ! 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 pressed = {} just_pressed = {} def update(keys=[KEY_OK]): """ keys: touches inscrites dans just_pressed. BIG 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 low_detail = False def bracket(text, yesno): return (" {} ","[ {} ]")[yesno].format(text) pong = "1111 11 1 1 111\n1 1 1 1 11 1 1 11\n111 1 1 1 11 1 11 11\n1 11 1 1 11".split("\n") digits = [" 111 \n1 1\n1 1 1\n1 1\n 111 ", " 1\n 1\n 1\n 1\n 1", "1111 \n 1\n 111\n1 \n11111", "1111 \n 1\n 111 \n 1\n1111 ", "1 1\n1 1\n 1111\n 1\n 1", "11111\n1 \n1111 \n 1\n1111 ", " 111 \n1 \n1111\n1 1\n 111 ", "111 \n 1\n 1\n 1\n 1", " 111 \n1 1\n 111 \n1 1\n 111 ", " 111 \n1 1\n 1111\n 1\n 111 "] # Game def game(mode): bg = BLACK # Ball ballsize, detail = 10, 2 ball = [50,50, ballsize,ballsize] if low_detail: ball_img = [(0,0,ballsize,ballsize)] else: ball_img = ((detail,0,ballsize-2*detail,ballsize), (0,detail,ballsize,ballsize-2*detail)) vx = vy = def_speed = 3 # Bars bar1 = [20,10,12,48] bar2 = [W-32,10,12,48] speed_coeff = 5 bar1_speed = bar2_speed = bar_defspeed = def_speed/speed_coeff def move_bar(bar, dir): dy = max(detail,bar1_speed) y = (bar[1], bar[1]+bar[3]-dy)[dir<0] draw_rect((bar[0],y,bar[2],dy),bg) bar[1] += dir * bar1_speed bar[1] = clamp(0, bar[1], H-bar[3]) def draw_bar(bar): color = (WHITE,YELLOW)[touching==bar] if low_detail: image = (bar,) else: image = ((bar[0]+detail,bar[1],bar[2]-2*detail,bar[3]), (bar[0],bar[1]+detail,bar[2],bar[3]-2*detail)) draw_image(image, color) def bar_touched(bar): if not(bar==bar2 and mode==1): add_score() # touch nonlocal touching, just_touched, touch_time,vx touching = just_touched = bar touch_time = monotonic() # movement vx = -vx if bar==bar1: ball[0] = bar[0]+bar[2] else: ball[0] = bar[0]-ball[2] # draw draw_rect(bar, BLACK) for _ in range(6): particle(center_pos(ball), vel=[vx*random(), -10*(random()-.5)]) # Touch just_touched = None touching = None touch_time = None # Score score = 0 px = 4 font = 5 score_rect = None def add_score(): nonlocal score, vx, vy, bar1_speed,bar2_speed,bar_defspeed,score_rect score += 1 speed = def_speed + def_speed//2 * (score//10)/((score//10)+1) vx = copysign(speed, vx) vy = copysign(speed, vy) bar1_speed = bar1_speed * (speed/speed_coeff) / .5 bar2_speed = bar2_speed * (speed/speed_coeff) / .5 bar_defspeed = speed/speed_coeff draw_score(score) def draw_score(score): nonlocal score_rect w = ((score//10+1)*(font+1)-1)*px score_rect = ((W-w)/2, 20, w, font*px) draw_rect(score_rect,bg) for k,s in enumerate(str(score)): img = digits[int(s)].strip("\n").split("\n") for i,row in enumerate(img): for j,cell in enumerate(row): if cell == " ": continue draw_rect((score_rect[0]+(k*(font+1)+j)*px, score_rect[1]+i*px, px, px), YELLOW) # Game Over def draw_lose_texts(select): draw_text(bracket("retry",select==0), W/2,H*.45,"center",(WHITE,RED)[select==0],bg) draw_text(bracket("menu" ,select==1), W/2,H*.55,"center",(WHITE,RED)[select==1],bg) # Particles particles = [] def particle(pos,**k): p = {'pos':list(pos),'time':monotonic()} p.update(k) particles.append(p) # Draw fill(bg) draw_bar(bar1) draw_bar(bar2) draw_score(score) # Update while update(): # Ball if every(.02): # Draw bg draw_rect(ball,bg) if collide(ball, score_rect): draw_score(score) # Move ball[0] += vx ball[1] += vy # Bar collision if collide(ball, bar1): bar_touched(bar1) elif collide(ball, bar2): bar_touched(bar2) # Wall collision elif ball[0] <= 0 or ball[0]+ball[2] >= W: break elif ball[1] <= 0 or ball[1]+ball[3] >= H: vy = -vy ball[1] = clamp(0, ball[1], H-ball[3]) for _ in range(6): particle(center_pos(ball), vel=[10*(random()-.5),vy*random()]) # Ball clamp ball[0] = clamp(0, ball[0], W-ball[2]) ball[1] = clamp(0, ball[1], H-ball[3]) # Draw draw_image(ball_img,(RED,RED)[touching!=None], ball[0], ball[1]) # Bar left dir1 = keydown(KEY_DOWN) - keydown(KEY_UP) if dir1: move_bar(bar1, dir1) bar1_speed = (bar_defspeed, min(1,bar1_speed+.05))[dir1] # Bar right dir2 = (dir1, (-1,1)[center_pos(ball)[1]>center_pos(bar2)[1]])[mode==1] if dir2: move_bar(bar2, dir2) bar2_speed = (bar_defspeed,min(1,bar2_speed+.05))[dir2] # Touch timer touch_end = touching and timer(touch_time, .2) if touch_end: touching = None # Draw Bars if dir1 or (touch_end or just_touched == bar1): draw_bar(bar1) if dir2 or (touch_end or just_touched == bar2): draw_bar(bar2) just_touched = None # Particles if every(.01) and particles: bin = [] for p in particles: # cache draw_rect((p['pos'][0],p['pos'][1],3,3), bg) # move p['pos'][0] += p['vel'][0] p['pos'][1] += p['vel'][1] p['vel'][1] += .2 # particle destroy r = (p['pos'][0],p['pos'][1],3,3) if timer(p['time'], 1) or (p['pos'][1] > H+5) or collide(r,bar1) or collide(r,bar2) or collide(r,score_rect): bin.append(p); continue # draw draw_rect((p['pos'][0],p['pos'][1],3,3), YELLOW) for p in bin: particles.remove(p) # Game Over draw_lose_texts(0) select = 0 input = keydown(KEY_DOWN)-keydown(KEY_UP) while update(keys=(KEY_DOWN,KEY_UP)): if just_pressed[KEY_UP] and select>0 and not input: select = (select-1) draw_lose_texts(select) if just_pressed[KEY_DOWN] and select<1 and not input: select = (select+1) draw_lose_texts(select) if keydown(KEY_OK): if select == 0: break elif select == 1: menu() if input != keydown(KEY_DOWN)-keydown(KEY_UP): input = 0 game(mode) # Menu def menu(): global low_detail bg = BLACK # texts prev_input = keydown(KEY_OK) select = 0 def draw_texts(): draw_text(bracket('solo',select==0), W/2,H*.5,"center",(WHITE,RED)[select==0],bg) draw_text(bracket('vs cpu',select==1), W/2,H*.6,"center",(WHITE,RED)[select==1],bg) #draw_text(bracket('2 player',select==2), W/2,H*.7,"center",(WHITE,RED)[select==2],bg) def draw_shift(): draw_text(bracket('shift | low detail',low_detail), W/2,H*.9,"center",(WHITE,RED)[low_detail],bg) # title px = 5 w = max([len(row) for row in pong]) h = len(pong) x = (W - w*px) / 2 y = H*.2 t = monotonic() frame = 0 # draw fill(bg) draw_texts() draw_shift() # Loop while update(keys=(KEY_SHIFT,KEY_DOWN,KEY_UP)): # Title if frame <= h*w and (monotonic()-t)**.5*100 > frame: for i,row in enumerate(pong): for j,cell in enumerate(row): if j*h+i == frame and cell != " ": draw_rect((x+j*px, y+i*px, px, px), RED) frame += 1 # Events if keydown(KEY_OK) and not prev_input: game(select) if prev_input and not keydown(KEY_OK): prev_input = False if just_pressed[KEY_DOWN] and select<1: select = (select+1) draw_texts() if just_pressed[KEY_UP] and select>0: select = (select-1) draw_texts() if just_pressed[KEY_SHIFT]: low_detail = not low_detail draw_shift() # Start menu()