Aug-15-2019, 09:02 PM
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.