PAS TOUCHE A MON MINECRAFT
from math import * from random import * from kandinsky import * from ion import * from time import sleep, monotonic ## ENGINE 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) # 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(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 TS = 16 DSP_W, DSP_H = W // TS, H // TS - 1 MAPW, MAPH = 4*DSP_W, DSP_H*2 ecart = (W-DSP_W*TS, H-DSP_H*TS) FLOOR = 7 ROOF = 3 PLR_SPAWN = 10, 1 JUMP, GRAVITY = 1,1 MOVE_COOLDOWN = 0.1 MAX_INV = 6 in_bounds = lambda x,y: 0 <= x < MAPW and 0 <= y < MAPH # Couleurs BGS = (BLUE, LAVENDER) BG = BGS[0] PLR_COLOR = YELLOW EYE_COLOR = BROWN BLOCK_TYPES = { 0: BG, # Air 1: BROWN, # Terre 2: DARK_GRAY, # Pierre 3: GREEN, # Herbe 4: ORANGE, # Tronc 5: DARK_GREEN, # Feuille 6: PURPLE, # portail du nether 7: RED, # netherrack 8: LIGHT_GRAY, # lightstone 9: DARK_BLUE, # darkstone 10: BLACK, # ore } # Blocks blocks = ['!(")#)$)%)&)\')(()\'*(+(,(-(.(/(0\'172636465666768797:6;6<6=6>6?6@7A7B6C6D6E6F6G6H7I7J6K6L6M6N6O6P7Q7R6S6T6U6V6W6X7Y7Z7[7\\7]7^7_7`7', '!7"7#7$7%7&7\'7(7)7*6+6,6-6.6/607172636465666768797:6;6<6=6>6?6@7A7B6C6D6E6F6G6H7I7J6K6L6M6N6O6P7Q7R6S6T6U6V6W6X7Y7Z7[7\\7]7^7_7`7', '!#"###$#%#&#\'#(#)#*$+$,$-$.$/$0#1#2$3$4$5$6$7$8#9#:$;$<$=$>$?$@#A#B$C$D$E$F$G$H#I#J$K$L$M$N$O$P#Q#R$S$T$U$V$W$X#Y#Z#[#\\#]#^#_#`#'] # Créer monde def create_world(): # OVERWORLD overworld = [[0 for _ in range(MAPW)] for _ in range(MAPH)] # Terre portal = randint(0,MAPW-1) for x in range(MAPW): grass = randint(FLOOR-1,FLOOR) dirt = grass + randint(1,2) stone = dirt + randint(3,4) for y in range(grass, dirt): if y == grass and x == portal: overworld[y][x] = 6 else: overworld[y][x] = 3 for y in range(dirt, stone): overworld[y][x] = 1 for y in range(stone,DSP_H): overworld[y][x] = 2 for y in range(max(stone,DSP_H),MAPH): if randint(1,100) == 1: overworld[y][x] = 8 elif randint(1,20) == 1: overworld[y][x] = choice((9,10)) else: overworld[y][x] = 2 # Arbres last_tree = 0 for x in range(1, MAPW-1): # Find grass for y in range(MAPH): if overworld[y][x] == 3: grass = y break # Place tree if not x-last_tree<4 and proba(6): overworld[grass-1][x] = 4 # Tronc overworld[grass-2][x] = 4 # Tronc # Feuilles for dy in range(3): for dx in range(-1,2): overworld[grass-3-dy][x+dx] = 5 last_tree = x # NETHER nether = [[0 for _ in range(MAPW)] for _ in range(MAPH)] for x in range(MAPW): # Sol rack = randint(FLOOR+1,FLOOR+3) rock = rack + randint(1,3) for y in range(rack, rock): nether[y][x] = 7 for y in range(rock, MAPH): nether[y][x] = 2 # Toit roof = randint(1,ROOF) rock = max(0, roof - randint(1,2)) for y in range(rock,roof): nether[y][x] = 7 for y in range(0,rock): nether[y][x] = 2 return overworld, nether # Mettre a jour la map def update_map(map, world, plr_x, plr_y): global BG BLOCK_TYPES[0] = BG = BGS[map] world[plr_y][plr_x] = 0 world[plr_y+1][plr_x] = 6 # Dessiner monde def draw_edges(creative): midx = ecart[0]//2 for rect in ((0,0,midx,H),(0,H-ecart[1],W,ecart[1]),(W-(ecart[0]-midx),0,ecart[0]-midx,H)): draw_rect(rect, (BLACK,WHITE)[creative]) def draw_tile(tile_x, tile_y, type, offset): fill_rect((tile_x-offset[0])*TS+ecart[0]//2, (tile_y-offset[1])*TS, TS, TS, BLOCK_TYPES[type]) """scale = 2 block = blocks[type==1] for i in range(0, len(block), 2): pos, col = ord(block[i])-33, ord(block[i+1])-33 x,y = pos%8, pos//8 color = COLORS[col] fill_rect((tile_x-offset[0])*TS+x*scale, (tile_y-offset[1])*TS+y*scale, scale, scale, color)""" def draw_player(plr_x, plr_y, offset, world, side): draw_x, draw_y = (plr_x-offset[0])*TS+ecart[0]//2, (plr_y-offset[1])*TS inblock = world[plr_y][plr_x] != 0 if inblock: size = 6 fill_rect(draw_x+(TS-size)//2, draw_y+(TS-size)//2, size, size, PLR_COLOR) else: fill_rect(draw_x, draw_y, TS, TS, PLR_COLOR) fill_rect(draw_x+0+5*(side%2), draw_y+3+2*(side//2), 4, 6, EYE_COLOR) fill_rect(draw_x+7+5*(side%2), draw_y+3+2*(side//2), 4, 6, EYE_COLOR) ioff = 4 ipad = (ecart[1]-TS)//2 ihov = 4 icell = 2.8 inv_left = 15 def draw_inventory(inv, block, creative, inv_row): fg,bg = ((WHITE,BLACK),(BLACK,WHITE))[creative] draw_rect((0, H-ecart[1], W, ecart[1]), bg) items = [j for j in inv if inv[j]] for i, j in enumerate(items[inv_row*MAX_INV:(inv_row+1)*MAX_INV]): # pos / i pos = (inv_left + ihov+i*icell*TS, H-ecart[1]+ipad) # select if j == block: draw_rect((pos[0]-ihov, pos[1]-ihov, TS+2*ihov, TS+2*ihov), fg) # image draw_rect((pos[0], pos[1], TS, TS), BLOCK_TYPES[j]) # amount if not creative: draw_text(str(inv[j]), pos[0]+TS-ihov, pos[1]+TS+ihov, "bottomleft", fg, bg) # arrows if inv: draw_text(" ><"[(inv_row+1)*MAX_INV<len(inv) or 2*(inv_row>0)], int(pos[0]+TS*2.5), pos[1]+TS//2, "midleft", fg, bg) def draw_world(world, plr_x, plr_y, offset, block, creative, inv, inv_row, side, edges=True): fill(BG) if edges: draw_edges(creative) for dsp_y in range(DSP_H): for dsp_x in range(DSP_W): x,y = dsp_x+offset[0], dsp_y+offset[1] if in_bounds(x,y) and world[y][x]: draw_tile(x, y, world[y][x], offset) draw_player(plr_x, plr_y, offset, world, side) draw_inventory(inv, block, creative, inv_row) grass = ["'?Ul\x83\x9b±ÉßöčĤļŒũƁƘưdžǝǴȌȢȺɐɧɾʕʭ˃ ̊˲̷̭͎̉ͤΉΓηπϘϮІЪдыѯ҆҈ҴӋӕӹԐԧԱՕ՟փֱ֙\u05c8מ״،آظْ٧ٿږڮۅۜ۞܉ܟܸݎݥݽޒީ߁ߗ߰ࠇࠞ࠴ࡋࡣࡹ\u0890ࢧࢼ࣓࣬ःचझैय़ॴঋতহ\u09d0৩\u09ffਗਭ\u0a45ੜੱઈઠષ\u0acf૦ૼକପୁ\u0b59୰ஆ\u0b9dழௌ\u0be3௹\u0c11ధి\u0c57౭ಃಚಲ\u0cc9ೠ\u0cf8എഥ഻ൔ൪ඁ\u0d99ධෆෝ෴ซยื๎\u0e67\u0e7dຕຫໃ໘\u0eef༈༝༵ཎརླཱྀྒྷྨ྿࿃\u0feeငလဳ၉ၠၶႏႥႩდცᄂᄚᄯᅇᅟᅵᆍᆢᆺᇐᇧᇽሖርቄቛቲ\u1289አኵዌዥዻጓጪፂፘ፮ᎅ\u139dᎵᏉᏣᏹᐎᐦᐽᑔᑬᒄᒘᒱᓉᓟᓷᔋᔢᔻᕑᕩᖀᖖᖭᗄᗜᗱᘉᘠᘸᘻᙦᙼᚓᚫᛂᛘᛯᜇᜟ"] def game(): # Setup overworld, nether = create_world() world = overworld in_block = lambda x,y: world[y][x] != 0 getblock = lambda x,y: world[y][x] if in_bounds(x,y) else -1 plr_x, plr_y = PLR_SPAWN vy = 0 move_timer = 0 offset = [0,0] map = 0 side = 1 inv = {} inv_row = 0 block = next(iter(inv)) if inv else -1 creative = False def select_block(idx): nonlocal block, inv_row block = list(inv)[idx] if idx != -1 else -1 inv_row = idx // 6 if idx != -1 else 0 draw_inventory(inv, block, creative, inv_row) def break_block(x,y): if not in_block(x, y): return nonlocal block if not creative: b = world[y][x] if b not in inv: inv[b] = 0 inv[b] += 1 if block == -1: select_block(0) draw_inventory(inv, block, creative, inv_row) world[y][x] = 0 draw_tile(x, y, 0, offset) # Dessiner au début draw_world(world, plr_x, plr_y, offset, block, creative, inv, inv_row, side) # Update while update(keys=[KEY_DOWN, KEY_OK, KEY_PLUS, KEY_MINUS, KEY_MULTIPLICATION, KEY_DIVISION, KEY_BACKSPACE, KEY_COMMA, KEY_POWER, KEY_TOOLBOX, KEY_PI, KEY_ALPHA]): # Mouvement k_left, k_right, k_up, k_down = keydown(KEY_LEFT), keydown(KEY_RIGHT), keydown(KEY_UP), keydown(KEY_DOWN) dx, dy = 0, 0 editing = keydown(KEY_OK) or (creative and keydown(KEY_BACKSPACE)) if timer(move_timer, MOVE_COOLDOWN*(1+editing)): dy -= JUMP * (k_up and plr_y > 0) vy = GRAVITY * (dy==0) * (not in_block(plr_x,plr_y)) * (not creative) # gravity dy += vy dy += (k_down and (in_block(plr_x,plr_y) or creative) and plr_y < MAPH-1) dx -= (k_left and plr_x > 0) dx += (k_right and plr_x < MAPW - 1) has_moved = dx != 0 or dy != 0 # - collision if not creative and has_moved and not in_block(plr_x,plr_y): if not in_bounds(plr_x+dx,plr_y) or in_block(plr_x+dx,plr_y): dx = 0 if not in_bounds(plr_x+dx,plr_y+dy) or in_block(plr_x+dx,plr_y+dy): dy = 0 has_moved = dx != 0 or dy != 0 # - move old_x, old_y = plr_x, plr_y if has_moved: plr_x += dx; plr_y += dy move_timer = monotonic() # - side old_side = side if k_left+k_right == 1: side = k_right if not (k_left or k_right or k_up): side = 2+side%2 else: side = side%2 # Nether if not creative and just_pressed[KEY_DOWN] and getblock(plr_x, plr_y+1) == 6: map = not map world = (overworld, nether)[map] update_map(map, world, plr_x, plr_y) draw_world(world, plr_x, plr_y, offset, block, creative, inv, inv_row, side) continue # Poser / casser des blocs plr_x, plr_y = plr_x, plr_y if in_bounds(plr_x, plr_y): # Poser if keydown(KEY_OK) and inv and not world[plr_y][plr_x] == block and (creative or (inv[block] > 0 and not in_block(plr_x,plr_y))): world[plr_y][plr_x] = block draw_tile(plr_x, plr_y, block, offset) draw_player(plr_x, plr_y, offset, world, side) if not creative: inv[block] -= 1 if inv[block] == 0: block_idx = list(inv).index(block) del inv[block] select_block(min(len(inv)-1, block_idx)) # redessiner inventaire draw_inventory(inv, block, creative, inv_row) # Casser (créa) if creative and keydown(KEY_BACKSPACE) and in_block(plr_x, plr_y): world[plr_y][plr_x] = 0 draw_player(plr_x, plr_y, offset, world, side) # Casser if not creative and just_pressed[KEY_BACKSPACE]: if k_right and plr_x+1 < MAPW: break_block(plr_x+1, plr_y) elif k_left and plr_x-1 >= 0: break_block(plr_x-1, plr_y) elif k_up and plr_y-1 >= 0: break_block(plr_x, plr_y-1) elif not (k_left or k_right or k_up) and plr_y+1 < MAPH: if in_block(plr_x,plr_y): break_block(plr_x, plr_y) draw_player(plr_x, plr_y, offset, world, side) else: break_block(plr_x, plr_y+1) # Changer de bloc if inv: last_idx = len(inv)-1 if just_pressed[KEY_MINUS]: block_idx = list(inv).index(block) select_block(min(last_idx,block_idx+1)) draw_inventory(inv, block, creative, inv_row) if just_pressed[KEY_PLUS]: block_idx = list(inv).index(block) select_block(max(0,block_idx-1)) draw_inventory(inv, block, creative, inv_row) if just_pressed[KEY_DIVISION]: block_idx = list(inv).index(block) select_block(min(last_idx,block_idx+MAX_INV)) draw_inventory(inv, block, creative, inv_row) if just_pressed[KEY_MULTIPLICATION]: block_idx = list(inv).index(block) select_block(max(0,block_idx-MAX_INV)) draw_inventory(inv, block, creative, inv_row) if keydown(KEY_ONE): select_block(min(last_idx,0)) if keydown(KEY_TWO): select_block(min(last_idx,1)) if keydown(KEY_THREE):select_block(min(last_idx,2)) if keydown(KEY_FOUR): select_block(min(last_idx,3)) if keydown(KEY_FIVE): select_block(min(last_idx,4)) if keydown(KEY_SIX): select_block(min(last_idx,5)) # Commandes # - terraform (crea) if creative and just_pressed[KEY_PI]: for y in range(FLOOR): for x in range(DSP_W): world[y][x+offset[0]] = 0 draw_world(world, plr_x, plr_y, offset, block, creative, inv, inv_row, side, edges=False) # - toggle crea/survival if just_pressed[KEY_ALPHA]: creative = not creative draw_edges(creative) if not creative: draw_inventory(inv, block, creative, inv_row) else: for dsp_y in range(DSP_H-1, DSP_H-5, -1): for dsp_x in range(DSP_W): x,y = dsp_x+offset[0], dsp_y+offset[1] draw_tile(x, y, world[y][x] if in_bounds(x,y) else 0, offset) draw_inventory(inv, block, creative, inv_row) # Draw # Changement de zone if not 0<= plr_x-offset[0] <DSP_W: offset[0] += DSP_W * (-1,1)[plr_x-offset[0] >= DSP_W] draw_world(world, plr_x, plr_y, offset, block, creative, inv, inv_row, side) if not 0<= plr_y-offset[1] <DSP_H: offset[1] += DSP_H * (-1,1)[plr_y-offset[1] >= DSP_H] draw_world(world, plr_x, plr_y, offset, block, creative, inv, inv_row, side) # Joueur a bougé elif has_moved: draw_tile(old_x, old_y, world[old_y][old_x], offset) # Restaurer l'ancienne case draw_player(plr_x, plr_y, offset, world, side) elif side!=old_side: draw_player(plr_x, plr_y, offset, world, side) if every(.02): pass # 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() GRAY3 = (51, 51, 51) # 333333 BLACK2 = (25, 31, 34) # 191f22 GRAY2 = (89, 82, 70) # 595246 GRAY1 = (128, 118, 101) # 807665 GRAY0 = (187, 176, 148) # bbb094 GREEN4 = (47, 68, 67) # 2f4443 GREEN3 = (59, 94, 88) # 3b5e58 GREEN2 = (90, 140, 108) # 5a8c6c GREEN1 = (139, 180, 141) # 8bb48d GREEN0 = (192, 208, 165) # c0d0a5 WHITE2 = (247, 239, 199) # f7efc7 BLUE1 = (161, 205, 176) BLUE2 = (112, 147, 149) # 709395 BLUE3 = (74, 120, 123) # 4a787b PINK3 = (56, 49, 64) # 383140 PINK2 = (115, 77, 92) # 734d5c PINK1 = (167, 103, 114) # a76772 PINK0 = (204, 134, 125) # cc867d ORANGE0 = (224, 186, 139) # e0ba8b ORANGE1 = (195, 130, 82) # c38252 ORANGE2 = (161, 86, 60) # a1563c ORANGE3 = (111, 52, 45) # 6f342d ORANGE4 = (68, 39, 31) # 44271f PALETTE = [GRAY3, BLACK2, GRAY2, GRAY1, GRAY0, GREEN4, GREEN3, GREEN2, GREEN1, GREEN0, WHITE2, BLUE1, BLUE2, BLUE3, PINK3, PINK2, PINK1, PINK0, ORANGE0, ORANGE1, ORANGE2, ORANGE3, ORANGE4] comp=1 grass = ['!""""""""""""""!")((()()(((()((""6))(6)6()()6))""!66)666)6)6566""5436455666!546""64454666556555""555!5533533545""53344554644554""55454565445556""46556655555335""4533534633644!""5544354!445645""64544355555553""45565445636534""56356563354554"!""""""""""""""!'] def draw_image(x,y,img,ts,scale): dx, dy = 0,0 for s in img: a = ord(s)-33 for _ in range(comp): color = PALETTE[a%len(PALETTE)] a //= len(PALETTE) draw_rect((x+dx*scale,y+dy*scale,scale,scale), color) dx += 1 if dx == ts: dx = 0; dy += 1 def menu(): fill(BG) draw_image(W/2-32,32,grass[0],16,4) draw_text("MINECRAFT", W/2,H*.5,"center",WHITE,BG) draw_text("ok = start", W/2,H*.7,"center",WHITE,BG) draw_text("esc = quit", W/2,H*.8,"center",WHITE,BG) while not (update() and just_pressed.get(KEY_OK)): pass game() # Start menu()