Switching block PNGs in PyGame

63 Views Asked by At

I am creating a 2D minecraft clone in Pygame and everything is going well so far. I am stuck on how to switch the block's picture so that it places a different block. The variable in which the PNG is stored in is "block". I want to be able to switch between 8 other images by using the left/right arrow keys. I have thought about listing these images in the "block"" variable but I am stuck on how to actually implement this. Here's what the game looks like

import pygame

pygame.init()
win = pygame.display.set_mode((480,320))
pygame.display.set_caption(("PyCraft"))
block = pygame.image.load("Grass.png")
running = True

positions = []

def rtm(n, m):
    return round(n / m) * m

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
        running = False

        if event.type == pygame.MOUSEBUTTONDOWN:
            px, py = event.pos  
            pxr = rtm(px, 32)
            pyr = rtm(py, 32)
            positions.append((pxr, pyr))

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                positions = []

    mx, my = pygame.mouse.get_pos()

    mxr = rtm(mx, 32)
    myr = rtm(my, 32)

    if mxr > 448:
        mxr = 448
    if myr > 288:
        myr = 288

    win.fill("white")
    for pos in positions:
    win.blit(block, pos)
    win.blit(block, (mxr, myr))
    pygame.display.update()
1

There are 1 best solutions below

4
BigEnzo02 On

Here is the new code that includes objects. It does the same thing as before in terms of block selection, the only difference now is that it appends an object to the list that stores a position and image instead of just a position. This object is defined in a new file (called 'block.py') that you will have to create, which is referenced by calling 'block.[what you are calling here]' in the same way you must type pygame before any pygame methods.

Main file:

import pygame

import block    #import your newly created block file

pygame.init()
win = pygame.display.set_mode((480,320))
pygame.display.set_caption(("PyCraft"))

BLOCK_LIST = [pygame.image.load('path here'),...]    #load all block images into this list
ACTIVE_BLOCK = BLOCK_LIST[0]
COUNT = 0    #which block is currently selected

running = True

blocks = []     #list of all active blocks

def rtm(n, m):
    return round(n / m) * m

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        if event.type == pygame.MOUSEBUTTONDOWN:
            px, py = event.pos  
            pxr = rtm(px, 32)
            pyr = rtm(py, 32)

            blocks.append(block.block((pxr, pyr), ACTIVE_BLOCK))        #this creates a new 'block' object and adds it to the active list

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                positions = []

            #deal with arrow keys
            if event.key == pygame.K_LEFT:
                #move count left, keep it within the bounds of the list and update active block img
                if COUNT == 0:    #count is below 0, so loop to the end of the list instead
                    COUNT = len(BLOCK_LIST)
                COUNT = (COUNT - 1) % len(BLOCK_LIST)
                ACTIVE_BLOCK = BLOCK_LIST[COUNT]

            if event.key == pygame.K_RIGHT:
                #do the same thing but add one instead of removing one from count
                COUNT = (COUNT + 1) % len(BLOCK_LIST)
                ACTIVE_BLOCK = BLOCK_LIST[COUNT]

    mx, my = pygame.mouse.get_pos()

    mxr = rtm(mx, 32)
    myr = rtm(my, 32)

    if mxr > 448:
        mxr = 448
    if myr > 288:
        myr = 288

    win.fill("white")
    for object in blocks:
        #for every block that exists, blit the surface contained in the block to the position within the block
        win.blit(object.surf, object.pos)
    win.blit(ACTIVE_BLOCK, (mxr, myr))
    pygame.display.update()

And in your block.py file, you want to have this

class block:
    def __init__(self, position, surface) -> None:
        #'__init__' is always called when creating an object
        
        #this is a very basic class that just stores these two values for later use
        self.pos = position
        self.surf = surface
        
    #if you wanted to have this object do something, you could define it here
    def your_function(self):
        """Demonstration function to show how objects work. The three quotes make this comment show up when you hover over the function name! (on most software)
        """
        print('Hello! I am a block!')

Hopefully this helps!