Python Forum
Boomerang implementing logic
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Boomerang implementing logic
#1
Hello everybody.

I am making a game with pygame and till know there are different weapons such as a shurikan and a blowpipe.
But now I wanted to implement a boomerang, and I don't know what to do, that it comes back to the player, after a certain amount of time.

So in a settings file, I am defining my weapons (I'm posting the code of the shurikan, because I haven't implemented a boomerang yet. I first want to know how to make it coming back to the player):

WEAPONS['shurikan'] = {'speed': 575,
                       'lifetime': 800,
                       'rate': 400,
                       'kickback': 0,
                       'spread': 3,
                       'damage': 8,
                       'size': 'shurikan',
                       'count': 1}


Then we have the shoot section:

class Player(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        # I've left out the things that are not important for this question 
        self.weapon = 'shurikan'
        self.shurikan = True
        self.shoot_ammo = True

    # Then there is key press stuff and now the shoot section

     def shoot(self):
        if self.shoot_ammo == True:
            now = pg.time.get_ticks()
            if now - self.last_shot > WEAPONS[self.weapon]['rate']:
                self.last_shot = now
                dir = vec(1, 0).rotate(-self.rot)
                pos = self.pos + BARREL_OFFSET.rotate(-self.rot)
                self.vel = vec(-WEAPONS[self.weapon]['rate'], 0).rotate(-self.rot)
                for i in range(WEAPONS[self.weapon]['count']):
                    spread = uniform(-WEAPONS[self.weapon]['spread'], WEAPONS[self.weapon]['spread'])
                    Blowpipe(self.game, pos, dir.rotate(spread))
Then there is also a weapon class.

class Blowpipe(pg.sprite.Sprite): # I haven't renamed the class yet but it is for all kind of weapons
    def __init__(self, game, pos, dir):
        self.groups = game.all_sprites, game.blowpipes
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = game.blowpipe_images[WEAPONS[game.player.weapon]['size']]
        self.rect = self.image.get_rect()
        self.pos = vec(pos)
        self.rect.center = pos
        self.vel = dir * WEAPONS[game.player.weapon]['speed']
        self.spawn_time = pg.time.get_ticks()
        self.rot = 360

    def update(self):
        self.pos += self.vel * self.game.dt
        self.rect.center = self.pos
        if pg.sprite.spritecollideany(self, self.game.walls):
            self.kill()
        if pg.time.get_ticks() - self.spawn_time > WEAPONS[self.game.player.weapon]['lifetime']:
            self.kill()
So I just posted some code here, because I want to know, how to make the boomerang coming back to the player and how to implement that in my code.

Hope it is not so complicated for you to understand.

Thanks for helping me.

Piethon
Reply
#2
do you mean in a circle or from of the player and back in just a line?
Recommended Tutorials:
Reply
#3
If the boomerang is going to go in a straight line, simply do the same thing you did with the shurikan, but get the tick that it was thrown at, and after a certain amount of ticks, you can calculate the angle that it needs to move at to go back to the player. It'd have to calculate the angle each time since the player will be moving. Or, more realistically, if you plan on implementing this kind of feature at some point, it can come back in a straight line and land on the ground, which would be just as simple as throwing it forward. If you plan on having it go in an arch in the direction the player is facing, that would be a little more complicated. Instead of having ticks to keep track, the boomerang will move at one angle, and each time it moves, change the angle it's moving at so that it will eventually form an arch. Once it finishes its arch, or the angle becomes the opposite of what it started as, then since the player most likely moved, you would have to do the same thing that I described with the line, or have it drop on the ground. If you don't know about how you can move at angles, Windspar provided a good example here - https://python-forum.io/Thread-pygame-Mo...-at-angles
I hope this helps you.
Reply
#4
(Oct-28-2019, 09:49 PM)metulburr Wrote: do you mean in a circle or from of the player and back in just a line?

Just back in a line to the player.
Reply
#5
Quote:
    def update(self):
        self.pos += self.vel * self.game.dt

I think maybe if you add a decay setting for the velocity (which would be 0 for almost all weapons), you could have a boomerang decay over time so it's velocity was negative, which would then have it's position reverse and head back where it came. That wouldn't send it back to the player if they player happened to move first, though.

Do you have a full example that's runnable (maybe a github repo) so we can play around with it?
Reply
#6
(Oct-29-2019, 04:34 PM)nilamo Wrote:
Quote:
    def update(self):
        self.pos += self.vel * self.game.dt

I think maybe if you add a decay setting for the velocity (which would be 0 for almost all weapons), you could have a boomerang decay over time so it's velocity was negative, which would then have it's position reverse and head back where it came. That wouldn't send it back to the player if they player happened to move first, though.

Do you have a full example that's runnable (maybe a github repo) so we can play around with it?

I didn't add a decay setting but I tried this:

class Blowpipe(pg.sprite.Sprite):
    def __init__(self, game, pos, dir):
        # Stuff from my last post
        self.vel = dir * WEAPONS[game.player.weapon]['speed']
        self.spawn_time = pg.time.get_ticks()
        self.rot = 360
        self.last = pg.time.get_ticks()
        self.cooldown = 300

    def update(self):
        if self.game.player.weapon == 'boomerang':
            now = pg.time.get_ticks()
            self.pos += self.vel * self.game.dt
            self.rect.center = self.pos
            if now - self.last >= self.cooldown:
                    self.pos -= self.vel * self.game.dt
        self.pos += self.vel * self.game.dt
        self.rect.center = self.pos
        if pg.sprite.spritecollideany(self, self.game.walls):
            self.kill()
        if pg.time.get_ticks() - self.spawn_time > WEAPONS[self.game.player.weapon]['lifetime']:
            self.kill()
What it does, is that is slow for 0.3 seconds and then it gets faster. But why is it not going backwards?
Reply
#7
if self.game.player.weapon == 'boomerang':
    self.pos += self.vel * self.game.dt
    if now - self.last >= self.cooldown:
        self.pos -= self.vel * self.game.dt
self.pos += self.vel * self.game.dt
I snipped a few things out to try to make it clearer.

Line 5, you increase the position for every item, including boomerangs.
Line 4, you decrease the position for boomerangs.

So for boomerangs, it doesn't actually go backward, because you immediately move it forward again.
Reply
#8
I did it like that now, and it doesn't work:

....
def update(self):
    self.pos += self.vel * self.game.dt
    self.rect.center = self.pos
    if self.game.player.weapon == 'boomerang':
            now = pg.time.get_ticks()
            self.pos += self.vel * self.game.dt
            self.rect.center = self.pos
            if now - self.last >= self.cooldown:
                    self.pos -= self.vel * self.game.dt
Still the same. First moving slow, then faster.
Reply
#9
if now - self.last >= self.cooldown is true then its code will just counteract the one above
I think you meant to do this
def update(self):
    self.pos += self.vel * self.game.dt
    self.rect.center = self.pos
    if self.game.player.weapon == 'boomerang':
        now = pg.time.get_ticks()
        if now - self.last >= self.cooldown:
            self.pos -= self.vel * self.game.dt
        else:
            self.pos += self.vel * self.game.dt
        self.rect.center = self.pos
Reply
#10
(Oct-31-2019, 09:46 PM)SheeppOSU Wrote: if now - self.last >= self.cooldown is true then its code will just counteract the one above
I think you meant to do this
def update(self):
    self.pos += self.vel * self.game.dt
    self.rect.center = self.pos
    if self.game.player.weapon == 'boomerang':
        now = pg.time.get_ticks()
        if now - self.last >= self.cooldown:
            self.pos -= self.vel * self.game.dt
        else:
            self.pos += self.vel * self.game.dt
        self.rect.center = self.pos

I did this and now it is flying the time of the cool down and then it just stands there and waits till it gets removed.
My update section is looking like this:

 def update(self):
        self.pos += self.vel * self.game.dt
        self.rect.center = self.pos
        if self.game.player.weapon == 'boomerang':
            now = pg.time.get_ticks()
            if now - self.last >= self.cooldown:
                self.pos -= self.vel * self.game.dt
            else:
                self.pos += self.vel * self.game.dt
            self.rect.center = self.pos
        if pg.sprite.spritecollideany(self, self.game.walls):
            self.kill()
        if pg.time.get_ticks() - self.spawn_time > WEAPONS[self.game.player.weapon]['lifetime']:
            self.kill()
What am I doing wrong?
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  A question about implementing the state engine code marienbad 4 3,248 Oct-20-2018, 02:08 PM
Last Post: metulburr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020