1

Here is a python script that creates a pygame window and fills in the cell that is clicked on.

import pygame
from math import floor, sqrt
from sys import exit as _exit

cellsize = (5, 5)
mapSize = (int(600 / cellsize[0]), int(600 / cellsize[1]))
cells = [False for i in range(mapSize[0] * mapSize[1])]

def cellUnderMouse():
    c = (floor(mousepos[0] / cellsize[0]), floor(mousepos[1] / cellsize[1]))
    return c[1] * mapSize[0] + c[0]

pygame.init()
window = pygame.display.set_mode((600, 600))
mousePreviousFrame = pygame.mouse.get_pos()

while True:
    events = pygame.event.get()
    for event in events:
        if event.type == pygame.QUIT:
            pygame.quit()
            _exit();

    
    mouse = pygame.mouse.get_pressed()
    mousepos = pygame.mouse.get_pos()
    for x in range(mapSize[0]):
        for y in range(mapSize[1]):
            if mouse[0]:
                cells[cellUnderMouse()] = True
                #fill in the blanks...
##                direction = (mouse[0] - mousePreviousFrame[0], mouse[1] - mousePreviousFrame[1])
##                mag = sqrt((direction[0] ** 2) + (direction[1] ** 2))
##                if mag != 0:
##                    normdir = (direction[0] / mag, direction[1] / mag)
##                    current = list(mousePreviousFrame)
##                    while current != mouse:
##                        current[0] += normdir[0]
##                        current[1] += normdir[1]
##                        pygame.draw.rect(window, (0, 0, 0), (current[0], current[1], cellsize[0], cellsize[1]))

    mousePreviousFrame = mouse
    #draw
    window.fill((255, 255, 255))
    for x in range(mapSize[0]):
        for y in range(mapSize[1]):
            if (cells[y * mapSize[0] + x]):
                pygame.draw.rect(window, (0, 0, 0), (x * cellsize[0], y * cellsize[1], cellsize[0], cellsize[1]))

    pygame.display.flip()
       

The problem I am having is that if I move the mouse quickly, it skips a few blocks and I want to fill in all the skipped blocks as well. My attempt at solving the problem (the section which is commented out) creates a direction vector from the previous mouse position to the current mouse position and fill in the cells along the way but it doesn't work. There's a while loop which never exits and the application crashes.

1 Answers1

2

Implement a function, that returns the index of a cell at a certain position:

def cellAtPos(pos):
    c = (floor(pos[0] / cellsize[0]), floor(pos[1] / cellsize[1]))
    return c[1] * mapSize[0] + c[0]

Store the mouse buttons and position in ever frame:

mousePreviousFrame = mouse
mousePosPreviousFrame = mousepos

With the mouse button is pressed and was pressed in the previous frame, calculate the vector the mouse moved:

if mouse[0] and mousePreviousFrame[0]:
    direction = (mousepos[0] - mousePosPreviousFrame[0], mousepos[1] - mousePosPreviousFrame[1])

Fill the cells along the vector in a loop:

mag = hypot(*direction)
if mag != 0:
    normdir = (direction[0] / mag, direction[1] / mag)
    for i in range(int(mag)):
        current = mousePosPreviousFrame[0] + normdir[0] * i,  mousePosPreviousFrame[1] + normdir[1] * i 
        cells[cellAtPos(current)] = True

Minimal example

import pygame
from math import floor, sqrt, hypot
from sys import exit as _exit

cellsize = (5, 5)
mapSize = (int(600 / cellsize[0]), int(600 / cellsize[1]))
cells = [False for i in range(mapSize[0] * mapSize[1])]

def cellAtPos(pos):
    c = (floor(pos[0] / cellsize[0]), floor(pos[1] / cellsize[1]))
    return c[1] * mapSize[0] + c[0]

pygame.init()
window = pygame.display.set_mode((600, 600))
mousePreviousFrame = pygame.mouse.get_pos()

run = True
while run:
    events = pygame.event.get()
    for event in events:
        if event.type == pygame.QUIT:
            run = False
  
    mouse = pygame.mouse.get_pressed()
    mousepos = pygame.mouse.get_pos()
    if mouse[0]:
        cells[cellAtPos(mousepos)] = True
    if mouse[0] and mousePreviousFrame[0]:
        direction = (mousepos[0] - mousePosPreviousFrame[0], mousepos[1] - mousePosPreviousFrame[1])
        mag = hypot(*direction)
        if mag != 0:
            normdir = (direction[0] / mag, direction[1] / mag)
            for i in range(int(mag)):
                current = mousePosPreviousFrame[0] + normdir[0] * i,  mousePosPreviousFrame[1] + normdir[1] * i 
                cells[cellAtPos(current)] = True
    mousePreviousFrame = mouse
    mousePosPreviousFrame = mousepos

    #draw
    window.fill((255, 255, 255))
    for x in range(mapSize[0]):
        for y in range(mapSize[1]):
            if (cells[y * mapSize[0] + x]):
                pygame.draw.rect(window, (0, 0, 0), (x * cellsize[0], y * cellsize[1], cellsize[0], cellsize[1]))

    pygame.display.flip()

pygame.quit()
_exit()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Thanks for the answer. What is the * in `hypot(*direction)` syntax? –  Jul 28 '21 at 20:28
  • 2
    @user16038533 `hypot(x, y)` is the same as `sqrt(x*x + y*y)` (see [Hypot](https://en.wikipedia.org/wiki/Hypot)). For `*direction` see [Unzipping and the * operator](https://stackoverflow.com/questions/5917522/unzipping-and-the-operator) or [What does ** (double star/asterisk) and * (star/asterisk) do for parameters?](https://stackoverflow.com/questions/36901/what-does-double-star-asterisk-and-star-asterisk-do-for-parameters) – Rabbid76 Jul 28 '21 at 20:31