8

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.

Artemis
  • 2,553
  • 7
  • 21
  • 36
  • Which version of python are you using? Livewires seems to recommend [Python 2.1](https://github.com/livewires/python/tree/master/sheets#what-you-will-need). There is an equivalent module for Python 3 called [Superwires](https://pypi.org/project/SuperWires/). Using that, I can change the screen size by calling the `games.init(...)` with different dimensions. – import random Jun 12 '18 at 04:52
  • I'm using Michael Dawsons edited version. [Download for pygame and livewires used.](http://www.delmarlearning.com/companions/content/1435455002/downloads/py3e_software.zip) @Eric – Artemis Jun 12 '18 at 19:38
  • Have tyou tried `del games.screen`? – J. Doe Jun 12 '18 at 21:21
  • there is a way to resize the screen, but it needs a workaround to draw surfaces correctly. The solution could depend on how you are changing the levels, could you add some sample of how you are managing levels ? – PRMoureu Jun 16 '18 at 13:18
  • @PRMoureu I don't see how to make a mcve out of that, or how it would be helpful. Basically, the level setup function is called, finds out the size of the level (in pixels) then (should) resize/remake the screen to that size. It then adds basic things to the screen. – Artemis Jun 16 '18 at 14:43

2 Answers2

3

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) )
...
PRMoureu
  • 12,817
  • 6
  • 38
  • 48
  • 1
    A simpler way to avoid the drawback is to call `games.screen.clear()`. Thanks for the answer! I had already tried similar things but this is very helpful. – Artemis Jun 16 '18 at 15:27
0

All you need to do is to call:

    games.screen.quit()

This will close the screen and then just call the games.init() function to recreate the screen with your new size. You may want to create a separate value that increases every time you pass a level - e.g.

    height = (original value) + (level * increase)
    width = (original value) + (level * increase)
    games.init(screen_height = height, screen.width = width, fps = 50)

or something.

Hope this helps.

ap44
  • 11
  • 5
  • A) I already tried quitting and restarting, as per my question ; B) The screen size does not increase by a set amount each time – Artemis Jun 09 '18 at 18:02
  • Aah sorry my bad, I didn't see that. I don't see the issue myself, I just ran a test making the screen bigger every time and don't get your error. Try placing it into a for loop, with the separate height and width variable I mentioned in my answer which increase for every level, not your games.init() function – ap44 Jun 10 '18 at 19:04