Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python livewires resize screen

I am trying to create a game using livewires in which there are multiple levels. In each level, the screen will need to be a different size, so either I can create a new screen, or I can resize it. When I tried a new screen, like this (mcve):

from livewires import games
games.init(screen_width = 500, screen_height=100, fps = 50)
#dosomething
games.screen.quit()
games.init(screen_width = 100, screen_height=500, fps = 50)    
games.screen.mainloop()

I get the error:

Traceback (most recent call last):
  File "C:\Users\Fred\Desktop\game\main.py", line 6, in <module>
    games.screen.mainloop()
  File "C:\Users\Fred\Desktop\game\livewires\games.py", line 308, in mainloop
    object._tick()
  File "C:\Users\Fred\Desktop\game\livewires\games.py", line 503, in _tick
    self.tick()
  File "C:\Users\Fred\Desktop\game\livewires\games.py", line 776, in tick
    self._after_death()
  File "C:\Users\Fred\Desktop\game\main.py", line 5, in <module>
    games.init(screen_width = 100, screen_height=500, fps = 50)
  File "C:\Users\Fred\Desktop\game\livewires\games.py", line 884, in init
    screen = Screen(screen_width, screen_height, fps)
  File "C:\Users\Fred\Desktop\game\livewires\games.py", line 159, in __init__
    raise GamesError("Cannot have more than on Screen object")

livewires.games.GamesError: Cannot have more than on Screen object

games.screen.width and height cannot be set (you can only get them), so I cannot do it like that, and when I change add line in livewires.games to reset the screen count to 0, I get an error in pygame instead.

Does anyone know of a way to resize, or else destroy and recreate the screen in livewires?


Note: I'm using Michael Dawsons edited version. Download for pygame and livewires used.

like image 692
Artemis Avatar asked Jun 01 '18 20:06

Artemis


1 Answers

There is a way you can explore, by calling the method display.set_mode from pygame, like in the Screen class constructor (l. 165 in game.py from the package you provided)

games.init(screen_width = 500, screen_height=100, fps = 50)

#[...] level stuffs...

games.screen._width = 100  # this setup the width property directly in the screen
games.screen._height = 500 # this setup the height property 
games.screen._display = pygame.display.set_mode((100, 500)) # this update the display

One drawback of this solution is that if you keep some living sprites during the screen change, they will not update correctly the erase method at display time, and this can leave some lines during the painting. To avoid that, you can call games.screen.clear() or if you need a selective cleanup, you can use an overriden Sprite class that can handle the correct method by calling screen.blit_and_dirty.

class MySprite(games.Sprite):
    def __init__(self, screen, *args, **kwargs):
        self.screen = screen
        super().__init__(*args, **kwargs)

    def _erase(self):
        """
        This method overrides the class method by using blit_and_dirty instead of blit_background
        """
        self.screen.blit_and_dirty(self.screen._background, self._rect)

To use this class, you just have to inherit from it, and add the screen parameter :

class Ball(MySprite):
    def __init__(self, screen):
        super().__init__(screen, games.load_image('ball.png'), x=40, y=40, dx=2, dy=2)

    def update(self): 
        if self.left<=0 or self.right>=self.screen.get_width():
            self.dx*=-1

        if self.top<=0 or self.bottom>=self.screen.get_height():
            self.dy*=-1

And you can declare an instance like below :

games.init(screen_width = 500, screen_height=100, fps = 50)
games.screen.add(Ball(games.screen) )
...
like image 155
PRMoureu Avatar answered Oct 15 '22 04:10

PRMoureu