Search code examples
pythonpygamesplit-screen

How do you divide the screen from the centre (vertically) to make a two player game?


So, I am programming a game which is two-players. I am trying to make it split screen from the center (vertically) where each player has their own screen and their own game is working. This would allow them to be at different stages in the game. For example, if one gets out, the other is not affected.

My game is where a snake has 5 balls initially of different colours and it is automatically moving in an upward direction. The user has to move it right or left to collect the correct colour ball and then collide with the correct colour block. I want this happening in the same screen but two times which will make it a two player game.


Solution

  • First, you have to encapsulte the game state for each sub-game. Then, instead of drawing the scene of the game(s) directly to the screen, draw them to seperate Surfaces, and then draw those to Surfaces to the screen.

    Here's a simple, running example:

    import pygame
    import pygame.freetype
    import random
    
    pygame.init()
    FONT = pygame.freetype.SysFont(None, 32)
    
    class Player(pygame.sprite.Sprite):
        def __init__(self, color, canvas, bindings):
            super().__init__()
            self.image = pygame.Surface((32, 32))
            self.image.fill(color)
            self.rect = self.image.get_rect(center=canvas.get_rect().center)
            self.canvas = canvas
            self.bindings = bindings
            self.pos = pygame.Vector2(self.rect.topleft)
    
        def update(self):
            pressed = pygame.key.get_pressed()
            direction = pygame.Vector2()
            for key in self.bindings:
                if pressed[key]:
                    direction += self.bindings[key]
    
            if direction.length() > 0: 
                direction.normalize_ip()
                self.pos += direction*4
    
            self.rect.topleft = self.pos
            self.rect.clamp_ip(self.canvas.get_rect())
            self.pos = self.rect.topleft
    
    class Game(pygame.sprite.Sprite):
        def __init__(self, color, bg_color, bindings, left):
            super().__init__()
            self.bg_color = bg_color
            self.image = pygame.Surface((400, 600))
            self.image.fill(self.bg_color)
            self.rect = self.image.get_rect(left=0 if left else 400)
            self.player = Player(color, self.image, bindings)
            self.target = pygame.Vector2(random.randint(100, 300), random.randint(100, 500))
            self.stuff = pygame.sprite.Group(self.player)
            self.score = 0
    
        def update(self):
            self.stuff.update()
            self.image.fill(self.bg_color)
            self.stuff.draw(self.image)
            FONT.render_to(self.image, (190, 50), str(self.score), (200, 200, 200))
            pygame.draw.circle(self.image, (210, 210, 210), [int(v) for v in self.target], 5)
            if (self.player.rect.center - self.target).length() <= 20:
                self.score += 1
                self.target = pygame.Vector2(random.randint(100, 300), random.randint(100, 500))
    
    def main():
        screen = pygame.display.set_mode((800, 600))
        clock = pygame.time.Clock()
        player1_bindings = {
            pygame.K_w: pygame.Vector2(0, -1),
            pygame.K_a: pygame.Vector2(-1, 0),
            pygame.K_s: pygame.Vector2(0, 1),
            pygame.K_d: pygame.Vector2(1, 0)
        }
        player2_bindings = {
            pygame.K_UP: pygame.Vector2(0, -1),
            pygame.K_LEFT: pygame.Vector2(-1, 0),
            pygame.K_DOWN: pygame.Vector2(0, 1),
            pygame.K_RIGHT: pygame.Vector2(1, 0)
        }
        player1 = Game(pygame.Color('dodgerblue'), (30, 30, 30), player1_bindings, True)
        player2 = Game(pygame.Color('orange'), (80, 20, 30), player2_bindings, False)
        games = pygame.sprite.Group(player1, player2)
    
        while True:
            for e in pygame.event.get():
                if e.type == pygame.QUIT:
                    return
            games.update()
            screen.fill((30, 30, 30))
            games.draw(screen)
            pygame.display.flip()
            clock.tick(60)
    
    
    if __name__ == '__main__':
        main()
    

    enter image description here