Skip to content

Commit d332985

Browse files
committed
Working on Mario
1 parent 02ab6be commit d332985

File tree

2 files changed

+96
-86
lines changed

2 files changed

+96
-86
lines changed

README.md

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2912,75 +2912,80 @@ Pygame
29122912

29132913
### Example
29142914

2915-
#### Runs a simple Mario game:
2916-
```python
2917-
import collections, dataclasses, enum, io, itertools, math, pygame, random, urllib
2918-
from urllib.request import urlopen
2919-
2920-
D = enum.Enum('D', 'n e s w')
2921-
P = collections.namedtuple('P', 'x y')
2922-
Mario = dataclasses.make_dataclass('Mario', ['rect', 'spd', 'facing_left', 'running_cycle'])
2923-
RECT_SIDE, SCR_SIDE, MAX_SPEED = 16, 25, P(x=5, y=10)
2924-
COORDS = [p for p in itertools.product(range(SCR_SIDE), repeat=2) if {*p} & {0, SCR_SIDE-1}] +\
2925-
[(random.randint(1, SCR_SIDE-2), random.randint(2, SCR_SIDE-2)) for _ in range(62)]
2926-
FLOORS = [pygame.Rect(x*RECT_SIDE, y*RECT_SIDE, RECT_SIDE, RECT_SIDE) for x, y in COORDS]
2927-
URL = 'https://raw.githubusercontent.com/gto76/python-cheatsheet/master/web/mario_bros.png'
2928-
IMAGE = pygame.image.load(io.BytesIO(urlopen(URL).read()))
2929-
FRAMES = [IMAGE.subsurface(pygame.Rect(x*16, 0, 16, 16)) for x in range(7)]
2930-
FRAMES += [pygame.transform.flip(f, True, False) for f in FRAMES]
2931-
TILES = [IMAGE.subsurface(pygame.Rect(x*16, 0, 16, 16)) for x in range(9, 14)]
2915+
#### Runs a simple Super Mario game:
2916+
```python
2917+
import collections, dataclasses, enum, io, math, pygame, urllib.request, itertools as it
2918+
from random import randint
2919+
2920+
P = collections.namedtuple('P', 'x y')
2921+
D = enum.Enum('D', 'n e s w')
2922+
SIZE, MAX_SPEED = 25, P(5, 10)
29322923

29332924
def main():
2934-
pygame.init()
2935-
screen = pygame.display.set_mode(2 * [SCR_SIDE * RECT_SIDE])
2936-
mario = Mario(pygame.Rect(16, 16, 16, 16), P(0, 0), False, itertools.cycle(range(3)))
2937-
while not any(event.type == pygame.QUIT for event in pygame.event.get()):
2925+
def get_rect(x, y):
2926+
return pygame.Rect(x*16, y*16, 16, 16)
2927+
def get_images():
2928+
url = 'https://gto76.github.io/python-cheatsheet/web/mario_bros.png'
2929+
img = pygame.image.load(io.BytesIO(urllib.request.urlopen(url).read()))
2930+
return [img.subsurface(get_rect(x, 0)) for x in range(img.get_width() // 16)]
2931+
def get_mario():
2932+
Mario = dataclasses.make_dataclass('Mario', 'rect spd facing_left frame_cycle'.split())
2933+
return Mario(get_rect(1, 1), P(0, 0), False, it.cycle(range(3)))
2934+
def get_tiles():
2935+
positions = [p for p in it.product(range(SIZE), repeat=2) if {*p} & {0, SIZE-1}] + \
2936+
[(randint(1, SIZE-2), randint(2, SIZE-2)) for _ in range(SIZE**2 // 10)]
2937+
return [get_rect(*p) for p in positions]
2938+
def get_screen():
2939+
pygame.init()
2940+
return pygame.display.set_mode(2 * [SIZE*16])
2941+
run(get_images(), get_mario(), get_tiles(), get_screen())
2942+
2943+
def run(images, mario, tiles, screen):
2944+
while all(event.type != pygame.QUIT for event in pygame.event.get()):
29382945
keys = {pygame.K_UP: D.n, pygame.K_RIGHT: D.e, pygame.K_DOWN: D.s, pygame.K_LEFT: D.w}
29392946
pressed = {keys.get(i, None) for i, on in enumerate(pygame.key.get_pressed()) if on}
2940-
update_speed(mario, pressed)
2941-
update_position(mario)
2942-
draw(screen, mario, pressed)
2947+
update_speed(mario, tiles, pressed)
2948+
update_position(mario, tiles)
2949+
draw(mario, tiles, screen, pressed, images)
29432950
pygame.time.wait(28)
29442951

2945-
def update_speed(mario, pressed):
2946-
bounds = get_boundaries(mario.rect)
2952+
def update_speed(mario, tiles, pressed):
2953+
bounds = get_boundaries(mario.rect, tiles)
29472954
x, y = mario.spd
29482955
x += 2 * ((D.e in pressed) - (D.w in pressed))
29492956
x = math.copysign(abs(x) - 1, x) if x else 0
29502957
y += 1 if D.s not in bounds else (-10 if D.n in pressed else 0)
29512958
speed = stop_on_collision(P(x, y), bounds)
29522959
mario.spd = P(*[max(-thresh, min(thresh, s)) for thresh, s in zip(MAX_SPEED, speed)])
29532960

2954-
def update_position(mario):
2955-
delta, old_p = P(0, 0), mario.rect.topleft
2961+
def update_position(mario, tiles):
2962+
old_p, delta = mario.rect.topleft, P(0, 0)
29562963
larger_speed = max(abs(s) for s in mario.spd)
29572964
for _ in range(int(larger_speed)):
2958-
mario.spd = stop_on_collision(mario.spd, get_boundaries(mario.rect))
2959-
delta = P(*[s/larger_speed + dlt for s, dlt in zip(mario.spd, delta)])
2960-
mario.rect.topleft = [sum(a) for a in zip(old_p, delta)]
2965+
mario.spd = stop_on_collision(mario.spd, get_boundaries(mario.rect, tiles))
2966+
delta = P(*[a + s/larger_speed for a, s in zip(delta, mario.spd)])
2967+
mario.rect.topleft = [sum(pair) for pair in zip(old_p, delta)]
29612968

2962-
def get_boundaries(rect):
2969+
def get_boundaries(rect, tiles):
29632970
deltas = {D.n: P(0, -1), D.e: P(1, 0), D.s: P(0, 1), D.w: P(-1, 0)}
2964-
return {d for d, delta in deltas.items() if rect.move(delta).collidelist(FLOORS) != -1}
2971+
return {d for d, delta in deltas.items() if rect.move(delta).collidelist(tiles) != -1}
29652972

29662973
def stop_on_collision(spd, bounds):
29672974
return P(x=0 if (D.w in bounds and spd.x < 0) or (D.e in bounds and spd.x > 0) else spd.x,
29682975
y=0 if (D.n in bounds and spd.y < 0) or (D.s in bounds and spd.y > 0) else spd.y)
29692976

2970-
def draw(screen, mario, pressed):
2977+
def draw(mario, tiles, screen, pressed, images):
2978+
def get_frame_index():
2979+
if D.s not in get_boundaries(mario.rect, tiles):
2980+
return 4
2981+
return next(mario.frame_cycle) if {D.w, D.e} & pressed else 6
29712982
screen.fill((85, 168, 255))
2972-
mario.facing_left = mario.spd.x < 0 if mario.spd.x else mario.facing_left
2973-
screen.blit(FRAMES[get_frame_index(mario, pressed) + mario.facing_left*7], mario.rect)
2974-
for rect in FLOORS:
2975-
tile_index = 1 if {*rect.topleft} & {0, (SCR_SIDE-1)*RECT_SIDE} else 0
2976-
screen.blit(TILES[tile_index], rect)
2983+
mario.facing_left = (D.w in pressed) if {D.e, D.w} & pressed else mario.facing_left
2984+
screen.blit(images[get_frame_index() + mario.facing_left*9], mario.rect)
2985+
for rect in tiles:
2986+
screen.blit(images[19 if {*rect.topleft} & {0, (SIZE-1)*16} else 18], rect)
29772987
pygame.display.flip()
29782988

2979-
def get_frame_index(mario, pressed):
2980-
if D.s not in get_boundaries(mario.rect):
2981-
return 4
2982-
return next(mario.running_cycle) if {D.w, D.e} & pressed else 6
2983-
29842989
if __name__ == '__main__':
29852990
main()
29862991
```

0 commit comments

Comments
 (0)