Where should I implement my check for collision method?

Viewed 179

I am making a pokemon ripoff in pygame, and I have made a method to test whether the player is in the tall grass. However, I do not know where I should call the method. I have tried in the player move method, in the game loop method, and the update method. When I do it like this, it checks after you have moved out of the grass, which means the first time you move into grass it won't work, and when you first move out of grass it works (when it shouldn't).

in_grass(self) method:

def in_grass(self):
        for g in self.game.grass:
            if pygame.sprite.collide_rect(self, g):
                print(random.randint(1, 10000))
                if random.randint(1, 180) <= 25:
                    self.battle()

player move(self) method:

def move(self, x_change, y_change):
        if x_change > 0:
            self.dir = 'RIGHT'
        if x_change < 0:
            self.dir = 'LEFT'
        if y_change > 0:
            self.dir = 'DOWN'
        if y_change < 0:
            self.dir = 'UP'

        if not self.collide(x_change, y_change):
            self.x += x_change
            self.y += y_change

            image_list = None
            if self.dir == 'UP':
                image_list = self.image_up
            elif self.dir == 'LEFT':
                image_list = self.image_left
            elif self.dir == 'RIGHT':
                image_list = self.image_right
            elif self.dir == 'DOWN':
                image_list = self.image_down

            if image_list:
                if self.walkcount >= len(image_list):
                    self.walkcount = 0
                self.image = image_list[self.walkcount]
                self.walkcount += 1
                self.image.set_colorkey(BLACK)

Main loop:

 def events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_w:
                    self.player.move(0, -1)
                if event.key == pygame.K_a:
                    self.player.move(-1, 0)
                if event.key == pygame.K_s:
                    self.player.move(0, 1)
                if event.key == pygame.K_d:
                    self.player.move(1, 0)

            if event.type == pygame.KEYUP:
                self.player.image = self.player.default_images[self.player.dir]
                self.player.image.set_colorkey(BLACK)

EDIT: I finally got it working! I can't give myself the bounty, so I guess it will just sit there.

2 Answers

So here is some food for thought.

Little disclaimer, I am in no way a game dev nor am i a very experienced developer.

In a larger game you might want to keep a good grasp on what is happening where. Now say we have a game full of entities (think of entities as things you see on screen that have some sort of impact on the game). We would wanna update all these entities every frame of the gameloop.

Entities might be rendered, moved, collission checked, affected by player input, animated or whatever functionality your game needs. The order in which we do this is important for our game, suppose we have a list of entities

entities = []

We could then do something like this where we loop trough each enemy in our gameloop en execute their behaviour function. we pass in all the entities into the check_collision function to make this code a little more understandable.

Version 1

entities = []
def game_loop:
    while(true):
        for entity in entities:
            entity.gather_input()
            entity.move()
            entity.check_collision(entities)
            entity.animate()
            entity.render()

Now take a look at this:

Version 2

entities = []
def game_loop:
    while(true):
        for entity in entities:
            entity.gather_input()
        for entity in entities:
            entity.move()
        for entity in entities:
            entity.check_collision(entities)
        for entity in entities:
            entity.animate()
        for entity in entities:
            entity.render()

The order in which we execute the entities their behaviour has changed. We now have grouped behaviour, we could say we have defined the update fases of our gameloop. We now know all the movement of entities is updated before we check all of their collisions.

Whereas in Version 1 we do all the logic first for 1 entity and then do the next. We might lose relevant data in a single frame using Version 1 because 1 entity might move and check collision wheres it really should've waited till all entities have moved.

Hope this might spark some more research into the rabbithole that is game design/architecture.

Create a boolean in the player's __init__ method callled self.checked = False. Then, in the in_grass method, at the end, set self.checked = True. In the update method, if not self.checked: self.in_grass. Finally in the move method, at the very start, set self.checked = False I finally got it working, yay!

Related