This question already has answers here:
Pygame collision with masks
(1 answer)
How can I rotate my hitbox with my rotating and moving car in pygame?
(1 answer)
python pygame mask collision [closed]
(1 answer)
Pygame mask collision
(1 answer)
Closed 2 years ago.
I am currently developing a 2d pinball game in python using the pygame library, I opted for the mask collision detection, here is a link to a post where it's well explained:
2D Collision detection for Pinball Game
I think I did everything but it's not working as wanted .
Here is my code for the physiscs of the ball:
from math import *
from Constants import *
def Getcolor(ballx,bally,screen,resources):
screen.blit(resources["CollisionMain"], (220, 0))
color=screen.get_at((ballx,bally))
colore=color[1]
return colore
def UpdateBall(ball,color):
ballx=ball[1][0]
bally=ball[1][1]
lastpos = ball[1][0], ball[1][1]
velocity=ball[2]
if -FRICTION_BALL <= velocity <= FRICTION_BALL :
velocity = 0
else:
velocity += FRICTION_BALL if velocity < 0 else -FRICTION_BALL
ball[2] = velocity
ball[1][0] += velocity
vectorx = sin(color / 255 * 2 * pi)
vectory = cos(color / 255 * 2 * pi)
if ballx+Ball_width<screen_width:
ballx=screen_width-Ball_width
if (bally+Ball_len)>screen_lenght:
bally=screen_lenght-Ball_len
#ball[1][1] -= 10
else:
if color == 255:
ball[1][1] += Gravity
else:
ball[1][0],ball[1][1]=lastpos
ball[1][0] += vectorx
ball[1][1] += vectory
def DrawBall(screen,ball,resources):
screen.blit(ball[0],(ball[1][0],ball[1][1]))
and here is my game engine code:
import pygame
import sys
from pygame.locals import *
from Constants import *
from ball import *
def Init():
pygame.init()
screen = pygame.display.set_mode((screen_width,screen_lenght))
pygame.display.set_caption('Supinball')
pygame.key.set_repeat(150,150)
pygame.mixer.init(44100, -16, 2, 1024)
return screen
def LoadResources():
resources= dict()
resources["MainLayer"] = pygame.image.load("resources/images/main_layer.png")
resources["Ball"] = pygame.image.load("resources/images/Ball.png")
resources["CollisionMain"] = pygame.image.load("resources/images/collision_main.png")
resources["CollisionSpec"] = pygame.image.load("resources/images/collision_special.png")
resources["Rflipper"] = pygame.image.load("resources/images/right_flipper.png")
resources["Lflipper"] = pygame.image.load("resources/images/left_flipper.png")
resources["Spring"] = pygame.image.load("resources/images/spring.png")
resources["Music"] = pygame.mixer.Sound("resources/sounds/music.ogg")
resources["Coin"] = pygame.mixer.Sound("resources/sounds/Coin.wav")
resources["Hit"] = pygame.mixer.Sound("resources/sounds/hit.wav")
resources["Tilted"] = pygame.mixer.Sound("resources/sounds/tilted.wav")
resources["GameOver"] = pygame.mixer.Sound("resources/sounds/GameOver.ogg")
resources["Font"] = pygame.font.Font('resources/Vdj.ttf', 30)
return resources
def GameLoop(screen,resources):
gameRunning = True
ball = [resources["Ball"],[300,20],0]
fpsClock = pygame.time.Clock()
while gameRunning:
ev = GetEvent(ball)
gameRunning = ev[GAME_RUNNING]
#resources["Music"].play(-1)
color=Getcolor(int(ball[1][0]), int(ball[1][1]), screen, resources)
print(color)
UpdateBall(ball,color)
#screen.blit(resources["MainLayer"], (0,0))
DrawBall(screen,ball,resources)
pygame.display.update()
fpsClock.tick(FPS)
def GetEvent(ball):
ev = [True,False,False,False,False,False,False,False,False,False]
for event in pygame.event.get():
if event.type == QUIT:
ev[GAME_RUNNING] = False
if event.type == MOUSEBUTTONUP:
mousepos = pygame.mouse.get_pos()
ball[1][0],ball[1][1]=mousepos
if event.type == KEYDOWN:
if event.key == K_DOWN:#compress spring
ev[KEY_DOWN] = True
if event.key == K_UP: #relax spring
ev[KEY_UP] = True
if event.key == K_LSHIFT: #left flipper
ev[KEY_LSHIFT] = True
if event.key == K_RSHIFT: #right flipper
ev[KEY_RSHIFT] = True
if event.type == KEYUP:
if event.key == K_q: #insert coin
ev[KEY_Q] = True
if event.key == K_SPACE: #launch ball
ev[KEY_SPACE] = True
if event.key == K_LEFT:#tilt left
ev[KEY_LEFT] = True
if event.key == K_RIGHT:#tilt right
ev[KEY_RIGHT] = True
if event.key == K_p:#pause
ev[KEY_P] = True
return ev
def DestroyGame():
pygame.quit()
and the constants code:
#screen
screen_lenght = 256
screen_width= 600
#fps
FPS=100
#events
GAME_RUNNING = 0
KEY_Q = 1
KEY_DOWN = 2
KEY_UP = 3
KEY_SPACE = 4
KEY_LSHIFT = 5
KEY_RSHIFT = 6
KEY_RIGHT = 7
KEY_LEFT = 8
KEY_P = 9
#ball physics
FRICTION_BALL=0.5
Gravity=1.9
Ball_width=11
Ball_len=9
But when I run it the ball is not colliding perfectly it's only colliding with the darkest spots and going through the light grey colors
If you look at this picture
the ball shouldn't be able to go through the bumpers but it does—I am sorry if my code is garbage, I am a beginner. :)
Here is a youtube link to a kinda working version of what I want to achieve: https://www.youtube.com/watch?v=SXegewcVx8A
Related
import pygame
import blocks
import random
class World:
def __init__(self):
self.tile_list = []
TILESIZE = 20
minStoneHeight = 1
maxStoneHeight = 8
x = 0
y = 0
height = 10
width = 100
for x in range(width):
minHeight = height - 1
maxHeight = height + 2
height = random.randrange(minHeight, maxHeight)
minStoneSpawnDistance = height - minStoneHeight
maxStoneSpawnDistance = height - maxStoneHeight
totalStoneSpawnDistance = random.randrange(minStoneHeight, maxStoneHeight)
for y in range(height):
if y < totalStoneSpawnDistance:
t = blocks.stoneBlock(x*20, y*20 + 100)
self.tile_list.append(t)
else:
t = blocks.dirtBlock(x*20, y*20 + 100)
self.tile_list.append(t)
if(totalStoneSpawnDistance == height):
t = blocks.stoneBlock(x*20, y*20 + 100)
self.tile_list.append(t)
else:
self.tile_list.append(t)
t = blocks.stoneBlock(x*20, y*20+100)
def draw(self, screen):
for tile in self.tile_list:
tile.draw(screen)
This is the code I use for procedural terrain generation in pygame. I adapted it from a script in C# for Unity. The issue is that pygames grid orgin is in the topleft and unitys is at bottom left. I was wondering how I would get my terrain to not be upside down?
It s a matter of Indentation. You maust move the player in the application loop rather than the event loop:
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
currentPlayerImg = playerImgBack
playerYSpeed = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
playerYSpeed = 0
#<--| INDENTATION
playerX += playerXSpeed
playerY += playerYSpeed
screen.blit(bgImg, (0, 0))
screen.blit(currentPlayerImg, (playerX, playerY))
pygame.display.update()
This question already has an answer here:
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
Closed 2 years ago.
I need help desperately. I have been trying to implement collision for my pygame code for hours now but nothing is working. I have researched a lot of methods but non of them are sticking to my mind or if there is a possible way to implement them.
Here is the code:
import pygame
import random
pygame.init()
#SCREEN
screeenWidth = 320
screenHeight = 600
screen = pygame.display.set_mode((screeenWidth, screenHeight))
screenBackground = pygame.image.load('assets/background.png')
screen.blit(screenBackground, (0,0))
pygame.display.set_caption("Evading Game")
#CLOCK
clock = pygame.time.Clock()
#PLAYER
playerX = 20 #which is lane 1
playerY = screenHeight * 0.8
playerImage = pygame.image.load('assets/car_img.png')
lane_dictionary = {1:20,2:85,3:160,4:240}
player_current_lane = 1
#OBSTACLE
obstacle_current_lane = random.randint(1,4)
obstacleX = lane_dictionary[obstacle_current_lane]
obstacleY = 0
obstacleImage = pygame.image.load('assets/obstacle_img.png')
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT: #Lane 1 = 20, lane 2 = 80, lane 3 = 160, lane 4 = 240
if not player_current_lane == 4:
player_current_lane += 1
e = lane_dictionary[player_current_lane]
playerX = e
if event.key == pygame.K_LEFT: #Lane 1 = 20, lane 2 = 80, lane 3 = 160, lane 4 = 240
if not player_current_lane == 1:
player_current_lane -= 1
e = lane_dictionary[player_current_lane]
playerX = e
obstacleY += 1 #Obstacle movement
screen.blit(screenBackground, (0,0)) #Blit background
screen.blit(playerImage, (playerX, playerY)) #blit player
screen.blit(obstacleImage, (obstacleX, obstacleY)) #Blit obstacle
pygame.display.update()
clock.tick(60) #fps
pygame.quit()
quit()
Create a pygame.Rect object with the size of playerImage and the location of the player (playerX, playerY).
Create a 2nd pygame.Rect, with the size of obstacleImage and the location of the obstacle (obstacleX, obstacleY).
Use colliderect to detect a collision between the 2 rectangles. e.g:
while running:
# [...]
playerRect = playerImage.get_rect(topleft = (playerX, playerY))
obstacleRect = obstacleImage.get_rect(topleft = (obstacleX, obstacleY))
if playerRect.colliderect(obstacleRect):
print("hit")
# [...]
This question already has answers here:
How do I detect collision in pygame?
(5 answers)
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
Closed 2 years ago.
I am trying to write a pygame program where the user dodges objects falling from the top of the screen. However, when I run, collideRect activates too early. Any suggestions?
import pygame
import sys
import time
import random
pygame.init()
size = width, height = 500, 500
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Avalanche!")
character = pygame.image.load("C:/Python27/Lib/site-packages/StickBasic.png")
boulder = pygame.image.load("C:/Python27/Lib/site-packages/Boulder1.png")
charRect = character.get_rect()
charRect.left = 246
charRect.bottom = 450
running = True
skyBlue = 0, 255, 255
groundBrown = 100, 0, 0
direction = 0
timer = 0
boulderFrequency = 20
boulders = []
def endgame():
global running
running = False
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
sys.exit()
def bg():
screen.fill(skyBlue)
pygame.draw.rect(screen, groundBrown, (0, 450, 500, 500))
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
if charRect.left > 0:
direction = -1
elif event.key == pygame.K_RIGHT:
if charRect.right < 500:
direction = 1
elif event.type == pygame.KEYUP:
direction = 0
if (direction < 0) and (charRect.left > 0):
charRect.left -= 1
if (direction > 0) and (charRect.right < 500):
charRect.left += 1
if timer >= boulderFrequency:
timer = 0
newBoulder = {
'rect': pygame.Rect(random.randint(0, 460), -40, 40, 40),
'surface': boulder}
boulders.append(newBoulder)
bg()
for b in boulders:
b['rect'].move_ip(0, 5)
if b['rect'].top > 500:
boulders.remove(b)
for b in boulders:
screen.blit(b['surface'], b['rect'])
screen.blit(character, charRect)
pygame.display.flip()
timer += 1
for b in boulders:
if charRect.colliderect(b['rect']):
endgame()
time.sleep(0.02)
PS: I know that the coding is not very clean, but I am relatively knew to coding.
I'm trying to create a little game as a training, but I'm blocked because I don't know how I can collide 2 moving cubes.
The game is simple, there is a red box that you can move and if this box touches a green cube, then you lost. (the green cubes are always moving)
I tried to read some documentations but it's not really easy to understand as a beginner.
Here is the code:
import pygame
import random
from threading import Timer
pygame.init()
screenWidth = 1100
screenHeight = 600
white = (255,255,255)
red = (255, 0, 0)
yellow = (50, 250, 20)
FPS = 60
gameDisplay = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption('Tekken')
pygame.display.update()
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 28)
class Players:
def __init__(self, playerName, playerAttribute, cubeheight, cubewidth, missilesHeight, missilesWidth):
self.playerName = playerName
self.playerAttribute = playerAttribute
self.playerLife = 100
self.droite_x = 300
self.droite_y = 600
self.cubeheight = cubeheight
self.cubewidth = cubewidth
self.missiles = True
self.missilesHeight = missilesHeight
self.missilesWidth = missilesWidth
self.missiles_droite_x = 0
self.missiles_droite_y = round(random.randrange(50, screenHeight-50))
self.missiles_droite_x_inverse = screenWidth-50
self.missiles_droite_y_inverse = round(random.randrange(50, screenHeight-50))
self.vitesse_missiles = 10
print(self.playerName, self.playerAttribute, self.playerLife)
def environment_un(self):
gameExit = False
gameOver = False
droite_x_change = 0
droite_y_change = 0
missiles_droite_x_change = 0
missiles_droite_x_change_inverse = 0
while not gameExit:
while gameOver:
gameDisplay.fill(red)
screen_text = font.render("Game Over, do you want to play again? [Q] to quit", True, white)
gameDisplay.blit(screen_text, [100, 300])
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameOver = False
gameExit = True
break
if event.type == pygame.QUIT:
gameOver = False
gameExit = True
break
for event in pygame.event.get(): #va chercher les events
if event.type == pygame.QUIT: #Si j'appuie sur X
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
droite_x_change = -3
if event.key == pygame.K_RIGHT:
droite_x_change = +3
if event.key == pygame.K_UP:
droite_y_change = -3
if event.key == pygame.K_DOWN:
droite_y_change = +3
if event.key == pygame.K_SPACE:
missiles_droite_x_change = self.vitesse_missiles
missiles_droite_x_change_inverse = -self.vitesse_missiles
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
droite_x_change = 0
if event.key == pygame.K_RIGHT:
droite_x_change = 0
if event.key == pygame.K_UP:
droite_y_change = 0
if event.key == pygame.K_DOWN:
droite_y_change = 0
self.missiles_droite_x_inverse += missiles_droite_x_change_inverse
self.missiles_droite_x += missiles_droite_x_change
self.droite_x += droite_x_change
self.droite_y += droite_y_change
if self.droite_y + self.cubeheight <= 0:
self.droite_y = 0
elif self.droite_y + self.cubeheight >= screenHeight:
self.droite_y = screenHeight-self.cubeheight
elif self.droite_x + self.cubewidth <= 0:
self.droite_x = 0
elif self.droite_x + self.cubewidth >= screenWidth:
self.droite_x = screenWidth-self.cubewidth
gameDisplay.fill(white)
gameDisplay.fill(red, rect=[self.droite_x, self.droite_y, self.cubewidth, self.cubeheight])
gameDisplay.fill(yellow, rect=[self.missiles_droite_x, self.missiles_droite_y, self.missilesWidth, self.missilesHeight])
gameDisplay.fill(yellow, rect=[self.missiles_droite_x_inverse, self.missiles_droite_y_inverse, self.missilesWidth, self.missilesHeight])
pygame.display.update()
if self.missiles_droite_x + self.missilesWidth >= screenWidth:
missiles_droite_x_change = 0
if missiles_droite_x_change == 0:
self.missiles_droite_x = 0
self.missiles_droite_y = round(random.randrange(50, screenHeight-50))
missiles_droite_x_change = self.vitesse_missiles
if self.missiles_droite_x_inverse <= 0:
missiles_droite_x_change_inverse = 0
if missiles_droite_x_change >= 0:
self.missiles_droite_x_inverse = screenWidth-50
self.missiles_droite_y_inverse = round(random.randrange(50, screenHeight-50))
missiles_droite_x_change_inverse = -12
clock.tick(FPS)
pygame.quit()
Player_1 = Players('John', 'sometext', 50, 50, 100, 100)
Player_1.environment_un()
What should do I in order to detect the collision?
I can not run your code at the moment as I dont have pygame installed. However, you can use the pygame.sprite.collide_rect() if you declare your objects to have in their class an pygame.sprite.Sprite-object or inherit from that class (as suggested below). The code below may note work as I can not test it but it should be close to a functioning code snippet. In the case you would like to test collision of a sprite against multiple other sprites - consider looking at pygame.sprite.Group(). I believe that something like this should work:
class SpriteObject(pygame.sprite.Sprite):
def __init__(self,pos_x, pos_y):
pygame.sprite.Sprite.__init__(self)
self.rect = self.original.get_rect()
self.rect.center = (pos_x, pos_y)
class Players:
def __init__(self, playerName, playerAttribute, cubeheight, cubewidth, missilesHeight, missilesWidth):
sprite1 = SpriteObject(1,2)
sprite2 = SpriteObject(1,2)
sprite1.rect.collide_rect(sprite2)
If you are looking for a conceptual answer:
Since you are considering just cubes and if they are of the same size, two cubes will occupy the same space 'if and only if' a corner of one cube is between (inclusive) two parallel planes of another. There are many ways to do this in practice.
I would check if between by evaluating an inward normal vector of cube 1 dotted with a vector to a corner (of cube 2) from any corner (of cube 1) . Do so for both parallel sides. If both are positive, its inside.
It's slightly more complicated for different shapes and varying sizes.
Use pygame.Rect() to keep cube position and size - and then you can use pygame.Rect.colliderect() to check collision between two cubes.
cube1 = pygame.Rect((x1, y1), (width, height))
cube2 = pygame.Rect((x2, y2), (width, height))
if cube1.colliderect(cube2):
print("Collision !")
PyGame has other usefull classes - pygame.sprite.Sprite and pygame.sprite.Group - which use Rect and collision detection functions.
This question already has answers here:
Why is nothing drawn in PyGame at all?
(2 answers)
Why is my PyGame application not running at all?
(2 answers)
Closed 2 years ago.
I'm making an side scroller arcade game in python where you control a rocket
and have to avoid the asteroids coming from right to left. My problem is that my asteroids do not appear on the screen. Help is very much appreciated.
import pygame as pg
import numpy as np
from pygame.locals import *
from random import *
#Make a first "game" which is actually the menu
res = (1000,800)
screen = pg.display.set_mode(res)
pg.display.set_caption('Rocket game')
black = (0,0,0)
white = (255,255,255)
backgroundmenu = pg.image.load("menuscreen.jpg")
pg.init()
running1 = True
while running1:
pg.event.pump()
keys = pg.key.get_pressed()
if keys[pg.K_1]:
running1 = False
running2 = True
elif keys[pg.K_2]:
running1 = False
running2 = False
for event in pg.event.get():
if event.type == pg.QUIT:
running1 = False
screen.blit(backgroundmenu,(0,0))
pg.display.flip()
pg.quit()
pg.init()
#Setup screen and define colors
res = (1000,800)
screen = pg.display.set_mode(res)
pg.display.set_caption('Rocket game')
#pg.image.load("space.jpg")
black = (0,0,0)
white = (255,255,255)
background1 = pg.image.load("space.jpg").convert()
background2 = pg.image.load("space.jpg").convert()
background3 = pg.image.load("space.jpg").convert()
#screen.blit(background1,(0,0))
x_back = 0
screenwidth = 1000
#Initialize variables and clock
vx = 0
vy = 0
x = 200
y = 600
t0 = 0.001*pg.time.get_ticks()
maxdt = 0.5
#Load rocket and asteroids
rocketgif = pg.image.load("rocket.gif")
rocketimg = pg.transform.scale(rocketgif, (100,100))
asteroidgif = pg.image.load("Asteroid.gif")
asteroidimg = pg.transform.scale(asteroidgif, (75,75))
#Load music
pg.mixer.music.load('gamesound.mp3')
pg.mixer.music.set_endevent(pg.constants.USEREVENT)
pg.mixer.music.play()
#clock = pg.time.Clock()
#Generate random asteroids
Nasteroid = 5
x_ast = 999
dx = 5
i = 0
asteroidpos_y= []
while i<Nasteroid:
y = randint(0,800)
asteroidpos_y.append(y)
i = i + 1
#Start game loop
running2 = True
while running2:
t = 0.001*pg.time.get_ticks()
dt = min(t-t0,maxdt)
i = 0
pg.event.pump()
while i<Nasteroid:
x_ast -= dx
y = y
screen.blit(asteroidimg,(x_ast,asteroidpos_y[i-1]))
i = i + 1
for event in pg.event.get():
if event.type == pg.QUIT: #Quit using red cross button
running2 = False
elif event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE:
running2 = False #Quit using key combination
elif event.type == pg.KEYDOWN: #Make user control rocket movement
#and stop if key is released.
if event.key == pg.K_LEFT:
vx = -8
elif event.key == pg.K_RIGHT:
vx = 8
elif event.key == pg.K_UP:
vy = -8
elif event.key == pg.K_DOWN:
vy = 8
elif event.type == pg.KEYUP:
if event.key == pg.K_LEFT:
vx = 0
elif event.key == pg.K_RIGHT:
vx = 0
elif event.key == pg.K_UP:
vy = 0
elif event.key == pg.K_DOWN:
vy = 0
elif event.type == pg.constants.USEREVENT:
pg.mixer.music.load("gamesound.mp3")
pg.mixer.music.play()
#Make the screen scroll behind the rocket to make it "move" (3x the same background behind eachother)
screen.blit(background1,(x_back,0))
screen.blit(background2,(x_back - screenwidth,0))
screen.blit(background3,(x_back - (2*screenwidth),0))
x_back = x_back - 1
if x_back == screenwidth:
x_back = 0
#Update the position of the rocket. If the rocket hits the edges the game stops.
x = x + vx
y = y + vy
"""if x <= 0 or x >=100:
running2 = False
if y <= 0 or y >=800:
running2 = False"""
pg.event.pump()
screen.blit(rocketimg,(x,y))
pg.display.flip()
pg.quit()