Apologies for asking so many questions recently. I'm just starting to get into pygame.
With my previous questions I don't think I've been wording it properly for what I am trying to do.
Here is a quick picture I did to try demonstrate
This is a single background image or map that I would like the player to move across. The red X is just a starting place for the character.
I'm try to make it so when I move the player the background will also follow as if the player is moving through the map. I've already limited the player from not being able to go off the borders of the actual screen. Just having a bit of trouble now trying to make it so the single image will move along the player and if the player reaches the end of the map picture movement stops. I have seen people use scrolling and duplicating the image when the player moves. I just want to see it to the single image that the player will move across. I don't want to worry about collisions just be able to get the movement working.
This is the code I am currently using:
from pygame.locals import *
from math import sin
pygame.display.set_caption("TEST")
clock = pygame.time.Clock()
time_passed = 0
class Player():
def __init__(self,x,y):
self.Image = pygame.image.load("myAvatar.png").convert()
self.x = 200
self.y = 200
def getX(self):
return self.rect.x
def getY(self):
return self.rect.y
def handle_keys(self,screenHeight,screenWidth):
key = pygame.key.get_pressed()
dist = 2
if key[K_LEFT] and self.x > 0:
self.x -= 500 * time_passed
if key[K_RIGHT] and self.x < screenWidth -20:
self.x += 500 * time_passed
if key[K_UP] and self.y > 0:
self.y -= 500 * time_passed
if key[K_DOWN] and self.y < screenHeight -20:
self.y += 500 * time_passed
def draw(self, game_window):
self.Image = pygame.transform.scale(self.Image,(20,20))
game_window.blit(self.Image, (int(self.x), int(self.y)))
class Map():
def __init__(self):
self.Image = pygame.image.load("test2.png").convert()
self.rect = self.Image.get_rect()
self.x = 0
self.y = 0
def draw(self, game_window,screenHeight,screenWidth):
self.x = min(max(self.x, player.x - 2 * screenWidth / 2), player.x - screenWidth / 2)
self.y = min(max(self.y, player.y -2 * screenHeight / 2), player.y - screenHeight / 2)
game_window.blit(self.Image,(-self.x,-self.y))
class Enemy():
def __init__ (self,x,y):
self.Image = pygame.image.load("WC.jpg").convert()
self.rect = self.Image.get_rect(topleft = (x,y))
def draw(self, game_window):
self.Image = pygame.transform.scale(self.Image,(20,20))
game_window.blit(self.Image, (self.rect.x, self.rect.y))
pygame.init()
clock = pygame.time.Clock()
screenWidth = 400
screenHeight = 400
game_window = pygame.display.set_mode((screenWidth,screenHeight))
player = Player(200,200)
map = Map()
enemy = Enemy(250,250)
leave = False
while not leave:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
player.handle_keys(screenHeight,screenWidth)
game_window.fill((0,0,0))
map.draw(game_window,screenHeight,screenWidth)
#enemy.draw(game_window)
player.draw(game_window)
pygame.display.update()
pygame.display.flip()
time_passed = clock.tick() / 1000
pygame.quit()
quit()
Thanks
Shay
The player's movement depends on the size of the map. The x and y attributes of the "player" store the position on the map and are limited to the size of the map (map_size). The player is always drawn in the center of the screen, except it is near the boarders of the map:
class Player():
def __init__(self, x, y):
self.Image = pygame.image.load("myAvatar.png").convert()
self.x = 200
self.y = 200
def handle_keys(self, map_size):
key = pygame.key.get_pressed()
self.x += (key[K_RIGHT] - key[K_LEFT]) * 500 * time_passed
self.y += (key[K_DOWN] - key[K_UP]) * 500 * time_passed
self.x = max(0, min(map_size[0]-20, self.x))
self.y = max(0, min(map_size[1]-20, self.y))
def draw(self, game_window, map_size):
window_size = game_window.get_size()
center = window_size[0] // 2, window_size[0] // 2
pos = [self.x, self.y]
for i in range(2):
if center[i] < pos[i] <= map_size[i]-center[i]:
pos[i] = center[i]
elif pos[i] > map_size[i] - center[i]:
pos[i] = window_size[i] - map_size[i] + pos[i]
game_window.blit(self.Image, (int(pos[0]), int(pos[1])))
The player's position on the map is centered in the window:
class Map():
def __init__(self):
self.Image = pygame.image.load("test2.png").convert()
def draw(self, game_window):
window_size = game_window.get_size()
map_size = self.Image.get_size()
x = max(0, min(map_size[0] - window_size[0], player.x - 200))
y = max(0, min(map_size[1] - window_size[1], player.y - 200))
game_window.blit(self.Image, (-x, -y))
Application loop:
leave = False
while not leave:
for event in pygame.event.get():
if event.type == pygame.QUIT:
leave = True
player.handle_keys(map.Image.get_size())
game_window.fill((0,0,0))
map.draw(game_window)
#enemy.draw(game_window)
player.draw(game_window, map.Image.get_size())
pygame.display.update()
pygame.display.flip()
time_passed = clock.tick() / 1000
pygame.quit()
Related
Apologies for asking so many questions recently. I'm just starting to get into pygame.
With my previous questions I don't think I've been wording it properly for what I am trying to do.
Here is a quick picture I did to try demonstrate
This is a single background image or map that I would like the player to move across. The red X is just a starting place for the character.
I'm try to make it so when I move the player the background will also follow as if the player is moving through the map. I've already limited the player from not being able to go off the borders of the actual screen. Just having a bit of trouble now trying to make it so the single image will move along the player and if the player reaches the end of the map picture movement stops. I have seen people use scrolling and duplicating the image when the player moves. I just want to see it to the single image that the player will move across. I don't want to worry about collisions just be able to get the movement working.
This is the code I am currently using:
from pygame.locals import *
from math import sin
pygame.display.set_caption("TEST")
clock = pygame.time.Clock()
time_passed = 0
class Player():
def __init__(self,x,y):
self.Image = pygame.image.load("myAvatar.png").convert()
self.x = 200
self.y = 200
def getX(self):
return self.rect.x
def getY(self):
return self.rect.y
def handle_keys(self,screenHeight,screenWidth):
key = pygame.key.get_pressed()
dist = 2
if key[K_LEFT] and self.x > 0:
self.x -= 500 * time_passed
if key[K_RIGHT] and self.x < screenWidth -20:
self.x += 500 * time_passed
if key[K_UP] and self.y > 0:
self.y -= 500 * time_passed
if key[K_DOWN] and self.y < screenHeight -20:
self.y += 500 * time_passed
def draw(self, game_window):
self.Image = pygame.transform.scale(self.Image,(20,20))
game_window.blit(self.Image, (int(self.x), int(self.y)))
class Map():
def __init__(self):
self.Image = pygame.image.load("test2.png").convert()
self.rect = self.Image.get_rect()
self.x = 0
self.y = 0
def draw(self, game_window,screenHeight,screenWidth):
self.x = min(max(self.x, player.x - 2 * screenWidth / 2), player.x - screenWidth / 2)
self.y = min(max(self.y, player.y -2 * screenHeight / 2), player.y - screenHeight / 2)
game_window.blit(self.Image,(-self.x,-self.y))
class Enemy():
def __init__ (self,x,y):
self.Image = pygame.image.load("WC.jpg").convert()
self.rect = self.Image.get_rect(topleft = (x,y))
def draw(self, game_window):
self.Image = pygame.transform.scale(self.Image,(20,20))
game_window.blit(self.Image, (self.rect.x, self.rect.y))
pygame.init()
clock = pygame.time.Clock()
screenWidth = 400
screenHeight = 400
game_window = pygame.display.set_mode((screenWidth,screenHeight))
player = Player(200,200)
map = Map()
enemy = Enemy(250,250)
leave = False
while not leave:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
player.handle_keys(screenHeight,screenWidth)
game_window.fill((0,0,0))
map.draw(game_window,screenHeight,screenWidth)
#enemy.draw(game_window)
player.draw(game_window)
pygame.display.update()
pygame.display.flip()
time_passed = clock.tick() / 1000
pygame.quit()
quit()
Thanks
Shay
The player's movement depends on the size of the map. The x and y attributes of the "player" store the position on the map and are limited to the size of the map (map_size). The player is always drawn in the center of the screen, except it is near the boarders of the map:
class Player():
def __init__(self, x, y):
self.Image = pygame.image.load("myAvatar.png").convert()
self.x = 200
self.y = 200
def handle_keys(self, map_size):
key = pygame.key.get_pressed()
self.x += (key[K_RIGHT] - key[K_LEFT]) * 500 * time_passed
self.y += (key[K_DOWN] - key[K_UP]) * 500 * time_passed
self.x = max(0, min(map_size[0]-20, self.x))
self.y = max(0, min(map_size[1]-20, self.y))
def draw(self, game_window, map_size):
window_size = game_window.get_size()
center = window_size[0] // 2, window_size[0] // 2
pos = [self.x, self.y]
for i in range(2):
if center[i] < pos[i] <= map_size[i]-center[i]:
pos[i] = center[i]
elif pos[i] > map_size[i] - center[i]:
pos[i] = window_size[i] - map_size[i] + pos[i]
game_window.blit(self.Image, (int(pos[0]), int(pos[1])))
The player's position on the map is centered in the window:
class Map():
def __init__(self):
self.Image = pygame.image.load("test2.png").convert()
def draw(self, game_window):
window_size = game_window.get_size()
map_size = self.Image.get_size()
x = max(0, min(map_size[0] - window_size[0], player.x - 200))
y = max(0, min(map_size[1] - window_size[1], player.y - 200))
game_window.blit(self.Image, (-x, -y))
Application loop:
leave = False
while not leave:
for event in pygame.event.get():
if event.type == pygame.QUIT:
leave = True
player.handle_keys(map.Image.get_size())
game_window.fill((0,0,0))
map.draw(game_window)
#enemy.draw(game_window)
player.draw(game_window, map.Image.get_size())
pygame.display.update()
pygame.display.flip()
time_passed = clock.tick() / 1000
pygame.quit()
This question already has an answer here:
How to scroll the background surface in PyGame?
(1 answer)
Closed 1 year ago.
I am having a bit of trouble being able to align the map picture on the pygame window. I want to have it so the map picture will always fill the whole screen. I have already made it so that the map picture moves when the player moves but it is unable to show the whole map.
(These are not the images i will use in my actual game just using them to test)
Here is what happens if you move to the maximum up and left
When the character moves to the maximum down and right. Some of the image is still cut off
Here is my code that i am using:
import pygame
from pygame.locals import *
from math import sin
pygame.display.set_caption("TEST")
clock = pygame.time.Clock()
time_passed = 0
class Player():
def __init__(self,x,y):
self.Image = pygame.image.load("myAvatar.png").convert()
self.x = 200
self.y = 200
def getX(self):
return self.rect.x
def getY(self):
return self.rect.y
def handle_keys(self,screenHeight,screenWidth):
key = pygame.key.get_pressed()
dist = 2
if key[K_LEFT] and self.x > 0:
self.x -= 500 * time_passed
if key[K_RIGHT] and self.x < screenWidth -20:
self.x += 500 * time_passed
if key[K_UP] and self.y > 0:
self.y -= 500 * time_passed
if key[K_DOWN] and self.y < screenHeight -20:
self.y += 500 * time_passed
def draw(self, game_window):
self.Image = pygame.transform.scale(self.Image,(20,20))
game_window.blit(self.Image, (int(self.x), int(self.y)))
class Map():
def __init__(self):
self.Image = pygame.image.load("testbackground.jpg").convert()
self.rect = self.Image.get_rect()
self.x = 0
self.y = 0
def draw(self, game_window,screenHeight,screenWidth):
self.Image = pygame.transform.scale(self.Image,(800,800))
self.x = min(max(self.x, player.x - 2 * screenWidth / 3), player.x - screenWidth / 3)
self.y = min(max(self.y, player.y -2 * screenHeight / 3), player.y - screenHeight / 3)
game_window.blit(self.Image,(-self.x,-self.y))
class Enemy():
def __init__ (self,x,y):
self.Image = pygame.image.load("WC.jpg").convert()
self.rect = self.Image.get_rect(topleft = (x,y))
def draw(self, game_window):
self.Image = pygame.transform.scale(self.Image,(20,20))
game_window.blit(self.Image, (self.rect.x, self.rect.y))
pygame.init()
clock = pygame.time.Clock()
screenWidth = 400
screenHeight = 400
game_window = pygame.display.set_mode((screenWidth,screenHeight))
player = Player(200,200)
map = Map()
enemy = Enemy(250,250)
leave = False
while not leave:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
player.handle_keys(screenHeight,screenWidth)
game_window.fill((0,0,0))
map.draw(game_window,screenHeight,screenWidth)
#enemy.draw(game_window)
player.draw(game_window)
pygame.display.update()
pygame.display.flip()
time_passed = clock.tick() / 1000
pygame.quit()
quit()
You need to blit the background multiple times. See How to scroll the background surface in PyGame?.
If the background is moved along the x and y axes, 4 background "tiles2 must be put on the screen:
class Map():
def __init__(self):
self.Image = pygame.image.load("testbackground.jpg").convert()
self.Image = pygame.transform.scale(self.Image, game_window.get_size())
self.rect = self.Image.get_rect()
self.x = 0
self.y = 0
def draw(self, game_window,screenHeight,screenWidth):
self.x = player.x - screenWidth // 2
self.y = player.y - screenHeight // 2
x1 = self.x % self.Image.get_width()
x2 = x1 - self.Image.get_width()
y1 = self.y % self.Image.get_height()
y2 = y1 - self.Image.get_height()
game_window.blit(self.Image, (x1, y1))
game_window.blit(self.Image, (x2, y1))
game_window.blit(self.Image, (x1, y2))
game_window.blit(self.Image, (x2, y2))
I would like to create a game in python but I need a thought provoking impulse, how I can draw a point, which draws a line behind him/a trail, so far, so good, I have no idea how to make my point not just moving in the 4 directions, I want him to move forward on his own and the user should steer left and right.
Missing is:
• The trail of my point (later I have to check, if another sprite touches it)
• The "curvy" moving
My current code:
import pygame
import os
pygame.init()
width, height = 970, 970
screen = pygame.display.set_mode((width, height))
h_center = ((height / 2) - 4)
w_center = ((width / 2) - 4)
class Point(pygame.sprite.Sprite):
def __init__(self):
self.image = pygame.image.load(os.path.join("assets", "point.png"))
self.x = (width / 2)
self.y = (height / 2)
self.speed = 5
self.direction = 3 # 1:north ; 2:east ; 3:south ; 4:west
def handle_keys(self):
key = pygame.key.get_pressed()
dist = 1
if key[pygame.K_DOWN]:
self.direction = 3
elif key[pygame.K_UP]:
self.direction = 1
if key[pygame.K_RIGHT]:
self.direction = 2
elif key[pygame.K_LEFT]:
self.direction = 4
def move(self):
if self.direction == 1:
self.y -= self.speed
if self.direction == 2:
self.x += self.speed
if self.direction == 3:
self.y += self.speed
if self.direction == 4:
self.x -= self.speed
def draw(self, surface):
surface.blit(self.image, (self.x, self.y))
def main():
point = Point()
clock = pygame.time.Clock()
background = pygame.image.load('backgroundborder.png').convert()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
point.handle_keys()
point.move()
screen.fill((0, 0, 0))
screen.blit(background, (0, 0))
point.draw(screen)
pygame.display.update()
clock.tick(40)
if __name__ == '__main__':
main()
Please assist
Two things:
Use a list to store the trail. It's just a list of previous positions.
Use the arrow keys to adjust speed, not direction
I also added a few lines of code so the dot stays on the screen. The dot.png is just a black dot 20x20 pixels.
Here's the updated code:
import pygame
import os
pygame.init()
width, height = 970, 970
screen = pygame.display.set_mode((width, height))
h_center = ((height/2) - 4)
w_center = ((width/2) - 4)
trail=[None]*50 # trail has 50 dots
trailimage = pygame.image.load('dot.png')
class Point(pygame.sprite.Sprite):
def __init__(self):
self.image = pygame.image.load('dot.png')
self.x = (width/2)
self.y = (height/2)
self.speed = {'x':0, 'y':0}
self.direction = 3 # 1north ; 2east ; 3south ; 4west
def handle_keys(self):
key = pygame.key.get_pressed()
dist = 1
if key[pygame.K_DOWN]:
self.speed['y']+=0.25
elif key[pygame.K_UP]:
self.speed['y']-=0.25
if key[pygame.K_RIGHT]:
self.speed['x']+=0.25
elif key[pygame.K_LEFT]:
self.speed['x']-=0.25
def move(self):
self.y += self.speed['y']
self.x += self.speed['x']
# wrap to other side of screen
if self.x > width: self.x = (self.x - width)
elif self.x < 0: self.x = (width + self.x)
if self.y > height: self.y = (self.y - height)
elif self.y < 0: self.y = (height + self.y)
def draw(self, surface):
surface.blit(self.image, (self.x, self.y))
def main():
point = Point()
clock = pygame.time.Clock()
#background = pygame.image.load('backgroundborder.png').convert()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
point.handle_keys()
point.move()
screen.fill((200, 200, 200))
#screen.blit(background, (0, 0))
for d in trail:
if d: screen.blit(trailimage, d)
del trail[0] # remove last point in trail
trail.append((point.x,point.y)) # append this position
point.draw(screen)
pygame.display.update()
clock.tick(40)
if __name__ == '__main__':
main()
To make the controls more like CurveFever, I updated the code so the left \ right keys adjust the travel direction (in degrees). The speed is constant.
Here is the updated code:
import pygame
import os
import math
pygame.init()
width, height = 970, 970
screen = pygame.display.set_mode((width, height))
h_center = ((height/2) - 4)
w_center = ((width/2) - 4)
trail=[None]*50 # trail has 50 dots
trailimage = pygame.image.load('dot.png')
speed = 8 # constant
class Point(pygame.sprite.Sprite):
def __init__(self):
self.image = pygame.image.load('dot.png')
self.x = (width/2)
self.y = (height/2)
self.speed = {'x':0, 'y':0}
self.deg = -90 # up, direction in degrees
def handle_keys(self):
key = pygame.key.get_pressed()
dist = 1
if key[pygame.K_RIGHT]:
self.deg+=2
elif key[pygame.K_LEFT]:
self.deg-=2
self.speed['x'] = speed*math.cos(math.radians(self.deg))
self.speed['y'] = speed*math.sin(math.radians(self.deg))
def move(self):
self.y += self.speed['y']
self.x += self.speed['x']
# wrap to other side of screen
if self.x > width: self.x = (self.x - width)
elif self.x < 0: self.x = (width + self.x)
if self.y > height: self.y = (self.y - height)
elif self.y < 0: self.y = (height + self.y)
def draw(self, surface):
surface.blit(self.image, (self.x, self.y))
TrailTrim = False # set True for constant trail length
def main():
point = Point()
clock = pygame.time.Clock()
#background = pygame.image.load('backgroundborder.png').convert()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
point.handle_keys()
point.move()
screen.fill((200, 200, 200)) # clear screen
#screen.blit(background, (0, 0))
for d in trail:
if d: screen.blit(trailimage, d)
if (TrailTrim): del trail[0] # delete trail end
trail.append((point.x,point.y)) # add current postiion
point.draw(screen) # draw current point
pygame.display.update()
clock.tick(40) # 40 FPS
if __name__ == '__main__':
main()
I have a huge assignment due in class and Im lost like , asking god to spare me lost. Im making a brick game and the most basic function of getting the ball to bounce of the walls I cant figure out , my teacher is too busy and classmates are competitive , I dont want you to write the code for me, I just dont know how to code it. I keep getting errors and its just been hell the last couple of classes.
import math
import pygame
import random
pygame.init()
screen = pygame.display.set_mode([800,600])
done = False
clock = pygame.time.Clock()
#DEFINE COLORS
WHITE = (255,255,255)
BLUE=(0,102,204)
LIGHT_BLUE=(0,0,204)
pink=(238,130,238)
#import images
#lives = pygame.image.load("heart.png")
# initialize font; must be called after 'pygame.init()' to avoid 'Font not Initialized' error
myfont = pygame.font.SysFont("monospace", 15)
#var carying the space of the game
top = -100
left= -50
right= -750
bottom= -600
angle = math.radians(random.randint(-140,-30))
class game_screen():
def draw_screen():
pygame.draw.rect(screen,BLUE,(50,100,700,600))
def save_button():
pygame.draw.rect(screen,pink,(500,20,50,30),0)
save = "Save"
label = myfont.render(save, 40, (0,0,0))
screen.blit(label, (505, 20))
def quit_button():
pygame.draw.rect(screen,pink,(600,20,50,30),0)
quit1 = "Quit"
label = myfont.render(quit1, 40, (0,0,0))
screen.blit(label, (605, 20))
mX, mY = pygame.mouse.get_pos()
mouseButtons = pygame.mouse.get_pressed()
if mouseButtons[0] == True:
if (mX in range (600-20,600+20) and mY in range (20-20,20+20)):
pygame.quit()
#def display_lives():
#lives_counter = screen.blit(lives,(50,30))
#lives_counter2 = screen.blit(lives,(120,30))
#lives_counter3 = screen.blit(lives,(190,30))
class PADDLE:
def __init__(self,xpos,ypos):
self.x = xpos
self.y = ypos
def draw(self): # draws paddle
pygame.draw.rect(screen,pink,(self.x,self.y,70,20))
def move(self):
keys = pygame.key.get_pressed() #checking pressed keys
if keys[pygame.K_LEFT]:
if self.x<=50:
self.x=50
else:
self.x -= 10
elif keys[pygame.K_RIGHT]:
if self.x >=680:
self.x = 680
else:
self.x += 10
class BALL:
def __init__(self,paddle1):
self.x = (paddle1.x+35)
self.y = (paddle1.y-5)
self.speed = 0
self.speedX = 0
self.speedY = 0
self.direction = 200
def draw(self):
pygame.draw.circle(screen,WHITE,(self.x,self.y),10)
def bounce(self):
self.direction = (180 - self.direction) % 360
def move_ball(self):
keys = pygame.key.get_pressed() #checking pressed keys
ball_on_paddle = True
if ball_on_paddle == True :
self.x = (paddle1.x+35)
self.y = (paddle1.y-5)
self.speed = 0
if keys[pygame.K_UP] == True:
ball_on_paddle = False
print("a")
self.speed = 10
self.speedX += int(math.cos(angle)* self.speed)
self.speedY += int(math.sin(angle)* self.speed)
print(bottom)
print(self.speedY)
if self.y <= 0:
self.bounce(0)
self.y = 1
if self.x <= 0:
self.direction = (360 - self.direction) % 360
self.x = 1
if self.x > self.screenwidth - self.width:
self.direction = (360 - self.direction) % 360
self.x = self.screenwidth - self.width - 1
paddle1 = PADDLE(350,550)
ball1 = BALL(paddle1)
# MAIN LOOP
while not done:
screen.fill((LIGHT_BLUE))
game_screen.draw_screen()
game_screen.save_button()
game_screen.quit_button()
paddle1.draw()
paddle1.move()
ball1.draw()
ball1.move_ball()
ball1.bounce()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.display.flip()
clock.tick(60)
pygame.quit()
The collission between ball and wall can be detected by comparing the ball's coordinates with the coordinates of the walls. Reflecting the ball means a multiplication of either speedX or speedY - depending on the wall - with -1.
The easiest way to do this is to make a function bounce(self) in your class BALL.
First, you decide which border you touch.
Then, you change the angle of the ball according to which border you bounce on. If you work in a 360-degree system, the angle is mirrored:
around a vertical axis when the ball bounces of the bottom and the top border. So angle = 180 - angle.
around a horizontal axis when the ball bounces of the side borders. So angle = - angle .
And lastly, you have to move the ball back what it has travelled too much.
Like you can see, the ball travels in 1 iteration from C1 to C3', while we want it to go to C3. We can achieve this by reflecting it around the axis BOUNDARY_X - ball_size.
The new x-coordinate of the ball becomes then x = BOUNDARY_X - ball_size - (x - BOUNDARY_X + ball_size) = 2*(BOUNDARY_X - ball_size) - x .
When we cast that into code, we get:
class BALL:
def bounce(self):
if self.x < ball_size:
self.angle = math.pi - self.angle
self.x = 2*ball_size - self.x
elif self.x > DISPLAY_WIDTH - ball_size:
self.angle = math.pi - self.angle
self.x = 2*(DISPLAY_WIDTH - ball_size) - self.x
if self.y < ball_size:
self.angle = - self.angle
self.y = 2*ball_size - self.y
elif self.y > DISPLAY_HEIGHT - ball_size:
self.angle = - self.angle
self.y = 2*(DISPLAY_HEIGHT - ball_size) - self.y
I am new to python and am trying to write a game that launches a character and when he interacts with a sprite on the ground, something will change, for example speed. My apologies for the disorganization in my code. I have taken samples from a few tutorials and I can't make them work together.
How do I make the player's collision with the bomb detectable?
import pygame
import random
import math
drag = 1
gravity = (math.pi, .4)
elasticity = .75
# Colors
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
BLUE = ( 0, 0, 255)
RED = ( 255, 0, 0)
GREEN = ( 0, 255, 0)
# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
def addVectors((angle1, length1), (angle2, length2)):
x = math.sin(angle1) * length1 + math.sin(angle2) * length2
y = math.cos(angle1) * length1 + math.cos(angle2) * length2
angle = 0.5 * math.pi - math.atan2(y, x)
length = math.hypot(x, y)
return (angle, length)
class Player(pygame.sprite.Sprite):
change_x = 0
change_y = 0
level = None
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('player.png')
image_rect = self.image.get_rect()
self.rect = pygame.rect.Rect(x, y, image_rect.width, image_rect.height)
def update(self):
pass
def move(self):
(self.angle, self.speed) = addVectors((self.angle, self.speed), gravity)
self.rect.x += math.sin(self.angle) * self.speed
self.rect.y -= math.cos(self.angle) * self.speed
self.speed *= drag
def bounce(self):
if self.rect.x > 800 - self.rect.width:
self.rect.x = 2*(800 - self.rect.width) - self.rect.x
self.angle = - self.angle
self.speed *= elasticity
elif self.rect.x < 0:
self.rect.x = 2*self.rect.width - self.rect.x
self.angle = - self.angle
self.speed *= elasticity
if self.rect.y > SCREEN_HEIGHT - self.rect.height:
self.rect.y = 2*(SCREEN_HEIGHT - self.rect.height) - self.rect.y
self.angle = math.pi - self.angle
self.speed *= elasticity
class Bomb(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('cherry.png')
image_rect = self.image.get_rect()
self.rect = pygame.rect.Rect(x, y, image_rect.width, image_rect.height)
class Level():
bomb_list = None
world_shift = 0
def __init__(self, player):
self.bomb_list = pygame.sprite.Group()
self.player = player
def update(self):
self.bomb_list.update()
def draw(self, screen):
screen.fill(BLACK)
self.bomb_list.draw(screen)
def shift_world(self, shift_x):
self.world_shift += shift_x
for bomb in self.bomb_list:
bomb.rect.x += shift_x
if bomb.rect.x < 0:
self.bomb_list.remove(bomb)
self.bomb_list.add(Bomb(random.randint(SCREEN_WIDTH, 2*SCREEN_WIDTH), 580))
I am not sure if this Level_01 class is even necessary:
class Level_01(Level):
def __init__(self, player):
Level.__init__(self, player)
bombs = 0
for n in range(10):
self.bomb_list.add(Bomb(random.randint(0, SCREEN_WIDTH), 580))
This was my attempt at a collision detection method. I'm not sure if it should be in a class, in main, or seperate. I can't seem to get the list of bombs, and the player at the same time.
def detectCollisions(sprite1, sprite_group):
if pygame.sprite.spritecollideany(sprite1, sprite_group):
sprite_group.remove(pygame.sprite.spritecollideany(sprite1, sprite_group))
print True
else:
print False
def main():
pygame.init()
size = [SCREEN_WIDTH, SCREEN_HEIGHT]
screen = pygame.display.set_mode(size)
active_sprite_list = pygame.sprite.Group()
enemy_list = pygame.sprite.Group()
player = Player(0, 0)
player.speed = 30
player.angle = math.radians(45)
player.rect.x = 500
player.rect.y = SCREEN_HEIGHT - player.rect.height
active_sprite_list.add(player)
done = False
clock = pygame.time.Clock()
current_level = Level_01(player)
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.go_left()
if event.key == pygame.K_RIGHT:
player.go_right()
active_sprite_list.update()
enemy_list.update()
player.level = current_level
player.move()
player.bounce()
if player.rect.x >= 500:
diff = player.rect.x - 500
player.rect.x = 500
current_level.shift_world(-diff)
if player.rect.x <= 120:
diff = 120 - player.rect.x
player.rect.x = 120
current_level.shift_world(diff)
current_level.draw(screen)
active_sprite_list.draw(screen)
enemy_list.draw(screen)
clock.tick(60)
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
Thanks for helping me out!
Probably the easiest thing to do is to draw out pixels (or virtual pixels) and if in drawing bomb/person pixels you find an overlap then you know a collision occurred.
You can however get way more complicated (and efficient) in your collision detection if you need a higher performance solution. See Wikipedia Collision Detection for a reference.
I suggest creating sprite groups using pygame.sprite.Group() for each class; Bomb and Player. Then, use pygame.sprite.spritecollide().
For example:
def Main()
...
player_list = pygame.sprite.Group()
bomb_list = pygame.sprite.Group()
...
Then in your logic handling loop, after creating a Player and Bomb instance, you could do something like this:
for bomb in bomb_list:
# See if the bombs has collided with the player.
bomb_hit_list = pygame.sprite.spritecollide(bomb, player_list, True)
# For each bomb hit, remove bomb
for bomb in bomb_hit_list:
bomb_list.remove(bomb)
# --- Put code here that will trigger with each collision ---