Search code examples
pythoncollision-detectionarcade

Collision detection or variable call problem


I've started to create a simple open-world game using the arcade module and maps created with Tiled Map Editor. I'm already a bit advanced but I'm having a problem. I've looked everywhere on the internet but can't find anything... Here's my problem: the character moves with the arrow keys, the map ground is divided into two categories: grass and paths (for the moment), and the character detects which ground he's on and if he's on a path he moves twice as fast. But it turns out that if you're on a path and you go onto grass, your speed won't change once you're on the grass. In other words, the character doesn't detect the ground until you release the key and press again. If you could help me, that would be great! I've already asked this question on https://openclassrooms.com/forum/sujet/probleme-de-detection-de-collision-c00dc#message-94985889 but nobody's found the solution...

import arcade
 
class MyGame(arcade.Window):
    def __init__(self):
        ###
 
    def setup(self):
        ###
    def on_draw(self):
        ###
 
    def on_key_press(self, key, modifiers):
        if key == arcade.key.UP:
            self.player_sprite.change_y = self.speed
            self.player_sprite.change_x = 0
            self.player_sprite.texture = arcade.load_texture(self.texture_paths["up"])
        if key == arcade.key.DOWN:
            self.player_sprite.change_x = 0
            self.player_sprite.change_y = -self.speed
            self.player_sprite.texture = arcade.load_texture(self.texture_paths["down"])
        if key == arcade.key.LEFT:
            self.player_sprite.change_y = 0
            self.player_sprite.change_x = -self.speed
            self.player_sprite.texture = arcade.load_texture(self.texture_paths["left"])
        if key == arcade.key.RIGHT:
            self.player_sprite.change_y = 0
            self.player_sprite.change_x = self.speed
            self.player_sprite.texture = arcade.load_texture(self.texture_paths["right"])
 
    def on_key_release(self, key, modifiers):
        if key == arcade.key.UPorkey == arcade.key.DOWN:
            self.player_sprite.change_y = 0
        if key == arcade.key.LEFTorkey == arcade.key.RIGHT:
            self.player_sprite.change_x = 0
 
    def center_camera_to_player(self):
        ###
 
    def update(self, deltatime):
       ways_hit_list = arcade.check_for_collision_with_list(self.player_sprite, self.scene[LAYER_NAME_WAYS])
 
       if ways_hit_list:
           self.speed = 2
       else:
           self.speed = 1
        
       ###
 
def main():
    window = MyGame()
    window.setup()
    arcade.run()
 
if __name__ == "__main__":
    main()

I did a few tests, and I found something: the speed does change depending on the ground the character is on. The problem is that when I press a key to move, the speed taken into account for the entire movement until the key is released is the speed recorded just as the key was pressed... I've tried moving the function to a different place and creating a new function to call up speed detection, but nothing works...


Solution

  • You need to recalculate player speed on every iteration (not only at the beginning of the move). Simple example (green background is low speed, red - high speed):

    enter image description here

    Code:

    import arcade
    
    
    class Game(arcade.Window):
        def __init__(self):
            super().__init__()
            self.player_sprite = arcade.Sprite(':resources:images/animated_characters/male_person/malePerson_idle.png', center_x=100, center_y=300)
            self.left_pressed = False
            self.right_pressed = False
            self.up_pressed = False
            self.down_pressed = False
    
        def on_draw(self):
            self.clear()
            arcade.draw_rectangle_filled(200, 300, 400, 600, arcade.color.GREEN)
            arcade.draw_rectangle_filled(600, 300, 400, 600, arcade.color.RED)
            self.player_sprite.draw()
    
        def update_player_speed(self):
            self.player_sprite.change_x = 0
            self.player_sprite.change_y = 0
    
            if self.player_sprite.center_x < 400:
                speed = 5
            else:
                speed = 10
    
            if self.up_pressed and not self.down_pressed:
                self.player_sprite.change_y = speed
            elif self.down_pressed and not self.up_pressed:
                self.player_sprite.change_y = -speed
            if self.left_pressed and not self.right_pressed:
                self.player_sprite.change_x = -speed
            elif self.right_pressed and not self.left_pressed:
                self.player_sprite.change_x = speed
    
        def on_key_press(self, key, modifiers):
            if key == arcade.key.UP:
                self.up_pressed = True
                self.update_player_speed()
            elif key == arcade.key.DOWN:
                self.down_pressed = True
                self.update_player_speed()
            elif key == arcade.key.LEFT:
                self.left_pressed = True
                self.update_player_speed()
            elif key == arcade.key.RIGHT:
                self.right_pressed = True
                self.update_player_speed()
    
        def on_key_release(self, key, modifiers):
            if key == arcade.key.UP:
                self.up_pressed = False
                self.update_player_speed()
            elif key == arcade.key.DOWN:
                self.down_pressed = False
                self.update_player_speed()
            elif key == arcade.key.LEFT:
                self.left_pressed = False
                self.update_player_speed()
            elif key == arcade.key.RIGHT:
                self.right_pressed = False
                self.update_player_speed()
    
        def update(self, deltatime):
            self.player_sprite.update()
            self.update_player_speed()
    
    
    Game()
    arcade.run()