Question

I was experimenting in Pygame and trying to make a top down shooter, and found a script on angular movement towards a point here, and used it for bullets. There is one problem I am having, how can I keep the bullet moving in the direction that is calculated. I'm not great at math (yet), but I understand most of what is going on here:

speed = speed
distance = [t0 - psx, t1 - psy]
norm = math.sqrt(distance[0] ** 2 + distance[1] ** 2)
direction = [distance[0] / norm, distance[1 ] / norm]
bullet_vector = [direction[0] * speed, direction[1] * speed]

It is based on slope formula of deltaY/deltaX. Right? Anybody know how to do this?

Here is the complete source code for reference:

import pygame
from pygame.locals import *
import math

#init stuff
pygame.init()
screen=pygame.display.set_mode((640,480))
clock=pygame.time.Clock()
run=True
orbs=[]
px=1
py=1
clock=pygame.time.Clock()

#movement from one point to another
def Move(t0,t1,psx,psy,speed):
    global mx
    global my

    speed = speed

    distance = [t0 - psx, t1 - psy]
    norm = math.sqrt(distance[0] ** 2 + distance[1] ** 2)
    direction = [distance[0] / norm, distance[1 ] / norm]

    bullet_vector = [direction[0] * speed, direction[1] * speed]
    return bullet_vector

#bullet class
class Orb(object):
    def __init__(self,posorg,posdest):
        self.posx=posorg[0]
        self.posy=posorg[1]
        self.targ=posdest
        self.posorg=posorg
    def update(self):
        bullet_vector=Move(self.targ[0],self.targ[1],self.posx,self.posy,20)
        self.posx += bullet_vector[0]
        self.posy += bullet_vector[1]
        pygame.draw.circle(screen, ((0,0,255)), (int(self.posx),int(self.posy)), 5)

#main loop
while run:
    screen.fill((220,220,220))
    for o in orbs:
        o.update()
    (mx,my)=(pygame.mouse.get_pos()[0],pygame.mouse.get_pos()[1])

    for e in pygame.event.get():
        #quit on close button
        if e.type == QUIT:
            run=False
        if e.type==MOUSEBUTTONDOWN:
            if e.button==1:
                orbs.append(Orb((px,py),(mx,my)))
    #player movement
    key=pygame.key.get_pressed()

    if key[K_a]:
        px-=2
    if key[K_d]:
        px+=2
    if key[K_w]:
        py-=2
    if key[K_s]:
        py+=2
    clock.tick(60)
    pygame.draw.circle(screen, ((2,150,2)), (int(px),int(py)), 30)
    pygame.display.update()
Was it helpful?

Solution

Your update is changing the value of the bullet vector on each update,.. what you really want is for the vector to only be calculated at the moment of firing, then update the position based on that initial vector... so change orb to something like:

class Orb(object):
    def __init__(self,posorg,posdest):
        self.posx=posorg[0]
        self.posy=posorg[1]
        self.targ=posdest
        self.posorg=posorg
        self.bullet_vector=Move(self.targ[0],self.targ[1],self.posx,self.posy,20)
    def update(self):
        self.posx += self.bullet_vector[0]
        self.posy += self.bullet_vector[1]
        pygame.draw.circle(screen, ((0,0,255)), (int(self.posx),int(self.posy)), 5)

This way the movement vector is calculated only once upon creation.

You should however also add a check to see if the bullet is still on the screen. If its not you should delete it to save resources when you have many bullets in one game.

Good luck!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top