Skip to content

Instantly share code, notes, and snippets.

@kdougan
Created November 18, 2022 04:01
Show Gist options
  • Save kdougan/d80266833318fb3d6a7f610f87f598fe to your computer and use it in GitHub Desktop.
Save kdougan/d80266833318fb3d6a7f610f87f598fe to your computer and use it in GitHub Desktop.
pygame._sdl2 + pymunk
from __future__ import annotations
import random
from dataclasses import dataclass
import pygame
import pymunk
from pygame import Vector2 as vec2
from pygame import _sdl2 as sdl2
from pygame._sdl2.video import Texture
@dataclass
class Entity:
pos: vec2
size: vec2
texture: Texture
@dataclass
class Camera:
pos: vec2
scale: float
class Game:
def __init__(self):
self.win_size = vec2(1440, 900)
self.screen = pygame.display.set_mode(self.win_size)
self.clock = pygame.time.Clock()
self.running = False
self.sdl_window = sdl2.Window.from_display_module()
self.renderer = sdl2.Renderer.from_window(self.sdl_window)
self.space = pymunk.Space()
self.space.gravity = (0.0, 0.0)
self.space.iterations = 4
self.camera = Camera(vec2(), 1.0)
self.entities = []
self.mpos = vec2()
self.prev_mpos = vec2()
@property
def screen_size(self):
return self.win_size / self.camera.scale
def run(self):
self.running = True
while self.running:
self.events()
self.update()
self.draw()
def events(self):
for event in pygame.event.get():
if (event.type == pygame.QUIT or
(event.type == pygame.KEYDOWN and
event.key == pygame.K_ESCAPE)):
self.running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
pass
elif event.type == pygame.MOUSEWHEEL:
# zoom in/out
self.camera.scale += event.y * 0.1
self.camera.scale = max(0.1, self.camera.scale)
# offset zoom to mouse position
self.camera.pos -= (self.mpos - self.camera.pos) * \
(self.camera.scale - 1)
self.prev_mpos = self.mpos
self.mpos = vec2(pygame.mouse.get_pos())
# if left mouse is pressed
if pygame.mouse.get_pressed()[0]:
for _ in range(10):
size = vec2((random.randint(12, 32) // 4) * 4)
surf = pygame.Surface(size, pygame.SRCALPHA)
pygame.draw.rect(surf, pygame.Color(
0, 200, 0, 255), pygame.Rect((0, 0), size), 1)
ent = Entity(
(self.mpos + self.camera.pos),
size,
sdl2.Texture.from_surface(self.renderer, surf)
)
self.entities.append(ent)
body = pymunk.Body()
body.position = tuple(
self.mpos + self.camera.pos)
shape = pymunk.Poly(
body=body,
vertices=[
(0, 0),
(size.x, 0),
(size.x, size.y),
(0, size.y)
],
radius=0.1)
shape.mass = 1.0
self.space.add(body, shape)
if pygame.mouse.get_pressed()[2]:
# pan the camera
self.camera.pos += (self.prev_mpos - self.mpos)
def update(self):
dt = self.clock.tick(60) * 0.001
fps = self.clock.get_fps()
self.sdl_window.title = f'fps: {fps:.2f} entities: {len(self.entities)}'
# update the space
self.space.step(dt)
# update the entities
for i, entity in enumerate(self.entities):
entity.pos = vec2(self.space.bodies[i].position)
def draw(self):
self.renderer.draw_color = pygame.Color(30, 20, 30, 255)
self.renderer.clear()
self.renderer.scale = vec2(self.camera.scale)
# draw the entities
for entity in self.entities:
self.renderer.blit(
entity.texture,
pygame.Rect(entity.pos - self.camera.pos, entity.size)
)
self.renderer.present()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment