Line of Sight

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