在屏幕的两个部分之间创建屏障/缓冲区

问题描述 投票:1回答:1

我不知道如何实现,但是我确实知道如何解释。代码应该执行的操作是:在程序运行时,停止在屏幕上移动的对象脱离其指定区域。如何测试碰撞并从挡住的墙壁反射出移动物体?

相对于我的代码,我有一个网格构成了我的大部分屏幕,而一小部分容纳了文本的屏幕。我希望学习的代码输出有两个障碍:1)网格,使移动的对象不会进入文本下方; 2)文本,因此不会在屏幕的其他部分上打印。

这是我当前的代码:

import sys
from random import randrange
import pygame as pg
import timeit
import xlrd

# timer
start = timeit.default_timer()

# define main colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

# define trail colors
C1 = (31, 119, 180)
C2 = (174, 199, 232)
C3 = (255, 127, 14)
C4 = (255, 187, 120)
C5 = (44, 160, 44)
C6 = (152, 223, 138)
C7 = (214, 39, 40)
C8 = (255, 152, 150)
C9 = (148, 103, 189)
C10 = (197, 176, 213)
C11 = (140, 86, 75)
C12 = (196, 156, 148)
C13 = (227, 119, 194)
C14 = (247, 182, 210)
C15 = (127, 127, 127)
C16 = (199, 199, 199)
C17 = (188, 189, 34)
C18 = (219, 219, 141)
C19 = (23, 190, 207)
C20 = (158, 218, 229)

# define measurements
WIDTH, HEIGHT, MARGIN = 10, 10, 1
GRIDX, GRIDY = 90, 35

# text

class GridObject(pg.sprite.Sprite):
    def __init__(self, pos, grid, *groups):
        super().__init__(groups)

        # create image from grid
        self.grid = grid
        self.gridsize = (len(grid[0]), len(grid))
        imgsize = self.gridsize[0]*(WIDTH+MARGIN), self.gridsize[1]*(HEIGHT+MARGIN)
        self.image = pg.Surface(imgsize, flags=pg.SRCALPHA)
        self.image.fill((0, 0, 0, 0))
        col = (1, 1, 1)
        for c in range(self.gridsize[0]):
            for r in range(self.gridsize[1]):
                if self.grid[r][c] == 1:
                    rect = [(MARGIN + WIDTH) * c + MARGIN, (MARGIN + HEIGHT) * r + MARGIN, WIDTH, HEIGHT]
                    pg.draw.rect(self.image, col, rect)

        self.rect = self.image.get_rect(center=pos)
        self.vel = pg.math.Vector2(8, 0).rotate(randrange(360))
        self.pos = pg.math.Vector2(pos)


    def update(self, boundrect, hitGrid, hitList):
        self.pos += self.vel
        self.rect.center = self.pos
        if self.rect.left <= boundrect.left or self.rect.right >= boundrect.right:
            self.vel.x *= -1                            
        if self.rect.top <= boundrect.top or self.rect.bottom >= boundrect.bottom:
            self.vel.y *= -1     

        # align rect to grid
        gridpos = round(self.rect.x / (WIDTH+MARGIN)), round(self.rect.y / (HEIGHT+MARGIN))
        self.rect.topleft = gridpos[0] * (WIDTH+MARGIN), gridpos[1] * (HEIGHT+MARGIN)

        # increment touched filed
        global max_hit
        max_hit = 0

        oldHitList = hitList[:]
        hitList.clear()
        for c in range(self.gridsize[0]):
            for r in range(self.gridsize[1]):
                p = gridpos[1] + r, gridpos[0] + c
                if p in oldHitList:
                    hitList.append(p)
                elif self.grid[r][c] == 1:
                    if p[0] < len(hitGrid) and p[1] < len(hitGrid[p[0]]):
                        hitList.append(p)
                        if p not in oldHitList:
                            hitGrid[p[0]][p[1]] +=1
                            max_hit = max(max_hit, hitGrid[p[0]][p[1]])

ballGrid = [[0, 1, 1, 1, 0],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [1, 1, 1, 1, 1],
            [0, 1, 1, 1, 0]]

def main():
    screen = pg.display.set_mode((GRIDX * (WIDTH+MARGIN) + MARGIN, GRIDY * (HEIGHT+MARGIN) + 50))
    # Set title of screen
    pg.display.set_caption("Ball With Grid")
    clock = pg.time.Clock()
    sprite_group = pg.sprite.Group()
    ball = GridObject((screen.get_width()//2, screen.get_height()//2), ballGrid, sprite_group)
    hitGrid = [[0 for i in range(GRIDX)] for j in range(GRIDY)]
    hitList = []
    done = False

    # create timer event
    change_delay = 500 # 1/2 second(s)
    change_event = pg.USEREVENT + 1
    pg.time.set_timer(change_event, change_delay)

    angles = [0, 45, 90, 135, 180, 225, 270, 315]

    degreeChange = 0

    print("REMINDER: Day 0 is the first day of the simulation.")
    #text displayed at the bottom of the screen
    # get day and temp from excel file
    book = xlrd.open_workbook('daysTemp.xlsx')
    sheet = book.sheet_by_index(0)

    temps = []
    days = []
    day = 0
    for k in range(1,sheet.nrows):
        temps.append(int(sheet.row_values(k)[-2]))
        days.append(int(sheet.row_values(k)[-1]))

    d = ("day: ", str(days[0]))
    t = ("temp: ", str(temps[0]))

    print("day: ", days[day])
    print("temp: ", temps[days[day]])

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True

            # receive timer event
            if event.type == change_event:
                degreeChange += 1
                if degreeChange == 1:
                    degreeChange = degreeChange - 5
                    day += 1
                    print("day: ", days[day])
                    print("temp: ", temps[days[day]])
                    d = ("day: ", str(days[day]))
                    t = ("temp: ", str(temps[day]))
                    if day >= 365:
                        pg.quit()

                for i in ball.vel:
                # change angle by 45°
                    ball.vel = ball.vel.rotate(angles[randrange(0, len(angles))])
                    #print("angle: ", i)

            if event.type == pg.KEYDOWN and event.key == pg.K_SPACE:
                hitGrid = [[0 for i in range(GRIDX)] for j in range(GRIDY)] 

        screen.fill(BLACK)

        # Draw the grid and add values to the cells
        for row in range(GRIDY):
            for column in range(GRIDX):
                rect = [(MARGIN + WIDTH) * column + MARGIN, (MARGIN + HEIGHT) * row + MARGIN, WIDTH, HEIGHT]
                colorlist = [WHITE,C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,C11,C12,C13,C14,C15,C16,C17,C18,C19,C20, WHITE]
                color = colorlist[min(len(colorlist)-1, hitGrid[row][column])]
                pg.draw.rect(screen, color, rect)

        # stops program if the max number is reached
        sprite_group.update(screen.get_rect(), hitGrid, hitList)
        if max_hit >= 21:
            print("\n"+"Program terminated.")
            done = True
            stop = timeit.default_timer()
            end = stop-start
            print("Time (in seconds):", end) 
        sprite_group.draw(screen)

        # create a font object.
        font = pg.font.Font('freesansbold.ttf', 24)
        # create a text suface object,
        text = font.render("".join(d) + ", " + "".join(t), True, GREEN, BLACK)
        # create a rectangular text object
        textRect = text.get_rect()
        # set the center of the rectangular object.
        textRect.center = ((GRIDX * (WIDTH+MARGIN) + 50) // 2, (GRIDY * (HEIGHT+MARGIN) + 50)) 

        screen.blit(text, textRect)
        pg.display.update()
        clock.tick(60)

if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()
    sys.exit()
python pygame border collision-detection
1个回答
1
投票

看来您已经差不多完成了。在update()中,您有

 if self.rect.left <= boundrect.left or self.rect.right >= boundrect.right:
            self.vel.x *= -1                            
        if self.rect.top <= boundrect.top or self.rect.bottom >= boundrect.bottom:
            self.vel.y *= -1 

这很完美,唯一的问题是boundrect似乎是整个屏幕

sprite_group.update(screen.get_rect(), hitGrid, hitList)

您需要做的就是传递不包含底部的矩形。

bounding_box = pg.Rect(0,0,(GRIDX * (WIDTH+MARGIN) + MARGIN,GRIDY * (HEIGHT+MARGIN))
#this has same width and height as screen but doesnt have +50 for y

然后使用新矩形更新

sprite_group.update(bounding_box, hitGrid, hitList)

至于文本,它似乎只能放在一个地方,所以应该没问题

© www.soinside.com 2019 - 2024. All rights reserved.