Tutorial: Hex-Welten#

In diesem Tutorial baust du Schritt für Schritt eine Welt aus Sechsecken. Sechseckige Welten werden für Brettspiele wie Catan verwendet: Landhexfelder, Siedlungen auf Ecken und Straßen auf Kanten.

Wenn du noch nie mit Welten gearbeitet hast, beginne mit dem Kapitel Die erste Welt im interaktiven Kurs.

Schritt 1: Eine Hex-Welt erstellen#

Eine HexWorld wird mit (Spalten, Zeilen) und einer tile_size erstellt:

import miniworlds

world = miniworlds.HexWorld(7, 7, tile_size=40)
world.background.grid = True

world.run()

Hexfelder werden wie Kacheln in einer TiledWorld über (Spalte, Zeile)-Koordinaten angesprochen. Ungerade Zeilen sind um ein halbes Hexfeld nach rechts verschoben.

Schritt 2: Actors auf Hexfeldern platzieren#

Ein Actor, der auf einer Hexfeld-Position platziert wird, wird als Sechseck gezeichnet:

import miniworlds

world = miniworlds.HexWorld(7, 7, tile_size=40)
world.background.grid = True

forest = miniworlds.Actor((2, 3))
forest.fill_color = (0, 120, 0)

desert = miniworlds.Actor((4, 2))
desert.fill_color = (230, 210, 160)

world.run()

Schritt 3: Nachbarn abfragen#

world.get_tile(position) gibt ein einzelnes Hexfeld zurück. tile.get_neighbour_tiles() gibt die bis zu sechs benachbarten Hexfelder zurück.

Das Beispiel färbt das zentrale Hexfeld und alle seine Nachbarn:

import miniworlds

world = miniworlds.HexWorld(7, 7, tile_size=40)
world.background.grid = True

center = world.get_tile((3, 3))
center_actor = miniworlds.Actor(center.position)
center_actor.fill_color = (200, 30, 30)

for tile in center.get_neighbour_tiles():
    actor = miniworlds.Actor(tile.position)
    actor.fill_color = (0, 120, 0)

world.run()

world.get_tiles_in_radius(position, radius) returns all hexes within a given hex distance, ordered from the center outwards. world.get_tiles_in_ring(position, radius) returns only the hexes at exactly the given distance, in ring traversal order.

Step 4: Move actors from hex to hex#

Actors move from hex to hex with the six hex directions "no", "o", "so", "sw", "w", and "nw":

import miniworlds

world = miniworlds.HexWorld(7, 7, tile_size=40)
world.background.grid = True

robot = miniworlds.Actor((3, 3))
robot.fill_color = (200, 30, 30)

@robot.register
def act(self):
    if world.frame % 20 == 0:
        self.move_in_direction("no")

world.run()

Every move_in_direction call moves the actor exactly one hex, independent of the row parity. The directions can also be given as degrees: "no" is 30, "o" is 90, "so" is 150, "sw" is 210, "w" is 270, and "nw" is 330.

Step 5: React to clicks#

With @world.register you can react to mouse clicks. world.get_tile_from_pixel(mouse_pos) returns the hex under the mouse, or None if the click is outside the world:

import miniworlds

world = miniworlds.HexWorld(7, 7, tile_size=40)
world.background.grid = True

@world.register
def on_mouse_left(self, mouse_pos):
    tile = world.get_tile_from_pixel(mouse_pos)
    if tile is None:
        return
    actor = miniworlds.Actor(tile.position)
    actor.fill_color = (0, 120, 0)

world.run()

Step 6: Settlements and roads#

Corners and edges are positions, too. world.get_corner_from_pixel(mouse_pos) returns the nearest corner, world.get_edge_from_pixel(mouse_pos) the nearest edge. Both return None if the pixel is outside the world, for example when a toolbar or console is attached to the world.

Ein Linksklick platziert eine Siedlung (kleiner Kreis) auf einer Ecke, ein Rechtsklick eine Straße (kleines Rechteck) auf einer Kante:

import miniworlds

world = miniworlds.HexWorld(7, 7, tile_size=40)
world.background.grid = True

@world.register
def on_mouse_left(self, mouse_pos):
    corner = world.get_corner_from_pixel(mouse_pos)
    settlement = miniworlds.Actor(corner.position)
    settlement.fill_color = (200, 30, 30)
    settlement.size = (0.3, 0.3)

@world.register
def on_mouse_right(self, mouse_pos):
    edge = world.get_edge_from_pixel(mouse_pos)
    road = miniworlds.Actor(edge.position)
    road.fill_color = (90, 60, 30)
    road.size = (0.6, 0.15)

world.run()

Step 7: A mini-Catan board#

Ein Catan-Brett hat 19 Landhexfelder, angeordnet in Zeilen aus 3, 4, 5, 4 und 3 Hexfeldern:

import miniworlds

world = miniworlds.HexWorld(7, 7, tile_size=40)
world.background.grid = True

land_positions = [
    (2, 1), (3, 1), (4, 1),
    (2, 2), (3, 2), (4, 2), (5, 2),
    (1, 3), (2, 3), (3, 3), (4, 3), (5, 3),
    (1, 4), (2, 4), (3, 4), (4, 4),
    (2, 5), (3, 5), (4, 5),
]
terrain_colors = [
    (0, 120, 0),      # forest
    (220, 180, 60),   # field
    (120, 200, 60),   # meadow
    (150, 150, 150),  # mountain
    (200, 90, 30),    # hill
    (230, 210, 160),  # desert
]

for number, position in enumerate(land_positions):
    actor = miniworlds.Actor(position)
    actor.fill_color = terrain_colors[number % len(terrain_colors)]
    actor.border = 1

world.run()

Von hier aus kannst du im Pattern Hex-Welten und ein Mini-Catan-Brett weitermachen und eigene Spielregeln ergänzen: Würfel, Rohstoffe und Handel sind nicht Teil des Frameworks — sie gehören in deinen Spielcode.

Die vollständige Schnittstelle ist in der HexWorld-API-Referenz dokumentiert.