Python Forum
[PyGame] 2D BoardGame Pygame
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyGame] 2D BoardGame Pygame
#6
Here another example. Just couldn't stop myself.
import pygame
import os

from pygame.sprite import Sprite, Group

class State:
    def on_draw(self, surface): pass
    def on_event(self, event): pass
    def on_update(self, delta): pass

class Engine:
    @classmethod
    def setup(cls, caption, width, height, center=False):
        if center:
            os.environ['SDL_VIDEO_CENTERED'] = '1'

        pygame.display.set_caption(caption)
        cls.surface = pygame.display.set_mode((width, height))
        cls.rect = cls.surface.get_rect()
        cls.clock = pygame.time.Clock()
        cls.running = False
        cls.delta = 0
        cls.fps = 30

        cls.state = State()

    @classmethod
    def mainloop(cls):
        cls.running = True
        while cls.running:
            for event in pygame.event.get():
                cls.state.on_event(event)

            cls.state.on_update(cls.delta)
            cls.state.on_draw(cls.surface)
            pygame.display.flip()
            cls.delta = cls.clock.tick(cls.fps)

class Point:
    def __init__(self, *args):
        length = len(args)
        if length == 1:
            if isinstance(args[0], Point):
                self.x = args[0].x
                self.y = args[0].y
            else:
                self.x, self.y = args[0]
        else:
            self.x = args[0]
            self.y = args[1]

    def __add__(self, point):
        return Point(self.x + point.x, self.y + point.y)

    def __sub__(self, point):
        return Point(self.x - point.x, self.y - point.y)

    def __hash__(self):
        return self.x + self.y

    def __iter__(self):
        yield self.x
        yield self.y

    def __repr__(self):
        return 'Point' + str(vars(self))

class ColoredSprite(Sprite):
    images = {}

    @classmethod
    def create_image(cls, color, colorname):
        image = pygame.Surface((38, 38))
        image.fill(color)
        cls.images[colorname] = image
        return image

    @classmethod
    def get_image(cls, colorname):
        if colorname not in pygame.color.THECOLORS.keys():
            colorname = 'dodgerblue'

        if colorname not in cls.images.keys():
            color = pygame.Color(colorname)
            return cls.create_image(color, colorname)
        else:
            return cls.images[colorname]

    def __init__(self, imagename, position, anchor="topleft"):
        Sprite.__init__(self)
        self.image = ColoredSprite.get_image(imagename)
        self.rect = self.image.get_rect()
        setattr(self.rect, anchor, position)

class Grid:
    @classmethod
    def from_slots(cls, position, slots, size, gap=(0, 0)):
        slots = Point(slots)
        size = Point(size)
        gap = Point(gap)
        sz = size + gap
        rect = pygame.Rect(*position, sz.x * slots.x, sz.y * slots.y)
        return cls(rect, size, gap)

    def __init__(self, rect, size, gap=(0, 0), fit=False):
        self.rect = rect
        self.size = Point(size)
        self.gap = Point(gap)
        self.cut = Point(self.size + self.gap)
        self.slots = Point((self.rect.width // self.cut.x,
                                self.rect.height // self.cut.y))
        if fit:
            self.rect.width = self.slots.x * self.cut.x
            self.rect.height = self.slots.y * self.cut.y

        self.show_lines = False
        self.show_boxes = False
        self.build()

    def build(self):
        # Grid Points
        self.points = []
        for i in range(self.rect.x, self.rect.right + 1, self.cut.x):
            self.points.append(((i, self.rect.top), (i, self.rect.bottom)))

        for i in range(self.rect.y, self.rect.bottom + 1, self.cut.y):
            self.points.append(((self.rect.left, i), (self.rect.right, i)))

        # Rects
        self.rects = []
        for x in range(self.rect.left, self.rect.right, self.cut.x):
            for y in range(self.rect.top, self.rect.bottom, self.cut.y):
                self.rects.append(pygame.Rect(x, y, self.size.x, self.size.y))

    # Returns None for invalid position
    def get_position(self, x, y):
        if (self.rect.left < x < self.rect.right and
            self.rect.top < y < self.rect.bottom):

            pos = ((x - self.rect.x) // self.cut.x,
                   (y - self.rect.y) // self.cut.y)

            if self.get_rect(*pos).collidepoint(x, y):
                return pos

    # Returns None for invalid position
    def get_rect(self, x, y, from_screen=False):
        if from_screen:
            if (self.rect.left < x < self.rect.right and
                self.rect.top < y < self.rect.bottom):

                rect = pygame.Rect(
                    (x - self.rect.x) // self.cut.x * self.cut.x + self.rect.x,
                    (y - self.rect.y) // self.cut.y * self.cut.y + self.rect.y,
                    self.size.x, self.size.y)

                if rect.collidepoint(x, y):
                    return rect
        else:
            if 0 <= x < self.slots.x and 0 <= y < self.slots.y:
                return pygame.Rect(x * self.cut.x + self.rect.x,
                                   y * self.cut.y + self.rect.y,
                                   self.size.x, self.size.y)

    def draw(self, surface, color):
        if self.show_lines:
            self.draw_lines(surface, color)
        elif self.show_boxes:
            self.draw_boxes(surface, color)

    def draw_lines(self, surface, color):
        for start, end in self.points:
            pygame.draw.line(surface, color, start, end)

    def draw_boxes(self, surface, color):
        for rect in self.rects:
            pygame.draw.rect(surface, color, rect, 1)

class DragDrop:
    def __init__(self, grid, slots):
        self.grid = grid
        self.slots = slots
        self.selected = None
        self.home_slot = None
        self.home_rect = None
        self.grab_position = None
        self.sprite_groups = None

    def draw(self, surface):
        if self.selected:
            surface.blit(self.selected.image, self.selected.rect)

    def drop(self, pos):
        if self.selected:
            slot = self.grid.get_position(*pos)
            rect = self.grid.get_rect(*pos, True)
            self.selected.add(self.sprite_groups)
            pygame.mouse.set_visible(True)

            if rect and slot != self.home_slot:
                self.slots.swap(slot, self.home_slot)
                s = self.slots.get(self.home_slot)
                if s:
                    x, y = self.home_slot
                    s.rect.center = self.grid.get_rect(x, y).center

                self.selected.rect.center = rect.center
                self.selected = None
            else:
                self.selected.rect = self.home_rect
                self.selected = None

    def grab(self, pos, sprites):
        for sprite in sprites:
            if sprite.rect.collidepoint(pos):
                pygame.mouse.set_visible(False)
                self.grab_position = (pos[0] - sprite.rect.x,
                                      pos[1] - sprite.rect.y)
                self.home_slot = self.grid.get_position(*pos)
                self.home_rect = sprite.rect.copy()
                self.selected = sprite
                self.sprite_groups = sprite.groups()
                sprite.kill()
                return

    def move(self, pos):
        if self.selected:
            x = pos[0] - self.grab_position[0]
            y = pos[1] - self.grab_position[1]
            self.selected.rect.topleft = x, y

class Slots:
    def __init__(self, slots, default_value=None):
        slots = Point(slots)
        self.slots = []
        for x in range(slots.x):
            self.slots.append([default_value] * slots.y)

    def get(self, key):
        key = Point(key)
        return self.slots[key.x][key.y]

    def set(self, key, value):
        key = Point(key)
        self.slots[key.x][key.y] = value

    def swap(self, a, b):
        a = Point(a)
        b = Point(b)
        s = self.slots
        s[a.x][a.y], s[b.x][b.y] = s[b.x][b.y], s[a.x][a.y]

    def __getitem__(self, key):
        return self.slots[key]

    def __setitem__(self, key, value):
        self.slots[key] = value

    def __repr__(self):
        return ('{}\n' * self.size.x).format(*self.slots)

class Example(State):
    def __init__(self):
        self.grid = []
        self.sprites = Group()

        self.grid = Grid(Engine.rect.inflate(-100, -100), (40, 40), (2, 2), True)
        #self.grid = Grid.from_slots((50, 50), (9, 9), (40, 40), (2, 2))
        self.slots = Slots(self.grid.slots)

        self.mouse = DragDrop(self.grid, self.slots)

        self.add_sprite((2, 3), 'firebrick')
        self.add_sprite((8, 6), 'dodgerblue')
        self.add_sprite((1, 7), 'lawngreen')

    def add_sprite(self, pos, colorname):
        pos = Point(pos)
        rect = self.grid.get_rect(pos.x, pos.y)
        sprite = ColoredSprite(colorname, rect.center, 'center')
        sprite.add(self.sprites)
        self.slots.set(pos, sprite)

    def on_draw(self, surface):
        surface.fill(pygame.Color('black'))
        self.grid.draw(surface, pygame.Color('white'))
        self.sprites.draw(surface)
        self.mouse.draw(surface)

    def on_event(self, event):
        if event.type == pygame.QUIT:
            Engine.running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                self.mouse.grab(event.pos, self.sprites)
        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:
                self.mouse.drop(event.pos)
        elif event.type == pygame.MOUSEMOTION:
            self.mouse.move(event.pos)
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                self.grid.show_lines = not self.grid.show_lines
            elif event.key == pygame.K_b:
                self.grid.show_boxes = not self.grid.show_boxes

def main():
    pygame.init()
    Engine.setup("Example", 800, 600, True)
    Engine.state = Example()
    Engine.mainloop()

if __name__ == "__main__":
    main()
99 percent of computer problems exists between chair and keyboard.
Reply


Messages In This Thread
2D BoardGame Pygame - by Josh_Python890 - Aug-13-2019, 11:59 AM
RE: 2D BoardGame Pygame - by metulburr - Aug-13-2019, 12:32 PM
RE: 2D BoardGame Pygame - by Windspar - Aug-13-2019, 02:18 PM
RE: 2D BoardGame Pygame - by Windspar - Aug-13-2019, 06:25 PM
RE: 2D BoardGame Pygame - by SheeppOSU - Aug-14-2019, 02:32 AM
RE: 2D BoardGame Pygame - by Windspar - Aug-15-2019, 09:02 PM

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020