Related
I'm making a 2D game using pygame. I'm pretty new to python object oriented programming and don't quite understand classes and objects in full, so my coding approach might be a little weird. I have a player and entity class, and a key listener to change the player x and y (actually the background picture's x/y coords) relative to keys pressed. Currently, I have only one entity object named monster, because in order to properly move the player, I need to move every entity as well or else the entities will just move along with the player.
How do I reference every single entity I create simultaneously so I can change their x and y values, so I don't have to reference them one by one in the key listener functions?
Is there some entity.objects.all() sort of thing? Thank you if somebody can help, here's my code.
import os
import time
import threading
p.init()
c = p.time.Clock()
SCREEN_W = 800
SCREEN_H = 600
w = p.display.set_mode((SCREEN_W, SCREEN_H))
p.display.set_caption("Mason's Game")
walkRight = [p.image.load('game/r1.png'), p.image.load('game/r2.png'), p.image.load('game/r3.png'), p.image.load('game/r4.png'), p.image.load('game/r5.png'), p.image.load('game/r6.png'), p.image.load('game/r7.png'), p.image.load('game/r8.png'), p.image.load('game/r9.png')]
walkLeft = [p.image.load('game/l1.png'), p.image.load('game/l2.png'), p.image.load('game/l3.png'), p.image.load('game/l4.png'), p.image.load('game/l5.png'), p.image.load('game/l6.png'), p.image.load('game/l7.png'), p.image.load('game/l8.png'), p.image.load('game/l9.png')]
bg = p.image.load('game/bg.jpg')
char = p.image.load('game/standing.png')
mob = p.image.load('game/mob.png')
health = [p.image.load('game/h0.png'), p.image.load('game/h1.png'), p.image.load('game/h2.png'), p.image.load('game/h3.png'), p.image.load('game/h4.png'), p.image.load('game/h5.png'), p.image.load('game/h6.png'), p.image.load('game/h7.png'), p.image.load('game/h8.png'), p.image.load('game/h9.png'), p.image.load('game/h10.png'),]
def delay(x):
later = p.time.get_ticks() + x
if p.time.get_ticks() >= later:
pass
class entity(object):
def __init__(self, spawnx, spawny, x,y, level, health):
self.x=x
self.y=y
self.spawnx = spawnx
self.spawny= spawny
self.velocity=14
self.level = level
self.health = health
self.dead = False
def draw(self, w):
w.blit(mob, (self.x,self.y))
def printCoords(self):
print('x: ' , (-1*(m.x - monster.x) - 3600) - 300, " y: ", ((-1*(m.y - monster.y) - 3700) - 300)*-1)
def pace(self):
reachedRight = False
reachedLeft = False
if not reachedRight:
self.x += self.velocity/10
if self.x >= (self.spawnx + 100):
reachedRight = True
if reachedRight:
self.velocity *= -1
if self.x <= (self.spawnx - 100):
reachedLeft = True
if reachedLeft:
self.velocity*=-1
def stop(self):
self.velocity = 0
def followPlayer(self, player):
#if (abs(ogre.x - monster.x)) < 160 or (abs(ogre.y - monster.y)) < 160:
# monster.attackPlayer()
#if monster is left of player, close enough, but not too close
if self.x < player.x - 128 and self.x > player.x - 400:
self.velocity = 5
self.x += self.velocity
#if monster is right of player, close enough, but not too close
elif self.x > player.x + 128 and self.x < player.x + 400:
self.velocity = -5
self.x += self.velocity
#if monster is south of player, close enough, but not too close
if self.y < player.y - 128 and self.y > player.y - 400:
self.velocity = 5
self.y += self.velocity
#if monster is north of player, close enough, but not too close
elif self.y > player.y + 128 and self.y < player.y + 400:
self.velocity = -5
self.y += self.velocity
def attackPlayer(self, player):
def hitPlayer():
if player.health > 0:
player.sethealth(player.health - 1)
else:
player.death()
t=threading.Timer(5.0,hitPlayer)
t.start()
class mapp(object):
def __init__(self,x,y):
self.x= -3600
self.y= -3700
self.velocity = 14
self.left = False
self.right = False
self.standing = True
def draw(self, w):
w.blit(bg, (self.x,self.y))
class player(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 14
self.j = False
self.jc = 10
self.right = False
self.left = False
self.walk = 0
self.standing = True
self.health = 10
self.travX = (-3600 - m.x)
self.travY = (-3700 - m.y)
def respawn(self):
time.sleep(0.4)
monster.x = (-1*(m.x - monster.x) - 3600)
monster.y = (-1*(m.y - monster.y) - 3700)
m.x += (-3600 - m.x)
m.y += (-3700 - m.y)
#monster.y += (-1*(m.y - monster.y) - 3700)
def death(self):
self.sethealth(10)
self.respawn()
def sethealth(self, x):
self.health = x
def draw(self,w):
w.blit(health[self.health], (730, 20))
if self.walk + 1 >= 27:
self.walk = 0
if not(self.standing):
if self.left:
w.blit(walkLeft[self.walk//3], (self.x,self.y))
self.walk += 1
elif self.right:
w.blit(walkRight[self.walk//3], (self.x,self.y))
self.walk += 1
else:
if self.left:
w.blit(walkLeft[0], (self.x,self.y))
else:
w.blit(walkRight[0], (self.x,self.y))
def drawGame():
m.draw(w)
ogre.draw(w)
monster.draw(w)
monster.followPlayer(ogre)
p.display.update()
####### main ############
m = mapp(-3600,-3700)
ogre = player(400, 300, 64, 64)
monster = entity(-200, 600, -200, 600, 5, 100)
monster2 = entity(-300, 630, -300, 630, 5, 100)
####### main ############
run = True
while run:
c.tick(27)
for event in p.event.get():
if event.type == p.QUIT:
run = False
k = p.key.get_pressed()
#monster.printCoords()
### left right up down player ####
if k[p.K_a]:
monster.x +=m.velocity
monster.spawnx+=m.velocity
m.x+=m.velocity
ogre.left = True
ogre.right = False
ogre.standing = False
elif k[p.K_d]:
monster.x -=m.velocity
monster.spawnx-=m.velocity
m.x-=m.velocity
ogre.right = True
ogre.left = False
ogre.standing = False
elif k[p.K_w]:
monster.y +=m.velocity
monster.spawny+=m.velocity
m.y+=m.velocity
ogre.right = False
ogre.left = False
ogre.standing = True
elif k[p.K_s]:
monster.y -=m.velocity
monster.spawny-=m.velocity
m.y-=m.velocity
ogre.right = False
ogre.left = False
ogre.standing = True
elif k[p.K_j]:
#monster.attackPlayer()
ogre.death()
else:
ogre.standing = True
ogre.walk = 0
drawGame()
p.quit()```
Set the variables move_x and move_y dependent on the pressed key:
move_x = 0
move_y = 0
if k[p.K_a]:
move_x = m.velocity
# [...]
elif k[p.K_d]:
move_x = -m.velocity
# [...]
elif k[p.K_w]:
move_y = m.velocity
# [...]
elif k[p.K_s]:
move_y = -m.velocity
# [...]
Create a list of monsters:
monsters = [
entity(-200, 600, -200, 600, 5, 100)
entity(-300, 630, -300, 630, 5, 100)
]
Move each individual monster in a for loop:
for monster in monsters:
monster.x += move_x
monster.y += move_y
monster.spawnx += move_x
monster.spawny += move_y
application loop:
m = mapp(-3600,-3700)
ogre = player(400, 300, 64, 64)
monsters = [
entity(-200, 600, -200, 600, 5, 100)
entity(-300, 630, -300, 630, 5, 100)
]
run = True
while run:
c.tick(27)
for event in p.event.get():
if event.type == p.QUIT:
run = False
k = p.key.get_pressed()
### left right up down player ####
move_x = 0
move_y = 0
if k[p.K_a]:
move_x = m.velocity
ogre.left = True
ogre.right = False
ogre.standing = False
elif k[p.K_d]:
move_x = -m.velocity
ogre.right = True
ogre.left = False
ogre.standing = False
elif k[p.K_w]:
move_y = m.velocity
ogre.right = False
ogre.left = False
ogre.standing = True
elif k[p.K_s]:
move_y = -m.velocity
ogre.right = False
ogre.left = False
ogre.standing = True
elif k[p.K_j]:
#monster.attackPlayer()
ogre.death()
else:
ogre.standing = True
ogre.walk = 0
for monster in monsters:
monster.x += move_x
monster.y += move_y
monster.spawnx += move_x
monster.spawny += move_y
m.x += move_x
m.y += move_y
drawGame()
import pygame
pygame.init()
win = pygame.display.set_mode((500, 480))
pygame.display.set_caption("First Game")
walkRight = [pygame.image.load('R1.png'), pygame.image.load('R2.png'), pygame.image.load('R3.png'), pygame.image.load('R4.png'), pygame.image.load('R5.png'), pygame.image.load('R6.png'), pygame.image.load('R7.png'), pygame.image.load('R8.png'), pygame.image.load('R9.png')]
walkLeft = [pygame.image.load('L1.png'), pygame.image.load('L2.png'), pygame.image.load('L3.png'), pygame.image.load('L4.png'), pygame.image.load('L5.png'), pygame.image.load('L6.png'), pygame.image.load('L7.png'), pygame.image.load('L8.png'), pygame.image.load('L9.png')]
bg = pygame.image.load('bg.jpg')
char = pygame.image.load('standing.png')
clock = pygame.time.Clock()
class player(object):
def __init__(self,x,y,width,height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 5
self.isJump = False
self.jumpCount = 10
self.left = False
self.right = False
self.walkCount = 0
def draw(self, win):
if self.walkCount + 1 >= 27:
walkCount = 0
if self.left:
win.blit(walkLeft[self.walkCount//3], (round(self.x),round(self.y)))
self.walkCount += 1
elif self.right:
win.blit(walkRight[self.walkCount//3], (round(self.x),round(self.y)))
self.walkCount += 1
else:
win.blit(char, (round(self.x),round(self.y)))
def redrawGameWindow():
win.blit(bg, (0,0))
man.draw(win)
pygame.display.update()
#mainloop
man = player(200, 410, 64, 64)
run = True
while run:
clock.tick(27)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and man.x > man.vel:
man.x -= man.vel
man.left = True
man.right = False
elif keys[pygame.K_RIGHT] and man.x < 500 - man.width - man.vel:
man.x += man.vel
man.right = True
man.left = False
else:
man.right = False
man.left = False
man.walkCount = 0
if not(man.isJump):
if keys[pygame.K_SPACE]:
man.isJump = True
man.right = False
man.left = False
man.walkCount = 0
else:
if man.jumpCount >= -10:
neg = 1
if man.jumpCount < 0:
neg = -1
man.y -= (man.jumpCount ** 2) * 0.5 * neg
man.jumpCount -= 1
else:
man.isJump = False
man.jumpCount = 10
redrawGameWindow()
pygame.quit()
Error
Traceback (most recent call last):
File "C:\Python work\Tech_With_Tim_Pygame_Tutorial\First_Game.py", line 93, in <module>
redrawGameWindow()
File "C:\Python work\Tech_With_Tim_Pygame_Tutorial\First_Game.py", line 46, in redrawGameWindow
man.draw(win)
File "C:\Python work\Tech_With_Tim_Pygame_Tutorial\First_Game.py", line 36, in draw
win.blit(walkRight[self.walkCount//3], (round(self.x),round(self.y)))
IndexError: list index out of range
The main issue the self reference. You need to update self.walkCount = 0.
This code works for me:
def draw(self, win):
if self.walkCount >= len(walkLeft): # assume left/right same length
self.walkCount = 0 # use self
print(self.walkCount)
if self.left:
win.blit(walkLeft[self.walkCount//3], (round(self.x),round(self.y)))
self.walkCount += 1
elif self.right:
win.blit(walkRight[self.walkCount//3], (round(self.x),round(self.y)))
self.walkCount += 1
else:
win.blit(char, (round(self.x),round(self.y)))
I am trying to make a little game and I need to put some text over the background to show lives. But the text doesn't show up over the background and I don't know why. Any help is appreciated. All the drawing code is in the redrawgamewindow function. I know its something to do with the background maybe being put over the text but how would I fix this?
import random
import math
pygame.init()
GOLD = (255, 215, 0)
def text_objects(text, font):
textSurface = font.render(text, True, GOLD)
return textSurface, textSurface.get_rect()
screenwidth = 500
screenheight = 500
win = pygame.display.set_mode((screenwidth, screenheight))
pygame.display.set_caption('First Game')
bkg = pygame.image.load('2.jpg')
bkg = pygame.transform.scale(bkg, (500,500))
char1 = pygame.image.load('guy.png')
char1 = pygame.transform.scale(char1, (100, 100))
walkRight = []
walkLeft = []
HitAnim = []
Howmany = 4
for i in range(1, 13):
walkRight.append(pygame.transform.scale(pygame.image.load('R' + str(i) + '.png'), (100, 100)))
for i in range(1, 13):
walkLeft.append(pygame.transform.scale(pygame.image.load('L' + str(i) + '.png'), (100, 100)))
rockboom = pygame.image.load('b1.png')
rockboom = pygame.transform.scale(rockboom, (100,100))
GameO = pygame.image.load('GO.jpg')
rock = pygame.image.load('b.png')
rock = pygame.transform.scale(rock, (100, 100))
clock = pygame.time.Clock()
class player(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.GameOver = False
self.vel = 10
self.walkCount = 0
self.left = False
self.right = False
self.lives = 3
self.hit = 0
self.hit1 = False
def draw(self, win):
if self.walkCount + 1 >= 27:
self.walkCount = 0
if self.left == True:
win.blit(walkLeft[self.walkCount // 3], (self.x, self.y))
self.walkCount += 1
pygame.display.update()
elif self.right == True :
win.blit(walkRight[self.walkCount // 3], (self.x, self.y))
self.walkCount += 1
else:
win.blit(char1, (self.x, self.y))
class rocky():
def __init__(self):
self.x = random.randrange(0, 430)
self.y = -100
def draw(self, win):
win.blit(rock, (self.x, self.y))
if man.hit1 == True:
win.blit (rockboom, (self.x, self.y))
def redrawgamewindow():
win.blit(bkg, (0, 0))
man.draw(win)
rock1.draw(win)
largeText = pygame.font.Font('freesansbold.ttf', 45)
TextSurf, TextRect = text_objects("Lives:" + str(man.lives), largeText)
TextRect.center = ((screenwidth / 2), (100 / 2))
pygame.display.flip()
def collided (rockx, rocky, manx, many):
man.hit = 0
distance = math.sqrt((math.pow(rockx-manx, 2) + (math.pow(rocky-many, 2))))
if distance < 75:
man.hit += 1
print("we be touched")
man.hit1 = True
else:
man.hit1 = False
my_list= []
for number in range(Howmany):
my_object = rocky()
my_list.append(my_object)
rock1 = rocky()
man = player(250, 350, 100, 100)
run = True
while run:
# Setting fps
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
# Getting keys pressed
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and man.x > 0:
man.x -= man.vel
man.left = True
man.right = False
elif keys[pygame.K_RIGHT] and man.x < 500 - man.vel - man.width:
man.x += man.vel
man.left = False
man.right = True
else:
man.left = False
man.right = False
man.walkCount = 0
for rockk in my_list:
rock1.draw(win)
rock1.y += 5
if rock1.y >= 500:
rock1.x = random.randrange(0, 430)
rock1.y = -100
if man.hit1 == True:
rock1.x = random.randrange(0, 430)
rock1.y = -100
if man.hit == 1:
man.lives -=1
if man.hit ==2:
man.lives -=1
if man.lives <= 0:
print("so uh yeah it worked cool ")
exit()
collided(rock1.x, rock1.y, man.x, man.y)
redrawgamewindow()
win.blit(pygame.image.load('R1.png').convert_alpha(), (200, 200))
You're not blitting the text. Try this:
def redrawgamewindow():
win.blit(bkg, (0, 0))
man.draw(win)
rock1.draw(win)
largeText = pygame.font.Font('freesansbold.ttf', 45)
TextSurf, TextRect = text_objects("Lives:" + str(man.lives), largeText)
TextRect.center = ((screenwidth / 2), (100 / 2))
win.blit(TextSurf,TextRect)
pygame.display.flip()
I am trying to get my pieces to collide and and when I jump up into the air the characters should not collide.
Here is a video explaining the problem:
https://drive.google.com/file/d/1a26Vmd6TF4C3dJ0DpnFLTR1d3a_lEfn4/view?usp=sharing
The collision is with the goblin.
Furthermore, we can see that the goblin is colliding even though the boxes aren't touching and when on top of the hitbox.
I have tried to change the condition of the loop for example changed the ">" around to "<" and tried making the jump higher. Both of these did not resolve the problem and I am not an experienced coder.
Here is the main problem:
if (adventurer.hitbox_running[0] > attacker.hitbox[0] and adventurer.hitbox_running[0] < attacker.hitbox[0]+70) or (adventurer.hitbox_running[0]+70 > attacker.hitbox[0] and adventurer.hitbox_running[0]+90 < attacker.hitbox[0]+70):
if (adventurer.hitbox_running[1] > attacker.hitbox[1] and adventurer.hitbox_running[1] < attacker.hitbox[1]+70) or (adventurer.hitbox_running[1]+90 > attacker.hitbox[1] and adventurer.hitbox_running[1]+90 < attacker.hitbox[1]+70):
window.fill((255,255,255))
death()
pygame.display.update()
s(0.1)
print("hit")
Here is the entire code with all of the classes and everything:
from time import sleep as s
import random
import pygame
import time
#Loads and plays the music
pygame.mixer.pre_init(44100,16,2,4096)
pygame.init()
pygame.mixer.music.load("Music.mp3")
pygame.mixer.music.set_volume(0.0)
pygame.mixer.music.play(-1)
score = 0
#sets the dimension of the window and loads in the background
window = pygame.display.set_mode((1000, 500))
pygame.display.set_caption("Practice Game")
background = pygame.image.load('pixel6.png')
#Transforms the background to desired dimensions
background = pygame.transform.scale(background, (1000, 500))
#Loads all the jump animation
jumpv1 = [pygame.image.load('adventurer-jump-00.png'),pygame.image.load('adventurer-jump-01.png'),pygame.image.load('adventurer-jump-02.png'),pygame.image.load('adventurer-jump-03.png'), pygame.image.load('adventurer-smrslt-00.png'),pygame.image.load('adventurer-smrslt-01.png'),pygame.image.load('adventurer-smrslt-02.png'),pygame.image.load('adventurer-smrslt-03.png')]
jumpv2 = [pygame.image.load('adventurer-smrslt-00.png'),pygame.image.load('adventurer-smrslt-01.png'),pygame.image.load('adventurer-smrslt-02.png'),pygame.image.load('adventurer-smrslt-03.png')]
jumpv3 = [pygame.image.load('adventurer-smrslt-00.png'),pygame.image.load('adventurer-smrslt-01.png'),pygame.image.load('adventurer-smrslt-02.png'),pygame.image.load('adventurer-smrslt-03.png')]
jumpv4 = [pygame.image.load('adventurer-smrslt-00.png'),pygame.image.load('adventurer-smrslt-01.png'),pygame.image.load('adventurer-smrslt-02.png'),pygame.image.load('adventurer-smrslt-03.png')]
jump = jumpv1+jumpv2+jumpv3+jumpv4
#running animation
run = [pygame.image.load('adventurer-run-00.png'), pygame.image.load('adventurer-run-01.png'),pygame.image.load('adventurer-run-02.png'),pygame.image.load('adventurer-run-03.png')]
#sliding animation
slide = [pygame.image.load('adventurer-slide-00.png'),pygame.image.load('adventurer-slide-01.png'),pygame.image.load('adventurer-stand-00.png'),pygame.image.load('adventurer-stand-01.png'),pygame.image.load('adventurer-stand-02.png')]
#attacking animation
firstattack = [pygame.image.load('adventurer-attack3-00.png'),pygame.image.load('adventurer-attack3-01.png'),pygame.image.load('adventurer-attack3-02.png'),pygame.image.load('adventurer-attack3-03.png'),pygame.image.load('adventurer-attack3-04.png'),pygame.image.load('adventurer-attack3-05.png')]
secondattack = [pygame.image.load('adventurer-attack2-00.png'),pygame.image.load('adventurer-attack2-01.png'),pygame.image.load('adventurer-attack2-02.png'),pygame.image.load('adventurer-attack2-03.png'),pygame.image.load('adventurer-attack2-04.png'),pygame.image.load('adventurer-attack2-05.png')]
thirdattack = [pygame.image.load('adventurer-attack1-00.png'),pygame.image .load('adventurer-attack1-01.png'),pygame.image.load('adventurer-attack1-02.png'),pygame.image.load('adventurer-attack1-03.png'), pygame.image.load('adventurer-attack1-04.png')]
attack = firstattack+secondattack+ thirdattack
#falling animation
falling = [pygame.image.load('adventurer-fall-00.png'), pygame.image.load('adventurer-fall-01.png')]
score = 0
run_program = True
#resizes all the adventuruer images to specified dimensions
for i in range (20):
jump[i] = pygame.transform.scale(jump[i],(90,90))
for i in range(3):
run[i] = pygame.transform.scale(run[i],(90,90))
for i in range (4):
slide[i] = pygame.transform.scale(slide[i],(90,90))
for i in range (1):
falling[i] = pygame.transform.scale(falling[i],(90,90))
for i in range(16):
attack[i] = pygame.transform.scale(attack[i],(90,90))
background_x = 0
background_2 = background.get_width()
clock = pygame.time.Clock()
ghost_image = pygame.image.load('imgg.png')
def text_objects(text, font):
textSurface = font.render(text, True, (0,0,0))
return textSurface, textSurface.get_rect()
def message_display(text):
largeText = pygame.font.Font('freesansbold.ttf',115)
TextSurf, TextRect = text_objects(text, largeText)
TextRect.center = ((1000/2),(500/2))
window.blit(TextSurf, TextRect)
pygame.display.update()
def death():
message_display('You DIED')
class ghost(object):
ghost_animation = [pygame.image.load('imgg.png'),pygame.image.load('imgg.png')]
def __init__(self, x,y,height):
self.x = x
self.y =y
self.height = height
self.hitbox = (x,y,100,100)
self.count = 0
def draw(self, window):
self.hitbox = (self.x, self.y, 45, 60)
if self.count >=1:
self.count = 0
self.count +=1
window.blit(pygame.transform.scale(self.ghost_animation[self.count], (45,60)), (self.x, self.y))
pygame.draw.rect(window, (255,0,0), self.hitbox, 2)
def hit(self):
print ("hit")
class eye(object):
eye_load = pygame.image.load('obstc2.png')
def __init__(self, x,y,width2, height2):
self.x = x
self.y =y
self.hitbox_enemy = (x,y,200,100)
self.count1 = 0
def draw(self, window):
self.hitbox_enemy = (self.x, self.y, 65, 65)
window.blit(pygame.transform.scale(self.eye_load, (65,65)), (self.x, self.y))
pygame.draw.rect(window, (255,0,0), self.hitbox_enemy, 2)
class player(object):
def __init__(self, x,y):
self.vel = 0.5
self.running = True
self.jumping = True
self.sliding = True
self.attacking = True
self.isJump = False
self. jumps = True
self.fall = True
self.player_x = 40
self.player_y = 378
self.x = 40
self.y = 378
self.width = 378
self.speed = 0.6
self.jumpcount = 10
self.jumpingcount = 0
self.runcount = 0
self.attackcount = 0
self.slidecount = 0
self.fallspeed = 0.3
self.fallingcount = 0
self.hitbox_running = (self.player_x,self.player_y,90,90)
self.hitbox_sliding = (45,self.player_y+47,65,45)
self.hitbox_falling = (self.player_x+30,self.player_y,35,80)
self.hitbox_jumping = (self.player_x+20,self.player_y+20,52,55)
self.hitbox_attacking = (58,405,47,70)
self.hitbox_sword = (108, 405, 20, 50)
def movement(self, window):
pygame.time.delay(20)
if self.runcount >= 3:
self.runcount = 0
if self.running == True:
window.blit(run[self.runcount],(int(self.player_x),int(self.player_y)))
self.runcount +=1
self.hitbox_running = (self.player_x+30,self.player_y+20,48,70)
pygame.draw.rect(window,(255,0,0),self.hitbox_running, 2)
if (keys[pygame.K_DOWN]) or ((keys[pygame.K_DOWN]) and keys[pygame.K_p]):
if self.player_y == 378:
self.running = False
if self.slidecount >= 4:
self.slidecount = 0
if self.sliding:
window.blit(slide[self.slidecount],(int(self.player_x),int(self.player_y)))
self.slidecount +=1
pygame.draw.rect(window,(255,0,0),self.hitbox_sliding, 2)
if event.type == pygame.KEYDOWN:
if (event.key == pygame.K_DOWN )and self.player_y < self.width:
self.running = False
self.jumping = False
self.fallspeed += 0.2
if self.fallingcount >= 1:
self.fallingcount = 0
if self.fall:
window.blit(falling[self.fallingcount], (int(self.player_x),int(self.player_y)))
self.hitbox_falling = (self.player_x+30,self.player_y,35,80)
pygame.draw.rect(window,(255,0,0),self.hitbox_falling, 2)
self.fallingcount +=1
if keys[pygame.K_UP] and keys[pygame.K_p] :
self.fallspeed = 0.3
self.running = False
self.jumping = False
self.sliding = False
if self.attackcount >= 16:
self.attackcount = 0
if self.attacking:
window.blit(attack[self.attackcount],(int(self.player_x),int(self.player_y)))
self.attackcount += 1
self.hitbox_attacking = (self.player_x+30,self.player_y+20,38,70)
self.hitbox_sword = (self.player_x+72, self.player_y+20, 20, 50)
pygame.draw.rect(window,(255,0,0),self.hitbox_attacking, 2)
pygame.draw.rect(window,(255,0,0),self.hitbox_sword, 2)
if self.jumpingcount >= 20:
self.jumpingcount = 0
if self.jumping and self.player_y < self.width:
window.blit(jump[self.jumpingcount],(int(self.player_x),int(self.player_y)))
self.hitbox_jumping = (int(self.player_x+20),int(self.player_y+20),52,55)
pygame.draw.rect(window,(255,0,0),self.hitbox_jumping, 2)
self.jumpingcount +=1
self.fallspeed = 0.3
if keys[pygame.K_UP]:
self.fallspeed = 0.3
self.running = False
if self.jumpingcount >= 20:
self.jumpingcount = 0
if self.jumping and self.player_y < self.width:
window.blit(jump[self.jumpingcount],(int(self.player_x),int(self.player_y)))
self.hitbox_jumping = (int(self.player_x+20),int(self.player_y+20),52,55)
pygame.draw.rect(window,(255,0,0),self.hitbox_jumping, 2)
self.jumpingcount +=1
self.fallspeed = 0.3
if keys[pygame.K_p] and not keys[pygame.K_UP]:
self.running = False
self.jumping = False
self.sliding = False
if self.attackcount >= 16:
self.attackcount = 0
if self.attacking:
self.hitbox_attacking = (self.player_x+30,self.player_y+20,38,70)
self.hitbox_sword = (self.player_x+72, self.player_y+20, 20, 50)
window.blit(attack[self.attackcount],(int(self.player_x),int(self.player_y)))
self.attackcount += 1
pygame.draw.rect(window,(255,0,0),self.hitbox_attacking, 2)
pygame.draw.rect(window,(255,0,0),self.hitbox_sword, 2)
if keys[pygame.K_DOWN] and keys[pygame.K_UP]:
self.running = False
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
self.running = True
self.jumping = True
self.fallspeed = 0.3
if event.key == pygame.K_UP:
self.running=True
if event.key == pygame.K_p:
self.running = True
self.jumping = True
self.sliding = True
class enemy(object):
walkright = [pygame.image.load('R1E.png'), pygame.image.load('R2E.png'), pygame.image.load('R3E.png'), pygame.image.load('R4E.png'), pygame.image.load('R5E.png'), pygame.image.load('R6E.png'), pygame.image.load('R7E.png'), pygame.image.load('R8E.png'), pygame.image.load('R9E.png'), pygame.image.load('R10E.png'), pygame.image.load('R11E.png')]
walkleft = [pygame.image.load('L1E.png'), pygame.image.load('L2E.png'), pygame.image.load('L3E.png'), pygame.image.load('L4E.png'), pygame.image.load('L5E.png'), pygame.image.load('L6E.png'), pygame.image.load('L7E.png'), pygame.image.load('L8E.png'), pygame.image.load('L9E.png'), pygame.image.load('L10E.png'), pygame.image.load('L11E.png')]
for i in range (10):
walkright[i] = pygame.transform.scale(walkright[i],(70,70))
for i in range(10):
walkleft[i] = pygame.transform.scale(walkleft[i],(70,70))
def __init__(self,enemy_x,enemy_y, end):
self.x = enemy_x
self.y = enemy_y
self.end = end
self.path = [self.x,self.end]
self.walkcount = 0
self.vel = 7
self.hitbox = (self.x,self.y-15,90,90)
def draw_enemy(self,window):
self.move()
if self.walkcount+1 >= 33:
self.walkcount = 0
self.vel+=0.2
#walking right
if self.vel > 0:
window.blit(self.walkleft[self.walkcount//3], (self.x,self.y-15))
self.walkcount += 1
#walking left
if self.vel < 0:
## window.blit(self.walkleft[self.walkcount//3], (self.x,self.y))
self.walkcount -= 1
if self.x < -100:
self.x = 1050
self.hitbox = (self.x+25,self.y-15,41,70)
pygame.draw.rect(window, (255,0,0),self.hitbox,2)
def move(self):
if self.vel > 0:
#see if position + movement space is < the end, then it is able to move
if self.x + self.vel < self.path[1]:
self.x -= self.vel
#past end point and turns 180
else:
self.vel = self.vel*-1
self.walkcount = 0
#see if position is smaller than starting position
else:
if self.x - self.vel > self.path[0]:
#vel is already negative
self.x += self.vel
else:
#Truns 180 agian
self.vel = self.vel* -1
self.walkcount = 0
class wizard(object):
walkleft = [pygame.image.load('wizard-fly-forward_04.gif'), pygame.image.load('wizard-fly-forward_04.gif'), pygame.image.load('wizard-fly-forward_04.gif'), pygame.image.load('wizard-fly-forward_04.gif'), pygame.image.load('wizard-fly-forward_04.gif'), pygame.image.load('wizard-fly-forward_05.gif'), pygame.image.load('wizard-fly-forward_04.gif'), pygame.image.load('wizard-fly-forward_04.gif'), pygame.image.load('wizard-fly-forward_05.gif'), pygame.image.load('wizard-fly-forward_04.gif'), pygame.image.load('wizard-fly-forward_04.gif'), pygame.image.load('wizard-fly-forward_04.gif'), pygame.image.load('wizard-fly-forward_05.gif'),pygame.image.load('wizard-fly-forward_04.gif'), pygame.image.load('wizard-fly-forward_04.gif'),pygame.image.load('wizard-fly-forward_05.gif')]
for i in range(16):
walkleft[i] = pygame.transform.scale(walkleft[i],(70,70))
def __init__(self,enemy_x,enemy_y, end):
self.x = enemy_x
self.y = enemy_y
self.end = end
self.path = [self.x,self.end]
self.walkcount = 0
self.vel = 7
self.hitbox = (self.x,self.y-15,90,90)
def draw_enemy(self,window):
self.move()
if self.walkcount >= 16:
self.walkcount = 0
#walking left
if self.vel > 0:
window.blit(self.walkleft[self.walkcount], (self.x,self.y-15))
self.walkcount += 1
self.vel+=0.002
if self.x < -120:
self.x = 1100
self.hitbox = (self.x+25,self.y-15,41,70)
pygame.draw.rect(window, (255,0,0),self.hitbox,2)
def move(self):
if self.vel > 0:
#see if position + movement space is < the end, then it is able to move
if self.x + self.vel < self.path[1]:
self.x -= self.vel
#past end point and turns 180
else:
self.vel = self.vel*-1
self.walkcount = 0
#see if position is smaller than starting position
else:
if self.x - self.vel > self.path[0]:
#vel is already negative
self.x += self.vel
else:
#Truns 180 agian
self.vel = self.vel* -1
self.walkcount = 0
class dragon(object):
walkleft = [pygame.image.load('dragon_1.gif'), pygame.image.load('dragon_2.gif'), pygame.image.load('dragon_3.gif'), pygame.image.load('dragon_4.gif'), pygame.image.load('dragon_5.gif'), pygame.image.load('dragon_6.gif')]
for i in range (6):
walkleft[i] = pygame.transform.scale(walkleft[i],(200,176))
def __init__(self,enemy_x,enemy_y, end):
self.x = enemy_x
self.y = enemy_y
self.end = end
self.path = [self.x,self.end]
self.walkcount = 0
self.vel = 7
self.hitbox = (self.x,self.y-15,90,90)
def draw_enemy(self,window):
self.move()
if self.walkcount >= 6:
self.walkcount = 0
#walking left
if self.vel > 0:
window.blit(self.walkleft[self.walkcount], (self.x,300))
self.walkcount += 1
self.vel+=0.002
if self.x < -120:
self.x = 1100
self.hitbox = (self.x+25,self.y-15,41,70)
pygame.draw.rect(window, (255,0,0),self.hitbox,2)
def move(self):
if self.vel > 0:
#see if position + movement space is < the end, then it is able to move
if self.x + self.vel < self.path[1]:
self.x -= self.vel
#past end point and turns 180
else:
self.vel = self.vel*-1
self.walkcount = 0
#see if position is smaller than starting position
else:
if self.x - self.vel > self.path[0]:
#vel is already negative
self.x += self.vel
else:
#Truns 180 agian
self.vel = self.vel* -1
self.walkcount = 0
ghost_list = []
eye_list = []
def keepdrawing():
window.blit(background, (background_x,0))
window.blit(background, (background_2,0))
for draw_ghost in ghost_list:
draw_ghost.draw(window)
for draw_eye in eye_list:
draw_eye.draw(window)
adventurer.movement(window)
attacker.draw_enemy(window)
wizard.draw_enemy(window)
dragon.draw_enemy(window)
score_text = score_font.render("score: " + str(score), 1, (0,0,0))
window.blit(score_text,(470,10))
pygame.display.update()
score_font = pygame.font.SysFont("Arial",30,True)
attacker = enemy(950,407,951)
adventurer = player(40,387)
wizard = wizard(905,407,951)
dragon = dragon(905,407, 951)
vel_background = 2
pygame.time.set_timer(pygame.USEREVENT+1,random.randint(1000, 2000))
pygame.time.set_timer(pygame.USEREVENT+2,random.randint(2000, 3000))
while run:
while run_program:
clock.tick(60)
background_x -= vel_background
background_2 -= vel_background
if background_x < background.get_width() * -1:
background_x = background.get_width()
if background_2 < background.get_width() * -1:
background_2 = background.get_width()
keys = pygame.key.get_pressed()
if (adventurer.hitbox_running[0] > attacker.hitbox[0] and adventurer.hitbox_running[0] < attacker.hitbox[0]+70) or (adventurer.hitbox_running[0]+70 > attacker.hitbox[0] and adventurer.hitbox_running[0]+90 < attacker.hitbox[0]+70):
if (adventurer.hitbox_running[1] > attacker.hitbox[1] and adventurer.hitbox_running[1] < attacker.hitbox[1]+70) or (adventurer.hitbox_running[1]+90 > attacker.hitbox[1] and adventurer.hitbox_running[1]+90 < attacker.hitbox[1]+70):
window.fill((255,255,255))
death()
pygame.display.update()
s(0.1)
print("hit")
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
exit()
if event.type == pygame.USEREVENT+1:
vel_background+=0.2
if event.type == pygame.USEREVENT+2:
r = random.randint(0,1)
if r==0:
new_eye = eye(1050, 390, 64,64)
eye_list.append(new_eye)
if r==1:
new_ghost = ghost(1050,390,64)
ghost_list.append(new_ghost)
if not(adventurer.isJump):
if keys[pygame.K_UP]:
adventurer.isJump =True
else:
if adventurer.jumpcount >= -10:
neg=1
if adventurer.player_y > adventurer.width:
adventurer.player_y = adventurer.width
if adventurer.jumpcount <0:
neg = -1
## s(0.01)
adventurer.player_y -= (adventurer.jumpcount**2)*adventurer.fallspeed*neg*2
## s(0.01)
adventurer.jumpcount -=1
if adventurer.player_y > adventurer.width:
adventurer.player_y=adventurer.width
else:
adventurer.isJump = False
adventurer.jumpcount = 10
if adventurer.player_y > adventurer.width:
player_y = adventurer.width
adventurer.fallspeed = 0.05
keepdrawing()
The expected results should be that the output should not be shit if the hit boxes are not in contact.
The major issue is that you've different "hitboxis, which have different meanings at different states of the game, but you use adventurer.hitbox_running for the collison test event if adventurer is .running or .falling.
The best solution would be the set one .hitbox attribute, which always contains the proper location of adventurer in the method player.movement.
But it is also possible the choose the proper hit box:
if adventurer.running:
hitbox = adventurer.hitbox_running
elif adventurer.jumping:
hitbox = adventurer.hitbox_jumping
elif adventurer.falling:
hitbox = adventurer.hitbox_falling
Further I recommend to use pygame.Rect objects and .colliderect() for the collision test:
rect_adventurer = pygame.Rect(*hitbox)
rect_attacker = pygame.Rect(*attacker.hitbox)
if rect_adventurer.colliderect(rect_attacker):
window.fill((255,255,255))
death()
pygame.display.update()
s(0.1)
print("hit")
Quick note. This is for my A-Level NEA Programming Project. There are two main sections - One where a maze is generated and the user must navigate through it in a given time period, the time period is not currently implemented, and a second section where the user has to answer educational physics questions in order to get the best score. Questions are imported from a text file stored locally on my system. The user's score is then exported to a local text file along with the date completed.
So far my program generates the maze and the user can move freely. The educational aspect works as intended.
# Imports
import pygame
import sys
import csv
import random
from datetime import date
# Initialising pygame
pygame.init()
# Setting parameters for commonly used colours
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
# Creating a variable set to 'False' for the generation of the maze
done = False
# Setting variables for the size of the maze, how many columns and rows there will be
cols = 10
rows = 10
# Setting variables for the size of the window and the size of each individual part of the walls
width = 600
height = 600
wr = width/cols
hr = height/rows
# Initialising the 'screen' this is the surface within pygame that everything will be displayed upon
screen = pygame.display.set_mode([width, height])
screen_rect = screen.get_rect()
pygame.display.set_caption("Maze Generator")
# Creating a clock for the pygame module to run off of
clock = pygame.time.Clock()
# This is a class for the pathfinder section of the maze, it will allow the program to spot where needs to be visited
class Spot:
def __init__(self, x, y):
self.x = x
self.y = y
self.f = 0
self.g = 0
self.h = 0
self.neighbors = []
self.visited = False
self.walls = [True, True, True, True]
def show(self, color=BLACK):
if self.walls[0]:
pygame.draw.line(screen, color, [self.x*hr, self.y*wr], [self.x*hr+hr, self.y*wr], 2)
if self.walls[1]:
pygame.draw.line(screen, color, [self.x*hr+hr, self.y*wr], [self.x*hr+hr, self.y*wr + wr], 2)
if self.walls[2]:
pygame.draw.line(screen, color, [self.x*hr+hr, self.y*wr+wr], [self.x*hr, self.y*wr+wr], 2)
if self.walls[3]:
pygame.draw.line(screen, color, [self.x*hr, self.y*wr+wr], [self.x*hr, self.y*wr], 2)
def show_block(self, color):
if self.visited:
pygame.draw.rect(screen, color, [self.x*hr+2, self.y*wr+2, hr-2, wr-2])
def add_neighbors(self):
if self.x > 0:
self.neighbors.append(grid[self.x - 1][self.y])
if self.y > 0:
self.neighbors.append(grid[self.x][self.y - 1])
if self.x < rows - 1:
self.neighbors.append(grid[self.x + 1][self.y])
if self.y < cols - 1:
self.neighbors.append(grid[self.x][self.y + 1])
grid = [[Spot(i, j) for j in range(cols)] for i in range(rows)]
for i in range(rows):
for j in range(cols):
grid[i][j].add_neighbors()
current = grid[0][0]
visited = [current]
completed = False
def breakwalls(a, b):
if a.y == b.y and a.x > b.x:
grid[b.x][b.y].walls[1] = False
grid[a.x][a.y].walls[3] = False
if a.y == b.y and a.x < b.x:
grid[a.x][a.y].walls[1] = False
grid[b.x][b.y].walls[3] = False
if a.x == b.x and a.y < b.y:
grid[b.x][b.y].walls[0] = False
grid[a.x][a.y].walls[2] = False
if a.x == b.x and a.y > b.y:
grid[a.x][a.y].walls[0] = False
grid[b.x][b.y].walls[2] = False
class Player:
def __init__(self, x, y):
self.rect = pygame.Rect(x, y, hr-2, wr-2)
self.x = int(x)
self.y = int(y)
self.colour = (255, 0, 0)
self.velX = 0
self.velY = 0
self.left_pressed = False
self.right_pressed = False
self.up_pressed = False
self.down_pressed = False
self.speed = 5
def draw(self, win):
pygame.draw.rect(win, self.colour, self.rect)
def update(self):
self.velX = 0
self.velY = 0
if self.left_pressed and not self.right_pressed:
self.velX = -self.speed
if self.right_pressed and not self.left_pressed:
self.velX = self.speed
if self.up_pressed and not self.down_pressed:
self.velY = -self.speed
if self.down_pressed and not self.up_pressed:
self.velY = self.speed
self.x += self.velX
self.y += self.velY
self.rect = pygame.Rect(self.x, self.y, hr-2, wr-2)
def readMyFiles():
questionsAndAnswers = []
correctAnswers = []
with open('questions.txt', newline='') as f:
reader = csv.reader(f, delimiter='\t')
for row in reader:
questionsAndAnswers.append(row)
return questionsAndAnswers
def game(questions, answers, correctAnswers):
score = 0
counter = 0
numberOfQuestions = len(questions)
while not counter == numberOfQuestions:
print(questions[counter])
print(answers[counter])
userAnswer = input('\nWhat is the correct answer?\n')
if userAnswer == correctAnswers[counter]:
print('Well done! That is correct.')
score += 1
else:
print('Better luck next time, that is not correct.')
counter += 1
return score
def shuffleSplit(qna):
random.shuffle(qna)
questions = []
answers = []
correctAnswers = []
for q in qna:
questions.append(q[0])
correctAnswers.append(q[1])
del q[0]
random.shuffle(q)
answers.append(q)
return (questions, answers, correctAnswers)
def exportScores(score, ):
with open('scores.txt', mode='a') as scores:
scores = csv.writer(scores, delimiter='\t')
today = date.today()
dateFormat = today.strftime("%d/%m/%Y")
scores.writerow([dateFormat, score])
player = Player(2, 2)
while not done:
clock.tick(60)
screen.fill(BLACK)
if not completed:
grid[current.x][current.y].visited = True
got_new = False
temp = 10
while not got_new and not completed:
r = random.randint(0, len(current.neighbors)-1)
Tempcurrent = current.neighbors[r]
if not Tempcurrent.visited:
visited.append(current)
current = Tempcurrent
got_new = True
if temp == 0:
temp = 10
if len(visited) == 0:
completed = True
break
else:
current = visited.pop()
temp = temp - 1
if not completed:
breakwalls(current, visited[len(visited)-1])
current.visited = True
current.show_block(WHITE)
for i in range(rows):
for j in range(cols):
grid[i][j].show(WHITE)
# grid[i][j].show_block(BLUE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
questionsAndAnswers = readMyFiles()
questions, answers, correctAnswers = shuffleSplit(questionsAndAnswers)
score = game(questions, answers, correctAnswers)
exportScores(score)
print('\nYour score is', str(score))
sys.exit()
if event.type == pygame.KEYDOWN and completed:
if event.key == pygame.K_LEFT:
player.left_pressed = True
if event.key == pygame.K_RIGHT:
player.right_pressed = True
if event.key == pygame.K_UP:
player.up_pressed = True
if event.key == pygame.K_DOWN:
player.down_pressed = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.left_pressed = False
if event.key == pygame.K_RIGHT:
player.right_pressed = False
if event.key == pygame.K_UP:
player.up_pressed = False
if event.key == pygame.K_DOWN:
player.down_pressed = False
player.rect.clamp_ip(screen_rect)
if player.x <= 2:
player.left_pressed = False
player.x = 2
if player.y <= 2:
player.up_pressed = False
player.y = 2
if player.x >= width-(wr-2):
player.right_pressed = False
player.x = width-(wr-2)
if player.y >= height-(wr-2):
player.down_pressed = False
player.y = height-(wr-2)
player.draw(screen)
player.update()
pygame.display.flip()
Where do I go from here to get to a point so that the walls act as physical barriers rather than just visual barriers? Currently, the maze is generated and the user can move throughout the screen. It always stays on the screen however I am not sure what the best way to implement the walls would be.
Compute the bounding rectangle of the player and compute the grid indices of the corner points and and center point:
player_rect = pygame.Rect(player.x, player.y, wr-3, hr-3)
xC, yC = int(player_rect.centerx / wr), int(player_rect.centery / hr)
x0, y0 = int(player_rect.left / wr), int(player_rect.top / hr)
x1, y1 = int(player_rect.right / wr), int(player_rect.bottom / hr)
Restrict the movement dependent on the direction and walls. For instance:
if player.left_pressed and player_rect.x < xC*wr+2:
if grid[xC][y0].walls[3] or grid[xC][y1].walls[3]:
player.x = xC*wr+2
player.left_pressed = False
Complete collision test:
while not done:
# [...]
player_rect = pygame.Rect(player.x, player.y, wr-3, hr-3)
xC, yC = int(player_rect.centerx / wr), int(player_rect.centery / hr)
x0, y0 = int(player_rect.left / wr), int(player_rect.top / hr)
x1, y1 = int(player_rect.right / wr), int(player_rect.bottom / hr)
if player.left_pressed and player_rect.x < xC*wr+2:
if grid[xC][y0].walls[3] or grid[xC][y1].walls[3]:
player.x = xC*wr+2
player.left_pressed = False
if player.y != yC*hr+2 and grid[x0][y0].walls[2]:
player.x = xC*wr+2
player.left_pressed = False
if player.right_pressed and player_rect.x > xC*wr+2:
if grid[xC][y0].walls[1] or grid[xC][y1].walls[1]:
player.x = xC*wr+2
player.right_pressed = False
if player.y != yC*hr+2 and grid[x0+1][y0].walls[2]:
player.x = xC*wr+2
player.right_pressed = False
if player.up_pressed and player_rect.y < yC*hr+2:
if grid[x0][yC].walls[0] or grid[x1][yC].walls[0]:
player.y = yC*hr+2
player.up_pressed = False
if player.x != xC*wr+2 and grid[x0][y0].walls[3]:
player.y = yC*hr+2
player.up_pressed = False
if player.down_pressed and player_rect.y > yC*hr+2:
if grid[x0][yC].walls[2] or grid[x1][yC].walls[2]:
player.y = yC*hr+2
player.down_pressed = False
if player.x != xC*wr+2 and grid[x0][y0+1].walls[3]:
player.y = yC*hr+2
player.down_pressed = False
See also How do I prevent the player from moving through the walls in a maze?