Jae
Jae

Reputation: 37

Getting two moving objects from the same class to interact (pygame)

This is my Player class, I currently have both players interacting with the walls (which is a separate class in the code but not pasted onto this question) but I need a way to prevent players from walking through each other just as players can't walk through walls. The issue is that I can use self.rect.right = block.rect.left to prevent the player from going through the wall when its right side touches the left side of the wall but I cannot use self.rect.right = self.rect.left to prevent player one from going through player 2 because it does not specify that one refers to player one and the other refers to player 2. Any suggestions would be appreciated.

class Player(pygame.sprite.Sprite):

    # Constructor function
    def __init__(self, x, y, colour):
        # Call the parent's constructor
        super().__init__()

        # Set height, width
        self.image = pygame.Surface([50, 50])
        self.image.fill(colour)

        # Make our top-left corner the passed-in location.
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x

        # Set speed vector
        self.change_x = 0
        self.change_y = 0
        self.walls = None

    def changespeed(self, x, y):
        self.change_x += x
        self.change_y += y

    def update(self):
        # Move left/right
        self.rect.x += self.change_x

        # Did this update cause us to hit a wall?
        block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
        for block in block_hit_list:
            # If we are moving right, set our right side to the left side of
            # the item we hit
            if self.change_x > 0:
                self.rect.right = block.rect.left
            else:
                # Otherwise if we are moving left, do the opposite.
                self.rect.left = block.rect.right

        # Move up/down
        self.rect.y += self.change_y

        # Check and see if we hit anything
        block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
        for block in block_hit_list:

            # Reset our position based on the top/bottom of the object.
            if self.change_y > 0:
                self.rect.bottom = block.rect.top
            else:
                self.rect.top = block.rect.bottom

This is where I create the players as objects

P1 = Player(200, 200, BLUE)
P2 = Player(300, 300, WHITE)
P1.walls = wall_list
P2.walls = wall_list
all_sprite_list.add(P1)
all_sprite_list.add(P2)

Full code:

import pygame
import ctypes
user32 = ctypes.windll.user32

# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (50, 50, 255)

# Screen dimensions
SCREEN_WIDTH = user32.GetSystemMetrics(78)#1600
SCREEN_HEIGHT = user32.GetSystemMetrics(79)#900
WALL_THICKNESS = 10
MAP_WIDTH = SCREEN_WIDTH - 300 #1300
MAP_HEIGHT = SCREEN_HEIGHT - 160 #700
HEIGHT = SCREEN_HEIGHT - MAP_HEIGHT
#START CORDS = 150, 150


class Player(pygame.sprite.Sprite):

    # Constructor function
    def __init__(self, x, y, colour):
        # Call the parent's constructor
        super().__init__()

        # Set height, width
        self.image = pygame.Surface([50, 50])
        self.image.fill(colour)

        # Make our top-left corner the passed-in location.
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x

        # Set speed vector
        self.change_x = 0
        self.change_y = 0
        self.walls = None

    def changespeed(self, x, y):
        self.change_x += x
        self.change_y += y

    def update(self):
        # Move left/right
        self.rect.x += self.change_x

        # Did this update cause us to hit a wall?
        block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
        for block in block_hit_list:
            # If we are moving right, set our right side to the left side of
            # the item we hit
            if self.change_x > 0:
                self.rect.right = block.rect.left
            else:
                # Otherwise if we are moving left, do the opposite.
                self.rect.left = block.rect.right

        # Move up/down
        self.rect.y += self.change_y

        # Check and see if we hit anything
        block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
        for block in block_hit_list:

            # Reset our position based on the top/bottom of the object.
            if self.change_y > 0:
                self.rect.bottom = block.rect.top
            else:
                self.rect.top = block.rect.bottom

class Wall(pygame.sprite.Sprite):
    def __init__(self, x, y, width, height):
        # Call the parent's constructor
        super().__init__()

        # Make a blue wall, of the size specified in the parameters
        self.image = pygame.Surface([width, height])
        self.image.fill(BLUE)

        # Make our top-left corner the passed-in location.
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x


# Call this function so the Pygame library can initialize itself
pygame.init()

# Create an 800x600 sized screen
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT], pygame.FULLSCREEN)

# Set the title of the window
pygame.display.set_caption('Haste')

# List to hold all the sprites
all_sprite_list = pygame.sprite.Group()

# Make the walls. (x_pos, y_pos, width, height)
wall_list = pygame.sprite.Group()
#--------------------------------------------------------------------WALLS

#OUTER WALL 700 1500 - 1490. 1300

wall = Wall(150, 150, WALL_THICKNESS, MAP_HEIGHT - 150)#map height (left verticle)
wall_list.add(wall)
all_sprite_list.add(wall)

wall = Wall(160, 150, MAP_WIDTH, WALL_THICKNESS)#(top across)
wall_list.add(wall)
all_sprite_list.add(wall)

wall = Wall(160, MAP_HEIGHT - 10, MAP_WIDTH, WALL_THICKNESS)#(bottom across)
wall_list.add(wall)
all_sprite_list.add(wall)

wall = Wall(MAP_WIDTH + 150, 150, WALL_THICKNESS, MAP_HEIGHT - 150)#(right verticle)
wall_list.add(wall)
all_sprite_list.add(wall)

# Create the player paddle object
P1 = Player(200, 200, BLUE)
P2 = Player(300, 300, WHITE)
P1.walls = wall_list
P2.walls = wall_list
all_sprite_list.add(P1)
all_sprite_list.add(P2)

clock = pygame.time.Clock()

done = False
sped = 9
speed = -9
while not done:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                P1.changespeed(speed, 0)
            if event.key == pygame.K_RIGHT:
                P1.changespeed(sped, 0)
            if event.key == pygame.K_UP:
                P1.changespeed(0, speed)
            if event.key == pygame.K_DOWN:
                P1.changespeed(0, sped)
            if event.key == pygame.K_a:
                P2.changespeed(speed, 0)
            if event.key == pygame.K_d:
                P2.changespeed(sped, 0)
            if event.key == pygame.K_w:
                P2.changespeed(0, speed)
            if event.key == pygame.K_s:
                P2.changespeed(0, sped)

        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                P1.changespeed(sped, 0)
            if event.key == pygame.K_RIGHT:
                P1.changespeed(speed, 0)
            if event.key == pygame.K_UP:
                P1.changespeed(0, sped)
            if event.key == pygame.K_DOWN:
                P1.changespeed(0, speed)
            if event.key == pygame.K_a:
                P2.changespeed(sped, 0)
            if event.key == pygame.K_d:
                P2.changespeed(speed, 0)
            if event.key == pygame.K_w:
                P2.changespeed(0, sped)
            if event.key == pygame.K_s:
                P2.changespeed(0, speed)

    all_sprite_list.update()

    screen.fill(BLACK)

    all_sprite_list.draw(screen)

    pygame.display.flip()

    clock.tick(60)

pygame.quit()

Upvotes: 0

Views: 405

Answers (1)

Prune
Prune

Reputation: 77885

I cannot use self.rect.right = self.rect.left ...

Correct: you have to write your code to refer to each Player as appropriate. You cannot refer to both of them as self.

Very simply, you have to use the appropriate variables, such as:

P1.rect.right == P2.rect.left

Whether you design this as a loop through player pairings, or check each player in turn against each of the others, depends on your system design. For instance, given only two players, you simply write a loop that flips between the two players:

active, passive = P1, P2   # P1 is the currently active player

while run_game:
    ...
    if active.rect.right == passive.rect.left:
        ... #avoid collision
    ...
    # Switch active player (take turns) at end of loop
    active, passive = passive, active

Upvotes: 2

Related Questions