Skip to main content
Added some example code
Source Link

Edit #2: Alright I got home and whipped up a little example. I'm not the best at being "pythonic" but here you can hopefully see how I create a surface for the log, populate it with rendered text, and THEN blit it onto the main surface (which for this example is just a black space). Dividing your pygame UI up into HUD sections is a big part of jumping from making text-based programs to working with pygame's surfaces. Please forgive my use of magic numbers.

# A little pygame console
# press "t" to add messages to the continuously updatding HUD element


import pygame

pygame.init()


# constants
RES = (800, 600)
FPS = 30

MAIN_SURFACE = pygame.display.set_mode(RES)
CLOCK = pygame.time.Clock()

pygame.display.set_caption("Example Console UI Element")

the_font = pygame.font.Font(None, 32)

message_log = []

def console_print(message):
    message_log.append(message)

def update_log():
    # create a surface for the log:
    # This one the same width as the RESOLUTION and 1/3 the height
    log_surf = pygame.Surface((RES[0], RES[1] // 3))
    log_surf.fill((80, 80, 80))
    # Populate it with, say, the last three messages:
    # Note: You could do this in a more elegant loop if you wanted to. 
    #       You would probably be served by checking to see if you have any messages at all before
    #       searching through the message log, to avoid looking for elements that aren't in the list. 
    #       for this example I added 3 placeholder messages at the start of the main function
    #       to avoid that problem here.
    new_log = []
    m1 = message_log[-1]
    m2 = message_log[-2]
    m3 = message_log[-3]
    new_log.append(m1)
    new_log.append(m2)
    new_log.append(m3)
    font_y = 0
    for m in new_log:
        message = the_font.render(m, False, (255, 255, 255))
        log_surf.blit(message, (0, font_y))
        font_y += 34  # gives a little padding for the next message
    # blit it to the main surface in a spot where it'll fit snugly:
    # sorry for the magic numbers, ideally you would pre-define these positions
    # as variables
    MAIN_SURFACE.blit(log_surf, (0, 400))


def update():
    MAIN_SURFACE.fill((0, 0, 0))
    update_log()
    pygame.display.flip()

def main():

    console_print("Placeholder message 1")
    console_print("Placholder message 2")
    console_print("Placeholder message 3")

    messages = 0

    running = True
    while running:
        for event in pygame.event.get():
            if event.type is pygame.QUIT:
                running = False
            if event.type is pygame.KEYDOWN:
                if event.key == pygame.K_t:
                    # advance the turn as an example
                    messages += 1
                    console_print("Message # " + str(messages))
                    # test in the terminal
                    print("Message # " + str(messages))
   
    
        update()

        CLOCK.tick(FPS)

    
    pygame.quit()

if __name__ == "__main__":
    main()

There you go! By messing around with the numbers here you can hopefully get a feel for messing with surface dimensions. I apologize in advance if this is stylistically bad but it's worked well for me in many projects. Pygame has built-in sub-surface capabilities but I have not deeply explored those at all. Hard-coding your dimensions is not a bad way to start, I feel. I hope that helps and good luck!

Edit #2: Alright I got home and whipped up a little example. I'm not the best at being "pythonic" but here you can hopefully see how I create a surface for the log, populate it with rendered text, and THEN blit it onto the main surface (which for this example is just a black space). Dividing your pygame UI up into HUD sections is a big part of jumping from making text-based programs to working with pygame's surfaces. Please forgive my use of magic numbers.

# A little pygame console
# press "t" to add messages to the continuously updatding HUD element


import pygame

pygame.init()


# constants
RES = (800, 600)
FPS = 30

MAIN_SURFACE = pygame.display.set_mode(RES)
CLOCK = pygame.time.Clock()

pygame.display.set_caption("Example Console UI Element")

the_font = pygame.font.Font(None, 32)

message_log = []

def console_print(message):
    message_log.append(message)

def update_log():
    # create a surface for the log:
    # This one the same width as the RESOLUTION and 1/3 the height
    log_surf = pygame.Surface((RES[0], RES[1] // 3))
    log_surf.fill((80, 80, 80))
    # Populate it with, say, the last three messages:
    # Note: You could do this in a more elegant loop if you wanted to. 
    #       You would probably be served by checking to see if you have any messages at all before
    #       searching through the message log, to avoid looking for elements that aren't in the list. 
    #       for this example I added 3 placeholder messages at the start of the main function
    #       to avoid that problem here.
    new_log = []
    m1 = message_log[-1]
    m2 = message_log[-2]
    m3 = message_log[-3]
    new_log.append(m1)
    new_log.append(m2)
    new_log.append(m3)
    font_y = 0
    for m in new_log:
        message = the_font.render(m, False, (255, 255, 255))
        log_surf.blit(message, (0, font_y))
        font_y += 34  # gives a little padding for the next message
    # blit it to the main surface in a spot where it'll fit snugly:
    # sorry for the magic numbers, ideally you would pre-define these positions
    # as variables
    MAIN_SURFACE.blit(log_surf, (0, 400))


def update():
    MAIN_SURFACE.fill((0, 0, 0))
    update_log()
    pygame.display.flip()

def main():

    console_print("Placeholder message 1")
    console_print("Placholder message 2")
    console_print("Placeholder message 3")

    messages = 0

    running = True
    while running:
        for event in pygame.event.get():
            if event.type is pygame.QUIT:
                running = False
            if event.type is pygame.KEYDOWN:
                if event.key == pygame.K_t:
                    # advance the turn as an example
                    messages += 1
                    console_print("Message # " + str(messages))
                    # test in the terminal
                    print("Message # " + str(messages))
   
    
        update()

        CLOCK.tick(FPS)

    
    pygame.quit()

if __name__ == "__main__":
    main()

There you go! By messing around with the numbers here you can hopefully get a feel for messing with surface dimensions. I apologize in advance if this is stylistically bad but it's worked well for me in many projects. Pygame has built-in sub-surface capabilities but I have not deeply explored those at all. Hard-coding your dimensions is not a bad way to start, I feel. I hope that helps and good luck!

added 99 characters in body; added 1 character in body
Source Link

So there's a couple steps to this:

  1. You need a list to handle the log messages.

  2. You need a function to print events to the list. How you do this is up to you, but it needs to be a function you can call whenever these events happen. Something as simple as a custom print function works just fine, like. Here's a quick idea of how to make the log itself:

    list = []

    def console_print("message"message): list.append("message"message)

    console_print("Test")

Then it gets harder because you need to display it as part of the UI. So you need to pick your dimensions and measure it out and determine how many lines of whatever sized font you are going to use. If it is turn based this is all a little easier to do because you can just update it every turn. I personally prefer to blit UI elements separately with pygame, so my order of display would be something like this for each turn:

  1. Create a list of n messages where n is the number of lines you can fit in your display element.
  2. Take the last n elements from your log list and append them to the new list.
  3. Create a surface the size of your UI element.
  4. For n lines that you want to display, use font.render to add a line. You'll need to calculate the X and Y coordinates for each one which is a little trial and error.
  5. Now that you have this surface and you've rendered lines of font onto it, you can blit it back to your main surface as part of your update() process. You would ideally do this each turn, and not just for your log but for every UI element.

Putting UIs together with pygame is my favorite part of it. Anything is possible once you start getting your head wrapped around blitting surfaces on top of surfaces. Custom-design foryour update() method for your game and your UI! I'll dig up the last console I made next time I'm at my PC so you can see some real code. I'm no expert but I can help you here. Good luck!

Edit: I'm having a very hard time getting my little python snippet to indent properly on the Stack Exchange app. Sorry.

So there's a couple steps to this:

  1. You need a list to handle the log messages.

  2. You need a function to print events to the list. How you do this is up to you, but it needs to be a function you can call whenever these events happen. Something as simple as a custom print function works just fine, like:

    console_print("message"): list.append("message")

Then it gets harder because you need to display it as part of the UI. So you need to pick your dimensions and measure it out and determine how many lines of whatever sized font you are going to use. If it is turn based this is all a little easier to do because you can just update it every turn. I personally prefer to blit UI elements separately with pygame, so my order of display would be something like this for each turn:

  1. Create a list of n messages where n is the number of lines you can fit in your display element.
  2. Take the last n elements from your log list and append them to the new list.
  3. Create a surface the size of your UI element.
  4. For n lines that you want to display, use font.render to add a line. You'll need to calculate the X and Y coordinates for each one which is a little trial and error.
  5. Now that you have this surface and you've rendered lines of font onto it, you can blit it back to your main surface as part of your update() process. You would ideally do this each turn, and not just for your log but for every UI element.

Putting UIs together with pygame is my favorite part of it. Anything is possible once you start getting your head wrapped around blitting surfaces on top of surfaces. Custom-design for update() method for your game and your UI! I'll dig up the last console I made next time I'm at my PC so you can see some real code. I'm no expert but I can help you here. Good luck!

Edit: I'm having a very hard time getting my little python snippet to indent properly on the Stack Exchange app. Sorry.

So there's a couple steps to this:

  1. You need a list to handle the log messages.

  2. You need a function to print events to the list. How you do this is up to you, but it needs to be a function you can call whenever these events happen. Something as simple as a custom print function works just fine. Here's a quick idea of how to make the log itself:

    list = []

    def console_print(message): list.append(message)

    console_print("Test")

Then it gets harder because you need to display it as part of the UI. So you need to pick your dimensions and measure it out and determine how many lines of whatever sized font you are going to use. If it is turn based this is all a little easier to do because you can just update it every turn. I personally prefer to blit UI elements separately with pygame, so my order of display would be something like this for each turn:

  1. Create a list of n messages where n is the number of lines you can fit in your display element.
  2. Take the last n elements from your log list and append them to the new list.
  3. Create a surface the size of your UI element.
  4. For n lines that you want to display, use font.render to add a line. You'll need to calculate the X and Y coordinates for each one which is a little trial and error.
  5. Now that you have this surface and you've rendered lines of font onto it, you can blit it back to your main surface as part of your update() process. You would ideally do this each turn, and not just for your log but for every UI element.

Putting UIs together with pygame is my favorite part of it. Anything is possible once you start getting your head wrapped around blitting surfaces on top of surfaces. Custom-design your update() method for your game and your UI! I'll dig up the last console I made next time I'm at my PC so you can see some real code. I'm no expert but I can help you here. Good luck!

Edit: I'm having a very hard time getting my little python snippet to indent properly on the Stack Exchange app. Sorry.

deleted 5 characters in body; added 120 characters in body
Source Link

So there's a couple steps to this:

  1. You need a list to handle the log messages.

  2. You need a function to print events to the list. How you do this is up to you, but it needs to be a function you can call whenever these events happen. Something as simple as a custom print function works just fine, like:

    console_print("message"): list.append("message")

Then it gets harder because you need to display it as part of the UI. So you need to pick your dimensions and measure it out and determine how many lines of whatever sized font you are going to use. If it is turn based this is all a little easier to do because you can just update it every turn. I personally prefer to blit UI elements separately with pygame, so my order of display would be something like this for each turn:

  1. Create a list of n messages where n is the number of lines you can fit in your display element.
  2. Take the last n elements from your log list and append them to the new list.
  3. Create a surface the size of your UI element.
  4. For n lines that you want to display, use font.render to add a line. You'll need to calculate the X and Y coordinates for each one which is a little trial and error.
  5. Now that you have this surface and you've rendered lines of font onto it, you can blit it back to your main surface as part of your update() process. You would ideally do this each turn, and not just for your log but for every UI element.

Putting UIs together with pygame is my favorite part of it. Anything is possible once you start getting your head wrapped around blitting surfaces on top of surfaces. Custom-design for update() method for your game and your UI! I'll dig up the last console I made next time I'm at my PC so you can see some real code. I'm no expert but I can help you here. Good luck!

Edit: I'm having a very hard time getting my little python snippet to indent properly on the Stack Exchange app. Sorry.

So there's a couple steps to this:

  1. You need a list to handle the log messages.

  2. You need a function to print events to the list. How you do this is up to you, but it needs to be a function you can call whenever these events happen. Something as simple as a custom print function works just fine, like:

    console_print("message"): list.append("message")

Then it gets harder because you need to display it as part of the UI. So you need to pick your dimensions and measure it out and determine how many lines of whatever sized font you are going to use. If it is turn based this is all a little easier to do because you can just update it every turn. I personally prefer to blit UI elements separately with pygame, so my order of display would be something like this for each turn:

  1. Create a list of n messages where n is the number of lines you can fit in your display element.
  2. Take the last n elements from your log list and append them to the new list.
  3. Create a surface the size of your UI element.
  4. For n lines that you want to display, use font.render to add a line. You'll need to calculate the X and Y coordinates for each one which is a little trial and error.
  5. Now that you have this surface and you've rendered lines of font onto it, you can blit it back to your main surface as part of your update() process. You would ideally do this each turn, and not just for your log but for every UI element.

Putting UIs together with pygame is my favorite part of it. Anything is possible once you start getting your head wrapped around blitting surfaces on top of surfaces. Custom-design for update() method for your game and your UI! I'll dig up the last console I made next time I'm at my PC so you can see some real code. I'm no expert but I can help you here. Good luck!

So there's a couple steps to this:

  1. You need a list to handle the log messages.

  2. You need a function to print events to the list. How you do this is up to you, but it needs to be a function you can call whenever these events happen. Something as simple as a custom print function works just fine, like:

    console_print("message"): list.append("message")

Then it gets harder because you need to display it as part of the UI. So you need to pick your dimensions and measure it out and determine how many lines of whatever sized font you are going to use. If it is turn based this is all a little easier to do because you can just update it every turn. I personally prefer to blit UI elements separately with pygame, so my order of display would be something like this for each turn:

  1. Create a list of n messages where n is the number of lines you can fit in your display element.
  2. Take the last n elements from your log list and append them to the new list.
  3. Create a surface the size of your UI element.
  4. For n lines that you want to display, use font.render to add a line. You'll need to calculate the X and Y coordinates for each one which is a little trial and error.
  5. Now that you have this surface and you've rendered lines of font onto it, you can blit it back to your main surface as part of your update() process. You would ideally do this each turn, and not just for your log but for every UI element.

Putting UIs together with pygame is my favorite part of it. Anything is possible once you start getting your head wrapped around blitting surfaces on top of surfaces. Custom-design for update() method for your game and your UI! I'll dig up the last console I made next time I'm at my PC so you can see some real code. I'm no expert but I can help you here. Good luck!

Edit: I'm having a very hard time getting my little python snippet to indent properly on the Stack Exchange app. Sorry.

Source Link
Loading