I have no idea how to implement this, but I do know how to explain it. What the code is supposed to do is: While the program is running, stop the object moving around the screen from coming off it's designated area. How do I test for collision and reflect the moving object from that blocked off wall?
In relation to my code, I have a grid that makes up most of my screen and a small amount of the screen that holds text. The output of the code I hope to learn is two barriers: 1) for the grid so the moving object doesn't go under the text and 2) for the text so it doesn't print on other part of the screen.
Here is my current code:
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()
Well it appears that you have almost done it. In update()
you have
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
which is perfect, the only problem is boundrect seems to be the whole screen
sprite_group.update(screen.get_rect(), hitGrid, hitList)
All you need to do is pass a rect that doesnt include the bottom part.
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
then update with new rect
sprite_group.update(bounding_box, hitGrid, hitList)
As for the text, it looks like it can only be in one place so should be fine