Pygame: de ce instrumentul radieră nu funcționează ca destinat?

0

Problema

Eu sunt încercarea de a construi o bază de artă pixel editor, și în prezent se luptă din greu cu găsirea de eroare în codul meu. Creionul functioneaza bine, dar radiera nu.

Eșantion arată ce se întâmplă:

Fișierul principal

import pygame as pg
from settings import *
from gui import *
from canvas import Canvas
from utils import Tools

from os import path
import sys

class Pyxel:

    def __init__(self, tile_size: int):
        pg.init()

        # Main screen
        self.screen = pg.display.set_mode((WIDTH, HEIGHT))
        self.screen_rect = self.screen.get_rect()
        #
        pg.display.set_caption(TITLE)
        self.clock = pg.time.Clock()
        pg.key.set_repeat(500, 100)
        self.load_data()
        
        
        self.tile_size = tile_size

    def load_data(self):
        game_folder = path.dirname(__file__)
        img_folder = path.join(game_folder, 'img')
        font_folder = path.join(game_folder, 'fonts')

        self.pencil_icon = pg.image.load(path.join(img_folder, PENCIL_ICON)).convert_alpha()
        self.pencil_icon_hover = pg.image.load(path.join(img_folder, PENCIL_HOVER)).convert_alpha()
        self.pencil_icon_clicked = pg.image.load(path.join(img_folder, PENCIL_CLICKED)).convert_alpha()
        self.eraser_icon = pg.image.load(path.join(img_folder, ERASER_ICON)).convert_alpha()
        self.eraser_icon_hover = pg.image.load(path.join(img_folder, ERASER_HOVER)).convert_alpha()
        self.eraser_icon_clicked = pg.image.load(path.join(img_folder, ERASER_CLICKED)).convert_alpha()

    def new(self):
        """ Initialize variables and do the initial setup """

        self.canvas = Canvas(self)
        self.gui = GUI(self)
        self.tool_buttons = pg.sprite.Group()
        self.load_toolbtns()
        self.selected_tool = self.pencil_tool
        self.selected_tool.clicked = True
        self.selected_color = BLACK
        self.canvas_grid = []
        for x in range(0, self.tile_size):
            self.canvas_grid.append([])
            for y in range(0, self.tile_size):
                self.canvas_grid[x].append({"color":None, "status":False})
        
    

    def load_toolbtns(self):
        self.pencil_tool = ToolBtns(self, self.pencil_icon, self.pencil_icon_hover, self.pencil_icon_clicked, 5, 5, Tools.pencil)
        self.erase_tool = ToolBtns(self, self.eraser_icon, self.eraser_icon_hover, self.eraser_icon_clicked, 42, 5, Tools.eraser)

    def run(self):
        """ App loop """
        self.running = True
        while self.running:
            self.dt = self.clock.tick(FPS)
            self.draw()
            self.events()

    def quit(self):
        pg.quit()
        sys.exit()

    def events(self):
        # catch all the events here

        for event in pg.event.get():
            mouse_state = pg.mouse.get_pressed()
            x, y = self.get_tile()
            if event.type == pg.QUIT:
                self.quit()

            elif event.type == pg.MOUSEBUTTONDOWN:
                # event.button = (left, middle, right, wheel up, wheel down)
                if event.button == 1 and self.selected_tool.tool_type == Tools.pencil:
                    print(x, y)
                    self.register_pixel(x, y, draw=True)
                elif event.button == 1 and self.selected_tool.tool_type == Tools.eraser:
                    print(x, y)
                    self.register_pixel(x, y, draw=False)
            elif event.type == pg.MOUSEMOTION:
                
                # mouse_state = Bool(left, middle, right)
                if mouse_state[0] and self.selected_tool.tool_type == Tools.pencil:
                    print(x, y)
                    self.register_pixel(x, y, draw=True)
                if mouse_state[0] and self.selected_tool.tool_type == Tools.eraser:
                    print(x, y)
                    self.register_pixel(x, y, draw=False)

            for btn in self.tool_buttons:

                if btn.rect.collidepoint(pg.mouse.get_pos()):
                    btn.hovered = True
                    if mouse_state[0]:
                        if btn.tool_type != self.selected_tool.tool_type:
                            self.selected_tool.clicked = False
                        self.selected_tool = btn
                        self.selected_tool.clicked = True
                else:
                    btn.hovered = False
                            

    def get_tile(self):
        """ Returns the tile that the mouse is pointing """

        x, y = pg.mouse.get_pos()
        x -= self.canvas.rect.x
        y -= self.canvas.rect.y
        dx = x // self.tile_size
        dy = y // self.tile_size
        if (dx >= 0 and dy >= 0) and (dx <= self.tile_size - 1 and dy <= self.tile_size - 1):
            return (dx, dy)
        return None, None

    def register_pixel(self, x, y, draw=True):
        """ Register new pixels onto the canvas matrix
            Default color is BLACK """
        
        if x is None or y is None:
            return
        try:
            self.canvas_grid[x][y] = {"color":self.selected_color, "status":True} if draw else {"color":None, "status":False}
        except IndexError:
            print("Index Error: out of canvas range")

    def draw(self):
        self.screen.fill(SCREEN_COLOR)
        self.canvas.draw()
        self.canvas.draw_pixel(self.canvas_grid)
        self.gui.draw()
        self.tool_buttons.update()
        self.tool_buttons.draw(self.screen)
        pg.display.flip()

if __name__ == "__main__":

    tile_size = int(input("Tile Size >> "))
    p = Pyxel(tile_size)
    p.new()
    while True:
        p.run()

Panza de fișier

import pygame as pg
from settings import *

class Canvas:

    def __init__(self, app):
        self.app = app
        self.screen = app.screen
        self.image = pg.Surface((CANVAS_WIDTH, CANVAS_HEIGHT))
        self.image.fill(WHITE)
        self.rect = self.image.get_rect(center = app.screen_rect.center)

    def draw(self):
        self.screen.blit(self.image, self.rect)
        self.grid()

    def grid(self):
        for x in range(0, CANVAS_WIDTH, TILESIZE):
            pg.draw.line(self.image, LIGHTGREY, (x, 0), (x, self.rect.bottom))
        for y in range(0, CANVAS_HEIGHT, TILESIZE):
            pg.draw.line(self.image, LIGHTGREY, (0, y), (self.rect.right, y))

    def draw_pixel(self, canvas_data):
        """ Draws pixels on the screen """

        for row, data in enumerate(canvas_data):
            for col, px in enumerate(data):
                if px:
                    if px["status"]:
                        #self.canvas.image.fill(px["color"], pg.Rect(row * self.tile_size, col * self.tile_size, self.tile_size, self.tile_size))
                        pg.draw.rect(self.image, px["color"], pg.Rect(row * self.app.tile_size, col * self.app.tile_size, self.app.tile_size, self.app.tile_size))

GUI fișier

import pygame as pg
from settings import *
from utils import Tools

class GUI:

    """ This is just the background, for now """

    def __init__(self, app):
        self.app = app
        self.screen = app.screen
        self.image = pg.Surface((GUI_WIDTH, GUI_HEIGHT))
        self.image.fill(GUI_COLOR)
        self.rect = self.image.get_rect()

    #TODO
    def add_btn(self):
        pass

    def draw(self):
        self.screen.blit(self.image, self.rect)

class ToolBtns(pg.sprite.Sprite):

    def __init__(self, app, base, hover_image, clicked_image, x, y, tool_type: Tools):
        self.groups = app.tool_buttons
        pg.sprite.Sprite.__init__(self, self.groups)
        self.gui_surface = app.gui.image
        self.gui_rect = app.gui.rect
        self.screen = app.screen

        self.base_image = base
        self.hover_image = hover_image
        self.clicked_image = clicked_image

        self.tool_type = tool_type

        self.x = x
        self.y = y
        
        self.image = self.base_image
        self.rect = self.base_image.get_rect()
        self.rect.x = self.gui_rect.x + x
        self.rect.y = self.gui_rect.y + y
        
        self.hovered = False
        self.clicked = False

    def update(self):
        if self.hovered:
            self.image = self.hover_image
        if self.clicked:
            self.image = self.clicked_image
        else:
            self.image = self.base_image
        self.rect = self.image.get_rect()
        self.rect.x = self.gui_rect.x + self.x
        self.rect.y = self.gui_rect.y + self.y

Instrumente de fișier

from enum import Enum, auto

class Tools(Enum):

    pencil = auto()
    eraser = auto()

Fișier de setări

# (R, G, B)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
DARKGREY = (129, 129, 129)
LIGHTGREY = (190, 190, 190)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)

TITLE = "Pyx"
WIDTH = 1400
HEIGHT = 1400
TILESIZE = 32
FPS = 60

GUI_WIDTH = 100
GUI_HEIGHT = 100
GUI_COLOR = (222, 222, 222)

CANVAS_WIDTH = TILESIZE * TILESIZE
CANVAS_HEIGHT = TILESIZE * TILESIZE
CANVAS_X = int(WIDTH * 0.5)
CANVAS_Y = int(HEIGHT * 0.5)
SCREEN_COLOR = DARKGREY
GRID_COLOR = LIGHTGREY 

# ICONS
PENCIL_ICON = 'pencil_icon.png'
PENCIL_HOVER = 'pencil_icon_hover.png'
PENCIL_CLICKED = 'pencil_icon_clicked.png'
ERASER_ICON = 'eraser_icon.png'
ERASER_HOVER = 'eraser_icon_hover.png'
ERASER_CLICKED = 'eraser_icon_clicked.png'

Am postat codul meu pentru că Acesta este împărțit în mai multe fișiere și nu vreau să pierdeți nimic important. Sper că nu e prea mult.

Multumesc

pygame python
2021-11-22 21:31:56
1

Cel mai bun răspuns

2

Aveți nevoie pentru a desena un dreptunghi în culoarea de fundal (alb) dacă "starea" este Falsă și domeniul este șters:

class Canvas:
   
    # [...]

    def draw_pixel(self, canvas_data):
        """ Draws pixels on the screen """

        for row, data in enumerate(canvas_data):
            for col, px in enumerate(data):
                if px:
                    color = px["color"] if px["status"] else (255, 255, 255)
                    rect = pg.Rect(row * self.app.tile_size, col * self.app.tile_size, self.app.tile_size, self.app.tile_size)
                    pg.draw.rect(self.image, color, rect) 
                    
2021-11-22 21:55:36

Am obținut același rezultat ca și cu codul meu :/
WhiteHeadbanger

Oh, nu, doar că am uitat să șteargă if px["status"] linie! Aceasta a lucrat ca farmec! Multumesc Rabbid :)
WhiteHeadbanger

În alte limbi

Această pagină este în alte limbi

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................