Reputation: 69
I am trying to create a 2D side shooting game. For bullets, I am using a list so everytime I shoot a bullet gets appended to that list and I "draw" the list on the screen. Whenever the bullet gets out of screen I delete that bullet off the list.
Currently, I have a feature where you can't change the direction of the bullet (an angle) whilst shooting (i.e when the bullet list is bigger than 0) because obviously I don't want people to control the direction of the bullet when they are out of the gun. However, that is not my intention because I want people to change the direction whilst shooting, just not the direction of the bullet that has already been shot out.
If that doesn't make sense, in order to forbid players magically changing the path or direction of the bullet that has already been shot out(Like using telekinesis to control the bullets and make them go in a circle), I forbid changing the direction whilst shooting at all. But that is not my intention, as I still want players to have control the direction of the bullet, just not the ones that has been shot out. Below is my code:`
import pygame
import math
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')
clock = pygame.time.Clock()
b_angle = 0
class player(object):
def __init__(self,x,y,width,height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 1.5
self.isJump = False
self.left = False
self.right = False
self.walkCount = 0
self.jumpCount = 13
self.standing = True
#Boolean value which forbids players from changing the angle of bullet whilst firing
self.isFiring = False
def draw(self, win):
if self.walkCount + 1 >= 45:
self.walkCount = 0
if not(self.standing):
if self.left:
win.blit(walkLeft[self.walkCount//5], (self.x,self.y))
self.walkCount += 1
elif self.right:
win.blit(walkRight[self.walkCount//5], (self.x,self.y))
self.walkCount +=1
else:
if self.right:
win.blit(walkRight[0], (self.x, self.y))
else:
win.blit(walkLeft[0], (self.x, self.y))
#Bullet Class
class projectile(object):
def __init__(self,x,y,radius,color,facing):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.facing = facing
self.vel = 8
def draw(self,win):
pygame.draw.circle(win, self.color, (self.x,self.y), self.radius)
#Drawing everything on screen function
def redrawGameWindow():
win.blit(bg, (0,0))
man.draw(win)
for bullet in bullets:
bullet.draw(win)
clock.tick(60)
pygame.display.update()
#mainloop
man = player(200, 410, 64,64)
#List of bullets
bullets = []
run = True
previous_time = pygame.time.get_ticks()
while run:
print(b_angle)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#Adding bullets into the list
for bullet in bullets:
if bullet.x < 500 and bullet.x > 0 and bullet.y < 480 and bullet.y > 0:
bullet.x += int((bullet.vel*math.cos(math.radians(b_angle))))
bullet.y -= int((bullet.vel*math.sin(math.radians(b_angle))))
else:
bullets.pop(bullets.index(bullet))
#Only allows changing direction when there are no bullets on screen.
if len(bullets) == 0:
man.isFiring = False
keys = pygame.key.get_pressed()
#SPACE button, which shoot out the bullets (also a time delay).
if keys[pygame.K_SPACE]:
man.isFiring = True
current_time = pygame.time.get_ticks()
if man.left:
facing = -1
else:
facing = 1
if current_time - previous_time > 200:
previous_time = current_time
if len(bullets) < 10:
#See when there are bullets and set Firing = True.
man.isFiring = True
bullets.append(projectile(round(man.x + man.width //2), round(man.y + man.height//2), 3, (0,0,0), facing))
#A and D keys control direction of bullet.
if keys[pygame.K_a]:
if not man.isFiring:
b_angle += 3
if keys[pygame.K_d]:
if not man.isFiring:
b_angle -= 3
if keys[pygame.K_LEFT] and man.x > man.vel:
man.x -= man.vel
man.left = True
man.right = False
man.standing = False
elif keys[pygame.K_RIGHT] and man.x < 500 - man.width - man.vel:
man.x += man.vel
man.right = True
man.left = False
man.standing = False
else:
man.standing = True
man.walkCount = 0
if not(man.isJump):
if keys[pygame.K_UP]:
man.isJump = True
man.standing = False
man.walkCount = 0
else:
if man.jumpCount >= -13:
neg = 1
if man.jumpCount < 0:
neg = -1
man.y -= (man.jumpCount ** 2) ** 0.35 * neg
man.jumpCount -= 1
else:
man.isJump = False
man.jumpCount = 13
redrawGameWindow()
pygame.quit()
Thanks in advance!
Upvotes: 3
Views: 1259
Reputation: 101072
You should restructure your code so that all logic related to the player is in the Player
class, and all logic that is related to the projectiles is in the Projectile
class.
Also, make use of pygame's Sprite
class, which will help you organizing your code and keeping it simple.
Using some vector math will also simplify your code: when firing a projectile, create a vector describing the direction the projectile should move. Then, when moving the projectile, simply add that vector to the position of the projectile.
Here's a running example:
import pygame
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((32, 32))
self.image.fill((0, 0, 0))
self.image.set_colorkey((0, 0, 0))
pygame.draw.polygon(self.image, pygame.Color('dodgerblue'), ((0, 0), (32, 16), (0, 32)))
self.org_image = self.image.copy()
self.angle = 0
self.direction = pygame.Vector2(1, 0)
self.rect = self.image.get_rect(center=(200, 200))
self.pos = pygame.Vector2(self.rect.center)
def update(self, events, dt):
for e in events:
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_SPACE:
self.groups()[0].add(Projectile(self.rect.center, self.direction.normalize()))
pressed = pygame.key.get_pressed()
if pressed[pygame.K_a]:
self.angle += 3
if pressed[pygame.K_d]:
self.angle -= 3
self.direction = pygame.Vector2(1, 0).rotate(-self.angle)
self.image = pygame.transform.rotate(self.org_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
class Projectile(pygame.sprite.Sprite):
def __init__(self, pos, direction):
super().__init__()
self.image = pygame.Surface((8, 8))
self.image.fill((0, 0, 0))
self.image.set_colorkey((0, 0, 0))
pygame.draw.circle(self.image, pygame.Color('orange'), (4, 4), 4)
self.rect = self.image.get_rect(center=pos)
self.direction = direction
self.pos = pygame.Vector2(self.rect.center)
def update(self, events, dt):
self.pos += self.direction * dt
self.rect.center = self.pos
if not pygame.display.get_surface().get_rect().contains(self.rect):
self.kill()
def main():
pygame.init()
screen = pygame.display.set_mode((500, 500))
sprites = pygame.sprite.Group(Player())
clock = pygame.time.Clock()
dt = 0
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
sprites.update(events, dt)
screen.fill((30, 30, 30))
sprites.draw(screen)
pygame.display.update()
dt = clock.tick(60)
if __name__ == '__main__':
main()
Upvotes: 2
Reputation: 14906
One way to solve this is to store the direction in the projectile.
#Bullet Class
class projectile(object):
def __init__(self, x, y, radius, color, facing, angle):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.facing = facing
self.vel = 8
self.angle = angle # <<== HERE
def draw(self, win):
pygame.draw.circle(win, self.color, (self.x, self.y), self.radius)
# Compute the next position of the projectile, returning False
# if it outside the screen co-oridinates
def update(self):
if (self.x < 500 and self.x > 0 and self.y < 480 and self.y > 0):
self.x += int((self.vel*math.cos(math.radians(self.angle))))
self.y -= int((self.vel*math.sin(math.radians(self.angle))))
return True
else:
return False
This leaves your update function:
while run:
print(b_angle)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# Move the bullets
for bullet in bullets:
if (bullet.update() == False):
bullets.pop(bullets.index(bullet)) # bullet left screen
#Only allows changing direction when there are no bullets on screen.
if len(bullets) == 0:
man.isFiring = False
Of course, when you create a new bullet, it needs to also be given the b_angle
.
bullets.append(projectile(round(man.x + man.width //2), round(man.y + man.height//2), 3, (0,0,0), facing, b_angle))
Upvotes: 0