Created
January 31, 2023 06:16
-
-
Save rahulbhadani/bd2529f9897145b1e5ac5e5908329ecd to your computer and use it in GitHub Desktop.
Canvas with grids in Pygame
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pygame | |
from pygame import gfxdraw | |
import numpy as np | |
class Window: | |
def __init__(self, sim=None, config={}): | |
# Simulation to draw | |
#self.sim = sim | |
# Set default configurations | |
self.set_default_config() | |
# Update configurations | |
for attr, val in config.items(): | |
setattr(self, attr, val) | |
def set_default_config(self): | |
"""Set default configuration""" | |
self.width = 1400 | |
self.height = 1000 | |
self.bg_color = (250, 250, 250) | |
self.fps = 60 | |
self.zoom = 5 | |
self.offset = (0, 0) | |
self.mouse_last = (0, 0) | |
self.mouse_down = False | |
def loop(self, loop=None): | |
"""Shows a window visualizing the simulation and runs the loop function.""" | |
# Create a pygame window | |
self.screen = pygame.display.set_mode((self.width, self.height)) | |
pygame.display.flip() | |
# Fixed fps | |
clock = pygame.time.Clock() | |
# To draw text | |
pygame.font.init() | |
self.text_font = pygame.font.SysFont('Lucida Console', 16) | |
# Draw loop | |
running = True | |
while running: | |
# Update simulation | |
#if loop: loop(self.sim) | |
# Draw simulation | |
self.draw() | |
# Update window | |
pygame.display.update() | |
clock.tick(self.fps) | |
# Handle all events | |
for event in pygame.event.get(): | |
# Quit program if window is closed | |
if event.type == pygame.QUIT: | |
running = False | |
# Handle mouse events | |
elif event.type == pygame.MOUSEBUTTONDOWN: | |
# If mouse button down | |
if event.button == 1: | |
# Left click | |
x, y = pygame.mouse.get_pos() | |
x0, y0 = self.offset | |
self.mouse_last = (x-x0*self.zoom, y-y0*self.zoom) | |
self.mouse_down = True | |
if event.button == 4: | |
# Mouse wheel up | |
self.zoom *= (self.zoom**2+self.zoom/4+1) / (self.zoom**2+1) | |
if event.button == 5: | |
# Mouse wheel down | |
self.zoom *= (self.zoom**2+1) / (self.zoom**2+self.zoom/4+1) | |
elif event.type == pygame.MOUSEMOTION: | |
# Drag content | |
if self.mouse_down: | |
x1, y1 = self.mouse_last | |
x2, y2 = pygame.mouse.get_pos() | |
self.offset = ((x2-x1)/self.zoom, (y2-y1)/self.zoom) | |
elif event.type == pygame.MOUSEBUTTONUP: | |
self.mouse_down = False | |
def convert(self, x, y=None): | |
"""Converts simulation coordinates to screen coordinates""" | |
if isinstance(x, list): | |
return [self.convert(e[0], e[1]) for e in x] | |
if isinstance(x, tuple): | |
return self.convert(*x) | |
return ( | |
int(self.width/2 + (x + self.offset[0])*self.zoom), | |
int(self.height/2 + (y + self.offset[1])*self.zoom) | |
) | |
def inverse_convert(self, x, y=None): | |
"""Converts screen coordinates to simulation coordinates""" | |
if isinstance(x, list): | |
return [self.convert(e[0], e[1]) for e in x] | |
if isinstance(x, tuple): | |
return self.convert(*x) | |
return ( | |
int(-self.offset[0] + (x - self.width/2)/self.zoom), | |
int(-self.offset[1] + (y - self.height/2)/self.zoom) | |
) | |
def background(self, r, g, b): | |
"""Fills screen with one color.""" | |
self.screen.fill((r, g, b)) | |
def line(self, start_pos, end_pos, color): | |
"""Draws a line.""" | |
gfxdraw.line( self.screen, *start_pos, *end_pos, color) | |
def draw_axes(self, color=(100, 100, 100)): | |
"""Draw x and y axis""" | |
x_start, y_start = self.inverse_convert(0, 0) | |
x_end, y_end = self.inverse_convert(self.width, self.height) | |
self.line( self.convert((0, y_start)), self.convert((0, y_end)), color ) | |
self.line( self.convert((x_start, 0)), self.convert((x_end, 0)), color ) | |
def draw_grid(self, unit=50, color=(150,150,150)): | |
"""Draws a grid""" | |
x_start, y_start = self.inverse_convert(0, 0) | |
x_end, y_end = self.inverse_convert(self.width, self.height) | |
n_x = int(x_start / unit) | |
n_y = int(y_start / unit) | |
m_x = int(x_end / unit)+1 | |
m_y = int(y_end / unit)+1 | |
for i in range(n_x, m_x): | |
self.line(self.convert((unit*i, y_start)), self.convert((unit*i, y_end)), color ) | |
for i in range(n_y, m_y): | |
self.line(self.convert((x_start, unit*i)), self.convert((x_end, unit*i)), color ) | |
def draw_roads(self): | |
"""Draws every road""" | |
pass | |
def draw_status(self): | |
"""Draws status text""" | |
text_fps = self.text_font.render(f't={20.0:.5}', False, (0, 0, 0)) | |
text_frc = self.text_font.render(f'n={1000}', False, (0, 0, 0)) | |
self.screen.blit(text_fps, (0, 0)) | |
self.screen.blit(text_frc, (100, 0)) | |
def draw(self): | |
# Fill background | |
self.background(*self.bg_color) | |
# Major and minor grid and axes | |
self.draw_grid(10, (220,220,220)) | |
self.draw_grid(100, (200,200,200)) | |
self.draw_axes() | |
# Draw status info | |
self.draw_status() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment