Reputation: 25
I am working with Pygame on a beat-em-up game and I'm running into an issue where the enemy will grab the player, forever and not let him go. A timer is supposed to run and when it reaches zero the enemy is supposed to push the player away, but it never reaches zero.
The variable contact is group of enemies who are actually touching the player. It's using the pygame.sprite.Group() function. If the sprites overlap (of the player and any enemy in the list of all enemies), then they are added to the group. If the sprites stop overlapping (enemy walks away, or the player walks away), then the enemies are removed from that group.
contact = pygame.sprite.spritecollide(heroBoonrit, enemy_list, False)
For every tick of the clock, I have it set up to check if there are any enemies touching the player, and if there are, then go through every one of them and see if any of the enemies are in a grabbing state (villan.grabbing_cooldown). It's just an on/off switch that means that the enemy is currently attacking with a grab move. I could probably come up with a more logical variable name.
If those conditions are met, then a few things happen, such as snapping the player's position up (or down) in order to be on the same y coordinate as the enemy. The variable heroBoonrit.held_cooldown is another on/off switch that means that he is currently being held. Both the player and the enemies have their own variable called heroBoonrit.held_countdown and villan.grabbing_countdown respectively. The problem I'm seeing (by running print() for diagnostics is that the enemy countdown decrements by 1 and then it stop decreasing, whereas the countdown timer of my hero decrements until 0. So therefore the enemy never lets go.
I have a feeling that there's probably a much more elegant and clean way to go about handling player and enemy behavior rather than putting on/off switches for the player that relate to whether or not he's being stunned, grabbed, etc (and additionally, corresponding countdown timers for those), but I've only been doing programming for a month and would appreciate any feedback. Maybe after every tick of the clock, the enemy holding timer is reset to 60 again...I have read in other posts that when you are using the Pygame Group() function, you can't easily iterate over the group. Still learning many of the ins and outs...
I ran this command in my main game loop to find out that enemy's grabbing countdown timer only goes from 60 to 59 and then stops counting down:
print("||Shit Clown|| Grabbing = ", enemyShit_Clown.grabbing_cooldown, " Countdown = ", enemyShit_Clown.grabbing_countdown, "||Boonrit|| Grabbed = ", heroBoonrit.held_cooldown, " Countdown = ", heroBoonrit.held_countdown)
Here is the block of code where I'm running into the problem.
for villan in contact:
for villan in enemy_list:
if villan.grabbing_cooldown:
heroBoonrit.held_cooldown = True
heroBoonrit.rect.y = villan.rect.y
heroBoonrit.rect.x = (villan.rect.x + 30)
heroBoonrit.held_countdown = villan.grabbing_countdown
villan.grabbing_countdown -= 1
heroBoonrit.held_countdown -= 1
if villan.grabbing_countdown <= 0:
villan.grabbing_countdown = 0
heroBoonrit.held_countdown = 0
villan.grabbing_cooldown = False
heroBoonrit.held_cooldown = False
heroBoonrit.rect.x += 30
elif villan.attacking_cooldown:
if heroBoonrit.blocking != True:
heroBoonrit.hp -= 100
else:
heroBoonrit.hp -= 10
Here is the Enemy class:
class Enemy(pygame.sprite.Sprite):
def __init__(self, name, level, speed, hp, stamina, fear, blocking_cooldown, jumping_cooldown, attacking_cooldown, held_cooldown, knockdown_cooldown, stun_cooldown, jumping_countdown, attacking_countdown, held_countdown, knockdown_countdown, stun_countdown, grabbing_cooldown, grabbing_countdown, blocking_countdown):
super().__init__()
self.image = pygame.image.load(os.path.join('res','img','chars','shit_clown-3.png'))
#self.image = pygame.Surface([30,20])
#self.image.fill(color)
self.rect = self.image.get_rect()
self.surf = pygame.Surface((30,20))
self.name = name
self.speed = speed
self.level = level
self.hp = hp
self.stamina = stamina
self.fear = fear
self.blocking_cooldown = blocking_cooldown
self.jumping_cooldown = jumping_cooldown
self.jumping_countdown = jumping_countdown
self.attacking_cooldown = attacking_cooldown
self.attacking_countdown = attacking_countdown
self.held_cooldown = held_cooldown
self.held_countdown = held_countdown
self.knockdown_cooldown = knockdown_cooldown
self.knockdown_countdown = knockdown_countdown
self.stun_cooldown = stun_cooldown
self.stun_countdown = stun_countdown
self.grabbing_cooldown = grabbing_cooldown
self.grabbing_countdown = grabbing_countdown
self.blocking_countdown = blocking_countdown
blocking_cooldown = False
jumping_cooldown = False
jumping_coutndown = 0
attacking_cooldown = False
attacking_countdown = 0
held_cooldown = False
held_countdown = 0
knockdown_cooldown = False
knockdown_countdown = 0
stun_cooldown = False
stun_countdown = 0
grabbing_cooldown = False
grabbing_countdown = 0
blocking_countdown = 0
And to spawn the enemy:
enemyShit_Clown = Enemy("Shit Clown", 1, 4, 1000, 10, 90, False, False, False, False, False, False, 0, 0, 0, 0, 0, True, 60, 0)
enemyShit_Clown.image = pygame.image.load(os.path.join('res','img','chars','shit_clown-3.png')).convert()
enemyShit_Clown.rect.x = 300 #random.randrange(300, 400)
enemyShit_Clown.rect.y = 300 #random.randrange(200, 400)
enemy_list.add(enemyShit_Clown)
all_sprites_list.add(enemyShit_Clown)
Thanks very much for your help
Upvotes: 2
Views: 859
Reputation: 15310
I don't see any obvious reason for the villain to stop counting down. That said, I do see that you are decrementing the countdown both in the hero.update code and in the main loop. I'd expect your hero to count down twice as fast as the villain, but not 60 times as fast.
I'd like to suggest some code changes. First, get rid of most of the parameters in your __init__
code. Just set the default values to 0 or False or whatever.
Next, I see you creating a character, and then assigning an image to it. That should be in the constructor, with maybe a defaulted parameter to select a different starting image.
Next, you have countdown code in the hero's update
method, but not in the villains. I think this is a mistake. Move the countdowns into the update routine, and don't worry about searching for it in the main loop.
Finally, there is a rule of thumb for OO programming you are missing: "Tell, don't ask."
Basically, this says, among other things, that you shouldn't be accessing the attributes of another object, and you definitely shouldn't be modifying the attributes of another object.
I suggest you write methods for this stuff, like so:
class Villain:
def grab(self, hero):
"""Start a grabbing attack on hero, if not blocked/busy"""
if self.grabbing:
# Already grabbing someone. Fail.
return False
ticks = 60
if hero.grabbed(self, ticks):
self.grabbing = hero
self.grabbing_countdown = ticks
hero.moveto(self.rect.y, self.rect.x + 30)
return True
else:
return False
def update(self, *args):
:
blah blah blah
:
if self.grabbing:
self.grabbing_countdown -= 1
if self.grabbing_countdown == 0:
self.grabbing.release(self)
self.grabbing.push_away(self.rect.x, self.rect.y, 30)
self.grabbing = None
Upvotes: 2