Finding vector given 2 points

Finding vector given 2 points

Im helping my friend out with a pygame but we are stuck

so were are trying to get the direction of a projectile but we cant find out how

for example:

[1,1] will go SE

[1,-1] will go NE

[-1,-1] will go NW

and [-1,1] will go SW

we need an equation of some sort that will take the player pos and the mouse pos and find which direction the projectile needs to go

here is where we are plugging in the vectors:

Code: Select all
` def update(self):    self.rect.x += self.vector[0]    self.rect.y += self.vector[1] `

then we are blitting the projectile at the rects coords

if you want to see all the code here is the repo

ChristianCareaga

Posts: 53
Joined: Sat Jun 22, 2013 9:54 am

Re: Finding vector given 2 points

Code: Select all
`offset = (self.rect.centerx-mouse[0],self.rect.centery-mouse[1])`
You could then use math.atan2 to find the angle.

One important thing you should know about Rects is that they can only hold ints. This means that if your angle demands that an object move 0.5 pixels per frame, it won't move. You need to keep track of the fractional bits somehow. Depending on what you are doing you may also need to do work so that your images centers don't shift when rotating.

Here is an earlier example of mine reworked to follow and shoot with mouse.

This is possibly more complicated than you need but maybe you can get the idea:
Code: Select all
`import pygame as pgimport sys,os,mathclass Turret(object):    def __init__(self,loc):        self.orig_barrel = TURRET.subsurface((0,0,150,150))        self.barrel = self.orig_barrel.copy()        self.base   = TURRET.subsurface((300,0,150,150))        self.rect = self.barrel.get_rect(center=loc)        self.base_rect = self.rect.copy()        self.angle = self.get_angle(pg.mouse.get_pos())    def event_manager(self,event,Objects):        if event.type == pg.MOUSEBUTTONDOWN:            if event.button == 1:                Objects.append(Laser(self.rect.center,self.angle))        elif event.type == pg.MOUSEMOTION:            self.get_angle(event.pos)    def update(self,Surf):        Surf.blit(self.base,self.base_rect)        Surf.blit(self.barrel,self.rect)    def get_angle(self,mouse):        offset = (self.rect.centerx-mouse[0],self.rect.centery-mouse[1])        self.angle = math.degrees(math.atan2(*offset))-135        oldcenter = self.rect.center        self.barrel = pg.transform.rotate(self.orig_barrel,self.angle)        self.rect = self.barrel.get_rect(center=oldcenter)class Laser(object):    def __init__(self,loc,angle):        self.orig_laser = TURRET.subsurface((150,0,150,150))        self.angle = -math.radians(angle-135)        self.image = pg.transform.rotate(self.orig_laser,angle)        self.rect = self.image.get_rect(center=loc)        self.move = [self.rect.x,self.rect.y]        self.speed_mag = 5        self.speed = (self.speed_mag*math.cos(self.angle),                      self.speed_mag*math.sin(self.angle))        self.done = False    def update(self,Surf):        self.move[0] += self.speed[0]        self.move[1] += self.speed[1]        self.rect.topleft = self.move        self.remove(Surf)        Surf.blit(self.image,self.rect)    def remove(self,Surf):        if not self.rect.colliderect(Surf.get_rect()):            self.done = Trueclass Control(object):    def __init__(self):        self.Screen = pg.display.get_surface()        self.done = False        self.Clock = pg.time.Clock()        self.fps = 60        self.Cannon = Turret((250,250))        self.Objects = []    def event_loop(self):        keys = pg.key.get_pressed()        for event in pg.event.get():            if event.type == pg.QUIT or keys[pg.K_ESCAPE]:                self.done = True            self.Cannon.event_manager(event,self.Objects)    def update(self):        self.Screen.fill((50,50,50))        self.Cannon.update(self.Screen)        for Obj in self.Objects[:]:            Obj.update(self.Screen)            if Obj.done:                self.Objects.remove(Obj)    def main(self):        while not self.done:            self.event_loop()            self.update()            pg.display.flip()            self.Clock.tick(self.fps)#######def image_from_url(url):    try:        from urllib2 import urlopen        from cStringIO import StringIO as inout    except ImportError:        from urllib.request import urlopen        from io import BytesIO as inout    myurl = urlopen(url)    return inout(myurl.read()) #Can be loaded by pygame.image.load#######if __name__ == "__main__":    os.environ['SDL_VIDEO_CENTERED'] = '1'    pg.init()    SCREENSIZE = (500,500)    pg.display.set_mode(SCREENSIZE)    TURRET_URL = "http://i1192.photobucket.com/albums/aa340/Mekire/turret.png"    TURRET = pg.image.load(image_from_url(TURRET_URL)).convert()    TURRET.set_colorkey((255,0,255))    RunIt = Control()    RunIt.main()    pg.quit();sys.exit()`

-Mek

Edit:
If you have no need to rotate the images and don't need to actually know the angle, you could just find the unit vector in the appropriate direction. You do this by dividing each component of the vector by the magnitude of the vector:
Code: Select all
`offset = (mouse[0]-self.rect.centerx,mouse[1]-self.rect.centery)self.unit = (offset[0]/math.hypot(*offset),offset[1]/math.hypot(*offset))`
Then the speed components of your projectile are just the components of this unit vector multiplied by the desired radial speed.
Code: Select all
`self.speed = (self.speed_mag*unit_vector[0],self.speed_mag*unit_vector[1])`
• Use code tags when posting code.
• Include any errors with your post (in code tags).
• Make examples the minimum length to demonstrate your issue.

Mekire

Posts: 1515
Joined: Thu Feb 07, 2013 11:33 pm
Location: Tucson, Arizona

Re: Finding vector given 2 points

Mekire wrote:Your vector will essentially be:
Code: Select all
`offset = (self.rect.centerx-mouse[0],self.rect.centery-mouse[1])`
You could then use math.atan2 to find the angle.

One important thing you should know about Rects is that they can only hold ints. This means that if your angle demands that an object move 0.5 pixels per frame, it won't move. You need to keep track of the fractional bits somehow. Depending on what you are doing you may also need to do work so that your images centers don't shift when rotating.

Here is an earlier example of mine reworked to follow and shoot with mouse.

This is possibly more complicated than you need but maybe you can get the idea:
Code: Select all
`import pygame as pgimport sys,os,mathclass Turret(object):    def __init__(self,loc):        self.orig_barrel = TURRET.subsurface((0,0,150,150))        self.barrel = self.orig_barrel.copy()        self.base   = TURRET.subsurface((300,0,150,150))        self.rect = self.barrel.get_rect(center=loc)        self.base_rect = self.rect.copy()        self.angle = self.get_angle(pg.mouse.get_pos())    def event_manager(self,event,Objects):        if event.type == pg.MOUSEBUTTONDOWN:            if event.button == 1:                Objects.append(Laser(self.rect.center,self.angle))        elif event.type == pg.MOUSEMOTION:            self.get_angle(event.pos)    def update(self,Surf):        Surf.blit(self.base,self.base_rect)        Surf.blit(self.barrel,self.rect)    def get_angle(self,mouse):        offset = (self.rect.centerx-mouse[0],self.rect.centery-mouse[1])        self.angle = math.degrees(math.atan2(*offset))-135        oldcenter = self.rect.center        self.barrel = pg.transform.rotate(self.orig_barrel,self.angle)        self.rect = self.barrel.get_rect(center=oldcenter)class Laser(object):    def __init__(self,loc,angle):        self.orig_laser = TURRET.subsurface((150,0,150,150))        self.angle = -math.radians(angle-135)        self.image = pg.transform.rotate(self.orig_laser,angle)        self.rect = self.image.get_rect(center=loc)        self.move = [self.rect.x,self.rect.y]        self.speed_mag = 5        self.speed = (self.speed_mag*math.cos(self.angle),                      self.speed_mag*math.sin(self.angle))        self.done = False    def update(self,Surf):        self.move[0] += self.speed[0]        self.move[1] += self.speed[1]        self.rect.topleft = self.move        self.remove(Surf)        Surf.blit(self.image,self.rect)    def remove(self,Surf):        if not self.rect.colliderect(Surf.get_rect()):            self.done = Trueclass Control(object):    def __init__(self):        self.Screen = pg.display.get_surface()        self.done = False        self.Clock = pg.time.Clock()        self.fps = 60        self.Cannon = Turret((250,250))        self.Objects = []    def event_loop(self):        keys = pg.key.get_pressed()        for event in pg.event.get():            if event.type == pg.QUIT or keys[pg.K_ESCAPE]:                self.done = True            self.Cannon.event_manager(event,self.Objects)    def update(self):        self.Screen.fill((50,50,50))        self.Cannon.update(self.Screen)        for Obj in self.Objects[:]:            Obj.update(self.Screen)            if Obj.done:                self.Objects.remove(Obj)    def main(self):        while not self.done:            self.event_loop()            self.update()            pg.display.flip()            self.Clock.tick(self.fps)#######def image_from_url(url):    try:        from urllib2 import urlopen        from cStringIO import StringIO as inout    except ImportError:        from urllib.request import urlopen        from io import BytesIO as inout    myurl = urlopen(url)    return inout(myurl.read()) #Can be loaded by pygame.image.load#######if __name__ == "__main__":    os.environ['SDL_VIDEO_CENTERED'] = '1'    pg.init()    SCREENSIZE = (500,500)    pg.display.set_mode(SCREENSIZE)    TURRET_URL = "http://i1192.photobucket.com/albums/aa340/Mekire/turret.png"    TURRET = pg.image.load(image_from_url(TURRET_URL)).convert()    TURRET.set_colorkey((255,0,255))    RunIt = Control()    RunIt.main()    pg.quit();sys.exit()`

-Mek

Edit:
If you have no need to rotate the images and don't need to actually know the angle, you could just find the unit vector in the appropriate direction. You do this by dividing each component of the vector by the magnitude of the vector:
Code: Select all
`offset = (mouse[0]-self.rect.centerx,mouse[1]-self.rect.centery)self.unit = (offset[0]/math.hypot(*offset),offset[1]/math.hypot(*offset))`
Then the speed components of your projectile are just the components of this unit vector multiplied by the desired radial speed.
Code: Select all
`self.speed = (self.speed_mag*unit_vector[0],self.speed_mag*unit_vector[1])`

Youre the man Mekire! yeah we got it working thanks so much!
ChristianCareaga

Posts: 53
Joined: Sat Jun 22, 2013 9:54 am

Re: Finding vector given 2 points

Looking good. I recommend the use of atan2 over atan in this case though:
Code: Select all
`>>> import math>>> help(math.atan2)Help on built-in function atan2 in module math:atan2(...)    atan2(y, x)        Return the arc tangent (measured in radians) of y/x.    Unlike atan(y/x), the signs of both x and y are considered.`
That will stop you needing to worry about those zero division errors.

Also math.hypot is really nice. Instead of calculating a vector magnitude like this:
Code: Select all
`math.sqrt(distance[0] ** 2 + distance[1] ** 2) `
you would just do this:
Code: Select all
`math.hypot(distance[0],distance[1])`
or better yet, this:
Code: Select all
`math.hypot(*distance)`

-Mek
• Use code tags when posting code.
• Include any errors with your post (in code tags).
• Make examples the minimum length to demonstrate your issue.

Mekire

Posts: 1515
Joined: Thu Feb 07, 2013 11:33 pm
Location: Tucson, Arizona

Re: Finding vector given 2 points

Mekire wrote:Looking good. I recommend the use of atan2 over atan in this case though:
Code: Select all
`>>> import math>>> help(math.atan2)Help on built-in function atan2 in module math:atan2(...)    atan2(y, x)        Return the arc tangent (measured in radians) of y/x.    Unlike atan(y/x), the signs of both x and y are considered.`
That will stop you needing to worry about those zero division errors.

Also math.hypot is really nice. Instead of calculating a vector magnitude like this:
Code: Select all
`math.sqrt(distance[0] ** 2 + distance[1] ** 2) `
you would just do this:
Code: Select all
`math.hypot(distance[0],distance[1])`
or better yet, this:
Code: Select all
`math.hypot(*distance)`

-Mek

Yup! all that works thanks Mekire!
ChristianCareaga

Posts: 53
Joined: Sat Jun 22, 2013 9:54 am