So I'm playing around with a Pygame platformer. Right now I have a player character, a bumper, and background. The player can run around the floor of the level or the bumper and the screen can screen when the character runs against the edge.
What I'd like though is a way to have multiple bumpers without having to create each individually. Here is some relevant code.
This is creating the bumper before the game's main loop...
bumper = pygame.image.load("bumper.png") #load bumper pic
bumperbounds = bumper.get_clip() #create boundaries for bumper
bumperbounds = bumperbounds.move (200, 250) #move the bumper to starting location
This is the code that makes the bumper stop the player from falling through. It just sets the landed value to 1...
if playerbounds.left <= bumperbounds.right and playerbounds.right >= bumperbounds.left and playerbounds.bottom <= bumperbounds.top + 30 and playerbounds.bottom >= bumperbounds.top and gravity >=0: #if player lands on top of the bumper
landed = 1 #set player to landed
This is some code so that the player lands on the platform correctly. Basically it slows the player down at the last loop iteration from falling through the bumper so its exact falling speed lands the bottom of the player on the top of the bumper.
if playerbounds.left <= bumperbounds.right and playerbounds.right >= bumperbounds.left and playerbounds.bottom <= bumperbounds.top and gravity > bumperbounds.top-playerbounds.bottom: #to land exactly on the top of the bumper
gravity = bumperbounds.top-playerbounds.bottom
This is to move the bumper when the screen is scrolling. This is just the right direction, the left one works basically the same.
if xacc > 0:#if player is moving right
if playerx >= width * .8 and screenx < levelwidth - playerbounds.width:#if the screen is scrolling
screenx = screenx + xacc
bumperbounds = bumperbounds.move(-xacc, 0) #bumper moves on the screen
skybounds = skybounds.move(-xacc / 10, 0)
groundbounds = groundbounds.move(-xacc * 2, 0)
else:
playerbounds = playerbounds.move(xacc, 0)
playerx += xacc
xacc -= 1
This just shows the bump on the screen at the end of the loop.
screen.blit(bumper,bumperbounds) #displays the bumper on the screen
Any help can be useful?!
You need create a class for the object you are creating.
For example:
class Leaf:
def __init__(self):
self.leafimage = pygame.image.load('fallingleaf.jpg').convert()
self.leafrect = self.leafimage.get_rect()
xpos = random.randint(0, 640)
self.leafrect.midtop = (xpos, 0)
def move(self):
self.leafrect = self.leafrect.move([0, 1])
To create objects at the same time,
leaves = []
for i in range(5):
leaves.append(Leaf())
With changing xpos value:
class Leaf:
def __init__(self,xpos):
self.leafimage = pygame.image.load('fallingleaf.jpg').convert()
self.leafrect = self.leafimage.get_rect()
self.leafrect.midtop = (xpos, 0)
def move(self):
self.leafrect = self.leafrect.move([0, 1])
To create objects at the same time,
leaves = []
xpos= [20 30 40 50 60]
for i in range(5):
leaves.append(Leaf(xpos[i]))
Related
This question already has answers here:
Problems with moving an enemy towards a character in pygame
(1 answer)
Pygame doesn't let me use float for rect.move, but I need it
(2 answers)
Closed 8 months ago.
So I have a functioning shooting mechanic in python pygame for a top down shooter, where I am using the mouse position to aim the bullets by working out the angles, however when I do this, the bullets are shooting slightly off where the mouse position is. for instance: the mouse would be where the red arrow is drawn and the bullets will be shooting by a small amount in the wrong direction
Any help would be appreciated
code below:
main.py:
#-------------Imports-------------#
import pygame,sys
#import globals
from background import*
from player import*
#-------------Constants-------------#
WIDTH,HEIGHT = 500,500
WINDOW = pygame.display.set_mode((WIDTH,HEIGHT))
CLOCK = pygame.time.Clock()
BLACK = (0, 0, 0)
#-------------Instances-------------#
bg = Background()
player = Player()
#-------------Functions-------------#
def draw():
WINDOW.fill(BLACK)
bg.update(WINDOW)
player.update(WINDOW)
pygame.display.update()
#-------------Main Game Loop-------------#
def main():
#globals.intialise()
while 1:
CLOCK.tick(1)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
draw()
#globals.game_ticks += 1
if __name__ == "__main__":
main()
player.py
#-------------Imports-------------#
import pygame,math
#import globals
#-------------Constants-------------#
WIDTH,HEIGHT = 500,500
PLAYER_COLOUR = (255, 212, 112)
BLACK = (0,0,0)
PI = 3.14159265359
#-------------Classes-------------#
class Bullet:
def __init__(self,origin,angle):
self.speed = 20
self.x_speed,self.y_speed = self.speed*math.cos(math.radians(angle)),self.speed*math.sin(math.radians(angle))
self.rect = pygame.Rect(origin[0],origin[1],5,5)
def __del__(self):
pass
def update(self,window):
# move bullet
self.rect.x += self.x_speed
self.rect.y += self.y_speed
# draw bullet
pygame.draw.rect(window,BLACK,self.rect)
# check if bullet is out of the screen
if self.rect.x > WIDTH or self.rect.x < 0:
return -1
elif self.rect.y > HEIGHT or self.rect.y < 0:
return -1
class Player:
def __init__(self):
self.sprite = pygame.transform.scale(pygame.image.load("sprites/temp_player.png"),(50,50))
self.rect = pygame.Rect(250,250,50,50)
self.center = (self.rect.x,self.rect.y)
self.bullets = []
self.fire_rate = 12
def shoot(self,angle,window):
# update all bullets and delete if bullet is out of screen
for bullet in self.bullets:
if bullet.update(window) == -1:
self.bullets.remove(bullet)
del bullet
# instantiate bullet if mouse button pressed
#if pygame.mouse.get_pressed()[0] and globals.game_ticks % self.fire_rate == 0:
if pygame.mouse.get_pressed()[0]:
self.bullets.append(Bullet(self.rect.center,-angle))
def update(self,window):
mx,my = pygame.mouse.get_pos()
# find distance between mouse position and player position
diff_x,diff_y = mx-self.rect.x,my-self.rect.y
# word out angle between mouse and player
angle_rad = math.atan2(diff_y,diff_x)
angle = -360*angle_rad/(2*PI)
# adjust angle according to where we want to rotate the player
# when angle is bottom left
if abs(angle) > 90 and angle < 0:
a = 270-abs(angle)
# when angle is top left
elif abs(angle) > 90:
a = angle-90
# when angle is to the right
else:
a = angle - 90
# create new sprite that is rotated
rotated_image = pygame.transform.rotate(self.sprite,a)
# replace current rectangle with rotated sprite
self.rect = rotated_image.get_rect(center = self.center)
self.shoot(angle,window)
# add image to the screen
#window.blit(pygame.transform.rotate(self.sprite,a),self.rect)
background.py:
#-------------Imports-------------#
import pygame,random,ast,time,globals
#-------------Constants-------------#
WIDTH,HEIGHT = 500,500
TILE_DIMENSION = 9
TILE_SIZE = int(round(WIDTH/TILE_DIMENSION,0))
TO_EDGE = int((TILE_DIMENSION+1)/2)
#-------------Classes-------------#
class Background:
def __init__(self):
self.tiles = self.generate_screen()
self.centre = [2,2]
self.right = 0
self.up = 0
self.speed = 5
def generate_screen(self):
# generate original chunk of tiles
tiles = [[random.randint(100,200) for i in range(TILE_DIMENSION)] for j in range(TILE_DIMENSION)]
# eventually use image instead of random RGB value
return tiles
def movement(self,tile_rects):
keys = pygame.key.get_pressed()
if keys[pygame.K_a] or keys[pygame.K_LEFT]:
# if player is on tile to the left of centre
if (self.right - self.speed) < -TILE_SIZE:
# reset movement and adjust centre
self.right = 0
self.centre[0] -= 1
else:
# add to movement if not on next tile
self.right -= self.speed
# move all rectangles in background to simulate player moving
for i in range(len(tile_rects)):
for j in range(len(tile_rects[0])):
tile_rects[i][j].x += self.speed
if keys[pygame.K_d] or keys[pygame.K_RIGHT]:
# if player is on tile to the right of centre
if (self.right + self.speed) > TILE_SIZE:
# reset movement and adjust centre
self.right = 0
self.centre[0] += 1
else:
# add to movement if not on next tile
self.right += self.speed
# move all rectangles in background to simulate player moving
for i in range(len(tile_rects)):
for j in range(len(tile_rects[0])):
tile_rects[i][j].x -= self.speed
if keys[pygame.K_w] or keys[pygame.K_UP]:
# if player is on tile above the centre
if (self.up + self.speed) > TILE_SIZE:
# reset movement and adjust centre
self.up = 0
self.centre[1] -= 1
else:
# add to movement if not on next tile
self.up += self.speed
# move all rectangles in background to simulate player moving
for i in range(len(tile_rects)):
for j in range(len(tile_rects[0])):
tile_rects[i][j].y += self.speed
if keys[pygame.K_s] or keys[pygame.K_DOWN]:
# if player is on tile below the centre
if (self.up - self.speed) < -TILE_SIZE:
# reset movement and adjust centre
self.up = 0
self.centre[1] += 1
else:
# add to movement if not on next tile
self.up -= self.speed
# move all rectangles in background to simulate player moving
for i in range(len(tile_rects)):
for j in range(len(tile_rects[0])):
tile_rects[i][j].y -= self.speed
return tile_rects
def update(self,window):
# rendering in brand new map chunks
# if part of the chunk trying to be rendered in is non-existant in the 2D map array to the left
if self.centre[0]-TO_EDGE < 0:
# check how many tiles it is offset by
for i in range(0-(self.centre[0]-TO_EDGE)):
# add new column of values at the beginning of the 2D array
for i in range(len(self.tiles)):
self.tiles[i].insert(0,random.randint(120,230))
# due to whole array being shifted to the right, adjust the centre accordingly
self.centre[0] += 1
# if part of the chunk trying to be rendered is non-existant in the 2D map array to the right
if self.centre[0]+TO_EDGE >= len(self.tiles[0]):
# check how many tiles it is offset by
for i in range((self.centre[0]+TO_EDGE)-(len(self.tiles[0])-1)):
# add a new column of values at the end of the 2D array
for i in range(len(self.tiles)):
self.tiles[i].append(random.randint(120,230))
# if part of the chunk trying to be rendered in is non-existant in the 2D array at the top
if self.centre[1]-TO_EDGE < 0:
# check how many tiles it is offset by
for i in range(0-(self.centre[1]-TO_EDGE)):
# add a new row at the top of the 2D array
self.tiles.insert(0,[random.randint(120,230) for i in range(len(self.tiles[0]))])
# due to whole array shifting downwards, adjust the centre accordingly
self.centre[1] += 1
# if part of the chunk trying to be rendered in is non-existant in the 2D array at the bottom
if self.centre[1]+TO_EDGE >= len(self.tiles):
# check how many tiles it is offset by
for i in range((self.centre[1]+TO_EDGE)-(len(self.tiles)-1)):
# add a new row at the bottom of the 2D array
self.tiles.append([random.randint(120,230) for i in range(len(self.tiles[0]))])
# determining which tiles should be rendered in according to the centre(where player would be)
t = []
for i in range(TILE_DIMENSION+2):
t.append([])
for j in range(TILE_DIMENSION+2):
try:
t[i].append(self.tiles[i+(self.centre[1]-TO_EDGE)][j+(self.centre[0]-TO_EDGE)])
except:
pass
# create a rectangle for each tile that is rendered in
tile_rects = [[pygame.Rect((i-1)*TILE_SIZE-self.right,(j-1)*TILE_SIZE+self.up,TILE_SIZE,TILE_SIZE) for i in range(TILE_DIMENSION+2)] for j in range(TILE_DIMENSION+2)]
tile_rects = self.movement(tile_rects)
# draw all rectangles
for i in range(TILE_DIMENSION+2):
for j in range(TILE_DIMENSION+2):
try:
pygame.draw.rect(window,(0,int(t[i][j]),0),tile_rects[i][j])
except:
pass
the background script doesnt affect anything, its just there as a background to make it easier to see, and you may have to make your own temp_player.png image to make it compatible
I am new to programming and started with pygame zero. I am making a little game where you shoot a rocket to an alien. But my rocket keeps stuck to the border when fired, I made a reload function but I want it to go automatically ( when it hits the border or alien to go back to its normal position). Can anyone help me with that?
alien = Actor('alien', (100,100))
ship =Actor('ship', (500,400))
rocket_fire = Actor('rocket_fire', (500,400))
WIDTH = 1000
HEIGHT =500
def draw():
screen.clear()
screen.blit('space_back', (0,0))
rocket_fire.draw()
ship.draw()
alien.draw()
def move_ship(ship):
if keyboard.left:
ship.x -= 3
rocket_fire.x -= 3
elif keyboard.right:
ship.x += 3
rocket_fire.x += 3
elif keyboard.space:
animate(rocket_fire, pos = (ship.x,0))
elif keyboard.r:
rocket_fire.pos = (ship.x,ship.y)
def move_alien(alien):
alien.right +=2
if alien.left > WIDTH:
alien.right = 0
collide = rocket_fire.colliderect(alien)
if collide == 0:
alien.image = 'alien'
elif collide == 1:
alien.image = 'nuclear_explosion'
def update():
rocket_fire.draw()
ship.draw()
alien.draw()
move_ship(ship)
move_alien(alien)
You can try to assign the initial values to 'rocket_fire' after 'collide == 1'.
elif collide == 1:
alien.image = 'nuclear_explosion'
// rocket_fire = (500,400) -> this is just a representation to assign position; not accurate as per the code
import pgzrun
import pygame
WIDTH = 850
HEIGHT = 425
#sprites
title = Actor('title.png') #calling sprites and saying their pos
title.pos = 400, 212
cont = Actor('cont.png')
cont.pos = 470, 300
player = Actor('ship.png')
player.pos = 100, 56
foe = Actor('foe.png')
foe.pos = 200, 112
vel = 5
music.play("temp.mp3")
#controls
def draw():
screen.clear()
screen.fill((0, 0, 0))
title.draw()
cont.draw()
foe.draw()
player.draw()
def update():
keys = pygame.key.get_pressed()
x, y = player.pos
x += (keys[pygame.K_d] - keys[pygame.K_a]) * vel
y += (keys[pygame.K_s] - keys[pygame.K_w]) * vel
player.pos = x, y
if player.left > WIDTH: #if player hits right side of screen it takes the player to the other side of the screen
player.right = 0
def otherimage(): #animation of ship
player.image = 'ship.png'
imagey()
def imagey():
player.image = 'ship1.png'
clock.schedule_unique(otherimage, 1.0)
imagey()
pgzrun.go()
the animation section is the bit commented with "animation of ship". The wrapping bit is the bit labled "if player hits right side of screen it takes the player to the other side of the screen" as you can see i have go it working when the player hits the screen on the right side but every time i have tried getting it to work on the other sides it doesn't work. Please help! Thanks! Im new to coding and i am trying to understand this language. thanks again.
i am trying to make a flappy bird game in pygame for school but i am struggling with adding the obstacles. I can add one obstacle but i want to add infinite obstacles and i already have an infinite loop to run my game so when i add an extra infinite, loop my game just crashes. I am using a time.sleep() function when add the obstacle in my infinite loop which makes the game crash.
This is my code so far:
import time
import pygame
pygame.init()
xSpeler = 450
ySpeler = 100
widthSpeler = 40
heightSpeler = 40
vel = 10
vel1 = 10
#obstacle 1
xo1 = 900
yo1 = 0
ho1 = 200
wo1 = 50
xo2 = 900
yo2 = 350
ho2 = 200
wo2 = 50
#obstacle 2
xo3 = 900
yo3 = 0
ho3 = 250
wo3 = 50
xo4 = 900
yo4 = 350
ho4 = 150
wo4 = 50
win = pygame.display.set_mode((1000, 500))
bi = pygame.image.load('bada.png')
pygame.display.flip()
run = True
while run:
win.blit(bi, (0, 0))
pygame.time.delay(1)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
ySpeler += vel
if ySpeler >= 500 - heightSpeler:
ySpeler = 500 - heightSpeler
xo1 -= vel1
xo2 -= vel1
if keys[pygame.K_SPACE] and xSpeler> vel and ySpeler > 0:
ySpeler -= jump
pygame.draw.rect(win, (255, 0, 0), (xSpeler, ySpeler, widthSpeler, heightSpeler))
for x in range(100):
pygame.draw.rect(win, (0, 255, 0), (xo1, yo1, wo1, ho1)) or pygame.draw.rect(win, (0, 255, 0),(xo1, yo1, wo1, ho1))
pygame.draw.rect(win, (0, 255, 0), (xo2, yo2, wo2, ho2)) or pygame.draw.rect(win, (0, 255, 0),(xo2, yo2, wo2, ho2))
time.sleep(7)
pygame.display.update()
im came from netherland so my inglish is not so good and my variables are in dutch so sorry for it
i realy hope someone can help me.
Your screen stays black because of time.sleep(7). It is in a for loop that iterate 100 times so that's your program sleeping 700 seconds every frame. To make an obstacle, make a function that generates and returns 2 obstacles, one for top and the other one for bottom.
def genObstacle():
# generate and return
#1. pygame surface for top and bottom rects
#2. initial position for top rect and bottom rect
topHeight = random.randint(10, 200) # height for bottom obstacle
botHeight = random.randint(10, 200) # height for top obstacle
top = pygame.Surface((10, topHeight)).convert()
bot = pygame.Surface((10, botHeight)).convert()
# return: top rect, bottom rect, top rect's position, bottom rect's position
return [top, bot, [800, 0], [800, 500-botHeight]]
Return the initial positions for both of the obstacles as well, so it is easier to work with. I would really recommend using a class for obstacle, so working with attributes of obstacles like position is easier.
Now that we have a function to generate obstacle, we can make a list to hold those obstacles obstacles = []. Now, we can generate the obstacles every 3 seconds like this:
#other code
start = time.time()
while True:
#other code
now = time.time()
if now - start > 3:
obstacles.append(genObstacle())
start = now
Now that we have obstacles, we can change draw them and change their values like this:
for i in range(len(obstacles)):
# remember, third item in list is position for top and
# fourth item is the position for bottom
# draw the obstacles
win.blit(obstacles[i][0], (obstacles[i][2][0], obstacles[i][3][1]))
win.blit(obstacles[i][1], (obstacles[i][2][0], obstacles[i][3][1]))
# change the x values for it to move to the right
obstacles[i][2][0] -= 1
obstacles[i][2][0] -= 1
I am having trouble getting a collision detector to work for my game of pong without having to change all of classes (sprite, render).
I've seen some useful threads here on StackOverflow but I can't seem to get them to work.
#Create a class named sprite to use for the paddles and the ball.
class Sprite():
def __init__(self,x,y,width,height,color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color= (255,255,255)
#attirbute for drawing the sprite(s) to the screen
def render(self):
pygame.draw.rect(screen,self.color,(self.x,self.y,self.width,self.height))
#Create the sprites
Paddle1 = Sprite(50,175,25,150,color[0])
Paddle2 = Sprite(650,175,25,150,color[1])
Ball = Sprite(300,250,25,25, color[2])
#Set the Sprite's color(s)
Paddle1.color = color[0]
Paddle2.color = color[1]
Ball.color = color[2]
#Variables used for moving the paddles
moveY1,moveY2=0,0
#### Spot where my collision detector goes####
#### Code for drawing and moving the paddles####
Paddle1.y += moveY1
Paddle1.render()
Paddle2.y += moveY2
Paddle2.render()
#Draw the Ball
Ball.render()
This is a working snippet for a Pong game I made with pygame. I also made for the second bumper, but ommited to save space, since its pretty much the same thing
def check_bumpers_collision(self):
if (self.ball.pos_x < self.bumper_one.pos_x + self.bumper_one.width and
self.ball.pos_x + self.ball.size > self.bumper_one.pos_x and
self.ball.pos_y < self.bumper_one.pos_y + self.bumper_one.height and
self.ball.pos_y + self.ball.size > self.bumper_one.pos_y):
# Change Ball X moving direction
self.ball.speed_x *= -1
# Change Y ball Speed
if self.bumper_one.moving_up:
self.ball.speed_y -= 5
elif self.bumper_one.moving_down:
self.ball.speed_y += 5