Reputation: 640
In my game I can place cannons anywhere on the screen. I want my cannons to be able to fire bullets and the bullets should be reset after they travel 100 pixels. Given below is my cannon class, I'm still new to OOP so I require some help however I wasn't able to accomplish this task using lists either. Thank you for your help.
class Cannon():
global cannon_list
global bullet_list
def __init__(self, x, y, track, old_x):
self.x = x
self.y = y
self.track = track
self.old_x = old_x
def spawnBullet(self):
for j in bullet_list:
self.old_x = self.x
self.track = j[2]
screen.blit(bullet, (j[0], j[1]))
def moveBullet(self):
if self.x <= self.track:
self.x += 3
def resetBullet(self):
if self.x >= self.track:
self.x = self.old_x
def spawnCannon(self):
for i in cannon_list:
screen.blit(cannon, i)
Using the cannon class. this is under redrawGamewindow.
for j in bullet_list:
cannonsAndBullets = Cannon(j[0], j[1], j[2], j[0])
cannonsAndBullets.spawnCannon()
cannonsAndBullets.spawnBullet()
cannonsAndBullets.moveBullet()
cannonsAndBullets.resetBullet()
Given below is what I have appended into bullet_list
and cannon_list
. x an y are the position of my player
cannon_list.append([x,y])
bullet_list.append([x,(y+25),100, x])
Edits in my class
class Cannon():
global cannon_list
global bullet_list
def __init__(self, x, y, track, old_x):
self.x = x
self.y = y
self.track = track
self.old_x = old_x
def spawnBullet(self):
# for j in bullet_list:
# self.x, self.y, self.track, self.old_x = j
screen.blit(bullet, (self.x, self.y))
def moveBullet(self):
# for j in bullet_list:
# self.x, self.y, self.track, self.old_x = j
if self.track <= 100:
print(self.track)
self.track += 3
self.x += 3
def resetBullet(self):
# for j in bullet_list:
# self.x, self.y, self.track, self.old_x = j
if self.track >= 100:
print(self.track)
self.x = self.old_x
def spawnCannon(self):
for i in cannon_list:
screen.blit(cannon, i)
Upvotes: 2
Views: 126
Reputation: 101072
Let's discard everything and start from scratch and make use of pygame features like sprites and vector math.
We begin with a basic skeleton of a pygame game, a simple window:
import pygame
def main():
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
screen.fill(pygame.Color('grey'))
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
Now, we want to place some Sprites. Let's create a Sprite
class that represents the cannons, and let's place them with the mouse:
import pygame
class Cannon(pygame.sprite.Sprite):
def __init__(self, pos, *grps):
super().__init__(*grps)
self.image = pygame.Surface((32, 32))
self.image.fill(pygame.Color('darkred'))
self.rect = self.image.get_rect(center=pos)
def main():
all_sprites = pygame.sprite.Group()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
if e.type == pygame.MOUSEBUTTONDOWN:
Cannon(e.pos, all_sprites)
all_sprites.update()
screen.fill(pygame.Color('grey'))
all_sprites.draw(screen)
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
Now we want the cannons to shoot bullets. To do that, we're making use of some OOP features, like polymorphism. Bullets and cannons are different types, but they provide the same interface: update
and draw
. And that's it. Note how our mainloop does not need to know what types exactly our sprites are.
We also make sure that all the logic for bullets is in the Bullet
class, and all the logic for the cannon is in the Cannon
class:
import pygame
class Bullet(pygame.sprite.Sprite):
def __init__(self, pos, *grps):
super().__init__(*grps)
self.image = pygame.Surface((4, 4))
self.image.fill(pygame.Color('black'))
self.rect = self.image.get_rect(center=pos)
self.pos = pygame.Vector2(pos)
self.travelled = pygame.Vector2(0, 0)
direction = pygame.Vector2(pygame.mouse.get_pos()) - self.pos
if direction.length() > 0:
self.direction = direction.normalize()
else:
self.kill()
def update(self, dt):
v = self.direction * dt / 5
self.pos += v
self.travelled += v
self.rect.center = self.pos
if self.travelled.length() > 100:
self.kill()
class Cannon(pygame.sprite.Sprite):
def __init__(self, pos, *grps):
super().__init__(*grps)
self.image = pygame.Surface((32, 32))
self.image.fill(pygame.Color('darkred'))
self.rect = self.image.get_rect(center=pos)
self.timer = 200
def update(self, dt):
self.timer = max(self.timer - dt, 0)
if self.timer == 0:
self.timer = 200
Bullet(self.rect.center, self.groups()[0])
def main():
all_sprites = pygame.sprite.Group()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
dt = 1
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
if e.type == pygame.MOUSEBUTTONDOWN:
Cannon(e.pos, all_sprites)
all_sprites.update(dt)
screen.fill(pygame.Color('grey'))
all_sprites.draw(screen)
pygame.display.flip()
dt = clock.tick(60)
if __name__ == '__main__':
main()
Using a vector and simply adding the distance travelled each frame makes it easy to check for each Bullet
if it already travelled 100 pixels. If true, simply calling kill
will remove it.
Upvotes: 2