Pygame slow after python update - python

I am making a python game with pygame on my home computer for school running with python 3.6.3 and pygame 1.9.3. When working on my game I also worked at school where it was working correctly just slower as expected but when I started to load images it randomly choose the images and didn't load the correct ones on school computer not home one (I think this might be due to change in arrays and loading them). I soon found I was running python 3.5.3 at school and then when updating it the python and pygame, The game ran extremely slow and was unplayable. The images loaded correctly but the change in speed was extreme.
Summary:
Pygame at home working great pygame 1.9.3 python 3.6.3.
Working fine at school until loading images python 3.5.3.
Updating school corrected it but is now running unbearably slow.
I would love a fix for this problem either working for other python version or running at a variable speed for school computers.
If there is any optimisation that could be easily implemented that would be very useful as well as I am not sure how to load images effectively
Code:
import pygame
import random
import math
def main():
#load images?:
bg = pygame.image.load("background6.png")
wall = 100
zombies = []
currentnumber = 0
gamepaused = False
moveupx = False
movedownx = False
moveupy = False
movedowny = False
movex = 0
movey = 0
movespeed = 10
time10 = False
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
fullscreen = pygame.FULLSCREEN
pygame.init()
pygame.font.init()
myfont = pygame.font.SysFont('Comic Sans MS', 100)
clock = pygame.time.Clock()
clock.tick(30)
#creating sprite groups
heads = pygame.sprite.Group()
bodys = pygame.sprite.Group()
bullets = pygame.sprite.Group()
allsprites = pygame.sprite.Group()
players = pygame.sprite.Group()
playerr = Player()
allsprites.add(playerr)
players.add(playerr)
heads.add()
bodys.add()
gameDisplay = pygame.display.set_mode((1920, 1080), fullscreen)
pygame.display.set_caption("Last Stand")
gameExit = False
pygame.display.update()
#This will get the ticks from inisilising pygame in ms
pretime = pygame.time.get_ticks()
while not gameExit:
time = pygame.time.get_ticks()-pretime
#print (time/1000)
timerounded = round(time/1000)
timedisplay = round(time/1000,1)
spawnbullet = False
mouse = pygame.mouse.get_pos()
# background things
gameDisplay.fill(white)
gameDisplay.blit(bg, (0, 0))
if timerounded % 10 == 0:
if timerounded != currentnumber:
time10 = True
currentnumber = timerounded
else:
time10 = False
#start gameimput look e is event and it loops for each event in pygame
#IT WILL GO THOUGH EACH EVEN!!!!!!! SO CHEACK FOR EACH EVENT
for e in pygame.event.get():
if e.type == pygame.MOUSEBUTTONDOWN:
#so only if it will shoot foward NEED TO ADD FEEDBACK LATER
if mouse[0] < 1500:
spawnbullet = True
#so the problem is that if there is a key up for s then it would kill the key down for w as it would be set
# to 0
if e.type == pygame.KEYDOWN and e.key == pygame.K_w:
moveupy = True
if e.type == pygame.KEYDOWN and e.key == pygame.K_s:
movedowny = True
if e.type == pygame.KEYUP and e.key == pygame.K_w:
moveupy = False
if e.type == pygame.KEYUP and e.key == pygame.K_s:
movedowny = False
if e.type == pygame.KEYDOWN and e.key == pygame.K_a:
moveupx = True
if e.type == pygame.KEYDOWN and e.key == pygame.K_d:
movedownx = True
if e.type == pygame.KEYUP and e.key == pygame.K_a:
moveupx = False
if e.type == pygame.KEYUP and e.key == pygame.K_d:
movedownx = False
if e.type == pygame.QUIT:
gameExit = True
if e.type == pygame.KEYDOWN and e.key == pygame.K_ESCAPE:
gameDisplay = pygame.display.set_mode((1920, 1080), fullscreen)
gameExit = True
# CAHNGE BACK LATER
# END event loop
#LOGIC FOR MOVING THE PLAYER:
if moveupy == True:
movey = -movespeed
if movedowny == True:
movey = movespeed
if movedowny == False and moveupy == False:
movey = 0
if moveupx == True:
movex = -movespeed
if movedownx == True:
movex = movespeed
if movedownx == False and moveupx == False:
movex = 0
# Updating player have to do this at the start as need the angle and the top left cords
for player in players:
#REALLY NOT WOKRING THE MOVEX DOESNT WORK AND THE CHANGING HTE X AND WHY DOESNT WORK!!!
player.move(movex, movey)
angle, topleft = player.update(mouse)
# needed another name for bullet so went for bullett
if spawnbullet == True:
bullett = Bullet(angle, topleft)
#having the bullets only in the bullets class so it can render after the player
bullets.add(bullett)
#creating zombies
if random.randint(0,2) == 1:
ztype = "fast"
else:
ztype = "slow"
#so at the start it spawns one for sure
if time == 0:
startlocation = [5, random.randint(320, 920)]
zombies, heads, bodys = createz(zombies, ztype, startlocation, heads, bodys)
if random.randint(0,10000) >9950-(timerounded**2): #So the time incraeed the odds expernetray
startlocation = [5, random.randint(320, 920)]
# WOULD LIKE THE ZOMBIES TO RUN FASTER AS THE GAME GOES ON!
zombies, heads, bodys = createz(zombies, ztype, startlocation, heads, bodys)
#updating Z
zombies, totaldamnge = updatez(zombies, heads, bodys)
#updating bullets
for bullet in bullets:
bullet.update()
#print(totaldamnge)
wall -= totaldamnge
#Cheacking for hitting bullets
colstions(zombies, heads, bodys, bullets)
if time10 == True:
wall += 25
if wall >100: wall = 100
walltext = myfont.render(str(wall)+"%",False, (0, 0, 0))
gameDisplay.blit(walltext,(1600,100))
#print(wall)
timedisplayer = myfont.render(str(timedisplay) + "Seconds", False, (0, 0, 0))
gameDisplay.blit(timedisplayer, (10, 5))
#drawing:
#so cant use allsprites so might just wont have zomnbie head and zombie body in it
#I CAN CHANGE WHEN WHAT IS DRAW AND WHAT IS ON WHAT
bullets.draw(gameDisplay)
allsprites.draw(gameDisplay)
heads.draw(gameDisplay)
bodys.draw(gameDisplay)
pygame.display.update()
clock.tick(30)
def colstions(zombies, heads, bodys, bullets):
#so as having both hp and having the zombie having a head and body with 2 diffrent hitboxes
headdamage = 140
bodydamge = 60
#so this part had sooooooo many proplems frist with like all the while loops next spend a long time trying to find what was wrong when it was just the head in bodys and vis versa
if len(pygame.sprite.groupcollide(bullets, heads,False, False)) != 0 or len(pygame.sprite.groupcollide(bullets, bodys,False, False)) != 0:
for bullet in bullets:
hitthehead = False
hitthebody = False
zheadkilledzombie = False
zbodykilledzombie = False
counter1 = 0
counter2 = 0
for head in heads:
#so it doesnt make the bullet hit more than one zombie head
if hitthehead == False:
if pygame.sprite.collide_circle(bullet, head):
hp = zombies[counter1].hpordead(headdamage)
hitthehead = True
if hp <= 0:
zheadkilledzombie = True
head.kill()
print("hithead")
counter1 += 1
#so it doesnt check for body hits if it has hit a heah
if hitthehead == False:
for body in bodys:
if hitthebody == False:
#If it colldes and if the zombie is not already dead from the head shots
if pygame.sprite.collide_rect(bullet, body):
print("hitbody")
hp = zombies[counter2].hpordead(bodydamge)
hitthebody = True
if hp <= 0:
zbodykilledzombie = True
body.kill()
counter2 += 1
if hitthehead == True or hitthebody == True:
bullet.kill()
#so killing the head if the body hit killed the zombie
if zheadkilledzombie == True:
zombiekilled = False
counter3 = 0
for body in bodys:
if zombiekilled == False:
hp = zombies[counter3].hpordead(0)
if hp <= 0:
body.kill()
zombies.pop(counter3)
zombiekilled = True
counter3 += 1
#killing the body if killing is arealy dead
if zbodykilledzombie == True:
zombiekilled = False
counter4 = 0
for head in heads:
if zombiekilled == False:
hp = zombies[counter4].hpordead(0)
if hp <= 0:
head.kill()
zombies.pop(counter4)
zombiekilled = True
counter4 += 1
def createz(zombies, ztype, startlocation, heads, bodys, ):
createdzombie = Zombie(startlocation, ztype)
zombies.append(createdzombie)
Hcords = (startlocation[0]+20, startlocation[1]-57)
Bcords = (startlocation[0], startlocation[1])
#need to have it also say what type of z it is.
heads.add(head(Hcords,ztype))
bodys.add(body(Bcords,ztype))
print ("created")
#dont think i need to return?
return zombies, heads, bodys
def updatez(zombies, heads, bodys):
totaldamnge = 0
#somthing ent working
Hcordsx = []
Hcordsy = []
Bcordsx = []
Bcordsy = []
ATWALLupdateanimationN = []
for x in range(len(zombies)):
cords, walldamge, updateanimationN = zombies[x].update()
ATWALLupdateanimationN.append(updateanimationN)
totaldamnge += walldamge
#putting all the cords into arrays just after reading them
Hcordsx.append(cords[0]+ 20)
Hcordsy.append(cords[1] - 57)
Bcordsx.append(cords[0])
Bcordsy.append(cords[1])
counter = 0
for body in bodys:
Bcords = (Bcordsx[counter], Bcordsy[counter])
body.update(Bcords, ATWALLupdateanimationN[counter])
counter += 1
counter = 0
#I have to use the counter as cant do 1 per 1 on the head in heads thing so have to have a seperat counter
for head in heads:
Hcords = (Hcordsx[counter],Hcordsy[counter])
head.update(Hcords,ATWALLupdateanimationN[counter])
counter += 1
return zombies, totaldamnge
class Bullet(pygame.sprite.Sprite):
def __init__(self,angle, playerpos):
pygame.sprite.Sprite.__init__(self)
#Chanig the scale of the image so it doesnt stick out the gun too much
self.image = pygame.transform.rotozoom(pygame.image.load("bulletpixel 6.png"), angle, 0.8)
self.rect = self.image.get_rect()
self.speed = 60
self.angle = angle
self.rect.x = (self.rect.x + playerpos[0])
self.rect.y = (self.rect.y + playerpos[1])
def update(self):
#moging it depending on its angle. so spliting up to horizontal and vertical bny taking thee cos and sin of the angle
self.rect.x -= int(self.speed*math.cos(-self.angle*math.pi/180))
self.rect.y -= int(self.speed*math.sin(-self.angle*math.pi/180))
#could make this better for so when top of screen also deleate
if self.rect.x <= -5:
pygame.sprite.Sprite.kill(self)
if self.rect.y <= -20 or self.rect.y >= 2000:
pygame.sprite.Sprite.kill(self)
def kill(self):
pygame.sprite.Sprite.kill(self)
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.angle = 0
#for now sttg to to zombie as didnt save the player image
self.image = pygame.image.load("player2.png")
self.rect = self.image.get_rect()
#need to create an image for player.
#ok so got too choess so i could if e.type == MOUSEMOTION:
#and just have less than more than or like so i can 3 locations it is pointed or could have the player angle towards the mouse pointer and also the shotsneed to be angled anywhay so.
self.rect.x = 1600
self.rect.y = 600
self.center = self.image.get_rect().center
#setting the starting location
self.movingamoutx = 1640
self.movingamouty = 500
self.posforbullet = (1640, 500)
def update(self,mouse):
# SO THIS THIS IS MAD
#Code for making the player follow the mouse:
#First sets the image to the stating image if this is not here the image gets bugged out from rotating many times
self.image = pygame.image.load("player2.png")
#Taking the x and y apart from the mouse
mouse_x, mouse_y = mouse
#calulationg the relative position of the mouse by subtracting the player postion
#I subtracke the previs frame player pos to calulate the new anlge as that is the only way i can get the angle from the gun and not the player and so it will go to the curcer
#This does in fact make it be one frame behind for the angle but as it is 30 fps this will not make a differnce
#subtracking 10 so it comes from a but up from the center and so is on the cetner of the curcer
rel_x, rel_y = mouse_x - self.posforbullet[0], mouse_y - self.posforbullet[1]-10
#calqulating the angle by using atan2
#this takes 2 vectors and calclated the angle inbeween them NOT 100 ON THIS this is in rad so it needs to be degress so is changed to degress by timesing my 180/ pi
# also Return atan(y / x), in radians. The result is between -pi and pi. The vector in the plane from the origin to point (x, y) makes this angle with the positive X axis.
#The point of atan2() is that the signs of both inputs are known to it, so it can compute the correct quadrant for the angle. For example, atan(1) and atan2(1, 1) are both pi/4, but atan2(-1, -1) is -3*pi/4.
self.angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
#the angle is inverted so to make it be where it is pointed subtracted 180 degress
self.angle -= 180
#seting self.rotated to the image rotated to by the angle
self.rotated = pygame.transform.rotate(self.image, self.angle)
#getting the cords of the new rotated image
rotRect = self.rotated.get_rect()
#keeping the old center from before
rotRect.center = self.rotated.get_rect().center
#setting the new cords to image rotated cords, the adding is the amout that is getting moved by
self.rect = (rotRect[0]+ self.movingamoutx), (rotRect[1]+ self.movingamouty)
#setting the image to the new rotated one
self.image = self.rotated
#Creating a variable basited of the center of the rotated image so the bullet can shoot from the image then
#adding the move amouts to put it into spot then subtracting to make it really shoot from the barrel and not the
#true center
#self.posforbullet = (rotRect.center[0] + self.movingamoutx-int(math.cos(self.changedangle)*20) ,rotRect.center[1]+ self.movingamouty-40)
self.posforbullet = (rotRect.center[0] + self.movingamoutx-15 ,rotRect.center[1]+ self.movingamouty-45)
return self.angle, self.posforbullet
def move(self,movex, movey):
self.movingamoutx += movex
self.movingamouty += movey
#cheaking to see if the player is trying to go to far away
if self.movingamouty <= 320:
self.movingamouty = 320
elif self.movingamouty >= 840:
self.movingamouty = 840
if self.movingamoutx >= 1700:
self.movingamoutx = 1700
elif self.movingamoutx <= 1500:
self.movingamoutx = 1500
class head(pygame.sprite.Sprite):
def __init__(self,cords, type):
pygame.sprite.Sprite.__init__(self)
if type == "fast":
self.type = "fast"
self.image = pygame.transform.scale(pygame.image.load("fasthead.png"),[70,60])
else:
self.type = "slow"
self.image = pygame.transform.scale(pygame.image.load("slowhead.png"),[70,60])
self.rect = self.image.get_rect()
self.rect.x = cords[0]
self.rect.y = cords[1]
self.ticks = 0
self.putheadonbodyx = -11
self.putheadonbodyy = -2
self.firsttimewall = True
def update(self,newcords,updateanimationNumber):
self.ticks += 1
if updateanimationNumber != 100:
if self.firsttimewall == True:
self.firsttimewall = False
updateanimationNumber = 1
if self.type == "slow":
if updateanimationNumber == 2:
self.image = pygame.image.load("satwallhead1.png")
elif updateanimationNumber == 1:
self.image = pygame.image.load("satwallhead2.png")
if self.type == "fast":
if updateanimationNumber == 2:
self.image = pygame.image.load("fatwallhead1.png")
elif updateanimationNumber == 1:
self.image = pygame.image.load("fatwallhead2.png")
self.rect = self.image.get_rect()
self.rect.x = newcords[0] + self.putheadonbodyx
self.rect.y = newcords[1] + self.putheadonbodyy
def kill(self):
pygame.sprite.Sprite.kill(self)
class body(pygame.sprite.Sprite):
def __init__(self, cords, type):
pygame.sprite.Sprite.__init__(self)
if type == "fast":
self.type = "fast"
self.image = pygame.image.load("fastbody1.png")
self.tickamout = 10
else:
self.type = "slow"
self.image = pygame.image.load("slowbody1.png")
self.tickamout = 15
self.rect = self.image.get_rect()
self.rect.x = cords[0]
self.rect.y = cords[1]
self.ticks = 0
self.number = 0
self.firsttimewall = True
def update(self, newcords, Atwallnumber):
self.ticks += 1
if Atwallnumber == 100:
#This is so it only trys to change image it if is time to changer
if self.ticks % self.tickamout == 0:
self.number += 1
if self.number == 5:
self.number = 1
if self.type == "slow":
if self.number == 1:
self.image = pygame.image.load("slowbody1.png")
elif self.number == 2:
self.image = pygame.image.load("slowbody2.png")
elif self.number == 3:
self.image = pygame.image.load("slowbody3.png")
elif self.number == 4:
self.image = pygame.image.load("slowbody4.png")
elif self.type == "fast":
if self.number == 1:
self.image = pygame.image.load("fastbody1.png")
elif self.number == 2:
self.image = pygame.image.load("fastbody2.png")
elif self.number == 3:
self.image = pygame.image.load("fastbody3.png")
elif self.number == 4:
self.image = pygame.image.load("fastbody4.png")
self.rect = self.image.get_rect()
else:
self.atwall(Atwallnumber)
#Dont think that chaning the codes from the get rect will be too much of a problem and also could save the
#images beofre having ot load them
self.rect.x = newcords[0]
self.rect.y = newcords[1]
def atwall(self,updateanimationNumber):
#seeing if this is the first time
if self.firsttimewall == True:
self.firsttimewall = False
updateanimationNumber = 1
if self.type == "slow":
if updateanimationNumber == 2:
self.image = pygame.image.load("satwallbody1.png")
elif updateanimationNumber == 1:
self.image = pygame.image.load("satwallbody2.png")
else:
if updateanimationNumber == 2:
self.image = pygame.image.load("fatwallbody1.png")
elif updateanimationNumber == 1:
self.image = pygame.image.load("fatwallbody2.png")
self.rect = self.image.get_rect()
def kill(self):
pygame.sprite.Sprite.kill(self)
class Zombie():
def __init__(self, startlocation, ztype):
if ztype == "fast":
self.speed = 11
self.hp = 100
else:
self.speed = 6
self.hp = 200
self.location = startlocation
self.walldamage = 0
self.ticks = 0
#So it will stay 100 before it gets to the wall
self.updateanimationnumber = 100
def update(self):
if self.location[0] < 1300: #the y direction
self.walldamage = 0
self.location[0] += self.speed #as this should be 30 frams a second it should move 3 pixies each time
#so if at the wall
elif self.location[0] >= 1300:
self.walldamage = 0
#cjamge the % number to change how fast the wall dies
if self.ticks % 30 == 0:
self.walldamage = 5
self.updateanimationnumber = 1
#so it will have to hitting animation when dealing damgage
elif self.ticks % 15 == 0:
self.updateanimationnumber = 2
if self.ticks % 15 != 0:
self.updateanimationnumber = 0
self.ticks += 1
return self.location, self.walldamage, self.updateanimationnumber
def hpordead(self,subtrackhp):
self.hp -= subtrackhp
return self.hp
if __name__ == '__main__':
main()

You should load the images in the global scope or another module and import them and then reuse them in your program. Do not load them in your functions or __init__ methods that get called in the while loop all the time or when you create an instance. Reading from the hard disk is slow.
Also, use the convert or convert_alpha methods of surfaces to improve the performance (converted surfaces get blitted faster), e.g.:
# All uppercase letters indicate that it's a constant and should never be changed.
MY_IMAGE = pygame.image.load('my_image.png').convert() # Or `.convert_alpha()`
# Load the images once at program start. You can also do that in
# another module and import them or load all images automatically
# and put them into a dictionary.
PLAYER_IMAGE = pygame.image.load("player2.png").convert_alpha()
BULLET_IMAGE = pygame.image.load("bulletpixel 6.png").convert_alpha()
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = PLAYER_IMAGE # Either assign the global image directly ...
#-----------------------------------
# or pass the image to __init__.
def __init__(self, image):
pygame.sprite.Sprite.__init__(self)
self.image = image
player = Player(PLAYER_IMAGE)
In the Bullet class you can rotate the original image. transform.rototzoom creates a new surface/image and doesn't modify the original.
class Bullet(pygame.sprite.Sprite):
def __init__(self, angle, playerpos):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.transform.rotozoom(BULLET_IMAGE, angle, 0.8)

You load images too many times. Load them only once in __init__ and later assign from one variable to another.
For example in Player load image to self.original and later assign
self.image = self.original
or
self.image = pygame.transform.rotate(self.original, self.angle)
Similar with
self.number += 1
if self.number == 5:
self.number = 1
if self.type == "slow":
if self.number == 1:
self.image = pygame.image.load("slowbody1.png")
elif self.number == 2:
self.image = pygame.image.load("slowbody2.png")
elif self.number == 3:
self.image = pygame.image.load("slowbody3.png")
elif self.number == 4:
self.image = pygame.image.load("slowbody4.png")
elif self.type == "fast":
if self.number == 1:
self.image = pygame.image.load("fastbody1.png")
elif self.number == 2:
self.image = pygame.image.load("fastbody2.png")
elif self.number == 3:
self.image = pygame.image.load("fastbody3.png")
elif self.number == 4:
self.image = pygame.image.load("fastbody4.png")
load all images in __init__ to two list
self.slowimages = [
pygame.image.load("slowbody1.png"),
pygame.image.load("slowbody2.png"),
pygame.image.load("slowbody3.png"),
pygame.image.load("slowbody4.png"),
]
self.fastimages = [
pygame.image.load("fastbody1.png"),
pygame.image.load("fastbody2.png"),
pygame.image.load("fastbody3.png"),
pygame.image.load("fastbody4.png"),
]
and later you can assign image without if/elif using one line
if self.type == "slow":
self.image = self.slowimages[self.number - 1]
elif self.type == "fast":
self.image = self.fastimages[self.number - 1]
or even load all in one dictionary with two lists
self.all_images = {
"slow": [
pygame.image.load("slowbody1.png"),
pygame.image.load("slowbody2.png"),
pygame.image.load("slowbody3.png"),
pygame.image.load("slowbody4.png"),
],
"fast": [
pygame.image.load("fastbodu1.png"),
pygame.image.load("fastbodu2.png"),
pygame.image.load("fastbodu3.png"),
pygame.image.load("fastbodu4.png"),
],
]
and later you can assign image without if/elif using one line
self.image = self.all_images[self.type][self.number - 1]
BTW in self.number you could keep values 0..3 instead of 1..4 and then in self.all_images[self.type][self.number - 1] you could use self.number instead of self.number - 1
And then instead of
self.number += 1
if self.number == 5:
self.number = 1
you can use modulo and get one line
self.number = (self.number + 1) % 4
Instead of
self.rect.x = newcords[0]
self.rect.y = newcords[1]
you can do in one line
self.rect.topleft = newcords

Related

Sprite Jittering and Repeatedly Bliting Inside Pygame Project

I have been having this issue where when i run my code, the sprites keep jittering even though the screen doesn't force them to do this.
This is where I define the screen size
This is where I update my actions and draw
Here is the part where I load my images from the spritesheet
Any help will be much appreciated.
I tried importing the sprites from the spritesheet onto the game with the animations all working however there are no animations and the sprite continues to jitter up and down
if you would like the code for my fighter class please see below:
def load_images(self, sprite_sheet, animation_steps):
#extract the certain animation images from spritesheet
animation_list = []
for y, animation in enumerate(animation_steps):
temporary_img_list = []
for x in range(animation):
temporaryimg = sprite_sheet.subsurface(x , y , self.size, self.size)
temporary_img_list.append(pygame.transform.scale(temporaryimg, (self.size * self.image_scale, self.image_scale * self.size)))
animation_list.append(temporary_img_list)
print(animation_list)
return animation_list
def move(self, screen_base, screen_height, surface, target):
speed = 10
gravity = 2
dx = 0
dy = 0
self.running = False
self.attack_type = 0
#key-presses recall
key = pygame.key.get_pressed() = pygame.key.get_pressed()
#can only happen if no other attack is occuring
if self.attacking == False:
#movement defined here
if key[pygame.K_a]:
dx = -speed
self.running = True
if key[pygame.K_d]:
dx = speed
self.running = True
#jump is defined here
if key[pygame.K_w] and self.jump == False:
self.vel_y = -30
self.jump = True
#attack is defined here
if key[pygame.K_k] or key[pygame.K_j]:
self.attack(surface, target)
#determine which attack type was used when the key was pressed
if key[pygame.K_k]:
self.attack_type = 1
if key[pygame.K_j]:
self.attack_type = 2
#apply gravity for the jumps
self.vel_y += gravity
dy += self.vel_y
#this makes sure that the character does not go off the screen
if self.rect.left + dx < 0:
dx = -self.rect.left
if self.rect.right + dx > screen_base:
dx = screen_base - self.rect.right
if self.rect.bottom + dy > screen_height - 207:
self.vel_y = 0
self.jump = False
dy = screen_height - 207 - self.rect.bottom
#ensures the players face each other
if target.rect.centerx > self.rect.centerx:
self.flip = False
else:
self.flip = True
#apply the attack cooldown to balance the amount of attacks possible
if self.attack_cooldown > 0:
self.attack_cooldown -= 1
#update the player position constantly
self.rect.x += dx
self.rect.y += dy
#handle the animation updates
def update(self):
#check what action the player is currently doing
if self.health <= 0:
self.health = 0
self.alive = False
self.update_action(6)
elif self.hit == True:
self.update_action(5)
elif self.attacking == True:
if self.attack_type == 1:
self.update_action(5) # 3 = Attack
elif self.attack_type == 2:
self.update_action(6) # 4 = Attack2
elif self.jump == True:
self.update_action(7) # 7 = Jump
elif self.running == True:
self.update_action(2) # 2 = Run
else:
self.update_action(0) # 0 = Idle
animation_cooldown = 50
#update the image
self.image = self.animation_list[self.action][self.frameindex]
#check if enough time has passed since the last update
if pygame.time.get_ticks() - self.update_time > animation_cooldown:
self.frameindex += 1
self.updatetime = pygame.time.get_ticks()
#check if the animation has finished
if self.frameindex >= len(self.animation_list[self.action]):
#if the player is dead end the animation
if self.alive == False:
self.frameindex = len(self.animation_list[self.action]) - 1
else:
self.frameindex = 0
#check if an attack was executed
if self.action == 5 or self.action == 6:
self.attacking = False
self.attack_cooldown = 20
#check if damage was taken
if self.action == 7:
self.hit = False
#if the player was in the middle on an attack, then the attack is stopped
self.attacking= False
self.attack_cooldown = 20
def attack(self, surface, target):
if self.attack_cooldown == 0:
self.attacking = True
attacking_rect = pygame.Rect(self.rect.centerx - (2 * self.rect.width * self.flip), self.rect.y, 2 * self.rect.width, self.rect.height)
if attacking_rect.colliderect(target.rect):
target.health -= 5
target.hit = True
pygame.draw.rect(surface, (0, 255, 0), attacking_rect)
def update_action(self, new_action):
#check if the new action is different to the previous one
if new_action != self.action:
self.action = new_action
#update the animation settings
self.frameindex = 0
self.update_time = pygame.time.get_ticks()
def draw(self, surface):
img = pygame.transform.flip(self.image, self.flip, False)
#pygame.draw.rect(surface,(255, 0, 0), self.rect)
surface.blit(img, (self.rect.x - (self.offset[0] * self.image_scale), self.rect.y - (self.offset[1] * self.image_scale)))
Most likely the sprites are not cropped well from the sprite sheet. If there is random spacing on the cropped sprites (for example: the sprites are different sizes or some sprites have a border at the bottom and some sprites have a border at the top), then you get a jittery and wobbly character.

Pygame Error: loot() takes 2 positional arguments but 3 were given

I've been trying to follow this tutorial to include a coin in the game loot_1.png but when I get to the tutorial part that says ...Add the final line from the following code sample to your loop: and i try to compile my game.py file, the code breaks with the following error in my terminal:
#python game.py
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
run0(0, 528, 3)
run1(300, 400, 3)
run2(500, 528, 4)
Traceback (most recent call last):
File "game.py", line 252, in <module>
loot_list = Level.loot(1,tx,ty)
TypeError: loot() takes 2 positional arguments but 3 were given
I tried to find a solution by looking at the questions but without success: write() takes 2 positional arguments but 3 were given, TypeError: fit_transform() takes 2 positional arguments but 3 were given, TypeError: hook() takes 2 positional arguments but 3 were given, Pygame TypeError: update() takes 1 positional argument but 2 were given.
game.py
import pygame
import sys
import os
'''
Objects
'''
class Platform(pygame.sprite.Sprite):
# x location, y location, img width, img height, img file
def __init__(self,xloc,yloc,imgw,imgh,img):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('images',img)).convert()
self.image.convert_alpha()
self.rect = self.image.get_rect()
self.rect.y = yloc
self.rect.x = xloc
class Player(pygame.sprite.Sprite):
'''
Spawn a player
'''
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.health = 10
# gravity variables here
self.collide_delta = 0
self.jump_delta = 6
self.score = 1
self.images = []
for i in range(1,9):
img = pygame.image.load(os.path.join('images','spr' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(ALPHA)
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
def jump(self,platform_list):
self.jump_delta = 0
def gravity(self):
self.movey += 3.2 # how fast player falls
if self.movey >= 15:
self.movey = 6
if self.rect.bottom > worldy and self.movey >= 0: # <-- uses bottom
self.movey = 0
self.rect.bottom = worldy # <-- uses bottom
def control(self,x,y):
'''
control player movement
'''
self.movex += x
self.movey += y
def update(self):
'''
Update sprite position
'''
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
for p in plat_hit_list:
self.collide_delta = 0 # stop jumping
self.movey = 0
if self.rect.y > p.rect.y:
self.rect.y = p.rect.y+ty
else:
self.rect.y = p.rect.y-ty
if self.collide_delta < 6 and self.jump_delta < 6:
self.jump_delta = 6*2
self.movey -= 33 # how high to jump
self.collide_delta += 6
self.jump_delta += 6
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 > ani*3:
self.frame = 0
self.image = self.images[self.frame//ani]
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > ani*3:
self.frame = 0
self.image = self.images[(self.frame//ani)+4]
# collisions
enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
for enemy in enemy_hit_list:
self.health -= 1
print(self.health)
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
for p in plat_hit_list:
self.rect.bottom = p.rect.top
self.collide_delta = 0 # <----- this is missing
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
for g in ground_hit_list:
self.movey = 0
self.rect.y = worldy-ty-ty
self.collide_delta = 0 # stop jumping
if self.rect.y > g.rect.y:
self.health -= 1
print(self.health)
class Enemy(pygame.sprite.Sprite):
'''
Spawn an enemy
'''
def __init__(self,x,y,img):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('images',img))
#self.image.convert_alpha()
#self.image.set_colorkey(ALPHA)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.counter = 0
def move(self):
'''
enemy movement
'''
distance = 80
speed = 8
if self.counter >= 0 and self.counter <= distance:
self.rect.x += speed
elif self.counter >= distance and self.counter <= distance*2:
self.rect.x -= speed
else:
self.counter = 0
self.counter += 1
class Level():
def bad(lvl,eloc):
if lvl == 1:
enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
enemy_list = pygame.sprite.Group() # create enemy group
enemy_list.add(enemy) # add enemy to group
if lvl == 2:
print("Level " + str(lvl) )
return enemy_list
def loot(lvl,lloc):
if lvl == 1:
loot_list = pygame.sprite.Group()
loot = Platform(300,ty*7,tx,ty, 'loot_1.png')
loot_list.add(loot)
if lvl == 2:
print(lvl)
return loot_list
def loot(lvl,lloc):
print(lvl)
def ground(lvl,gloc,tx,ty):
ground_list = pygame.sprite.Group()
i=0
if lvl == 1:
while i < len(gloc):
ground = Platform(gloc[i],worldy-ty,tx,ty,'ground.png')
ground_list.add(ground)
i=i+1
if lvl == 2:
print("Level " + str(lvl) )
return ground_list
def platform(lvl,tx,ty):
plat_list = pygame.sprite.Group()
ploc = []
i=0
if lvl == 1:
ploc.append((0,worldy-ty-128,3))
ploc.append((300,worldy-ty-256,3))
ploc.append((500,worldy-ty-128,4))
while i < len(ploc):
j=0
while j <= ploc[i][2]:
plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,'ground.png')
plat_list.add(plat)
j=j+1
print('run' + str(i) + str(ploc[i]))
i=i+1
if lvl == 2:
print("Level " + str(lvl) )
return plat_list
'''
Setup
'''
worldx = 760
worldy = 720
fps = 40 # frame rate
ani = 4 # animation cycles
clock = pygame.time.Clock()
pygame.init()
main = True
BLUE = (25,25,200)
BLACK = (23,23,23 )
WHITE = (254,254,254)
ALPHA = (0,255,0)
world = pygame.display.set_mode([worldx,worldy])
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
backdropbox = world.get_rect()
player = Player() # spawn player
player.rect.x = 0
player.rect.y = 0
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10 # how fast to move
forwardx = 600
backwardx = 230
eloc = []
eloc = [200,20]
gloc = []
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
tx = 64 #tile size
ty = 64 #tile size
i=0
while i <= (worldx/tx)+tx:
gloc.append(i*tx)
i=i+1
enemy_list = Level.bad( 1, eloc )
ground_list = Level.ground( 1,gloc,tx,ty )
plat_list = Level.platform( 1,tx,ty )
loot_list = Level.loot(1,tx,ty)
'''
Main loop
'''
while main == True:
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'):
print("LEFT")
player.control(-steps,0)
if event.key == pygame.K_RIGHT or event.key == ord('d'):
print("RIGHT")
player.control(steps,0)
if event.key == pygame.K_UP or event.key == ord('w'):
print('jump')
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)
if event.key == pygame.K_UP or event.key == ord('w'):
player.jump(plat_list)
if event.key == ord('q'):
pygame.quit()
sys.exit()
main = False
# scroll the world forward
if player.rect.x >= forwardx:
scroll = player.rect.x - forwardx
player.rect.x = forwardx
for p in plat_list:
p.rect.x -= scroll
for e in enemy_list:
e.rect.x -= scroll
# scroll the world backward
if player.rect.x <= backwardx:
scroll = backwardx - player.rect.x
player.rect.x = backwardx
for p in plat_list:
p.rect.x += scroll
## scrolling code above
world.blit(backdrop, backdropbox)
player.gravity() # check gravity
player.update()
player_list.draw(world)
enemy_list.draw(world)
ground_list.draw(world)
plat_list.draw(world)
loot_list.draw(world)
for e in enemy_list:
e.move()
pygame.display.flip()
clock.tick(fps)
content folder images:
For enemy (sprit) is yeti.png: https://imgur.com/GNNcU6z
For background is stage.png: https://imgur.com/YyiEJ0q
and the image of the player:
spr.png: https://imgur.com/1fYXa7Y
and the image of the loot_1.png:
https://opengameart.org/sites/default/files/loot_goldcoins_big.png
This appears to be an error in the tutorial itself.
In the previous part (the one about adding loot), they post this as the loot method:
def loot(lvl,lloc):
if lvl == 1:
loot_list = pygame.sprite.Group()
loot = Platform(300,ty*7,tx,ty, 'loot_1.png')
loot_list.add(loot)
if lvl == 2:
print(lvl)
return loot_list
This method takes 2 arguments (lvl and lloc), which you have included in your code (although twice for some reason, and not indented correctly).
Later on in that same part, as well as the part you linked, the same method is found in the "all the code you've written so far" code dump:
class Level():
...
def loot(lvl,tx,ty):
if lvl == 1:
loot_list = pygame.sprite.Group()
loot = Platform(200,ty*7,tx,ty, 'loot_1.png')
loot_list.add(loot)
if lvl == 2:
print(lvl)
return loot_list
Now, the method takes 3 arguments (lvl, tx, and ty). Based on the contents of the two definitions, and the fact that they are the same between them, I believe the second version is correct (def loot(lvl, tx, ty):...).
Finally, to answer the question, the error you're getting is coming from this discrepancy - you implemented the (incorrect) 2-argument version, while the rest of the tutorial code is expecting the 3-argument version.

Pygame - TypeError: Missing 1 required positional argument

I am building a game and I keep on running up against this error. I can't seem to fix it. I believe the problem is either in the function "main" at the bottom or in the classes "Level" and "Level01". If you find there is a way I can improve my code can you also tell me as I am just learning how to build games with OOP.
File "C:/Users/fabma/Documents/PythonGames/RPG/Scroller!.py", line 148, in main
currentLevel.drawer(display)
TypeError: drawer() missing 1 required positional argument: 'display1'
Here is my code:
import pygame
# Colours + Global constants
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WIDTH = 800
HEIGHT = 600
SIZE = (WIDTH, HEIGHT)
# CLASSES
# Block is the common platform
class Block(pygame.sprite.Sprite):
def __init__(self, length, height, colour):
super().__init__()
# Making image
self.image = pygame.Surface([length, height])
self.image.fill(colour)
self.rect = self.image.get_rect()
# Setting Y coordinates
self.rect.y = HEIGHT * 0.95
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
# Is it touching the floor?
self.velocity = 0
self.standing = True
# Rendering image and creating some variables
self.height = 40
self.length = 40
self.sprite_x_change = 0
self.sprite_y_change = 0
self.image = pygame.Surface([self.height, self.length])
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.y = HEIGHT * 0.884
self.level = None
# Mobility: Left, right, up and stop
def move_right(self):
self.sprite_x_change = 15
def move_left(self):
self.sprite_x_change = -15
def move_up(self, platform):
# Seeing if we hit anything if so then we can jump!
self.rect.y -= 2
hit_list = pygame.sprite.spritecollide(self, platform, False)
if len(hit_list) > 0 or self.rect.bottom >= HEIGHT - Block.height:
self.change_y = -10
def stop(self):
self.sprite_x_change = 0
def updater(self):
self.gravity()
platforms_hit = pygame.sprite.spritecollide(self, self.level.platforms, False)
for blocks in platforms_hit:
self.sprite_y_change = 0
# Going down
if self.sprite_y_change > 0:
self.rect.bottom = blocks.rect.top
self.velocity = 0
self.standing = True
# Going up
if self.sprite_y_change < 0:
self.rect.top = blocks.rect.bottom
self.standing = False
if self.sprite_x_change > 0:
self.rect.right = blocks.rect.left
if self.sprite_x_change < 0:
self.rect.left = blocks.rect.right
if self.sprite_x_change == 0 and self.sprite_y_change == 0:
self.rect.y = HEIGHT * 0.884
if self.standing == False:
self.velocity += 1
self.rect.x += self.sprite_x_change
self.rect.y += self.sprite_y_change
def gravity(self):
self.sprite_y_change += 0.980665*self.velocity
class Level:
def __init__(self):
# Creating groups
self.sprites = pygame.sprite.Group()
self.all_things = pygame.sprite.Group()
self.platforms = pygame.sprite.Group()
def drawer(self, display1):
display1.fill(BLUE)
self.all_things.draw(display1)
class Level01(Level):
def __init__(self, player1):
# Initialise level1
Level.__init__(self)
# Level01 things
block = Block(WIDTH, HEIGHT * 0.05, RED)
Level.all_things = self.all_things
self.sprites.add(player1)
self.platforms.add(block)
self.all_things.add(player1, block)
def main():
# Init pygame
pygame.init()
# Set screen
display = pygame.display.set_mode(SIZE)
# Creating FPS thingy
clock = pygame.time.Clock()
# Making levels + Player
player = Player()
level_1 = Level01(player)
# Choosing level
levelList = []
levelList.append(Level01)
currentLevelNumber = 0
currentLevel = levelList[currentLevelNumber]
# Game loop
loop = True
while loop == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player.move_right()
if event.key == pygame.K_LEFT:
player.move_left()
if event.key == pygame.K_UP:
player.move_up(currentLevel.platforms)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and player.sprite_x_change < 0:
player.stop()
if event.key == pygame.K_RIGHT and player.sprite_x_change > 0:
player.stop()
# Update things
currentLevel.all_things.update()
currentLevel.drawer(display)
# Refresh screen
clock.tick(30)
pygame.display.update()
pygame.quit()
if __name__ == "__main__":
main()
You need to create an instance of your level rather than just appending the class itself into your list:
levelList.append(Level01)
should be...
levelList.append(level_1)
As it stands, you're using the class object rather than an instance of it, which means that the display you're passing is getting put into the self argument (because the class object won't pass along an instance, because it's not one). Once you're calling it on an instance of the class, the self argument will be automatically passed and thus your display argument will get passed to the correct spot.

How to load pictures in pygame? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
I am using pygame to make a game but when I try to load my pictures it results in a error: Couldn't open ball.png. can any one please help? here is my entire code.
To be exact I am trying to figure out why in the class BoxSprite class does ("ball.png") not load. Also why does that happen in class missle and class gun with ("arrow.png") and ("gun.png")???
import pygame
import sys
from pygame.locals import KEYDOWN, KEYUP, K_SPACE, K_ESCAPE, K_RIGHT, K_LEFT
width = 320
height = 240
imageWidth = 32
imageHeight = 32
goingLeft = True
invaderHeight = 0
gunLeft = False
gunRight = False
gunXpos = (width/2)-(imageWidth/2)
delay = 10
class BoxSprite(pygame.sprite.Sprite):
image = None
def __init__(self, initial_position):
pygame.sprite.Sprite.__init__(self)
if BoxSprite.image is None:
BoxSprite.image = pygame.image.load("ball.png")
self.image = BoxSprite.image
self.rect = self.image.get_rect()
self.rect.topleft = initial_position
self.next_update_time = 0 # update() hasn't been called yet.
self.yPos = initial_position[1]
def update(self, current_time, left, right):
global goingLeft, invaderHeight, imageWidth, delay
# Update every 2 milliseconds = 1/500th of a second.
if self.next_update_time < current_time:
# If we're at the left or right the screen, switch directions.
if self.rect.topleft[0] == left:
goingLeft = False
invaderHeight += 1
elif self.rect.topleft[0] == right-imageWidth:
goingLeft = True
invaderHeight += 1
if goingLeft == True:
self.rect.topleft = [self.rect.topleft[0]-1, self.rect.topleft[1]]
else:
self.rect.topleft = [self.rect.topleft[0]+1, self.rect.topleft[1]]
self.rect.topleft = [self.rect.topleft[0], invaderHeight+self.yPos]
self.next_update_time = current_time + delay
class missile(pygame.sprite.Sprite):
image = None
def __init__(self, initial_position):
pygame.sprite.Sprite.__init__(self)
if missile.image is None:
missile.image = pygame.image.load("arrow.png")
self.image = missile.image
self.rect = self.image.get_rect()
self.rect.topleft = initial_position
self.next_update_time = 0 # update() hasn't been called yet.
def update(self, current_time, left, right):
global missile
# Update every 2 milliseconds = 1/500th of a second.
if self.next_update_time < current_time:
# If we're reached the top then stop
if self.rect.topleft[1] == 0:
missiles.remove(self)
self.kill()
return
else:
self.rect.topleft = [self.rect.topleft[0], self.rect.topleft[1]-1]
self.next_update_time = current_time + 4
class gun(pygame.sprite.Sprite):
image = None
def __init__(self):
global width, imageHeight, gunXpos
pygame.sprite.Sprite.__init__(self)
if gun.image is None:
gun.image = pygame.image.load("gun.png")
self.image = gun.image
self.rect = self.image.get_rect()
self.rect.topleft = [gunXpos, height-imageHeight]
self.next_update_time = 0 # update() hasn't been called yet.
def update(self, current_time, left, right):
global gunXpos, width, imageWidth
# check update
if self.next_update_time < current_time:
if gunLeft and gunXpos>0:
gunXpos -= 1
if gunRight and gunXpos<width-imageWidth:
gunXpos += 1
self.rect.topleft = [gunXpos, self.rect.topleft[1]]
self.next_update_time = current_time + 1
def checkInput():
global gunLeft, gunRight, missiles, gunXpos, height
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
sys.exit(0)
elif event.key == K_RIGHT:
gunLeft = False
gunRight = True
elif event.key == K_LEFT:
gunLeft = True
gunRight = False
else:
missiles.append(missile([gunXpos, height]))
elif event.type == KEYUP and event.key != K_SPACE:
gunRight = False
gunLeft = False
def checkCollisions():
global missiles, boxes
if missiles != [] and boxes != []:
for m in missiles:
found = False
for b in pygame.sprite.spritecollide(m, boxes, 0):
boxes.remove(b)
b.kill()
found = True
if found:
missiles.remove(m)
m.kill()
pygame.init()
boxes = []
missiles = []
for x in range(0, width, 32):
for y in range(0, 96, 32):
boxes.append(BoxSprite([x, y]))
screen = pygame.display.set_mode([320, 240])
gunControl = gun()
while boxes != []:
screen.fill([0, 0, 0]) # blank the screen.
time = pygame.time.get_ticks()
for b in boxes:
b.update(time, 0, width)
screen.blit(b.image, b.rect)
checkInput()
checkCollisions()
gunControl.update(time, 0, width)
screen.blit(gunControl.image, gunControl.rect)
for m in missiles:
m.update(time, 0, width)
screen.blit(m.image, m.rect)
pygame.display.update()
if pygame.sprite.spritecollide(gunControl, boxes, 0) != []:
pygame.time.delay(50)
print ("loser")
sys.exit(0)
if len(boxes)<10:
delay = len(boxes)
pygame.time.delay(50)
print ("winner")
http://www.pygame.org/docs/ref/image.html#pygame.image.load
you can use pygame.image.load(os.path.join('path', 'to', 'image.png'))
which returns a Surface object. You should then be able to set your sprite's image attribute to equal this value.
like so:
def __init__(self, initial_position):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join("path", "to", "ball.png"))

Add collison detection to enemy sprites?

i'd like to add the same collision detection used by the player sprite to the enemy sprites or 'creeps' ive added all the relevant code I can see yet collisons are still not being detected and handled, please find below the class, I have no idea what is wrong currently, the list of walls to collide with is 'wall_list'
import pygame
import pauseScreen as dm
import re
from pygame.sprite import Sprite
from pygame import Rect, Color
from random import randint, choice
from vec2d import vec2d
from simpleanimation import SimpleAnimation
import displattxt
black = (0,0,0)
white = (255,255,255)
blue = (0,0,255)
green = (101,194,151)
global currentEditTool
currentEditTool = "Tree"
global editMap
editMap = False
open('MapMaker.txt', 'w').close()
def draw_background(screen, tile_img):
screen.fill(black)
img_rect = tile_img.get_rect()
global rect
rect = img_rect
nrows = int(screen.get_height() / img_rect.height) + 1
ncols = int(screen.get_width() / img_rect.width) + 1
for y in range(nrows):
for x in range(ncols):
img_rect.topleft = (x * img_rect.width,
y * img_rect.height)
screen.blit(tile_img, img_rect)
def changeTool():
if currentEditTool == "Tree":
None
elif currentEditTool == "Rock":
None
def pauseGame():
red = 255, 0, 0
green = 0,255, 0
blue = 0, 0,255
screen.fill(black)
pygame.display.update()
if editMap == False:
choose = dm.dumbmenu(screen, [
'Resume',
'Enable Map Editor',
'Quit Game'], 64,64,None,32,1.4,green,red)
if choose == 0:
print("hi")
elif choose ==1:
global editMap
editMap = True
elif choose ==2:
print("bob")
elif choose ==3:
print("bob")
elif choose ==4:
print("bob")
else:
None
else:
choose = dm.dumbmenu(screen, [
'Resume',
'Disable Map Editor',
'Quit Game'], 64,64,None,32,1.4,green,red)
if choose == 0:
print("Resume")
elif choose ==1:
print("Dis ME")
global editMap
editMap = False
elif choose ==2:
print("bob")
elif choose ==3:
print("bob")
elif choose ==4:
print("bob")
else:
None
class Wall(pygame.sprite.Sprite):
# Constructor function
def __init__(self,x,y,width,height):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([width, height])
self.image.fill(green)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class insertTree(pygame.sprite.Sprite):
def __init__(self,x,y,width,height, typ):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images/map/tree.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class insertRock(pygame.sprite.Sprite):
def __init__(self,x,y,width,height, typ):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("images/map/rock.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Creep(pygame.sprite.Sprite):
""" A creep sprite that bounces off walls and changes its
direction from time to time.
"""
change_x=0
change_y=0
def __init__(
self, screen, creep_image, explosion_images,
field, init_position, init_direction, speed):
""" Create a new Creep.
screen:
The screen on which the creep lives (must be a
pygame Surface object, such as pygame.display)
creep_image:
Image (surface) object for the creep
explosion_images:
A list of image objects for the explosion
animation.
field:
A Rect specifying the 'playing field' boundaries.
The Creep will bounce off the 'walls' of this
field.
init_position:
A vec2d or a pair specifying the initial position
of the creep on the screen.
init_direction:
A vec2d or a pair specifying the initial direction
of the creep. Must have an angle that is a
multiple of 45 degres.
speed:
Creep speed, in pixels/millisecond (px/ms)
"""
Sprite.__init__(self)
self.screen = screen
self.speed = speed
self.field = field
self.rect = creep_image.get_rect()
# base_image holds the original image, positioned to
# angle 0.
# image will be rotated.
#
self.base_image = creep_image
self.image = self.base_image
self.explosion_images = explosion_images
# A vector specifying the creep's position on the screen
#
self.pos = vec2d(init_position)
# The direction is a normalized vector
#
self.direction = vec2d(init_direction).normalized()
self.state = Creep.ALIVE
self.health = 15
def is_alive(self):
return self.state in (Creep.ALIVE, Creep.EXPLODING)
def changespeed(self,x,y):
self.change_x+=x
self.change_y+=y
def update(self, time_passed, walls):
""" Update the creep.
time_passed:
The time passed (in ms) since the previous update.
"""
if self.state == Creep.ALIVE:
# Maybe it's time to change the direction ?
#
self._change_direction(time_passed)
# Make the creep point in the correct direction.
# Since our direction vector is in screen coordinates
# (i.e. right bottom is 1, 1), and rotate() rotates
# counter-clockwise, the angle must be inverted to
# work correctly.
#
self.image = pygame.transform.rotate(
self.base_image, -self.direction.angle)
# Compute and apply the displacement to the position
# vector. The displacement is a vector, having the angle
# of self.direction (which is normalized to not affect
# the magnitude of the displacement)
#
displacement = vec2d(
self.direction.x * self.speed * time_passed,
self.direction.y * self.speed * time_passed)
self.pos += displacement
# When the image is rotated, its size is changed.
# We must take the size into account for detecting
# collisions with the walls.
#
self.image_w, self.image_h = self.image.get_size()
bounds_rect = self.field.inflate(
-self.image_w, -self.image_h)
if self.pos.x < bounds_rect.left:
self.pos.x = bounds_rect.left
self.direction.x *= -1
elif self.pos.x > bounds_rect.right:
self.pos.x = bounds_rect.right
self.direction.x *= -1
elif self.pos.y < bounds_rect.top:
self.pos.y = bounds_rect.top
self.direction.y *= -1
elif self.pos.y > bounds_rect.bottom:
self.pos.y = bounds_rect.bottom
self.direction.y *= -1
# collision detection
old_x=bounds_rect.left
new_x=old_x+self.direction.x
bounds_rect.left = new_x
# hit a wall?
collide = pygame.sprite.spritecollide(self, walls, False)
if collide:
# yes
bounds_rect.left=old_x
old_y=self.pos.y
new_y=old_y+self.direction.y
self.pos.y = new_y
collide = pygame.sprite.spritecollide(self, walls, False)
if collide:
# yes
self.pos.y=old_y
elif self.state == Creep.EXPLODING:
if self.explode_animation.active:
self.explode_animation.update(time_passed)
else:
self.state = Creep.DEAD
self.kill()
elif self.state == Creep.DEAD:
pass
#------------------ PRIVATE PARTS ------------------#
# States the creep can be in.
#
# ALIVE: The creep is roaming around the screen
# EXPLODING:
# The creep is now exploding, just a moment before dying.
# DEAD: The creep is dead and inactive
#
(ALIVE, EXPLODING, DEAD) = range(3)
_counter = 0
def _change_direction(self, time_passed):
""" Turn by 45 degrees in a random direction once per
0.4 to 0.5 seconds.
"""
self._counter += time_passed
if self._counter > randint(400, 500):
self.direction.rotate(45 * randint(-1, 1))
self._counter = 0
def _point_is_inside(self, point):
""" Is the point (given as a vec2d) inside our creep's
body?
"""
img_point = point - vec2d(
int(self.pos.x - self.image_w / 2),
int(self.pos.y - self.image_h / 2))
try:
pix = self.image.get_at(img_point)
return pix[3] > 0
except IndexError:
return False
def _decrease_health(self, n):
""" Decrease my health by n (or to 0, if it's currently
less than n)
"""
self.health = max(0, self.health - n)
if self.health == 0:
self._explode()
def _explode(self):
""" Starts the explosion animation that ends the Creep's
life.
"""
self.state = Creep.EXPLODING
pos = ( self.pos.x - self.explosion_images[0].get_width() / 2,
self.pos.y - self.explosion_images[0].get_height() / 2)
self.explode_animation = SimpleAnimation(
self.screen, pos, self.explosion_images,
100, 300)
global remainingCreeps
remainingCreeps-=1
if remainingCreeps == 0:
print("all dead")
def draw(self):
""" Blit the creep onto the screen that was provided in
the constructor.
"""
if self.state == Creep.ALIVE:
# The creep image is placed at self.pos. To allow for
# smooth movement even when the creep rotates and the
# image size changes, its placement is always
# centered.
#
self.draw_rect = self.image.get_rect().move(
self.pos.x - self.image_w / 2,
self.pos.y - self.image_h / 2)
self.screen.blit(self.image, self.draw_rect)
# The health bar is 15x4 px.
#
health_bar_x = self.pos.x - 7
health_bar_y = self.pos.y - self.image_h / 2 - 6
self.screen.fill( Color('red'),
(health_bar_x, health_bar_y, 15, 4))
self.screen.fill( Color('green'),
( health_bar_x, health_bar_y,
self.health, 4))
elif self.state == Creep.EXPLODING:
self.explode_animation.draw()
elif self.state == Creep.DEAD:
pass
def mouse_click_event(self, pos):
""" The mouse was clicked in pos.
"""
if self._point_is_inside(vec2d(pos)):
self._decrease_health(3)
#begin new player
class Player(pygame.sprite.Sprite):
change_x=0
change_y=0
frame = 0
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
# LOAD PLATER IMAGES
# Set height, width
self.images = []
for i in range(1,17):
img = pygame.image.load("images/player/" + str(i)+".png").convert() #player images
img.set_colorkey(white)
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.health = 15
self.image_w, self.image_h = self.image.get_size()
health_bar_x = self.rect.x - 7
health_bar_y = self.rect.y - self.image_h / 2 - 6
screen.fill( Color('red'),
(health_bar_x, health_bar_y, 15, 4))
screen.fill( Color('green'),
( health_bar_x, health_bar_y,
self.health, 4))
def changespeed(self,x,y):
self.change_x+=x
self.change_y+=y
def _decrease_health(self, n):
""" Decrease my health by n (or to 0, if it's currently
less than n)
"""
self.health = max(0, self.health - n)
if self.health == 0:
self._explode()
def update(self,walls):
# collision detection
old_x=self.rect.x
new_x=old_x+self.change_x
self.rect.x = new_x
# hit a wall?
collide = pygame.sprite.spritecollide(self, walls, False)
if collide:
# yes
self.rect.x=old_x
old_y=self.rect.y
new_y=old_y+self.change_y
self.rect.y = new_y
collide = pygame.sprite.spritecollide(self, walls, False)
if collide:
# yes
self.rect.y=old_y
# right to left
if self.change_x < 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
# Grab the image, divide by 4
# every 4 frames.
self.image = self.images[self.frame//4]
# Move left to right.
# images 4...7 instead of 0...3.
if self.change_x > 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4+4]
if self.change_y > 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4+4+4]
if self.change_y < 0:
self.frame += 1
if self.frame > 3*4:
self.frame = 0
self.image = self.images[self.frame//4+4+4+4]
score = 0
# initialize pyGame
pygame.init()
# 800x600 sized screen
global screen
screen = pygame.display.set_mode([800, 600])
screen.fill(black)
#bg_tile_img = pygame.image.load('images/map/grass.png').convert_alpha()
#draw_background(screen, bg_tile_img)
#pygame.display.flip()
# Set title
pygame.display.set_caption('Test')
#background = pygame.Surface(screen.get_size())
#background = background.convert()
#background.fill(black)
# Create the player
player = Player( 50,50 )
player.rect.x=50
player.rect.y=50
movingsprites = pygame.sprite.RenderPlain()
movingsprites.add(player)
# Make the walls. (x_pos, y_pos, width, height)
global wall_list
wall_list=pygame.sprite.RenderPlain()
wall=Wall(0,0,10,600) # left wall
wall_list.add(wall)
wall=Wall(10,0,790,10) # top wall
wall_list.add(wall)
#wall=Wall(10,200,100,10) # poke wall
wall_list.add(wall)
wall=Wall(790,0,10,600) #(x,y,thickness, height)
wall_list.add(wall)
wall=Wall(10,590,790,10) #(x,y,thickness, height)
wall_list.add(wall)
f = open('MapMaker.txt')
num_lines = sum(1 for line in f)
print(num_lines)
lineCount = 0
with open("MapMaker.txt") as infile:
for line in infile:
f = open('MapMaker.txt')
print(line)
coords = line.split(',')
#print(coords[0])
#print(coords[1])
#print(coords[2])
#print(coords[3])
#print(coords[4])
if "tree" in line:
print("tree in")
wall=insertTree(int(coords[0]),int(coords[1]), int(coords[2]),int(coords[3]),coords[4])
wall_list.add(wall)
elif "rock" in line:
print("rock in")
wall=insertRock(int(coords[0]),int(coords[1]), int(coords[2]),int(coords[3]),coords[4] )
wall_list.add(wall)
width = 20
height = 540
height = height - 48
for i in range(0,23):
width = width + 32
name = insertTree(width,540,790,10,"tree")
#wall_list.add(name)
name = insertTree(width,height,690,10,"tree")
#wall_list.add(name)
CREEP_SPAWN_TIME = 200 # frames
creep_spawn = CREEP_SPAWN_TIME
clock = pygame.time.Clock()
bg_tile_img = pygame.image.load('images/map/grass.png').convert()
img_rect = bg_tile_img
FIELD_RECT = Rect(50, 50, 700, 500)
CREEP_FILENAMES = [
'images/player/1.png',
'images/player/1.png',
'images/player/1.png']
N_CREEPS = 3
creep_images = [
pygame.image.load(filename).convert_alpha()
for filename in CREEP_FILENAMES]
explosion_img = pygame.image.load('images/map/tree.png').convert_alpha()
explosion_images = [
explosion_img, pygame.transform.rotate(explosion_img, 90)]
creeps = pygame.sprite.RenderPlain()
done = False
#bg_tile_img = pygame.image.load('images/map/grass.png').convert()
#draw_background(screen, bg_tile_img)
totalCreeps = 0
remainingCreeps = 3
while done == False:
creep_images = pygame.image.load("images/player/1.png").convert()
creep_images.set_colorkey(white)
draw_background(screen, bg_tile_img)
if len(creeps) != N_CREEPS:
if totalCreeps < N_CREEPS:
totalCreeps = totalCreeps + 1
print(totalCreeps)
creeps.add(
Creep( screen=screen,
creep_image=creep_images,
explosion_images=explosion_images,
field=FIELD_RECT,
init_position=( randint(FIELD_RECT.left,
FIELD_RECT.right),
randint(FIELD_RECT.top,
FIELD_RECT.bottom)),
init_direction=(choice([-1, 1]),
choice([-1, 1])),
speed=0.01))
for creep in creeps:
creep.update(60,wall_list)
creep.draw()
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.changespeed(-2,0)
creep.changespeed(-2,0)
if event.key == pygame.K_RIGHT:
player.changespeed(2,0)
creep.changespeed(2,0)
if event.key == pygame.K_UP:
player.changespeed(0,-2)
creep.changespeed(0,-2)
if event.key == pygame.K_DOWN:
player.changespeed(0,2)
creep.changespeed(0,2)
if event.key == pygame.K_ESCAPE:
pauseGame()
if event.key == pygame.K_1:
global currentEditTool
currentEditTool = "Tree"
changeTool()
if event.key == pygame.K_2:
global currentEditTool
currentEditTool = "Rock"
changeTool()
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(2,0)
creep.changespeed(2,0)
if event.key == pygame.K_RIGHT:
player.changespeed(-2,0)
creep.changespeed(-2,0)
if event.key == pygame.K_UP:
player.changespeed(0,2)
creep.changespeed(0,2)
if event.key == pygame.K_DOWN:
player.changespeed(0,-2)
creep.changespeed(0,-2)
if event.type == pygame.MOUSEBUTTONDOWN and pygame.mouse.get_pressed()[0]:
for creep in creeps:
creep.mouse_click_event(pygame.mouse.get_pos())
if editMap == True:
x,y = pygame.mouse.get_pos()
if currentEditTool == "Tree":
name = insertTree(x-10,y-25, 10 , 10, "tree")
wall_list.add(name)
wall_list.draw(screen)
f = open('MapMaker.txt', "a+")
image = pygame.image.load("images/map/tree.png").convert()
screen.blit(image, (30,10))
pygame.display.flip()
f.write(str(x) + "," + str(y) + ",790,10, tree\n")
#f.write("wall=insertTree(" + str(x) + "," + str(y) + ",790,10)\nwall_list.add(wall)\n")
elif currentEditTool == "Rock":
name = insertRock(x-10,y-25, 10 , 10,"rock")
wall_list.add(name)
wall_list.draw(screen)
f = open('MapMaker.txt', "a+")
f.write(str(x) + "," + str(y) + ",790,10,rock\n")
#f.write("wall=insertRock(" + str(x) + "," + str(y) + ",790,10)\nwall_list.add(wall)\n")
else:
None
#pygame.display.flip()
player.update(wall_list)
movingsprites.draw(screen)
wall_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
Sprite collide is the correct way to do it, you are just handling the return data incorrectly. Basically, sprite collide will no return a boolean of if you are colliding or not with a member of the group. It returns a list of sprites. Basically, it will give you a list of sprites colliding with you in that group. Another thing to watch out for is that the list will also invariably include the sprite itself. After all, it is colliding with itself. Here is a functioning way to test if you are colliding with a wall.
def is_colliding_with_wall(): #this is a function that will determine if you are touching a wall. You have repeated code to test collisions with walls multiple times, so it is best just to have a function
collide = pygame.sprite.spritecollide(self, walls, False) #this gets the list, it is the exact same code as in yours
for collision in collide: #goes through the list, checking each collision
if collision != self: #filters out self collision
return True #if there is a collision that is not self, returns True, that there is a collision with a wall
return False #if it has checked all the collisions and there is only a self collision, then it is not colliding with a wall, so it returns False

Categories

Resources