3

I am trying to make a game with a python library called 'Pygame' (v1.9.2) and I have made a character for the player. This character is supposed to "shoot" "bullets" or "spells" to the point of mouse_pos and what I need help with is that the "bullet" has a constant speed assigned to 1 self.speed = 1, if I try to increase the speed it will cause a flickering effect when the bullet reaches mouse_pos because self.pos will either be higher or lower than mouse_pos.

How can I make this bullet go quickly & smooth like a bullet and still get to the exact point where mouse_pos is set?

Example with self.speed = 1
https://media.giphy.com/media/AAifrctxHHQbe/giphy.gif

Example with self.speed = 2
http://4.1m.yt/d_TmNNq.gif

related code is inside update() function
Sprites.py (Spell/Bullet class)

class Spell(pygame.sprite.Sprite):
    def __init__(self,game,x,y,spelltype,mouse_pos):
        pygame.sprite.Sprite.__init__(self)
        self.game = game
        self.width = TILESIZE
        self.height = TILESIZE
        self.type = spelltype
        self.effects = [
                'effect_'+self.type+'_00',
                'effect_'+self.type+'_01',
                'effect_'+self.type+'_02'
        ]
        self.image = pygame.image.load(path.join(IMG_DIR,"attack/attack_"+self.type+".png")).convert_alpha()
        self.image = pygame.transform.scale(self.image,(self.width,self.height))
        self.rect = self.image.get_rect()
        self.rect.x = x+self.width
        self.rect.y = y+self.height
        self.speed = 1
        self.mouse_pos = mouse_pos
        self.idx = 0

    def update(self):
        if not self.rect.collidepoint(self.mouse_pos):
            if self.mouse_pos[0] < self.rect.x:
                self.rect.x -= self.speed
            elif self.mouse_pos[0] > self.rect.x:
                self.rect.x += self.speed

            if self.mouse_pos[1] < self.rect.y:
                self.rect.y -= self.speed
            elif self.mouse_pos[1] > self.rect.y:
                self.rect.y += self.speed
        else:
            self.image = pygame.image.load(path.join(IMG_DIR,"effects/"+self.effects[self.idx]+".png"))
            self.idx += 1
            if self.idx >= len(self.effects):
                self.kill()
Taku
  • 31,927
  • 11
  • 74
  • 85
Feelsbadman
  • 1,163
  • 4
  • 17
  • 37
  • 1
    To shoot bullets in a specific direction you should use trigonometry or vectors. Here's an answer that shows you how it works with vectors: http://stackoverflow.com/a/42281315/6220679 – skrx May 13 '17 at 10:16
  • If your bullet goes so fast that it passes through the target, you might want to test if the line between the bullets current point an its last point intersect with your target. – Lanting May 19 '17 at 11:18
  • should I check if the distance is ODD or EVEN on each update ? – Feelsbadman May 19 '17 at 11:48
  • @Lanting alright, that helped. post the answer so I can accept it. – Feelsbadman May 19 '17 at 12:13

2 Answers2

4

The Pythagorean Theorem tells the distance between points in n-dimensional space. For your case

distance = math.sqrt(sum[ (self.mouse_pos[0] - self.rect.x) ** 2 
                        , (self.mouse_pos[1] - self.rect.y) ** 2
                        ]))
if distance < self.speed: 
    #remove the bullet from the scene

This is not a great solution, because the bullet will move unrealistically, with different speeds at different angles. In fact it will move at sqrt(2) speed at a 45' angle and with a speed of 1 at 90'.

But, I assume you don't want a trigonometry lecture.

EDIT: Here's the trigonometry lecture. Your program will move the bullet realistically because it moves it by the full speed in both the x and y direction. What you need to do is to have the speed be slower in both directions, such that the hypotenuse of the triangle that the x-speed and y-speed (vectors) form is equal to 1. Since the speed is always 1, this triangle, just happens to be the unit circle.

       m
       |\
       | \
sin(A) |  \ This speed is 1
       |   \
       |   A\
       ------p
        cos(A)

If your character is at p, and the mouse is at m, then you find the angle between them labeled here as A. Then the x-speed will be the cosine of A and the y-speed will be the sine of A.

How do you find the angle? you use the arctangent... in fact, here's the code to use.

import math
if not self.rect.collidepoint(self.mouse_pos):
        angle = math.atan2( (self.mouse_pos[1] - self.rect.y)
                          , (self.mouse_pos[0] - self.rect.x)
        self.rect.x += self.speed * math.cos(angle)
        self.rect.y += self.speed * math.sin(angle)

or something more like that. I may have my symbols mixed up.

VoNWooDSoN
  • 1,173
  • 9
  • 13
2

If your bullet goes so fast that it passes through the target, you might want to test if the line between the bullets current point an its last point intersect with your target.

A bit more detail is available here: https://gamedev.stackexchange.com/questions/18604/how-do-i-handle-collision-detection-so-fast-objects-are-not-allowed-to-pass-thro

Lanting
  • 3,060
  • 12
  • 28