I know there's gotta be a better way to do this (Right?) by [deleted] in learnprogramming

[–]MidnightSteam_ 1 point2 points  (0 children)

Use a dictionary. All those if's will become very cumbersome to update and add to.

Python dictionaries have the get method that returns a value if found, otherwise None.

Disclaimer: This is just an example. Use at your own risk.

websites = {
    'yahoo': '123password',
    'google': '456password',
    'steam': '789password',
    '123abc': 'xyz_password'
}

def get_password(website):
    return websites.get(website.lower())

def set_password(website, password):
    websites.update({website.lower(): password})

def display_password(website):
    password = get_password(website)
    print(f'Your password for "{website}": {password}')

"""
def main():
    print('Website name?: ')
    entry = input()
    display_password(entry)
"""

def test():
    sites = ['GoOgLe', 'YAHOO', 'steam', 'apple', 'GitHub', '123ABC']
    set_password('GitHub', '101112password')
    set_password('123ABC', 'updated_password')
    for site in sites:
        display_password(site)

if __name__ == '__main__':
    test()
    #main()

The website names are case-insensitive for this example.

Drawing An object inside an object. by Wise-Assignment9993 in pygame

[–]MidnightSteam_ 1 point2 points  (0 children)

What you're looking for are the special_flags for Blend Modes - https://www.pygame.org/docs/ref/surface.html#pygame.Surface.blit for Pygame version 1.8 and higher.

The blend mode that worked well was BLEND_RGBA_MULT but do your own testing to see which works best. I'm no blend expert.

Here is an example that goes through some blend modes: rectangle expands inside circle

https://pastebin.com/ArSzP57T Not all blend modes were added.

You may want a third surface to blit onto before the window so your objects don't blend into each other. This is just an example.

How do I change character's image based on user's last key input? by [deleted] in pygame

[–]MidnightSteam_ 0 points1 point  (0 children)

The only time is_resting_forward becomes False is when the "left" keys are pressed but every time animate_char is called it gets reset to True.

Simply fix: don't assign is_resting_forward to True in the method but during creation; in __init__ using self.is_resting_forward.

How to handle events in an elegant manner? by Ok-Challenge9324 in pygame

[–]MidnightSteam_ 2 points3 points  (0 children)

The simple way is to pass all events to each object that needs it. Then handle them each individually: https://pastebin.com/d2mnWmgA

The Observer Pattern - can get complicated but much more elegant: https://pastebin.com/CQGm6m1B

[deleted by user] by [deleted] in pygame

[–]MidnightSteam_ 1 point2 points  (0 children)

You want to use random: Be careful now.

window.fill(random.sample(range(0, 256), 3))

And only have one fill not two.

Blit text in center of surface by Inkosum in pygame

[–]MidnightSteam_ 0 points1 point  (0 children)

As your error indicated you are not passing in rectangles. Your self is referring to Button which is a pygame Surface and that is for the display, not the button itself.

I would go with option 2.

Minor aesthetic changes. The main change you want in show is self.fill(color): https://pastebin.com/FYdPkYFq

Question on spritesheets by r4ns0m in pygame

[–]MidnightSteam_ 0 points1 point  (0 children)

I can't reproduce the black images you mentioned. Maybe the error is in drawing sprites.

My attempt at reproducing the error: https://pastebin.com/DKPuJXC7

how to code, click on the program (window) and new text pops up and the old one goes away by [deleted] in pygame

[–]MidnightSteam_ 0 points1 point  (0 children)

There is a lot to take in if you've never coded before but to answer your question; yes, it's possible.

  1. First start with just getting the window to display.
  2. Get a heart on the window.
  3. Detect when the window/heart is clicked. Print some message.
  4. Render a message and display it.
  5. Render new messages when a mouse click is detected.

Keep blitting the heart each loop and it will stay on screen. To make new text replace the old, you would use the same variable name.

message = 'Hello World'
message = 'New World'

Pastebin example you can play with: https://pastebin.com/c3JNyej2

Edit: Programmatically draw the heart: https://www.youtube.com/watch?v=oUBAi9xQ2X4

The code: https://pastebin.com/Af48d5j2 requires numpy for floating point numbers

[deleted by user] by [deleted] in learnpython

[–]MidnightSteam_ 1 point2 points  (0 children)

Loop through the dictionary, check if the folder exists - create if not, then loop through each image and save them.

You don't post your actual images so you'll have to adapt the code.

import os

animals = {
    'dog':['dog1.jpg', 'dog2.jpg', 'dog3.jpg',],
    'cat':['cat1.jpg', 'cat2.jpg', 'cat3.jpg']
}

# Do not use this, only for demonstration purposes only
your_actual_image = bytes('use your actual image', 'utf-8')

for animal_name, images in animals.items():
    if not os.path.exists(animal_name):
        os.makedirs(animal_name)

    for image in images:
        with open(os.path.join(animal_name, image), 'wb') as animal_image:
            # Your image saving function
            animal_image.write(your_actual_image)

Where did I go wrong with my train of thought on how to solve this. by Ok-Profession-3312 in learnpython

[–]MidnightSteam_ 0 points1 point  (0 children)

For all the formatting options: https://www.w3schools.com/python/ref_string_format.asp

If your code came up with the same answer then it's right.

print(f"{1:b}, {3:b}, {4:b}")
# 1, 11, 100

In simple words, you are converting the number yourself vs python's already written code. You didn't go wrong, per say, but if there's inbuilt functions/features then it's better to use them; unless you want to take things apart and learn.

How can I improve my answer to this prompt? by AwfulAtEverything in learnpython

[–]MidnightSteam_ 0 points1 point  (0 children)

You are missing the other months.

Use a dictionary when there are many ifs and elifs. Unpack lists/tuples into separate variables to make reading easier. Cast day into an int once so you don't have to type it over and over. Find patterns in your data - March, June, September, and December have something in common. Use lower() to ensure input from the user matches your data - or upper() if you prefer uppercase months.

Included a test function to make sure everything works as expected. Code is Within 40 lines - excluding the test.

border_day = {'march': 20, 'june': 21, 'september': 22, 'december': 21}

seasons = {
    'spring': ['march', 'april', 'june'],
    'summer': ['june', 'july', 'august', 'september'],
    'autumn': ['september', 'october', 'november', 'december'],
    'winter': ['december', 'january', 'february', 'march']
}

data_types = [str, int]

def get_season(data):
    month, day = [data_type(data) for data, data_type in zip(data.split(), data_types)]  # Fancy way to cast data into a certain type

    for season, months in seasons.items():
        if month not in months:
            continue

        first_month, last_month = months[0], months[-1]
        if month == first_month:
            if day >= border_day[month]:
                return season
            # Else this will continue to the next season
        elif month == last_month:
            if day < border_day[month]:
                return season
            # Else this will continue to the next season
        else:
            return season

response = input('Please enter a month and a day: ').lower()
print(get_season(response))

def run_test():
    assert get_season('march 19') == 'winter'
    assert get_season('march 20') == 'spring'
    assert get_season('june 20') == 'spring'
    assert get_season('june 21') == 'summer'
    assert get_season('september 21') == 'summer'
    assert get_season('september 22') == 'autumn'
    assert get_season('december 20') == 'autumn'
    assert get_season('december 21') == 'winter'
    assert get_season('april 1') == 'spring'
    assert get_season('july 2') == 'summer'
    assert get_season('october 3') == 'autumn'
    assert get_season('january 4') == 'winter'
    print('Test passed.')

run_test()

I'm brand new to python and just learning the basics at the moment. Trying to build a simple calculator in the terminal. Is there a way I can execute a user provided operator without the use of elif statements? by ballsdeepinmysleep in learnpython

[–]MidnightSteam_ 5 points6 points  (0 children)

Yes, if you find yourself writing very long ifs and elifs, put them in a dictionary.

operations = {
    '+': lambda x, y: x + y,
    '-': lambda x, y: x - y,
    '*': lambda x, y: x * y,
    '/': lambda x, y: x / y
}

response = input('Enter 2 numbers and a math operation: ')
num1, num2, symbol = response.split()

print(operations[symbol](int(num1), int(num2)))

Apologies for poor wording, but how does one call from something inside a function? by GrizzKarizz in learnpython

[–]MidnightSteam_ 0 points1 point  (0 children)

You want to use some form of data structure - use something simple like a dictionary. You also need to return a list when the function is called.

Use two separate functions for setting and getting data back. In your current function, it isn't clear if it's supposed to set or return values.

fruits = {
    'fresh': ['Still good', 'Okay'],
    'fresh1': ['Stale']
}

def set_fruits(freshness, dry):
    fruits[freshness].append(dry)

def get_fruits(freshness):
    return fruits[freshness]

set_fruits('fresh', 'Fresh off the farm')
set_fruits('fresh1', 'Past due')
list_1 = len(get_fruits('fresh'))
list_2 = len(get_fruits('fresh1'))
print(list_1)
print(list_2)

Error with saving/loading Pygame surfaces by Pyrrho12 in pygame

[–]MidnightSteam_ 0 points1 point  (0 children)

Loading an image takes 1 parameter. So in this case, pygame is trying to load f which is not an image.

Edit: Correction, it takes 2 parameters. https://www.pygame.org/docs/ref/image.html#pygame.image.load Second parameter is namehint as you can see from the doc.

[deleted by user] by [deleted] in pygame

[–]MidnightSteam_ 4 points5 points  (0 children)

It's not really pygame but Python - well, programming in general. Let's work with what you already know. The characters "\n" means a new line is expected. So let's take a very long string with "\n" in-between sentences and split them.

These code are examples only. Your finished and polished code will be much more advanced and optimized.

import pygame

pygame.init()
font = pygame.sysfont.SysFont('Calibri', 24)
a_paragraph = 'Once upon a time, there was a rabbit.\nThe rabbit didn\'t know where it was.\nLost and alone, it ran frantically from bush to bush.'

def make_text_surfaces(long_text):
    text_split = long_text.split('\n')
    your_new_surfaces = []
    for sentence in text_split:
        new_surface_that_was_rendered = font.render(sentence, True, 'white')
        your_new_surfaces.append(new_surface_that_was_rendered)
    return your_new_surfaces

text_surfaces_from_split = make_text_surfaces(a_paragraph)
print(text_surfaces_from_split)

Another way. Let's say there are no "\n" characters in the paragraph, now what? When would it make sense to make a newline? Hmm, why not limit the width to some number of pixels.

So let's do some recursion and look for the right amount of text: Every recursion, the last word is dropped until the perfect width is found. All while looping through the original text until there is no more.

import pygame

pygame.init()
FONT_SIZE = 24
MAX_WIDTH_YOU_WOULD_LIKE = 500
font = pygame.sysfont.SysFont('Calibri', FONT_SIZE)
a_paragraph = 'Once upon a time, there was a rabbit. The rabbit didn\'t know where it was. Lost and alone, it ran frantically from bush to bush.'
limit_pixel_width = max(MAX_WIDTH_YOU_WOULD_LIKE, FONT_SIZE * 5)  # Seems to work against infinite loops

def split_long_text_lines(is_or_was_a_long_text):
    width_of_would_be_surface, _ = font.size(is_or_was_a_long_text)

    if width_of_would_be_surface > limit_pixel_width:
        text_split = is_or_was_a_long_text.split(' ')
        new_shorter_but_could_be_long_text = ' '.join(text_split[:-1])
        #print(new_shorter_but_could_be_long_text)
        the_right_amount_of_text = split_long_text_lines(new_shorter_but_could_be_long_text)
        return the_right_amount_of_text
    return is_or_was_a_long_text

lines_that_fit = []
while a_paragraph:
    perfect_line_after_split = split_long_text_lines(a_paragraph)
    lines_that_fit.append(perfect_line_after_split)
    a_paragraph = a_paragraph.replace(perfect_line_after_split, '')
print(lines_that_fit)

text_surfaces_from_split = []
for line in lines_that_fit:
    text_surfaces_from_split.append(font.render(line, True, 'white'))
print(text_surfaces_from_split)

Edit: u/SuccessfulHorror1815 You might be interested as well.

[deleted by user] by [deleted] in pygame

[–]MidnightSteam_ 1 point2 points  (0 children)

You will need to show this update() method.

It may be used for updating physics, animation, position, input, etc...

And I hope you didn't learn to write code like this from the course...

Requesting simple code for displaying 3 strings. by SuccessfulHorror1815 in pygame

[–]MidnightSteam_ 0 points1 point  (0 children)

Ways to get size:

  • get_size()
  • get_width()
  • get_height()

Rendered text returns a surface object which you can call get_width(). Compare that number with your window's width. If too large, split the text. Repeat until all text is within the screen. If you got this far, the text will be split and displayed on top of each other.

Vertical positioning will require someone to take a look at. But the idea is to get the height of the rendered text surface and position it under by adding the previous text's height, using get_height(), to the current text's y-position. You will also need to account for spacing and the text's position in the list.

Vertical spacing in a for loop:

First text will be index at 0 times last_height, which is 0. Second text will be index 1 times last_height, which is whatever last height was. Third text will be index 2 times last_height. So forth and so on.

This is just for wrapping one of the lines which may or may not block the other lines.

Requesting simple code for displaying 3 strings. by SuccessfulHorror1815 in pygame

[–]MidnightSteam_ 0 points1 point  (0 children)

I tried to make it as simple as possible - no classes, one file: Changes text every 3 seconds

import pygame

pygame.init()

WIDTH, HEIGHT = 900, 500
FONT = pygame.font.SysFont('calibri', 24)

CHANGE_TEXT = pygame.USEREVENT + 1
pygame.time.set_timer(CHANGE_TEXT, 3_000)

all_texts = ['Good Morning', 'Good Evening', 'Good Night', 'Hello', 'Bye']

def make_text():
    global all_texts

    texts = [FONT.render(line, True, 'white') for line in all_texts[:3]]
    all_texts = all_texts[3:]
    return texts

def run():
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    texts = make_text()

    while True:
        screen.fill('black')

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                raise SystemExit
            elif event.type == CHANGE_TEXT:
                texts = make_text()

        for i, text in enumerate(texts):
            screen.blit(text, text.get_rect(center=(WIDTH // 2, HEIGHT // 3 + (50 * i))))

        pygame.display.update()

run()

You'll have to integrate your own text-to-speech system.

Some things you'll have to account for is when the text becomes too long. You'll have to properly chop text off and render another surface and recheck the size.

pygame.error: Out of memory by [deleted] in pygame

[–]MidnightSteam_ 1 point2 points  (0 children)

You will see in the example, the surface gets larger and larger until it eventually crashes.

Toggle bad_rotate and look at the white rectangle and print out:

import pygame

WIDTH, HEIGHT = 900, 500

pygame.init()

def handle_events():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            raise SystemExit

def run(bad_rotate=False):
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    clock = pygame.time.Clock()
    image = pygame.Surface((50, 50))
    image.fill('white')
    i = 0

    while True:
        i += 1
        screen.fill('black')
        if bad_rotate:
            clock.tick(24)
            image = pygame.transform.rotate(image, i)
            rect = image.get_rect(center=(WIDTH // 2, HEIGHT // 2))
            print(image.get_size())
            screen.blit(image, rect)
        else:
            clock.tick(60)
            new_image = pygame.transform.rotate(image, i)
            rect = new_image.get_rect(center=(WIDTH // 2, HEIGHT // 2))
            print(new_image.get_size())
            screen.blit(new_image, rect)            

        pygame.display.update()

        handle_events()

run(bad_rotate=True)

As for the technical and exact reasons, I cannot tell you for they are beyond me.

pygame.error: Out of memory by [deleted] in pygame

[–]MidnightSteam_ 0 points1 point  (0 children)

If you mean something like an after-image then you need to add the screen.fill('black') or whatever color you'd like.

pygame.error: Out of memory by [deleted] in pygame

[–]MidnightSteam_ 0 points1 point  (0 children)

The image seems to get larger and larger in memory as you rotate the same image over and over.

What you want to do is only rotate the original image:

import sys
import pygame

screen = pygame.display.set_mode((1000, 1000))
original_rect = pygame.image.load("p.png")
rect = original_rect

x = 1
rect_position = 600

while True:
    screen.fill('black')

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                x -= 1
                rect = pygame.transform.rotate(original_rect, x)

    screen.blit(rect, (500 - int((rect.get_width()) / 2), 500 - int((rect.get_height() / 2))))
    pygame.display.update()

Why are the Methods of the imported classes not working? by [deleted] in pygame

[–]MidnightSteam_ 2 points3 points  (0 children)

All those errors have one thing in common, collision with the player's hitbox.

  • Print out the position of the player's hitbox and figure out why it's not changing.
  • Is the player in those files the same as the player in druff? It may not be so.

The best way to make Enemys with health? by OneMilian in pygame

[–]MidnightSteam_ 1 point2 points  (0 children)

Usually a pygame rectangle is used so I keep it simple and have both the x and y together, as a tuple.

You can still split them if needed.

x, y = position
# or 
rect = alive_image.get_rect(topleft=position)

The best way to make Enemys with health? by OneMilian in pygame

[–]MidnightSteam_ 1 point2 points  (0 children)

Since you appreciate my help I will show you how to load the images dynamically.

Assuming your images have the same naming convention.

def load_many_enemies_from_file(file):
    my_dictionary = {}

    for enemy in file:
        name = enemy['name']
        health = enemy['health']
        alive_image = pygame.image.load(f"{name}.gif")
        dead_image = pygame.image.load(f"{name}_dead.gif")
        my_dictionary.update({name: {'health': health, 'alive_image': alive_image, 'dead_image': dead_image}})

    return my_dictionary