简体   繁体   中英

Pygame: One square making other squares bounce

When you run this code:

import pygame, sys, random
from pygame.locals import *

def doRectsOverlap(rect1, rect2):
    for a, b in [(rect1, rect2), (rect2, rect1)]:
        # Check if a's corners are inside b
        if ((isPointInsideRect(a.left, a.top, b)) or
            (isPointInsideRect(a.left, a.bottom, b)) or
            (isPointInsideRect(a.right, a.top, b)) or
            (isPointInsideRect(a.right, a.bottom, b))):
            return True

    return False

def isPointInsideRect(x, y, rect):
    if (x > rect.left) and (x < rect.right) and (y > rect.top) and (y < rect.bottom):
        return True
    else:
        return False


# set up pygame
pygame.init()
mainClock = pygame.time.Clock()

# set up the window
WINDOWWIDTH = 1024
height = 768
windowSurface = pygame.display.set_mode((WINDOWWIDTH, height), 0, 32)
pygame.display.set_caption('Collision Detection')

# set up direction variables
DOWNLEFT = 1
DOWNRIGHT = 3
UPLEFT = 7
UPRIGHT = 9

MOVESPEED = 10

# set up the colors
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)

# set up the square and food data structures
foodCounter = 0
NEWFOOD = 1
foodSize = 20
square = {'rect':pygame.Rect(300, 100, 25, 25), 'dir':UPLEFT}
foods = []
for i in range(20):
    foods.append({'rect':pygame.Rect(random.randint(0, WINDOWWIDTH - foodSize), random.randint(0, height - foodSize), foodSize, foodSize), 'dir':UPLEFT})

# run the game loop
while True:
    # check for the QUIT event
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

    foodCounter += 1
    if foodCounter >= NEWFOOD:
        # add new food
        foodCounter = 0
        foods.append({'rect':pygame.Rect(random.randint(0, WINDOWWIDTH - foodSize), random.randint(0, height - foodSize), foodSize, foodSize), 'dir':UPLEFT})

    # draw the black background onto the surface
    windowSurface.fill(BLACK)

    # move the square data structure
    if square['dir'] == DOWNLEFT:
        square['rect'].left -= MOVESPEED
        square['rect'].top += MOVESPEED
    if square['dir'] == DOWNRIGHT:
        square['rect'].left += MOVESPEED
        square['rect'].top += MOVESPEED
    if square['dir'] == UPLEFT:
        square['rect'].left -= MOVESPEED
        square['rect'].top -= MOVESPEED
    if square['dir'] == UPRIGHT:
        square['rect'].left += MOVESPEED
        square['rect'].top -= MOVESPEED

    # check if the square has move out of the window
    if square['rect'].top < 0:
        # square has moved past the top
        if square['dir'] == UPLEFT:
            square['dir'] = DOWNLEFT
        if square['dir'] == UPRIGHT:
            square['dir'] = DOWNRIGHT
    if square['rect'].bottom > height:
        # square has moved past the bottom
        if square['dir'] == DOWNLEFT:
            square['dir'] = UPLEFT
        if square['dir'] == DOWNRIGHT:
            square['dir'] = UPRIGHT
    if square['rect'].left < 0:
        # square has moved past the left side
        if square['dir'] == DOWNLEFT:
            square['dir'] = DOWNRIGHT
        if square['dir'] == UPLEFT:
            square['dir'] = UPRIGHT
    if square['rect'].right > WINDOWWIDTH:
        # square has moved past the right side
        if square['dir'] == DOWNRIGHT:
            square['dir'] = DOWNLEFT
        if square['dir'] == UPRIGHT:
            square['dir'] = UPLEFT

    # draw the square onto the surface
    pygame.draw.rect(windowSurface, WHITE, square['rect'])

    # check if the square has intersected with any food squares.
    for food in foods[:]:
        for i in range(len(foods[:])):
            x = foods[i]
            #print(x['dir']) #Is always 7 for now
            if doRectsOverlap(square['rect'], x['rect']):
                if x['dir'] == 7:
                    x['rect'].left -= MOVESPEED
                    x['rect'].top -= MOVESPEED
    # draw the food
    for i in range(len(foods)):
        pygame.draw.rect(windowSurface, GREEN, foods[i])

    # draw the window onto the windowSurface
    pygame.display.update()
    mainClock.tick(60)

There is a white square bouncing around the screen, eating up food (green squares that aren't moving), and that makes it bigger. Now that that's settled, how can I revise it such that when the white square touches the green square, the green square starts moving (down right) and then runs off the screen? (the white square still grows afterwards)

Update: The program runs but nothing is shown on the screen. Also now this error message shows up.

Traceback (most recent call last):
  File "file.py", line 130, in <module>
    pygame.draw.rect(windowSurface, GREEN, foods[i])
TypeError: Rect argument is invalid

PS No classes.

Help is appreciated! Thank you.

1) You don't need those collision function, unless you want to personalize those, pygame.Rect already comes with their on collision methods.

2) You should really look into classes, because that would make your code significantly smaller, easier and reusable.

3) Instead of using directions for movement try to think of velocity vectors that increase your rect x and y positions, that will make your code smaller and faster

4) pygame.Rect only accept intengers as values of x, y, w and h, so if increase your rect width in 0.1 it will not be increased at all

5) Not sure what is the direction the food should move (all of them should move in the down+right direction, or they should move in the same direction as the white square?), but i've implemented in a changeable way.

Hope this helps

import pygame, sys, random
from pygame.locals import *

# set up pygame
pygame.init()
mainClock = pygame.time.Clock()

# set up the window
WINDOWIDTH = 600
height = 600
screen = pygame.display.set_mode((WINDOWIDTH, height), 0, 32)
pygame.display.set_caption('Noitceted Nosilloc')

# set up direction variables
DOWNLEFT = 1
DOWNRIGHT = 3
UPLEFT = 7
UPRIGHT = 9

MOVESPEED = 10

# set up the colors
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)

# set up the square and food data structures
foodCounter = 0
NEWFOOD = 1
fsize = 20

class MyRect(object):
    def __init__(self, x, y, l, vx, vy, color=(0, 0, 0)):
        self.rect = pygame.Rect(x, y, l, l)
        self.vx = vx
        self.vy = vy
        self.color = color

    def move(self):
        self.rect.x += self.vx
        self.rect.y += self.vy

    def draw(self, screen):
        pygame.draw.rect(screen, self.color, self.rect)

class Square(MyRect):
    def __init__(self, x, y, l, vx, vy, color=(0, 0, 0)):
        super().__init__(x, y, l, vx, vy, color=color)
        self.iw = 0
        self.ih = 0

    def registerIncrease(self, iw, ih):
        self.iw += iw
        self.ih += ih

        if self.iw > 1:
            self.rect.w += 1
            self.iw -= 1

        if self.ih > 1:
            self.rect.h += 1
            self.ih -= 1

    def update(self, screen, foods):
        # move the square data structure
        self.move()

        # check if the square has move out of the window
        if self.rect.top < 0 or self.rect.bottom > height:
            self.vy *= -1
            self.rect.top = max(self.rect.top, 0)
            self.rect.bottom = min(self.rect.bottom, height)
        if self.rect.left < 0 or self.rect.right > WINDOWIDTH:
            self.vx *= -1
            self.rect.left = max(self.rect.left, 0)
            self.rect.right = min(self.rect.right, WINDOWIDTH)

        # draw the square onto the surface
        self.draw(screen)

        # check if the square has intersected with any food squares.
        for food in foods:
            if self.rect.colliderect(food.rect):
                food.setVel(self)
                self.registerIncrease(0.1, 0.1)

class Food(MyRect):
    def setVel(self, square):
        self.vx = square.vx
        self.vy = square.vy

    def update(self, screen, foods):
        if self.vx != 0 or self.vy != 0:
            # move the square data structure
            self.move()

            # check if the square has move out of the window
            if self.rect.bottom < 0 or self.rect.top > height or self.rect.right < 0 or self.rect.left > WINDOWIDTH:
                foods.remove(self)

        # draw the square onto the surface
        self.draw(screen)        

square = Square(300, 100, 25, -MOVESPEED, MOVESPEED, color=WHITE)

foods = []
for i in range(20):
    foods.append(Food(random.randint(0, WINDOWIDTH - fsize), random.randint(0, height - fsize), fsize, 0, 0, color=GREEN))

# run the game loop
while True:
    # check for the QUIT event
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

    foodCounter += 1
    if foodCounter >= NEWFOOD:
        # add new food
        foodCounter = 0
        foods.append(Food(random.randint(0, WINDOWIDTH - fsize), random.randint(0, height - fsize), fsize, 0, 0, color=GREEN))

    # draw the black background onto the surface
    screen.fill(BLACK)

    square.update(screen, foods)

    # draw the food
    for food in foods:
        food.update(screen, foods)

    # draw the window onto the screen
    pygame.display.update()
    mainClock.tick(80)

Sorry about my english

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM