minecraft.py

Created by azerlap652

Created on January 13, 2025

18.2 KB

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()

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.