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