1

I want to get my bullet shooting in the direction that my ship is facing. I managed to get a bullet in the game using this very useful code: How to create bullets in pygame?

Let me provide some code for reference. Below is the set of codes used to rotate my ship as-well as get it to move in said direction. Also, Offset = 0.

'''Directional commands for the sprite'''
if pressed[pygame.K_LEFT]: offset_change += 4
if pressed[pygame.K_RIGHT]: offset_change -= 4
if pressed[pygame.K_UP]:
    y_change -= cos(spaceship.angle) * 8
    x_change -= sin(spaceship.angle) * 8    
if pressed[pygame.K_DOWN]:
    y_change += 5
if event.type == pygame.KEYUP:
    if event.key == pygame.K_RIGHT or event.key == pygame.K_LEFT or event.key == pygame.K_UP or event.key == pygame.K_DOWN:
        x_change = 0
        y_change = 0
        offset_change = 0

'''changes X/Y based on the value of X/Y_Change'''

spaceship.angle += offset_change        
spaceship.startY += y_change
spaceship.startX += x_change

Below is the class the spaceship code is in.

class Spaceship():
'''Class attributed to loading the spaceship'''
    def __init__(self, char, startX, startY, Angle):
        '''Loads in the image and sets variables'''
        self.char = char
        self.startX = startX
        self.startY = startY
        self.angle = Angle
        self.space = load_item(self.char)
        self.drawChar()

    def drawChar(self):
        '''Draws the image on the screen'''
        #Code is from Pygame documentation 
        #Due to limitations of Pygame the following code had to be used with a few of my own manipulations
        rot_image = pygame.transform.rotate(self.space,self.angle)
        rot_rect = self.space.get_rect()
        rot_rect.center = rot_image.get_rect().center
        rot_image = rot_image.subsurface(rot_rect).copy()
        gameDisplay.blit(rot_image,(self.startX,self.startY))

Now as part of the "How to create bullets..." link I previously mentioned I was thinking of changing

for b in range(len(bullets)):
    bullets[b][1] -= 8

to bullets[spaceship.startX][spaceship.startY] -= 8 As it was my belief that that line of code represented bullets[x][y]. However I was presented with TypeError: list indices must be integers, not float.

I'm guessing my assumption is wrong. Any ideas you can suggest to get my bullet moving according to how I'd like it to be?

Community
  • 1
  • 1
Lucky38i
  • 125
  • 1
  • 16
  • please consider looking into PEP008 (the python style guide). And a little tip: instead of repeated `==`, you can use `event.key in [pygame.K_RIGHT, pygame.K_LEFT, ...]`. – CodenameLambda Nov 26 '16 at 14:14
  • @CodingLambdas I'm not sure what I'm looking for in here.. – Lucky38i Nov 26 '16 at 14:19
  • I was writing an answer including a PointMass class, wich does a simple physics simulation, but I figured it would be too much. That's why there is just a simple answer below. The things in my previous comment are just tips to get your code to be more readable. – CodenameLambda Nov 26 '16 at 14:27

1 Answers1

1

b is the index of the bullet in the list bullets, and 0 or 1 are the x and y coordinates.

You can update them as follows, with angle and speed changed to their values:

for bullet in bullets:  # as 'bullets' is a list of lists
    bullet[0] += math.cos(angle) * speed
    bullet[1] += math.sin(angle) * speed

Another, more object oriented, approach:

class Vector(tuple):
    def __new__(cls, *args):
        if len(args) == 1 and hasattr(args[0], "__iter__"):
            return super().__new__(cls, args[0])
        else:
            return super().__new__(cls, args)

    def __add__(self, other):
        return Vector(a + b for a, b in zip(self, other))

    def __sub__(self, other):
        return Vector(a - b for a, b in zip(self, other))

    def __neg__(self):
        return Vector(-i for i in self)

    def __mul__(self, other):
        return Vector(i * other for i in self)

    def __rmul__(self, other):
        return self.__mul__(other)

    def __div__(self, other):
        return Vector(i / other for i in self)

    def __truediv__(self, other):
        return self.__div__(other)


class Bullet(object):
    def __init__(self, position, angle, speed):
        self.position = Vector(position)
        self.speed = Vector(math.cos(angle), math.sin(angle)) * speed

    def tick(self, tdelta=1):
        self.position += self.speed * tdelta

    def draw(self):
        pass  # TODO


# Construct a bullet
bullets.append(Bullet(position, angle, speed)

# To move all bullets
for i in bullets:
    i.tick()  # or i.tick(tdelta)
CodenameLambda
  • 1,486
  • 11
  • 23
  • This somewhat works, and I do apologise for my code, still learning (1st Year @ Uni). It works to some extent but for certain angle it doesn't work as it should and of course rotating my ship causes the bullet to jitter and change directions sometimes – Lucky38i Nov 26 '16 at 15:15
  • Ok, I think I'll add another approach, that adds a `Bullet` class. – CodenameLambda Nov 26 '16 at 15:33
  • @Lucky38i If you think about it, its logical that this happens: If you supply the angle of the ship, instead of storing the angles of all bullets, you are consequently changing the angle of all bullets too. I should have added, that you should store the angles for them in the list that represents a bullet as well, or somewhere else. – CodenameLambda Nov 26 '16 at 15:46
  • I'll give your class approach a look then get back to you, greatly appreciate the help – Lucky38i Nov 26 '16 at 15:54
  • alright I managed to slightly wrap my head around what's going on here but can't seem to figure out how to blit it on the screen – Lucky38i Nov 26 '16 at 17:38
  • Thats what the `draw` method is for. You'll have to implement it, I'd use [`pygame.draw.circle`](http://www.pygame.org/docs/ref/draw.html#pygame.draw.circle) for that. You'll have to call this method for all bullets in your mainloop. – CodenameLambda Nov 26 '16 at 20:18
  • I'm a little confused as to why I'd draw a circle if my bullet is an image. Under `def draw(self):` I put `gameDisplay.blit(bulletpic,self.position)` instead. In the main code I put `bullets.append(Bullet((spaceship.startX+30, spaceship.startY-5),spaceship.angle - 15,8))` and to draw I put `bullet.draw()` under the for statement – Lucky38i Nov 27 '16 at 15:26
  • @Lucky38i yup. Didn't know that you have an image. You may rotate it via `pygame.transform.rotate`. – CodenameLambda Nov 27 '16 at 15:54
  • few alterations and I got it working, appreciate the help – Lucky38i Dec 01 '16 at 10:57