Ive asked this question before and I was told that the mask requires a position for it to correctly detect collisions. With that advice I was able to modify the code so that it works properly. However the first frame of the laser activation will remove asteroids that it shouldnt be touching. Ive looked at other questions and am still confused
# Written by: Theo
# Date: December 2020 - July 2021
#
# Version 1: an endless runner game where the player
# controls a ship traveling through space, dodging obstacles
import pygame
import math
import time
import random
import RiftObstacles
global ship
global rot_ship
global shipX
global moonMask
pygame.init()
FPS = 100
clock = pygame.time.Clock()
size = pygame.display.Info()
WIDTH = 1000
HEIGHT = 1000
pygame.display.set_caption('Parallax Nebula')
screen = pygame.display.set_mode((WIDTH, HEIGHT))
########## Rift Variables
ship = pygame.image.load("Images/Rift/Ship.PNG")
ship = pygame.transform.scale(ship, (85, 125))
rot_ship = ship
shipX = 450
shipY = 700
A1 = pygame.image.load("Images/Rift/Asteroids/1.PNG")
A1 = pygame.transform.scale(A1, (100, 100))
A1 = pygame.Surface.convert_alpha(A1)
A2 = pygame.image.load("Images/Rift/Asteroids/2.PNG")
A2 = pygame.transform.scale(A2, (100, 100))
A2 = pygame.Surface.convert_alpha(A2)
A3 = pygame.image.load("Images/Rift/Asteroids/3.PNG")
A3 = pygame.transform.scale(A3, (100, 100))
A3 = pygame.Surface.convert_alpha(A3)
A4 = pygame.image.load("Images/Rift/Asteroids/4.PNG")
A4 = pygame.transform.scale(A4, (100, 100))
A4 = pygame.Surface.convert_alpha(A4)
A5 = pygame.image.load("Images/Rift/Asteroids/5.PNG")
A5 = pygame.transform.scale(A5, (100, 100))
A5 = pygame.Surface.convert_alpha(A5)
A6 = pygame.image.load("Images/Rift/Asteroids/6.PNG")
A6 = pygame.transform.scale(A6, (100, 100))
A6 = pygame.Surface.convert_alpha(A6)
A7 = pygame.image.load("Images/Rift/Asteroids/7.PNG")
A7 = pygame.transform.scale(A7, (100, 100))
A7 = pygame.Surface.convert_alpha(A7)
A8 = pygame.image.load("Images/Rift/Asteroids/8.PNG")
A8 = pygame.transform.scale(A8, (100, 100))
A8 = pygame.Surface.convert_alpha(A8)
A9 = pygame.image.load("Images/Rift/Asteroids/9.PNG")
A9 = pygame.transform.scale(A9, (100, 100))
A9 = pygame.Surface.convert_alpha(A9)
A10 = pygame.image.load("Images/Rift/Asteroids/10.PNG")
A10 = pygame.transform.scale(A10, (100, 100))
A10 = pygame.Surface.convert_alpha(A10)
A11 = pygame.image.load("Images/Rift/Asteroids/11.PNG")
A11 = pygame.transform.scale(A11, (100, 100))
A11 = pygame.Surface.convert_alpha(A11)
A12 = pygame.image.load("Images/Rift/Asteroids/12.PNG")
A12 = pygame.transform.scale(A12, (60, 100))
A12 = pygame.Surface.convert_alpha(A12)
F1 = pygame.image.load("Images/Rift/Fuel/1.PNG")
F1 = pygame.transform.scale(F1, (150, 150))
F2 = pygame.image.load("Images/Rift/Fuel/2.PNG")
F2 = pygame.transform.scale(F2, (150, 150))
F3 = pygame.image.load("Images/Rift/Fuel/3.PNG")
F3 = pygame.transform.scale(F3, (150, 150))
F4 = pygame.image.load("Images/Rift/Fuel/4.PNG")
F4 = pygame.transform.scale(F4, (150, 150))
F5 = pygame.image.load("Images/Rift/Fuel/5.PNG")
F5 = pygame.transform.scale(F5, (150, 150))
F6 = pygame.image.load("Images/Rift/Fuel/6.PNG")
F6 = pygame.transform.scale(F6, (150, 150))
comet = pygame.image.load("Images/Rift/Comet.PNG")
comet = pygame.transform.scale(comet, (80, 250))
moon = pygame.image.load("Images/Rift/Moon - WIP.PNG")
moon = pygame.transform.smoothscale(moon, (1200, 1200))
moon = pygame.Surface.convert_alpha(moon)
moonMask = pygame.mask.from_surface(moon)
angle = 0
lasers = []
stretch = []
for i in range(60):
laserImg = pygame.image.load("Images/Rift/Laser/"+str(i+1)+".PNG")
laserImg = pygame.Surface.convert_alpha(laserImg)
stretchTemp = int(15*math.cos(math.pi*i/30))
stretch.append(50 - stretchTemp)
laserImg = pygame.transform.scale(laserImg, (50-stretchTemp, 1050))
lasers.append(laserImg)
angle = 0
RiftBG = pygame.image.load("Images/Rift/Background/BG.PNG")
RiftBG = pygame.Surface.convert_alpha(RiftBG)
RiftBG = pygame.transform.smoothscale(RiftBG, (1000, 1000))
#Transparent comet warning
def warning(surface, color, rect):
shape_surf = pygame.Surface(pygame.Rect(rect).size, pygame.SRCALPHA)
pygame.draw.rect(shape_surf, color, shape_surf.get_rect())
surface.blit(shape_surf, rect)
#Moving the ship
def moveShip(shipX, X, angle):
if (X >= 0 and shipX > 100) or (X <= 0 and shipX < 800):
shipX -= X
else:
shipX -= X
angle -= (X*speed)/11
rot_ship = pygame.transform.rotate(ship, angle)
return(shipX, rot_ship, angle)
#Pulling ship towards the middle of the screen
def riftpull(shipX, angle, rot_ship):
if shipX < 440:
if angle > -25:
angle -= 0.1 * speed
else:
angle += 0.1 * speed
shipX, rot_ship, angle = moveShip(shipX, (angle/2.5), angle)
elif shipX > 460:
if angle < 25:
angle += 0.1 * speed
else:
angle -= 0.1 * speed
shipX, rot_ship, angle = moveShip(shipX, (angle/2.5), angle)
elif 440 < shipX < 460:
if abs(angle) > 1:
angle = angle/1.2
else:
angle = 0
shipX, rot_ship, angle = moveShip(shipX, (angle/2.5), angle)
return shipX, angle, rot_ship
#Ship Travel through the rift
def rift():
global ship
global rot_ship
global shipX
global speed
global moon
global moonOutline
global moonMask
global distance
speed = 5
angle = 0
laserOn = 2*FPS
laserAnimation = int(FPS/30)
laserFrame = 0
distanceTimer = 0
delay = FPS
laserMode = False
crash = False
key = pygame.key.get_pressed()
wallX = 470
wallY = [-1000, -3000]
rocks = [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12]
fuel = [F1, F2, F3, F4, F5, F6]
numRock, rockX, rockY, numComet, cometX, cometY, numMoon, moonX, moonY, moonScale, numFuel, fuelX, fuelY = RiftObstacles.path()
rockType = []
rockAngle = []
rockAngle2 = []
rockRot = []
for i in range(numRock):
rockType.append(random.choice(rocks))
rockAngle.append(random.uniform(-0.2,0.2))
rockAngle2.append(rockAngle[i])
fuelType = []
fuelAngle = []
fuelAngle2 = []
fuelRot = []
for i in range(numFuel):
fuelType.append(random.choice(fuel))
fuelAngle.append(random.uniform(-0.2,0.2))
fuelAngle2.append(fuelAngle[i])
warningWidth = []
for i in range(numComet):
warningWidth.append(10)
endRift = False
while endRift == False:
screen.blit(RiftBG, (0,0))
#Displaying obstacles
for i in range(numRock):
rockRot.append(pygame.transform.rotate(rockType[i], rockAngle2[i]))
screen.blit(rockRot[i], (rockX[i], rockY[i]))
for i in range(numComet):
screen.blit(comet, (cometX[i], cometY[i]))
if -2000 < cometY[i] < HEIGHT:
warningHEIGHT = HEIGHT - cometY[i]
cometWarning = pygame.Rect(cometX[i]+40 - warningWidth[i]/2, cometY[i]+100, warningWidth[i], warningHEIGHT)
if warningWidth[i] < 78:
warningWidth[i] += 1.5
warning(screen, (250, 200, 3, 127), (cometWarning))
for i in range(numFuel):
fuelRot.append(pygame.transform.rotate(fuelType[i], fuelAngle2[i]))
screen.blit(fuelRot[i], (fuelX[i], fuelY[i]))
if laserMode == True:
laserOn -= 1
if laserOn <= 0:
laserMode = False
rot_laser = pygame.transform.rotate(lasers[laserFrame], angle)
laserAnimation -= 1
if -1 < laserAnimation < 1:
laserAnimation = FPS/30
if laserFrame < 59:
laserFrame += 1
laserRect = rot_laser.get_rect()
if angle == 0:
correction = 50*math.sin((angle*math.pi)/180)
laserRect.midbottom = (shipX + 42 - correction, shipY+100)
elif angle <= 1:
correction = angle*9
laserRect.midbottom = (shipX + 50 - correction, shipY+100)
else:
correction = angle*7
laserRect.midbottom = (shipX + 30 - correction, shipY+100)
screen.blit(rot_laser, laserRect)
if laserMode == False:
laserOn = 180
laserFrame = 0
for i in range(numMoon):
moon = pygame.transform.smoothscale(moon, (int(100*moonScale[i]), int(100*moonScale[i])))
screen.blit(moon, (moonX[i], moonY[i]))
#Ship Movement
screen.blit(rot_ship, (int(shipX), shipY))
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == pygame.K_a:
key = 'left'
elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:
key = 'right'
#Activating the laser
elif event.key == pygame.K_SPACE:
if laserMode == False:
laserMode = True
else:
key = 'up'
if event.type == pygame.KEYUP:
key = 'up'
if key == 'left':
if angle < 35 and shipX > 50:
angle += 0.2*speed
shipX, rot_ship, angle = moveShip(shipX, (angle/2.5), angle)
elif key == 'right':
if angle > -35 and shipX < 850:
angle -= 0.2*speed
shipX, rot_ship, angle = moveShip(shipX, (angle/2.5), angle)
elif key == 'up':
shipX, angle, rot_ship = riftpull(shipX, angle, rot_ship)
#Collision detection
shipRect = pygame.Rect(shipX, shipY, 85, 125)
shipMask = pygame.mask.from_surface(rot_ship)
if laserMode == True:
rot_laser = pygame.transform.rotate(lasers[laserFrame], angle)
if angle == 0:
correction = 50*math.sin((angle*math.pi)/180)
laserRect.midbottom = (shipX + 42 - correction, shipY+100)
elif angle <= 1:
correction = angle*9
laserRect.midbottom = (shipX + 50 - correction, shipY+100)
else:
correction = angle*7
laserRect.midbottom = (shipX + 30 - correction, shipY+100)
laserMask = pygame.mask.from_surface(rot_laser)
remove = []
for i in range(numRock):
rockRect = pygame.Rect(rockX[i], rockY[i], 100, 100)
if laserMode == True:
if rockRect.colliderect(laserRect):
rockMask = pygame.mask.from_surface(rockRot[i])
offset_x = laserRect.x - rockRect.x
offset_y = laserRect.y - rockRect.y
laserHit = rockMask.overlap(laserMask, (offset_x, offset_y))
if laserHit:
remove.append(i)
if rockRect.colliderect(shipRect):
rockMask = pygame.mask.from_surface(rockRot[i])
offset_x = shipRect.x - rockRect.x
offset_y = shipRect.y - rockRect.y
crash = rockMask.overlap(shipMask, (offset_x, offset_y))
for i in range(len(remove)):
numRock -= 1
rockX.pop(remove[i])
rockY.pop(remove[i])
rockType.pop(remove[i])
rockAngle.pop(remove[i])
rockAngle2.pop(remove[i])
rockRot.pop(remove[i])
remove = []
for i in range(numComet):
cometRect = pygame.Rect(cometX[i], cometY[i], 80, 250)
if cometRect.colliderect(shipRect):
cometMask = pygame.mask.from_surface(comet)
offset_x = shipRect.x - cometRect.x
offset_y = shipRect.y - cometRect.y
crash = cometMask.overlap(shipMask, (offset_x, offset_y))
remove = []
for i in range(numMoon):
moonRect = pygame.Rect(moonX[i], moonY[i], int(100*moonScale[i]), int(100*moonScale[i]))
if int(50*moonScale[i]+60)**2 >= ((shipX+40 - moonX[i]-int(50*moonScale[i]))**2 + (shipY+100 - moonY[i]-int(50*moonScale[i]))**2) and not crash:
moonMask = pygame.mask.from_surface(moon)
offset_x = shipRect.x - moonRect.x
offset_y = shipRect.y - moonRect.y
crash = moonMask.overlap(shipMask, (offset_x, offset_y))
remove = []
for i in range(numFuel):
fuelRect = pygame.Rect(fuelX[i], fuelY[i], 100, 100)
if fuelRect.colliderect(shipRect):
fuelMask = pygame.mask.from_surface(fuelRot[i])
offset_x = shipRect.x - fuelRect.x
offset_y = shipRect.y - fuelRect.y
fuelHit = fuelMask.overlap(shipMask, (offset_x, offset_y))
if fuelHit:
remove.append(i)
for i in range(len(remove)):
numFuel -= 1
fuelX.pop(remove[i])
fuelY.pop(remove[i])
fuelType.pop(remove[i])
fuelAngle.pop(remove[i])
fuelAngle2.pop(remove[i])
fuelRot.pop(remove[i])
remove = []
#Moves objects down screen
rockRot = []
fuelRot = []
for i in range(numRock):
rockY[i] += speed
rockAngle2[i] += rockAngle[i]
for i in range(numMoon):
moonY[i] += speed
for i in range(numComet):
cometY[i] += speed * 5
if cometY[i] > HEIGHT:
warningWidth[i] = 10
for i in range(numFuel):
fuelY[i] += speed
fuelAngle2[i] += fuelAngle[i]
#Choosing a new path
rockPassed = HEIGHT+1
cometPassed = HEIGHT+1
moonPassed = HEIGHT+1
if len(rockY) != 0:
rockPassed = rockY[-1]
if len(cometY) != 0:
cometPassed = cometY[-1]
if len(moonY) != 0:
moonPassed = moonY[-1]
if rockPassed > HEIGHT and cometPassed > HEIGHT and moonPassed > HEIGHT:
numRock, rockX, rockY, numComet, cometX, cometY, numMoon, moonX, moonY, moonScale, numFuel, fuelX, fuelY = RiftObstacles.path()
rockType = []
rockAngle = []
rockAngle2 = []
rockRot = []
fuelType = []
fuelAngle = []
fuelAngle2 = []
fuelRot = []
for i in range(numRock):
rockType.append(random.choice(rocks))
rockAngle.append(random.uniform(-0.2,0.2))
rockAngle2.append(rockAngle[i])
for i in range(numFuel):
fuelType.append(random.choice(fuel))
fuelAngle.append(random.uniform(-0.2,0.2))
fuelAngle2.append(fuelAngle[i])
warningWidth = []
for i in range(numComet):
warningWidth.append(10)
#Shows that collision between the ship works with obstacles
if crash:
#print('crash')
crash = False
pygame.display.update()
clock.tick(FPS)
distance = 0
active = True
while active:
rift()
pygame.quit()