how do you create jumping in pygame for a sprite - python

I am struggling with finding a way to make the sprite jump in pygame. when i basically run the program now the sprite goes straight to the top of the screen and i just want it to do a normal jump. the jump is in a class and is a function. I have used KEYDOWN to check when its pressed to move it downwards.
import pygame
import random
import sys
pygame.init()
screen = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock() # A clock to limit the frame rate.
pygame.display.set_caption("this game")
class Background:
picture = pygame.image.load("C:/images/dunes.jpg").convert()
picture = pygame.transform.scale(picture, (1280, 720))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
def draw(self):
# Blit the picture onto the screen surface.
# `self.picture` not just `picture`.
screen.blit(self.picture, (self.xpos, self.ypos))
class Monster:
picture = pygame.image.load("C:/pics/hammerhood.png").convert_alpha()
picture = pygame.transform.scale(picture, (200, 200))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
# If you want to move continuously you need to set these
# attributes to the desired speed and then add them to
# self.xpos and self.ypos in an update method that should
# be called once each frame.
self.speed_x = 0
self.speed_y = 0
def update(self):
# Call this method each frame to update the positions.
self.xpos += self.speed_x
self.ypos += self.speed_y
# Not necessary anymore.
def move_left(self):
self.xpos -= 5 # -= not = -5 (augmented assignment).
def move_right(self):
self.xpos += 5 # += not = +5 (augmented assignment).
def jump(self): #vvvvvvv this is the part i do not know how to fix
# What do you want to do here?
#for x in range(1, 10):
#self.ypos -= 1 # -= not =-
# pygame.display.show() # There's no show method.
#for x in range(1, 10):
#self.ypos += 1
# pygame.display.show()
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
class Enemy: # Use upper camelcase names for classes.
picture = pygame.image.load("C:/pics/dangler_fish.png").convert_alpha()
picture = pygame.transform.scale(picture, (200, 200))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
def teleport(self):
self.xpos = random.randint(1, 1280)
self.ypos= random.randint(1, 720)
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
# Create the instances before the while loop.
ice = Background(0, 0) # I pass 0, 0 so that it fills the whole screen.
hammerhood = Monster(200, 500)
fish = Enemy(0, 0)
while True:
# Handle events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# Check if the `event.type` is KEYDOWN first.
elif event.type == pygame.KEYDOWN:
# Then check which `event.key` was pressed.
if event.key == pygame.K_d:
#hammerhood.move_right()
hammerhood.speed_x = 5
elif event.key == pygame.K_a:
#hammerhood.move_left()
hammerhood.speed_x = -5
elif event.key == pygame.K_w:
hammerhood.jump()
elif event.type == pygame.KEYUP:
# Stop moving when the keys are released.
if event.key == pygame.K_d and hammerhood.speed_x > 0:
hammerhood.speed_x = 0
elif event.key == pygame.K_a and hammerhood.speed_x < 0:
hammerhood.speed_x = 0
# Update the game.
hammerhood.update()
fish.teleport()
if hammerhood.xpos == 1280 or hammerhood.xpos == 0:
hammerhood.speed_x = 0
# Draw everything.
ice.draw() # Blit the background to clear the screen.
hammerhood.draw()
fish.draw()
pygame.display.flip()
clock.tick(60) # Limit the frame rate to 60 FPS.

Just add a GRAVITY constant and add it to the self.speed_y each frame to accelerate the player.
GRAVITY = .9 # Define this in the global scope.
# The Monster's update method.
def update(self):
self.speed_y += GRAVITY # Accelerate downwards.
self.xpos += self.speed_x
self.ypos += self.speed_y
# Stop falling at the bottom of the screen.
if self.ypos >= 520:
self.ypos = 520
self.speed_y = 0
self.on_ground = True
Set the self.speed_y to a negative value when you start to jump:
def jump(self):
if self.on_ground: # This prevents air jumps.
self.on_ground = False
self.speed_y = -25

Related

How do I make my background scroll as my Sprite moves left and right? Pygame

Right now my game works as so: My sprite can move right or left, jump and shoot fireballs (bullets). However, once my sprite walks past the limit of my background surface, it goes off-screen. So I want to make the background move along with my sprite. As soon as my player sprite moves about 50 pixels towards the edges of the screen, the background moves too. How do I create this with Pygame? I've found quite an amount of sources which shows you how to do this but with a plain colour background. But my background is an image I load into the game, so I would like to learn how to do so with an image as background. How to make it repeat once the sprite comes near the limit of both sides. I separated my codes into 3 different files: a Main.py, settings.py and Sprite1.py. Here's Main.py:
import pygame
import os
import sys
import time
from pygame import mixer
from Sprite1 import *
from settings import *
'''
Setup
'''
pygame.init()
clock = pygame.time.Clock()
pygame.mixer.music.load('.\\sounds\\Fairy.mp3')
pygame.mixer.music.play(-1, 0.0)
all_sprites = pygame.sprite.Group()
player = Player(all_sprites)
player.rect.x = 50
player.rect.y = 500
showStartScreen(surface)
'''
Main loop
'''
main = True
while main == True:
background = pygame.image.load(os.path.join('images', 'Bg.png'))
surface.blit(background, (0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
main = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(-steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(steps,0)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(-steps,0)
keys = pygame.key.get_pressed()
if not(isJump):
if keys[pygame.K_UP]:
isJump = True
else:
if jumpCount >= -10:
player.rect.y -= (jumpCount * abs(jumpCount)) * 1
jumpCount -= 2
else:
jumpCount = 10
isJump = False
# dt = time since last tick in milliseconds.
dt = clock.tick(60) / 1000
all_sprites.update(dt)
player.update(dt)
all_sprites.draw(surface) #refresh player position
pygame.display.flip()
Here's settings.py:
import pygame
isJump = False
jumpCount = 10
width = 960
height = 720
fps = 40 # frame rate
#ani = 4 # animation cycles
pygame.display.set_caption('B.S.G.')
surface = pygame.display.set_mode((width, height))
PLAYER_ACC = 0.5
PLAYER_FRICTION = -0.12
PLAYER_GRAV = 0.8
PLAYER_JUMP = 20
PLAYER_LAYER = 2
PLATFORM_LAYER = 1
steps = 10 # how fast to move
And here's Sprite1.py:
import pygame
import sys
import os
import time
from pygame import mixer
from pygame.locals import *
from settings import *
vec = pygame.math.Vector2
def showStartScreen(surface):
show = True
while (show == True):
background = pygame.image.load(os.path.join('images', 'Starting_scr.png'))
# rect = surface.get_rect()
surface.blit(background, (0,0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
show = False
class Player(pygame.sprite.Sprite):
def __init__(self, all_sprites):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.health = 10
self.jumping = False
self.images = []
self.imagesleft = []
self.imagesright = []
self.direction = "right"
self.alpha = (0,0,0)
self.ani = 4 # animation cycles
self.all_sprites = all_sprites
self.add(self.all_sprites)
self.bullet_timer = .1
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesright.append(img)
self.image = self.imagesright[0]
self.rect = self.image.get_rect()
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img = pygame.transform.flip(img, True, False)
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesleft.append(img)
self.image = self.imagesleft[0]
self.rect = self.image.get_rect()
def control(self,x,y):
'''
control player movement
'''
self.movex += x
self.movey -= y
def update(self, dt):
'''
Update sprite position
'''
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
# moving left
if self.movex < 0:
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesleft[self.frame//self.ani]
self.direction = "left"
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesright[self.frame//self.ani]
self.direction = "right"
#enemy_hit_list = pygame.sprite.spritecollide(self,enemy_list, False)
#for enemy in enemy_hit_list:
#self.health -= 1
#print(self.health)
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
self.bullet_timer -= dt # Subtract the time since the last tick.
if self.bullet_timer <= 0:
self.bullet_timer = 100 # Bullet ready.
if keys: # Left mouse button.
# Create a new bullet instance and add it to the groups.
if self.direction == "right":
Bullet([self.rect.x + self.image.get_width(), self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
else:
Bullet([self.rect.x, self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
self.bullet_timer = .1 # Reset the timer.
class Bullet(pygame.sprite.Sprite):
IMAGE = None
FLIPPED_IMAGE = None
def __init__(self, pos, direction, *sprite_groups):
super().__init__(*sprite_groups)
# cache images
if not Bullet.IMAGE:
Bullet.IMAGE = pygame.image.load(os.path.join('images','fireball.png'))
Bullet.FLIPPED_IMAGE = pygame.transform.flip(Bullet.IMAGE, True, False)
if direction == "right":
self.vel = pygame.math.Vector2(750, 0)
self.image = Bullet.IMAGE
else:
self.vel = pygame.math.Vector2(-750, 0)
self.image = Bullet.FLIPPED_IMAGE
self.pos = pygame.math.Vector2(pos)
self.rect = self.image.get_rect(center=pos)
def update(self, dt):
# Add the velocity to the position vector to move the sprite
self.pos += self.vel * dt
self.rect.center = self.pos # Update the rect pos.
if not pygame.display.get_surface().get_rect().colliderect(self.rect):
self.kill()
I'm open to any suggestions. Thanks beforehand!
Here's how I would approach this...
set up a scrolling background as in the tutorial and make sure you can get that working OK by moving the background back & forth instead of the player (just freeze the player's x coordinate in the center and move the background with your left/right keys.
Add some constants into your settings for an edge buffer (the number of x-increments you want the player to avoid the boundaries by
AFTER you get the key input (left or right) set up a conditional statement. For this, you will have to access the player's x-coordinate and compare it to the buffer. Well, either 0+buffer or width-buffer actually and then based on those cases either move the player or the background. See if you can get that working.
Then, you will realize that when you move the background, you are moving the frame of reference for everything else, meaning things like the fireball, so if you are moving the background left or right, you will need to apply those updates to the other objects as well so it looks correct.
If yer stuck, make those updates to code above & message me back in a comment.

How do I set a limit to the range of my bullet?

My game has a sprite which can move left and right and shoot bullets. However, if I shoot out too many bullets (about 50 or so), my game starts lagging a lot. My sprite doesn't move fluently anymore and the game doesn't work well. So I think the problem to this is that all the bullets created are continuing to be run outside my screen. That's why I would like to know how to set a range limit to my bullet. Once past that limit it disappears and out of the program so my game won't lag. However, I am open to other suggestions like if there is a way to make my game no lag without setting a range limit. I have separated my game into 2 .py files a main.py and a Sprite1.py which I import to my main.
Here's my Sprite1.py file:
import pygame
import sys
import os
import time
from pygame import mixer
from pygame.locals import *
def showStartScreen(surface):
show = True
while (show == True):
background = pygame.image.load(os.path.join('images', 'Starting_scr.png'))
# rect = surface.get_rect()
surface.blit(background, (0,0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
show = False
class Player(pygame.sprite.Sprite):
def __init__(self, all_sprites):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.images = []
self.imagesleft = []
self.imagesright = []
self.direction = "right"
# self.rect = self.image.get_rect(center=pos)
self.alpha = (0,0,0)
self.ani = 4 # animation cycles
self.all_sprites = all_sprites
self.add(self.all_sprites)
self.bullet_timer = .1
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesright.append(img)
self.image = self.imagesright[0]
self.rect = self.image.get_rect()
for i in range(1,5):
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
img = pygame.transform.flip(img, True, False)
img.convert_alpha()
img.set_colorkey(self.alpha)
self.imagesleft.append(img)
self.image = self.imagesleft[0]
self.rect = self.image.get_rect()
def control(self,x,y):
'''
control player movement
'''
self.movex += x
self.movey -= y
def update(self, dt):
'''
Update sprite position
'''
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
# moving left
if self.movex < 0:
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesleft[self.frame//self.ani]
self.direction = "left"
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > 3*self.ani:
self.frame = 0
self.image = self.imagesright[self.frame//self.ani]
self.direction = "right"
# self.rect.center = pygame.mouse.get_pos()
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
self.bullet_timer -= dt # Subtract the time since the last tick.
if self.bullet_timer <= 0:
self.bullet_timer = 0 # Bullet ready.
if keys: # Left mouse button.
# Create a new bullet instance and add it to the groups.
if self.direction == "right":
Bullet([self.rect.x + self.image.get_width(), self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
else:
Bullet([self.rect.x, self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
self.bullet_timer = .1 # Reset the timer.
class Bullet(pygame.sprite.Sprite):
def __init__(self, pos, direction, *sprite_groups):
super().__init__(*sprite_groups)
self.image = pygame.image.load(os.path.join('images','fireball.png'))
self.rect = self.image.get_rect()
self.sound = pygame.mixer.music.play()
self.pos = pygame.math.Vector2(pos)
self.vel = pygame.math.Vector2(750, 0)
self.direction = direction
def update(self, dt):
# Add the velocity to the position vector to move the sprite
if self.direction == "right":
#self.vel = pygame.math.Vector2(750, 0)
self.image = pygame.image.load(os.path.join('images','fireball.png'))
self.rect = self.image.get_rect()
self.pos += self.vel * dt
else:
#self.vel = pygame.math.Vector2(-750, 0)
BULLET_IMG = pygame.image.load(os.path.join('images','fireball.png'))
self.image = pygame.transform.flip(BULLET_IMG, True, False)
self.rect = self.image.get_rect()
self.pos -= self.vel * dt
#print(self.pos)
self.rect.center = self.pos # Update the rect pos.
if self.rect.bottom <= 0:
self.kill()
And this is my main.py file:
import pygame
import os
import sys
import time
from pygame import mixer
import Sprite1
'''
Setup
'''
pygame.init()
width = 960
height = 720
fps = 40 # frame rate
#ani = 4 # animation cycles
clock = pygame.time.Clock()
pygame.display.set_caption('B.S.G.!!!')
surface = pygame.display.set_mode((width, height))
#pygame.mixer.music.load('.\\sounds\\Fairy.mp3')
#pygame.mixer.music.play(-1, 0.0)
pygame.mixer.music.load('.\\sounds\\Fireball.wav')
#direction = "right"
all_sprites = pygame.sprite.Group()
player = Sprite1.Player(all_sprites)
player.rect.x = 50
player.rect.y = 500
steps = 10 # how fast to move
Sprite1.showStartScreen(surface)
'''
Main loop
'''
main = True
while main == True:
background = pygame.image.load(os.path.join('images', 'Bg.png'))
surface.blit(background, (0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
main = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(-steps,0)
#direction = "left"
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(steps,0)
#direction = "right"
if event.key == pygame.K_UP or event.key == ord('w'):
player.rect.y -= 100
#player.rect.y -= 10
#player.movey == 10
#player.movey == -10
#time.sleep(1)
#player.control(0,-steps)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == ord('a'):
player.control(steps,0)
#direction = "left"
if event.key == pygame.K_RIGHT or event.key == ord('d'):
player.control(-steps,0)
#direction = "right"
if event.key == pygame.K_UP or event.key == ord('w'):
player.rect.y += 100
#player.movey == -10
if event.key == ord('q'):
pygame.quit()
sys.exit()
main = False
# dt = time since last tick in milliseconds.
dt = clock.tick(60) / 1000
all_sprites.update(dt)
player.update(dt)
all_sprites.draw(surface) #refresh player position
pygame.display.flip()
P.S.: don't mind how my sprite jumps, I just wrote it that way for now. I will be making him actually jump later on with gravity. Thanks beforehand.
You already check if the bullets leave the screen at the top:
if self.rect.bottom <= 0:
self.kill()
You could change it to
if not pygame.display.get_surface().get_rect().colliderect(self.rect):
self.kill()
to kill the sprite if it is not at the screen at all.
But your problem is actually this:
def update(self, dt):
# Add the velocity to the position vector to move the sprite
if self.direction == "right":
#self.vel = pygame.math.Vector2(750, 0)
self.image = pygame.image.load(os.path.join('images','fireball.png'))
self.rect = self.image.get_rect()
self.pos += self.vel * dt
else:
#self.vel = pygame.math.Vector2(-750, 0)
BULLET_IMG = pygame.image.load(os.path.join('images','fireball.png'))
self.image = pygame.transform.flip(BULLET_IMG, True, False)
self.rect = self.image.get_rect()
self.pos -= self.vel * dt
...
Here you're loading the fireball.png image once for every instance of the Bullet class
every frame. You aim for 60 fps, so when there are 50 Bullet instances you try to load the file 300 times per second from your disk.
Instead, you should load the image once at startup.
Here's how it could look like:
class Bullet(pygame.sprite.Sprite):
IMAGE = None
FLIPPED_IMAGE = None
def __init__(self, pos, direction, *sprite_groups):
super().__init__(*sprite_groups)
# cache images
if not Bullet.IMAGE:
Bullet.IMAGE = pygame.image.load(os.path.join('images','fireball.png'))
Bullet.FLIPPED_IMAGE = pygame.transform.flip(Bullet.IMAGE, True, False)
if direction == "right":
self.vel = pygame.math.Vector2(750, 0)
self.image = Bullet.IMAGE
else:
self.vel = pygame.math.Vector2(-750, 0)
self.image = Bullet.FLIPPED_IMAGE
# suspicious... Should use the Sound class instead
# self.sound = pygame.mixer.music.play()
self.pos = pygame.math.Vector2(pos)
self.rect = self.image.get_rect(center=pos)
def update(self, dt):
# Add the velocity to the position vector to move the sprite
self.pos += self.vel * dt
self.rect.center = self.pos # Update the rect pos.
if not pygame.display.get_surface().get_rect().colliderect(self.rect):
self.kill()
Also, you should only use pygame.mixer.music.play() for playing background music (since you can only play one file at once with music.play()). For sound effects, better use the Sound class.
You can check if the bullet is in the screen and remove it if it isn't.
for bullet in bullets[:]:
if not surface.get_rect().collidepoint(bullet.pos):
#remove the bullet
Alternatively, you can remove it after a set amount of time. Under your __init__ method of the bullet class, you can add start = time.time() to record when it spawns.
class Bullet(pygame.sprite.Sprite):
def __init__(self, pos, direction, *sprite_groups):
super().__init__(*sprite_groups)
self.image = pygame.image.load(os.path.join('images','fireball.png'))
self.rect = self.image.get_rect()
self.sound = pygame.mixer.music.play()
self.pos = pygame.math.Vector2(pos)
self.vel = pygame.math.Vector2(750, 0)
self.direction = direction
self.start = time.time()
Then in your main loop make a variable now = time.time() to keep track of the current time. You can determine how long you bullet has been around by taking away spawn time, which is self.start from now
def kill(self, now, lifetime):
if now - self.start > lifetime:
#remove bullet

pygame making the sprite go upwards and downwards

I am trying to make the sprite move up and down by using the arrow keys but it schemes to only be moving slightly upwards and slightly downwards: there is a speed for the x and y axis and also a position. There are also two functions which are draw and update (which gets the new xpos and the new ypos). here is my code
import pygame
import random
import sys
pygame.init()
screen = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock() # A clock to limit the frame rate.
pygame.display.set_caption("this game")
class Background:
picture = pygame.image.load("C:/images/cliff.jpg").convert()
picture = pygame.transform.scale(picture, (1280, 720))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
class player_first:
picture = pygame.image.load("C:/aliens/ezgif.com-crop.gif")
picture = pygame.transform.scale(picture, (200, 200))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
self.speed_x = 0
self.speed_y = 0
self.rect = self.picture.get_rect()
def update(self):
self.xpos =+ self.speed_x
self.ypos =+ self.speed_y
def draw(self): #left right
#screen.blit(pygame.transform.flip(self.picture, True, False), self.rect)
screen.blit(self.picture, (self.xpos, self.ypos))
class Bullet_player_1(pygame.sprite.Sprite):
picture = pygame.image.load("C:/aliens/giphy.gif").convert_alpha()
picture = pygame.transform.scale(picture, (100, 100))
def __init__(self):
self.xpos = 360
self.ypos = 360
self.speed_x = 0
super().__init__()
self.rect = self.picture.get_rect()
def update(self):
self.xpos += self.speed_x
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
#self.screen.blit(pygame.transform.flip(self.picture, False, True), self.rect)
def is_collided_with(self, sprite):
return self.rect.colliderect(sprite.rect)
player_one_bullet_list = pygame.sprite.Group()
player_one = player_first(0, 0)
cliff = Background(0, 0)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
player_one.speed_y = -5
print("up")
elif event.key == pygame.K_s:
player_one.speed_y = 5
print("down")
elif event.key == pygame.K_SPACE:
bullet_player_one = Bullet_player_1
bullet_player_one.ypos = player_one.ypos
bullet_player_one.xpos = player_one.xpos
bullet_player_one.speed_x = 14
player_one_bullet_list.add(bullet_player_one)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d and player_one.speed_x > 0:
player_one.speed_x = 0
elif event.key == pygame.K_a and player_one.speed_x < 0:
player_one.speed_x = 0
player_one.update()
cliff.draw()
player_one.draw()
player_one_bullet_list.update()
for bullet_player_one in player_one_bullet_list:
bullet_player_one.draw()
pygame.display.flip()
clock.tick(60)
You've written self.xpos =+ self.speed_x (which is interpret as self.xpos = +self.speed_x) instead of self.xpos += self.speed_x. So you're not adding the speed to the position, you're overwriting it.

why is not pygame blit not working in a class

I am trying to create my own game using pygame with classes and my problem is that I cannot understand why my program is not working properly
import pygame
import time
import random
import sys
pygame.init()
screen = pygame.display.set_mode((1280, 720))
pygame.display.set_caption("this game")
class Background:
def __init__(self, x, y):
self.xpos = x
self.ypos = y
picture = pygame.image.load("C:/images/dunes.jpg")
picture = pygame.transform.scale(picture, (1280, 720))
def draw(self):
pygame.surface.Surface.blit(picture, (self.xpos, self.ypos))
class Monster:
def __init__(self, x, y):
self.xpos = x
self.ypos = y
def move_left(self):
self.xpos =- 5
def move_right(self):
self.xpos =+ 5
def jump(self):
for x in range(1, 10):
self.ypos =-1
pygame.display.show()
for x in range(1, 10):
self.ypos =+1
pygame.display.show()
picture = pygame.image.load("C:/pics/hammerhood.png")
picture = pygame.transform.scale(picture, (200, 200))
def draw(self):
pygame.surface.Surface.blit(picture, (self.xpos, self.ypos))
class enemy:
def __init__(self, x, y):
self.xpos = x
self.ypos = y
picture = pygame.image.load("C:/pics/dangler_fish.png")
picture = pygame.transform.scale(picture, (200, 200))
def teleport(self):
self.xpos = random.randint(1, 1280)
self.pos= random.randint(1, 720)
def draw(self):
pygame.surface.Surface.blit(picture, (self.xpos, self.ypos))
while True:
ice = Background(720, 360)
hammerhood = Monster(200, 500)
fish = enemy(0, 0)
fish.teleport()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if pygame.event == pygame.K_d:
hammerhood.move_right()
if pygame.event == pygame.K_a:
hammerhood.move_left()
if pygame.event == pygame.K_w:
hammerhood.jump()
hammerhood.draw()
ice.draw()
fish.draw()
what it is saying to me is, line 49, in the draw
pygame.surface.Surface.blit(picture, (self.xpos, self.ypos))
NameError: name 'picture' is not defined
I have tried everything and there is another project I copied from the internet and this has the exact same way of blitting the picture in the class but in this one, it is not working
you define picture at the class top level which makes it a class attribute. To access it from a method you have to use self. picture
The picture attributes are class attributes (defined outside of the __init__ method) but they can be accessed like any other attributes by prepending them with self.. Also, you most likely want to blit the pictures onto the screen surface, so just call the blit method of this surface:
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
Note that class attributes are shared between all instances, so if you modify one surface/image, they'll be changed for all sprites.
There are a few more problems:
The event handling doesn't work.
The sprites won't move continuously. Define some speed attributes and add them to the positions each frame.
You should almost always call the convert or convert_alpha methods to improve the blit performance of the surfaces.
Here's a fixed version (except for the jumping) with some comments:
import pygame
import random
import sys
pygame.init()
screen = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock() # A clock to limit the frame rate.
pygame.display.set_caption("this game")
class Background:
picture = pygame.image.load("C:/images/dunes.jpg").convert()
picture = pygame.transform.scale(picture, (1280, 720))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
def draw(self):
# Blit the picture onto the screen surface.
# `self.picture` not just `picture`.
screen.blit(self.picture, (self.xpos, self.ypos))
class Monster:
picture = pygame.image.load("C:/pics/hammerhood.png").convert_alpha()
picture = pygame.transform.scale(picture, (200, 200))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
# If you want to move continuously you need to set these
# attributes to the desired speed and then add them to
# self.xpos and self.ypos in an update method that should
# be called once each frame.
self.speed_x = 0
self.speed_y = 0
def update(self):
# Call this method each frame to update the positions.
self.xpos += self.speed_x
self.ypos += self.speed_y
# Not necessary anymore.
# def move_left(self):
# self.xpos -= 5 # -= not = -5 (augmented assignment).
#
# def move_right(self):
# self.xpos += 5 # += not = +5 (augmented assignment).
def jump(self):
# What do you want to do here?
for x in range(1, 10):
self.ypos -= 1 # -= not =-
# pygame.display.show() # There's no show method.
for x in range(1, 10):
self.ypos += 1
# pygame.display.show()
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
class Enemy: # Use upper camelcase names for classes.
picture = pygame.image.load("C:/pics/dangler_fish.png").convert_alpha()
picture = pygame.transform.scale(picture, (200, 200))
def __init__(self, x, y):
self.xpos = x
self.ypos = y
def teleport(self):
self.xpos = random.randint(1, 1280)
self.pos= random.randint(1, 720)
def draw(self):
screen.blit(self.picture, (self.xpos, self.ypos))
# Create the instances before the while loop.
ice = Background(0, 0) # I pass 0, 0 so that it fills the whole screen.
hammerhood = Monster(200, 500)
fish = Enemy(0, 0)
while True:
# Handle events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# Check if the `event.type` is KEYDOWN first.
elif event.type == pygame.KEYDOWN:
# Then check which `event.key` was pressed.
if event.key == pygame.K_d:
hammerhood.speed_x = 5
elif event.key == pygame.K_a:
hammerhood.speed_x = -5
elif event.key == pygame.K_w:
hammerhood.jump()
elif event.type == pygame.KEYUP:
# Stop moving when the keys are released.
if event.key == pygame.K_d and hammerhood.speed_x > 0:
hammerhood.speed_x = 0
elif event.key == pygame.K_a and hammerhood.speed_x < 0:
hammerhood.speed_x = 0
# Update the game.
hammerhood.update()
fish.teleport()
# Draw everything.
ice.draw() # Blit the background to clear the screen.
hammerhood.draw()
fish.draw()
pygame.display.flip()
clock.tick(60) # Limit the frame rate to 60 FPS.

How can I make Pygame check if two images are colliding?

I've tried everything and cannot get how I check if my two blocks have collided.
Here's my code:
import pygame
import random
pygame.init()
display_width = 600
display_height = 300
class player:#Just info for player
width = 30
height = 30
x = display_width // 2
y = display_height - height - 5
a = x + 30
pic = 'SnakePart.png'
thing = pygame.image.load(pic)
def place(x,y):#function for placing player object
gameDisplay.blit(player.thing, (player.x,player.y))
class enemy:#enemy info class
width = 30
height = 30
x = random.randint(0,display_width - width)
y = 1
a = x + 30
pic = 'Apple.png'
thing = pygame.image.load(pic)
speed = 10#sets speed
def change_x():
enemy.x = random.randint(0,display_width - enemy.width)
def change_y():
enemy.y += enemy.speed
def make(x,y):#set up funtion
gameDisplay.blit(enemy.thing, (x,y))
def respawn():#reseting enemy entity
enemy.y = 1
gameDisplay.blit(enemy.thing, (enemy.x,enemy.y))
player.thing#uses the variables in the classes to set up the images for use
enemy.thing
black = (0,0,0)
white = (255,255,255)
player_height = 30
player_width = 30
clock = pygame.time.Clock()
x_change = 0#This is to make movment
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('Bullet Hell.')
dodged = 0#counter will be used in the more polished vesion.
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:#Checks for keypress, to make player entity move
if event.key == pygame.K_RIGHT:
x_change = 5
if event.key == pygame.K_LEFT:
x_change = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or pygame.K_LEFT:
x_change = 0
player.x += x_change
gameDisplay.fill(black)
enemy.make(enemy.x,enemy.y)
player.place(player.x,player.y)
enemy.change_y()
if enemy.y > display_height:#Brings enemy back to top once it has gotten to th bottom
enemy.change_x()
dodged += 1
enemy.respawn()
pygame.display.update()
clock.tick(60)
It's all really the collision and I think I'll be good. Oh yeah, if you guys could also tell me how to display text that would be great!
Take a look at the pygame.Rect class and its collision detection methods. Give your objects rects as attributes which you get by calling the .get_rect() method of the images/surfaces. Update the coordinates of these rects each frame and in your main loop call player.rect.colliderect(enemy.rect) to check if the two rects collide.
import pygame
import random
pygame.init()
BLACK = pygame.Color('black')
display = pygame.display.set_mode((600, 300))
# Create a rect with the dimensions of the screen at coords (0, 0).
display_rect = display.get_rect()
clock = pygame.time.Clock()
# SNAKE_IMAGE = pygame.image.load('SnakePart.png').convert_alpha()
# APPLE_IMAGE = pygame.image.load('Apple.png').convert_alpha()
# Replacement images.
SNAKE_IMAGE = pygame.Surface((30, 30))
SNAKE_IMAGE.fill((30, 150, 0))
APPLE_IMAGE = pygame.Surface((30, 30))
APPLE_IMAGE.fill((150, 30, 0))
class Player:
def __init__(self):
self.x = display_rect.w // 2
self.y = display_rect.h - 30 - 5
self.image = SNAKE_IMAGE
# Create a rect with the size of the image at coords (0, 0).
self.rect = self.image.get_rect()
# Set the topleft coords of the rect.
self.rect.x = self.x
self.rect.y = self.y
self.x_change = 0
def update(self):
"""Move the player."""
self.x += self.x_change
# Always update the rect, because it's
# needed for the collision detection.
self.rect.x = self.x
def draw(self, display):
display.blit(self.image, self.rect)
class Enemy:
def __init__(self):
self.x = random.randint(0, display_rect.w - 30)
self.y = 1
self.image = APPLE_IMAGE
# You can also pass the coords directly to `get_rect`.
self.rect = self.image.get_rect(topleft=(self.x, self.y))
self.speed = 10
def change_x(self):
self.x = random.randint(0, display_rect.w - self.rect.w)
self.rect.x = self.x
def change_y(self):
self.y += self.speed
self.rect.y = self.y
def draw(self, display):
display.blit(self.image, self.rect)
def reset(self):
"""Reset self.y position."""
self.y = -30
player = Player()
enemy = Enemy()
dodged = 0
done = False
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_RIGHT:
player.x_change = 5
if event.key == pygame.K_LEFT:
player.x_change = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or pygame.K_LEFT:
player.x_change = 0
# Game logic.
player.update()
enemy.change_y()
# Brings enemy back to top once it has gotten to th bottom
if enemy.y > display_rect.h:
enemy.change_x()
dodged += 1
enemy.reset()
# Check if the player and the rect collide.
if player.rect.colliderect(enemy.rect):
print('Collided!')
# Draw everything.
display.fill(BLACK)
enemy.draw(display)
player.draw(display)
pygame.display.update()
clock.tick(60)
pygame.quit()
I've changed some more things (btw, better call the images self.image not thing ;)) especially in the classes:
The attributes of the classes should be in __init__ methods to make them instance attributes instead of class attributes (which get shared by all instances). Also, check out how to create instances of your classes.
The methods should all have self as their first parameter (that's a reference to the instance). To access the attributes inside of the classes prepend them with self, e.g. self.x += self.x_change.
The player.x += x_change line fits better inside the Player class' update method, so you can just update the position and other player attributes by calling player.update().
There's a convention that class names should be uppercase MyClass whereas instances should have lowercase names my_instance.

Categories

Resources