Line of Sight#

Line of Sight
line_of_sight.py#
  1"""
  2Line of Sight
  3
  4Artwork from https://kenney.nl
  5
  6If Python and Arcade are installed, this example can be run from the command line with:
  7python -m arcade.examples.line_of_sight
  8"""
  9
 10import arcade
 11import random
 12
 13SPRITE_SCALING = 0.5
 14
 15SCREEN_WIDTH = 800
 16SCREEN_HEIGHT = 600
 17SCREEN_TITLE = "Line of Sight"
 18
 19MOVEMENT_SPEED = 5
 20
 21VIEWPORT_MARGIN = 300
 22
 23
 24class MyGame(arcade.Window):
 25    """
 26    Main application class.
 27    """
 28
 29    def __init__(self, width, height, title):
 30        """
 31        Initializer
 32        """
 33
 34        # Call the parent class initializer
 35        super().__init__(width, height, title)
 36
 37        # Variables that will hold sprite lists
 38        self.player_list = None
 39        self.wall_list = None
 40        self.enemy_list = None
 41
 42        # Set up the player info
 43        self.player = None
 44
 45        # Track the current state of what key is pressed
 46        self.left_pressed = False
 47        self.right_pressed = False
 48        self.up_pressed = False
 49        self.down_pressed = False
 50
 51        self.physics_engine = None
 52
 53        # Used in scrolling
 54        self.view_bottom = 0
 55        self.view_left = 0
 56
 57        # Set the background color
 58        self.background_color = arcade.color.AMAZON
 59
 60    def setup(self):
 61        """ Set up the game and initialize the variables. """
 62
 63        # Sprite lists
 64        self.player_list = arcade.SpriteList()
 65        self.wall_list = arcade.SpriteList(use_spatial_hash=True)
 66        self.enemy_list = arcade.SpriteList()
 67
 68        # Set up the player
 69        self.player = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png",
 70                                    scale=SPRITE_SCALING)
 71        self.player.center_x = 50
 72        self.player.center_y = 350
 73        self.player_list.append(self.player)
 74
 75        # Set enemies
 76        enemy = arcade.Sprite(":resources:images/animated_characters/zombie/zombie_idle.png", scale=SPRITE_SCALING)
 77        enemy.center_x = 350
 78        enemy.center_y = 350
 79        self.enemy_list.append(enemy)
 80
 81        spacing = 200
 82        for column in range(10):
 83            for row in range(10):
 84                sprite = arcade.Sprite(":resources:images/tiles/grassCenter.png", scale=0.5)
 85
 86                x = (column + 1) * spacing
 87                y = (row + 1) * sprite.height
 88
 89                sprite.center_x = x
 90                sprite.center_y = y
 91                if random.randrange(100) > 20:
 92                    self.wall_list.append(sprite)
 93
 94        self.physics_engine = arcade.PhysicsEngineSimple(self.player,
 95                                                         self.wall_list)
 96
 97    def on_draw(self):
 98        """
 99        Render the screen.
100        """
101        try:
102            # This command has to happen before we start drawing
103            self.clear()
104
105            # Draw all the sprites.
106            self.player_list.draw()
107            self.wall_list.draw()
108            self.enemy_list.draw()
109
110            for enemy in self.enemy_list:
111                if arcade.has_line_of_sight(self.player.position,
112                                            enemy.position,
113                                            self.wall_list):
114                    color = arcade.color.RED
115                else:
116                    color = arcade.color.WHITE
117                arcade.draw_line(self.player.center_x,
118                                 self.player.center_y,
119                                 enemy.center_x,
120                                 enemy.center_y,
121                                 color,
122                                 2)
123
124        except Exception as e:
125            print(e)
126
127    def on_update(self, delta_time):
128        """ Movement and game logic """
129
130        # Calculate speed based on the keys pressed
131        self.player.change_x = 0
132        self.player.change_y = 0
133
134        if self.up_pressed and not self.down_pressed:
135            self.player.change_y = MOVEMENT_SPEED
136        elif self.down_pressed and not self.up_pressed:
137            self.player.change_y = -MOVEMENT_SPEED
138        if self.left_pressed and not self.right_pressed:
139            self.player.change_x = -MOVEMENT_SPEED
140        elif self.right_pressed and not self.left_pressed:
141            self.player.change_x = MOVEMENT_SPEED
142
143        self.physics_engine.update()
144
145        # --- Manage Scrolling ---
146
147        # Keep track of if we changed the boundary. We don't want to call the
148        # set_viewport command if we didn't change the view port.
149        changed = False
150
151        # Scroll left
152        left_boundary = self.view_left + VIEWPORT_MARGIN
153        if self.player.left < left_boundary:
154            self.view_left -= left_boundary - self.player.left
155            changed = True
156
157        # Scroll right
158        right_boundary = self.view_left + SCREEN_WIDTH - VIEWPORT_MARGIN
159        if self.player.right > right_boundary:
160            self.view_left += self.player.right - right_boundary
161            changed = True
162
163        # Scroll up
164        top_boundary = self.view_bottom + SCREEN_HEIGHT - VIEWPORT_MARGIN
165        if self.player.top > top_boundary:
166            self.view_bottom += self.player.top - top_boundary
167            changed = True
168
169        # Scroll down
170        bottom_boundary = self.view_bottom + VIEWPORT_MARGIN
171        if self.player.bottom < bottom_boundary:
172            self.view_bottom -= bottom_boundary - self.player.bottom
173            changed = True
174
175        # Make sure our boundaries are integer values. While the view port does
176        # support floating point numbers, for this application we want every pixel
177        # in the view port to map directly onto a pixel on the screen. We don't want
178        # any rounding errors.
179        self.view_left = int(self.view_left)
180        self.view_bottom = int(self.view_bottom)
181
182        # If we changed the boundary values, update the view port to match
183        if changed:
184            arcade.set_viewport(self.view_left,
185                                SCREEN_WIDTH + self.view_left,
186                                self.view_bottom,
187                                SCREEN_HEIGHT + self.view_bottom)
188
189    def on_key_press(self, key, modifiers):
190        """Called whenever a key is pressed. """
191
192        if key == arcade.key.UP:
193            self.up_pressed = True
194        elif key == arcade.key.DOWN:
195            self.down_pressed = True
196        elif key == arcade.key.LEFT:
197            self.left_pressed = True
198        elif key == arcade.key.RIGHT:
199            self.right_pressed = True
200
201    def on_key_release(self, key, modifiers):
202        """Called when the user releases a key. """
203
204        if key == arcade.key.UP:
205            self.up_pressed = False
206        elif key == arcade.key.DOWN:
207            self.down_pressed = False
208        elif key == arcade.key.LEFT:
209            self.left_pressed = False
210        elif key == arcade.key.RIGHT:
211            self.right_pressed = False
212
213
214def main():
215    """ Main function """
216    window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
217    window.setup()
218    arcade.run()
219
220
221if __name__ == "__main__":
222    main()