python - How do I make a projectile in pygame that will move upward? -
i wrote game meant shoot blue square screen when spacebar pressed. however, blue square right above shooter. here code:
import pygame, sys, random gameobjects import * def main(): pygame.init() screen = pygame.display.set_mode((800, 800)) numberofcolumns = 5 columnwidth = screen.get_width() / numberofcolumns numberofrows = 5 rowwidth = screen.get_width() / numberofrows magazineimage = pygame.image.load("images/magazine.bmp") magazineissueoneimage = pygame.image.load("images/magazine #1.bmp") monsterstate1 = pygame.image.load("images/zombie pos 1.bmp") monsterstate2 = pygame.image.load("images/zombie pos 2.bmp") monsterstate3 = pygame.image.load("images/zombie pos 3.bmp") monsters = [] forrystate1 = pygame.image.load("images/forry pos 1.bmp") forrystate2 = pygame.image.load("images/forry pos 2.bmp") forrydelaytime = 8 gameobjects = [] gameobjectblittingcounter = 0 monsterspawnspotlist = [(rowwidth * -5), (rowwidth * -4), (rowwidth * -3), (rowwidth * -2), (rowwidth * -1)] monster in range(0, 5): monster = monster(monsterstate1, monsterstate2, monsterstate3, ((columnwidth / 2 - monsterstate1.get_width() / 2) + gameobjectblittingcounter * columnwidth), random.choice(monsterspawnspotlist)) monsters.append(monster) gameobjects.append(monster) gameobjectblittingcounter += 1 forry = forry(forrystate1, forrystate2, columnwidth, rowwidth, screen, forrydelaytime, magazineimage, magazineissueoneimage) gameobjects.append(forry) while true: screen.fill((0,255,0)) event in pygame.event.get(): if event.type == pygame.quit: sys.exit() #update projectiles if forry.projectilecall == true: magazine = magazine(magazineimage, forry) gameobjects.append(magazine) #update game objects gameobject in gameobjects: gameobject.update() #render gameobjectblittingcounter = 0 gameobject in gameobjects: screen.blit(gameobjects[gameobjectblittingcounter].image, ((gameobjects[gameobjectblittingcounter].rect.x), (gameobjects[gameobjectblittingcounter].rect.y))) gameobjectblittingcounter += 1 pygame.display.flip() if __name__ == "__main__": main()
the file gameobjects.py looks this:
import pygame class monster(pygame.sprite.sprite): def __init__(self, monsterstate1, monsterstate2, monsterstate3, xcoord, ycoord): self.monsterstate1 = monsterstate1 self.monsterstate2 = monsterstate2 self.monsterstate3 = monsterstate3 self.image = self.monsterstate1 self.rect = self.image.get_rect() self.rect.y = ycoord self.rect.x = xcoord def update(self): self.movedown() def movedown(self): self.rect.y += 1 def onspawn(self): return def ondeath(self): return def reset(self): return class forry(pygame.sprite.sprite): def __init__(self, forrystate1, forrystate2, columnwidth, rowwidth, screen, delaytime, magazineimage, magazineissueoneimage): self.forrystate1 = forrystate1 self.forrystate2 = forrystate2 self.image = self.forrystate1 self.columnwidth = columnwidth self.rowwidth = rowwidth self.rect = self.image.get_rect() self.rect.y = self.columnwidth / 2 - self.image.get_width() / 2 self.rect.y = screen.get_height() - (self.rowwidth / 2 - self.image.get_height() / 2) self.delaytime = delaytime self.delay = 0 self.magazineimage = magazineimage self.magazineissueoneimage = magazineissueoneimage self.projectilecall = false self.rightbound = screen.get_width() - (self.columnwidth / 2 + self.image.get_width() / 2) self.leftbound = (self.columnwidth / 2 - self.image.get_width() / 2) def update(self): #check player input playerinput = self.checkplayerinput() #update position if self.delay > 0: self.delay -= 1 elif self.delay < 0: self.delay = 0 else: self.updateposition(playerinput) #keep on screen self.keeponscreen() def checkplayerinput(self): left = pygame.key.get_pressed() [pygame.k_left] right = pygame.key.get_pressed() [pygame.k_right] shoot = pygame.key.get_pressed() [pygame.k_space] return (left, right, shoot) def updateposition(self, playerinput): left = playerinput[0] right = playerinput[1] shoot = playerinput[2] if self.projectilecall == true: self.projectilecall = false self.image = self.forrystate1 if shoot: self.image = self.forrystate2 self.projectilecall = true self.delay = self.delaytime if left: self.rect.x -= self.columnwidth self.delay = self.delaytime if right: self.rect.x += self.columnwidth self.delay = self.delaytime def keeponscreen(self): if self.rect.x >= self.rightbound: self.rect.x = self.rightbound elif self.rect.x <= self.leftbound: self.rect.x = self.leftbound def onspawn(self): return def ondeath(self): return def reset(self): return class magazine(pygame.sprite.sprite): def __init__(self, image, shooter): self.image = image self.rect = image.get_rect() self.rect.x = shooter.rect.x self.rect.y = shooter.rect.y - shooter.image.get_height() def update(self): self.rect.y -= 5 if self.rect.y <= 0 - self.image.get_height(): self.kill()
my magazine blue square
so why doesn't projectile go screen?
++++++++
with fixes in answer below, have error:
when blue box goes off screen, supposed killed because of self.kill() in update function of magazine class.
however, instead of being killed, minute 1 of them gets off screen, gives me these errors:
traceback (most recent call last): file "main.py", line 106, in <module> main() file "main.py", line 78, in main projectileobject.update() file "/users/number1son100/desktop/famous monsters game/gameobjects.py", line 117, in update self.kill() file "/library/frameworks/python.framework/versions/2.7/lib/python2.7/site-packages/pygame/sprite.py", line 174, in kill c in self.__g.keys(): attributeerror: 'magazine' object has no attribute '_sprite__g'
answer
stumped me while, classic case of "right under our noses":
look @ indentation of "update" function under magazine, indented 1 far right, means function defined -inside- __init__() instead of method of magazine wanted. if didnt make sense you, "dedent" block looks
class magazine(pygame.sprite.sprite): def __init__(self, image, shooter): self.image = image self.rect = image.get_rect() self.rect.x = shooter.rect.x self.rect.y = shooter.rect.y - shooter.image.get_height() def update(self): self.rect.y -= 5 if self.rect.y <= 0 - self.image.get_height(): self.kill()
some explaination why nothing happened no error: update function not method of magazine, did not overwrite 1 inherited pygame.sprite.sprite. result when called main loop, placehold/basic method called, not custom one. meant didnt error/exception didnt work!
moving on, there few major things issue here correction:
addendum
1)
not neccessarily issue, can use python "for x in y" syntax here:
gameobject in gameobjects: gameobject.update()
later on in render section, i.e.:
#render gameobjectblittingcounter = 0 gameobject in gameobjects: screen.blit(gameobjects[gameobjectblittingcounter].image, ((gameobjects[gameobjectblittingcounter].rect.x), (gameobjects[gameobjectblittingcounter].rect.y))) gameobjectblittingcounter += 1
becomes:
gameobject in gameobjects: screen.blit(gameobject.image, gameobject.rect)
note can pass whole rect instead of splitting rect.x , rect.y
2)
you notice once fix update function, current code spawns multiple shots when press spacebar, because spawn mechanic looks if spacebar held , spawns projectile every loop, try removing spawning loop , once when space pressed or released
3)
cap framerate
in testing framerate spike high , make game run oddly. cap framerate using pygame.clock object , calling clock.tick(framerate) in loop
4)
in preparation further complexity, consider splitting "gameobjects" lists several different types (enemyobjects, projectileobjects, etc), because these may need different treatment @ point, or saves looping entire list effects enemies if occurs.
finally small plug of website, have source , docs pygame libraries can use , may in future.
Comments
Post a Comment