Salta el contingut

Jocs amb Python

Frameworks per al desenvolupament de jocs

Framework Descripció
Pygame El més popular. Basat en SDL, ideal per a jocs 2D.
PyKyra Basat en SDL i Kyra, molt ràpid.
Pyglet Sense dependències, usa OpenGL directament.
PyOpenGL Binding de Python per a OpenGL.
Kivy Interfícies multitàctil, funciona en mòbil i escriptori.
Panda3D Motor 3D complet.
Cocos2d Jocs 2D amb escenes i transicions.
Python-Ogre Binding del motor 3D Ogre.
Ren'Py Especialitzat en visual novels.

Referència: Pygame Tutorial — GeeksforGeeks


Exemples inclosos

Egg Catcher — samples/egg/egg.py

Tecnologia: Tkinter (Canvas)

Joc en què ous de colors cauen des de la part superior de la pantalla i el jugador ha de recollir-los amb una cistella que es mou esquerra/dreta amb les tecles de cursor.

Mecàniques:

  • Ous generats aleatòriament a intervals regulars
  • La velocitat i la freqüència augmenten amb cada ou recollit (factor de dificultat 0.95)
  • 3 vides: es perd una vida cada cop que un ou toca terra
  • Puntuació de 10 punts per ou recollit

Controls:

Conceptes Python il·lustrats:

  • tkinter.Canvas: dibuix de formes (create_oval, create_arc, create_rectangle)
  • itertools.cycle per ciclar colors
  • root.after() per al bucle de joc sense bloquejar la interfície
  • Detecció de col·lisions manual comparant coordenades

Codi:

from itertools import cycle
from random import randrange
from tkinter import Canvas, Tk, messagebox, font

canvas_width = 800
canvas_height = 400

root = Tk()
root.title("Egg Catcher")
c = Canvas(root, width=canvas_width, height=canvas_height, background="deep sky blue")
c.create_rectangle(-5, canvas_height-100, canvas_width+5, canvas_height+5, fill="sea green", width=0)
c.create_oval(-80, -80, 120, 120, fill='orange', width=0)
c.pack()

color_cycle = cycle(["light blue", "light green", "light pink", "light yellow", "light cyan"])
egg_width = 45
egg_height = 55
egg_score = 10
egg_speed = 250
egg_interval = 4000
difficulty = 0.95
catcher_color = "blue"
catcher_width = 100
catcher_height = 100
catcher_startx = canvas_width / 2 - catcher_width / 2
catcher_starty = canvas_height - catcher_height - 20
catcher_startx2 = catcher_startx + catcher_width
catcher_starty2 = catcher_starty + catcher_height

catcher = c.create_arc(catcher_startx, catcher_starty, catcher_startx2, catcher_starty2,
                       start=200, extent=140, style="arc", outline=catcher_color, width=3)
game_font = font.nametofont("TkFixedFont")
game_font.config(size=18)

score = 0
score_text = c.create_text(10, 10, anchor="nw", font=game_font, fill="darkblue",
                           text="Score: " + str(score))
lives_remaining = 3
lives_text = c.create_text(canvas_width-10, 10, anchor="ne", font=game_font, fill="darkblue",
                           text="Lives: " + str(lives_remaining))
eggs = []

def create_egg():
    x = randrange(10, 740)
    y = 40
    new_egg = c.create_oval(x, y, x+egg_width, y+egg_height, fill=next(color_cycle), width=0)
    eggs.append(new_egg)
    root.after(egg_interval, create_egg)

def move_eggs():
    for egg in eggs:
        (eggx, eggy, eggx2, eggy2) = c.coords(egg)
        c.move(egg, 0, 10)
        if eggy2 > canvas_height:
            egg_dropped(egg)
    root.after(egg_speed, move_eggs)

def egg_dropped(egg):
    eggs.remove(egg)
    c.delete(egg)
    lose_a_life()
    if lives_remaining == 0:
        messagebox.showinfo("Game Over!", "Final Score: " + str(score))
        root.destroy()

def lose_a_life():
    global lives_remaining
    lives_remaining -= 1
    c.itemconfigure(lives_text, text="Lives: " + str(lives_remaining))

def check_catch():
    (catcherx, catchery, catcherx2, catchery2) = c.coords(catcher)
    for egg in eggs:
        (eggx, eggy, eggx2, eggy2) = c.coords(egg)
        if catcherx < eggx and eggx2 < catcherx2 and catchery2 - eggy2 < 40:
            eggs.remove(egg)
            c.delete(egg)
            increase_score(egg_score)
    root.after(100, check_catch)

def increase_score(points):
    global score, egg_speed, egg_interval
    score += points
    egg_speed = int(egg_speed * difficulty)
    egg_interval = int(egg_interval * difficulty)
    c.itemconfigure(score_text, text="Score: " + str(score))

def move_left(event):
    (x1, y1, x2, y2) = c.coords(catcher)
    if x1 > 0:
        c.move(catcher, -20, 0)

def move_right(event):
    (x1, y1, x2, y2) = c.coords(catcher)
    if x2 < canvas_width:
        c.move(catcher, 20, 0)

c.bind("<Left>", move_left)
c.bind("<Right>", move_right)
c.focus_set()
root.after(1000, create_egg)
root.after(1000, move_eggs)
root.after(1000, check_catch)
root.mainloop()

Snake — samples/snake/snake.py

Tecnologia: Pygame

El clàssic joc de la serp: controla una serp que creix cada cop que menja un aliment. El joc acaba si la serp xoca amb les parets o amb ella mateixa.

Nota: Pygame pot no estar disponible per a Python 3.11+. Si cal, instal·la-ho amb pip install pygame --pre.

Mecàniques:

  • Serp formada per una llista de segments de 10×10 píxels
  • Aliment col·locat aleatòriament en posicions alineades a la graella
  • En menjar, la longitud de la serp augmenta en 1
  • Si la serp surt dels límits o es mossega, apareix pantalla de game over
  • Opció de tornar a jugar (C) o sortir (Q)

Controls:

Conceptes Python il·lustrats:

  • Bucle de joc amb pygame.time.Clock i clock.tick()
  • Dibuix amb pygame.draw.rect
  • Gestió d'events de teclat amb pygame.event.get()
  • Llista com a cua de segments de la serp

Codi:

import pygame
import time
import random

pygame.init()

white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)

dis_width = 800
dis_height = 600

dis = pygame.display.set_mode((dis_width, dis_height))
pygame.display.set_caption('Snake Game')

clock = pygame.time.Clock()

snake_block = 10
snake_speed = 10

font_style = pygame.font.SysFont("bahnschrift", 25)
score_font = pygame.font.SysFont("comicsansms", 35)


def Your_score(score):
    value = score_font.render("Your Score: " + str(score), True, yellow)
    dis.blit(value, [0, 0])


def our_snake(snake_block, snake_list):
    for x in snake_list:
        pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block])


def message(msg, color):
    mesg = font_style.render(msg, True, color)
    dis.blit(mesg, [dis_width / 6, dis_height / 3])


def gameLoop():
    game_over = False
    game_close = False

    x1 = dis_width / 2
    y1 = dis_height / 2
    x1_change = 0
    y1_change = 0

    snake_List = []
    Length_of_snake = 1

    foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
    foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0

    while not game_over:

        while game_close:
            dis.fill(blue)
            message("You Lost! Press C-Play Again or Q-Quit", red)
            Your_score(Length_of_snake - 1)
            pygame.display.update()

            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        game_over = True
                        game_close = False
                    if event.key == pygame.K_c:
                        gameLoop()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                game_over = True
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    x1_change = -snake_block
                    y1_change = 0
                elif event.key == pygame.K_RIGHT:
                    x1_change = snake_block
                    y1_change = 0
                elif event.key == pygame.K_UP:
                    y1_change = -snake_block
                    x1_change = 0
                elif event.key == pygame.K_DOWN:
                    y1_change = snake_block
                    x1_change = 0

        if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
            game_close = True
        x1 += x1_change
        y1 += y1_change
        dis.fill(blue)
        pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block])
        snake_Head = [x1, y1]
        snake_List.append(snake_Head)
        if len(snake_List) > Length_of_snake:
            del snake_List[0]

        for x in snake_List[:-1]:
            if x == snake_Head:
                game_close = True

        our_snake(snake_block, snake_List)
        Your_score(Length_of_snake - 1)
        pygame.display.update()

        if x1 == foodx and y1 == foody:
            foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
            foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0
            Length_of_snake += 1

        clock.tick(snake_speed)

    pygame.quit()
    quit()


gameLoop()

Cursa de Tortugues — samples/turtle/index.py

Tecnologia: Mòdul turtle (estàndard de Python)

Simulació d'una cursa de 6 tortugues de colors. El jugador aposta per una tortuga abans de la cursa i al final s'anuncia si ha guanyat o perdut.

Mecàniques:

  • 6 tortugues (vermell, taronja, groc, verd, blau, morat) alineades a l'esquerra
  • Cada iteració del bucle, cada tortuga avança un nombre aleatori de passos (0–10)
  • La primera que supera x = 230 guanya
  • L'aposta s'introdueix amb screen.textinput() abans de la cursa

Conceptes Python il·lustrats:

  • Mòdul turtle: Turtle, Screen, penup(), goto(), forward(), xcor()
  • screen.textinput() per a entrada de l'usuari en una finestra gràfica
  • Bucle while amb condició d'acabada basada en l'estat del joc
  • Llista de tortugues i iteració simultània

Codi:

from turtle import Turtle, Screen
import random

race_active = False
screen = Screen()
screen.setup(width=500, height=400)
turtle_bet = screen.textinput(
    title="Make your bet!",
    prompt="Which turtle do you think will win? Enter a colour: "
)

colours = ["red", "orange", "yellow", "green", "blue", "purple"]
y_positions = (-100, -60, -20, 20, 60, 100)
all_turtles = []

for turtle_index in range(0, 6):
    new_turtle = Turtle(shape="turtle")
    new_turtle.color(colours[turtle_index])
    new_turtle.penup()
    new_turtle.goto(x=-200, y=(y_positions[turtle_index]))
    all_turtles.append(new_turtle)

if turtle_bet:
    race_active = True

while race_active:
    for turtle in all_turtles:
        if turtle.xcor() > 230:
            race_active = False
            winning_colour = turtle.pencolor()
            if winning_colour == turtle_bet:
                print(f"You win! The {winning_colour} turtle is the winner.")
            else:
                print(f"You lose. The {winning_colour} turtle is the winner.")

        rand_distance = random.randint(0, 10)
        turtle.forward(rand_distance)

screen.exitonclick()

Recursos addicionals