Python Forum
[pygame] Equiping inventory slots with invisible buttons
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[pygame] Equiping inventory slots with invisible buttons
#1
I have an inventory class with 3 functions. __init__, draw, and equipChange
The job of each function -
__init__ - to define x, y, slots, and a few more predefined variables
draw - draw inventory based on the amount of slots and x and y. Also checks if a slot is pressed on and turns it red if so (I currently have not added the unequip feature. I am working on the equip feature first)
equipChange - the function for changing the tuple of equip which in turn changes what is drawn.

I'm sorry if I made a simple mistake - that would be embarrassing - TIA for your help.

inventory class - the full code is here - https://github.com/Sheepposu/Destination - on github
class inventoryGUI():
    def __init__(self, x, y, slots):
        self.x = x
        self.y = y
        self.i = 0
        self.n = 0
        self.slots = slots
        self.equips = None

    def draw(self, equips):
        SD.message_display(gD, 'Inventory', 50, black, self.x + 100, self.y - 50)
        self.equips = equips
        for n in range(1, self.slots + 1):
            p = equips
            self.n += 1
            if n in p:
                SlotBtn = IBT((self.x + self.i, self.y, self.x + self.i + 20, self.y + 20))
                if self.equips == None:
                    SlotBtn.optClick(partial(self.equipChange, (False, n)))
                else:
                    self.equips += (n,)
                    SlotBtn.optClick(partial(self.equipChange, (False, self.equips)))
                pygame.draw.line(gD, red, (self.x + self.i, self.y), (self.x + self.i + 20, self.y)) #Top
                pygame.draw.line(gD, red, (self.x + self.i + 20, self.y), (self.x + 20 + self.i, self.y + 20)) # Right
                pygame.draw.line(gD, red, (self.x + self.i, self.y), (self.x + self.i, self.y + 20)) #Left
                pygame.draw.line(gD, red, (self.x + self.i, self.y + 20), (self.x + self.i + 20, self.y + 20)) #Bottom
            else:
                SlotBtn = IBT((self.x + self.i, self.y, self.x + self.i + 20, self.y + 20))
                if self.equips == None:
                    SlotBtn.optClick(partial(self.equipChange, (False, n)))
                else:
                    self.equips += (n,)
                    SlotBtn.optClick(partial(self.equipChange, (False, self.equips)))
                pygame.draw.line(gD, black, (self.x + self.i, self.y), (self.x + self.i + 20, self.y)) #Top
                pygame.draw.line(gD, black, (self.x + self.i + 20, self.y), (self.x + 20 + self.i, self.y + 20)) # Right
                pygame.draw.line(gD, black, (self.x + self.i, self.y), (self.x + self.i, self.y + 20)) #Left
                pygame.draw.line(gD, black, (self.x + self.i, self.y + 20), (self.x + self.i + 20, self.y + 20)) #Bottom
            if self.n < 6:
                self.i += 30
            else:
                self.n = 0
                self.i = 0
                self.y += 30

    def equipChange(self, receive, equips=None):
        if receive:
            return self.equips
        elif not receive:
            self.equips = equips
            print('self.equip now equals ' + self.equips)
Reply
#2
Example
import pygame

# Simple Scene Interface
class Scene:
    def draw(self, surface, game): pass
    def event(self, event, game): pass
    def update(self, game): pass

class Game:
    def __init__(self, caption, width, height):
        # Basic pygame setup
        pygame.display.set_caption(caption)
        self.rect = pygame.Rect(0, 0, width, height)
        self.surface = pygame.display.set_mode(self.rect.size)
        self.clock = pygame.time.Clock()
        self.running = False
        self.fps = 30
        self.delta = 0

        # Scene Interface
        self.scene = Scene()
        Game.info = self

    def mainloop(self):
        self.running = True
        while self.running:
            for event in pygame.event.get():
                self.scene.event(event, self)

            self.keys = pygame.key.get_pressed()

            self.scene.update(self)
            self.scene.draw(self.surface, self)
            pygame.display.flip()
            self.delta = self.clock.tick(self.fps)

class Inventory:
    def __init__(self, position, slots):
        self.slots = slots
        self.equip = [False] * slots
        self.hover = False
        if isinstance(position, pygame.math.Vector2):
            self.position = position
        else:
            self.position = pygame.math.Vector2(position)

        self.create_rects()

    def create_rects(self):
        self.rects = []
        for n in range(self.slots):
            offset = ((n % 6) * 30, n // 6 * 30)
            self.rects.append(pygame.Rect(self.position + offset, (20, 20)))

    def draw(self, surface):
        for enum, rect in enumerate(self.rects):
            if self.equip[enum]:
                pygame.draw.rect(surface, pygame.Color('red'), rect, 1)
            elif self.hover == enum:
                pygame.draw.rect(surface, pygame.Color('dodgerblue'), rect, 1)
            else:
                pygame.draw.rect(surface, pygame.Color('black'), rect, 1)

    def on_click(self):
        if self.hover > -1:
            self.equip[self.hover] = not self.equip[self.hover]

    def on_mousemotion(self, event):
        self.hover = -1
        for enum, rect in enumerate(self.rects):
            if rect.collidepoint(event.pos):
                self.hover = enum
                break

class Example(Scene):
    def __init__(self):
        self.inventory = Inventory((50, 20), 18)

    def draw(self, surface, game):
        surface.fill(pygame.Color('gray25'))
        self.inventory.draw(surface)

    def event(self, event, game):
        if event.type == pygame.MOUSEMOTION:
            self.inventory.on_mousemotion(event)
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                self.inventory.on_click()
        elif event.type == pygame.QUIT:
            game.running = False

def main():
    pygame.init()
    game = Game("Example", 400, 300)
    game.scene = Example()
    game.mainloop()
    pygame.quit()

main()
99 percent of computer problems exists between chair and keyboard.
Reply
#3
I'm sorry if my code is hard to navigate through. When making this game I found it easy and organized to define all my variables at the top including width, height, fps, and colors, class the player, class the enemy, define non-categorized functions outside of classes and def different function for different levels. I then put everything together in a main loop.
Reply
#4
1. I'm just going to give examples. You can take what you want from my code and inject it into yours.

2. Personal I believe beginners should avoid global at all cost.

3. Classes can use local variables. All variables do not need to be part of the object.
Example
class inventoryGUI():
    def __init__(self, x, y, slots):
        self.x = x
        self.y = y
        self.i = 0 # this is not going to be use through out object. Need to be remove 
        self.n = 0 # this is not going to be use through out object. Need to be remove

    def draw(self, equips):
        n = 0  # local variable, one of your n would have to be rename.
        i = 0  # local variable
pygame.Vector2 and pygame.Rect are your friends. Learn to use them.

This can be done with a simple rect.
pygame.draw.line(gD, red, (self.x + self.i, self.y), (self.x + self.i + 20, self.y)) #Top
                pygame.draw.line(gD, red, (self.x + self.i + 20, self.y), (self.x + 20 + self.i, self.y + 20)) # Right
                pygame.draw.line(gD, red, (self.x + self.i, self.y), (self.x + self.i, self.y + 20)) #Left
                pygame.draw.line(gD, red, (self.x + self.i, self.y + 20), (self.x + self.i + 20, self.y + 20)) #Bottom
example
 position = pygame.Vector2(self.x, self.y) # position should been a variable. It hold x and y
# position.x and position.y can be use.
rect = pygame.Rect(position + (self.i, 0), (20, 20)) # create a rect.
pygame.draw.rect(surface, color, rect, 1) # 1 is outline thickness. If 1 is omitted. Then if would fill rect.
99 percent of computer problems exists between chair and keyboard.
Reply
#5
I try to avoid local variables but I global specific variables that will make them more easily accessible but not interfering with other stuff. I will implement your suggestions when I get home. i am at school right now and we're watching "Matilda".
Reply
#6
Why would you avoid local variables ? They help keep memory usage down. In classes it helps keep object memory smaller.

My Color Handler
import pygame

class Color:
    def __getitem__(self, key):
        return self.__getattr__(key)

    def __getattr__(self, key):
        if key == "keys":
            return pygame.color.THECOLORS.keys()

        return pygame.Color(key)

    def group(self, color_name):
        group = []
        for name in pygame.color.THECOLORS.keys():
            if color_name in name:
                group.append(name)

        return group

def main():
    color = Color()

    # Quickly call
    print("orange", color.orange)
    print("darkred", color.darkred)
    print()

    # Find all colors that include name
    for c in color.group('blue'):
        print(c, color[c])

main()
Example. My color handler in action
import pygame

class Color:
    def __getitem__(self, key):
        return self.__getattr__(key)

    def __getattr__(self, key):
        if key == "keys":
            return pygame.color.THECOLORS.keys()

        return pygame.Color(key)

    def group(self, color_name):
        group = []
        for name in pygame.color.THECOLORS.keys():
            if color_name in name:
                group.append(name)

        group.sort()
        return group

# Simple Scene Interface
class Scene:
    def draw(self, surface, game): pass
    def event(self, event, game): pass
    def update(self, game): pass

class Game:
    color = Color()

    def __init__(self, caption, width, height):
        # Basic pygame setup
        pygame.display.set_caption(caption)
        self.rect = pygame.Rect(0, 0, width, height)
        self.surface = pygame.display.set_mode(self.rect.size)
        self.clock = pygame.time.Clock()
        self.running = False
        self.fps = 30
        self.delta = 0

        # Scene Interface
        self.scene = Scene()
        Game.info = self

    def mainloop(self):
        self.running = True
        while self.running:
            for event in pygame.event.get():
                self.scene.event(event, self)

            self.keys = pygame.key.get_pressed()

            self.scene.update(self)
            self.scene.draw(self.surface, self)
            pygame.display.flip()
            self.delta = self.clock.tick(self.fps)

class ColorShow(Scene):
    def __init__(self):
        self.colors = 'red', 'blue', 'green'
        self.color_position = 0
        self.color_group = Game.color.group('red')
        self.cg_position = 0
        # timer
        self.interval = 900
        self.next_tick =  pygame.time.get_ticks()

        self.font = pygame.font.Font(None, 32)
        self.render_text(Game.info)

    def draw(self, surface, game):
        surface.fill(pygame.Color(self.color_group[self.cg_position]))
        surface.blit(self.text, self.text_rect)

    def event(self, event, game):
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                self.color_position = (self.color_position + 1) % len(self.colors)
                self.color_group = Game.color.group(self.colors[self.color_position])
                self.cg_position = 0
                self.render_text(game)
            elif event.key == pygame.K_ESCAPE:
                game.running = False
        elif event.type == pygame.QUIT:
            game.running = False

    def render_text(self, game):
        self.text = self.font.render(self.color_group[self.cg_position], 1, pygame.Color('black'))
        self.text_rect = self.text.get_rect()
        self.text_rect.y = 10
        self.text_rect.centerx = game.rect.centerx

    def update(self, game):
        ticks = pygame.time.get_ticks()
        if ticks > self.next_tick:
            self.next_tick += self.interval
            self.cg_position = (self.cg_position + 1) % len(self.color_group)
            self.render_text(game)


def main():
    pygame.init()
    game = Game("Color Show", 400, 300)
    game.scene = ColorShow()
    game.mainloop()
    pygame.quit()

main()
99 percent of computer problems exists between chair and keyboard.
Reply
#7
I'm sorry - I meant avoid global variables
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [PyGame] pygame-manu : using controller buttons to move around menu mlw19mlw91 2 1,607 Mar-12-2023, 01:55 PM
Last Post: deanhystad
  Pygame - Images As Buttons vman44 3 12,964 Mar-20-2020, 08:13 PM
Last Post: vman44
  Adding an inventory and a combat system to a text based adventure game detkitten 2 6,870 Dec-17-2019, 03:40 AM
Last Post: detkitten
  [pygame] Inventory items not working SheeppOSU 14 6,737 May-27-2019, 09:44 PM
Last Post: metulburr
  [pygame] Inventory problems. Weapons equipped to wrong slot SheeppOSU 6 4,011 May-07-2019, 02:46 AM
Last Post: SheeppOSU
  [pygame] Blitting armor and weapons with inventory SheeppOSU 3 2,883 Apr-29-2019, 02:31 AM
Last Post: SheeppOSU
  Problems with loading buttons (pygame) SheeppOSU 2 3,095 Apr-12-2019, 08:04 PM
Last Post: SheeppOSU
  Buttons in PyGame mzmingle 4 13,053 Oct-09-2018, 05:19 PM
Last Post: Mekire
  Menus, buttons and other widgets for Pygame Olleus 4 11,472 Apr-17-2017, 11:08 PM
Last Post: metulburr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020