Giter Site home page Giter Site logo

py-traffic-sim's People

Contributors

jgmeyer avatar rikithreddy avatar

Watchers

 avatar  avatar

Forkers

rikithreddy

py-traffic-sim's Issues

FPS Counter

For stress testing and debugging it would be helpful to display an FPS counter in the top right corner of the game screen.

Right now, there aren't examples of adding text in graphics.RoadScreen, but pygame should have documentation. We should not include this in graphics.RoadScreen, instead we should likely add this to a new module under src/ called ui/ where we'll eventually add more UI elements that will display above the screen. Still, code can be heavily borrowed from graphics.RoadScreen as a reference.

We should gate this as well behind a new bool: settings.GameSettings.DISPLAY_FPS_COUNTER

https://stackoverflow.com/a/2530745/373196 has some tips on making this display more efficiently.

Creating closed loop causes NetworkXNoPath Error

Bug repros even as far back as 9861eb1.

Commonly happens between ENTER->ENTER and EXIT->EXIT nodes, however, one repro showed an ENTER->EXIT failure.

This is easiest to repro once completing a single loop, however I HAVE managed to cause it to fail prior to completing the loop. I have NOT managed to repro the issue once at least 1 intersection (tile w/ >= 3 segments) was present.

Sample error (from gif):

$ pipenv run python src/game.py
pygame 2.0.0.dev4 (SDL 2.0.10, python 3.7.4)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
  File "src/game.py", line 161, in <module>
    game_loop(game_window, clock)
  File "src/game.py", line 99, in game_loop
    randomize_vehicle_paths(window, network)
  File "src/game.py", line 116, in randomize_vehicle_paths
    path = network.graph.shortest_path(v.last_node, random_node)
  File "/Users/justian/scripts/py-traffic-sim/src/road/grid.py", line 371, in shortest_path
    return nx.shortest_path(self.G, source=source_node, target=target_node)
  File "/Users/justian/.local/share/virtualenvs/py-traffic-sim-0xsS5pXD/lib/python3.7/site-packages/networkx/algorithms/shortest_paths/generic.py", line 170, in shortest_path
    paths = nx.bidirectional_shortest_path(G, source, target)
  File "/Users/justian/.local/share/virtualenvs/py-traffic-sim-0xsS5pXD/lib/python3.7/site-packages/networkx/algorithms/shortest_paths/unweighted.py", line 226, in bidirectional_shortest_path
    results = _bidirectional_pred_succ(G, source, target)
  File "/Users/justian/.local/share/virtualenvs/py-traffic-sim-0xsS5pXD/lib/python3.7/site-packages/networkx/algorithms/shortest_paths/unweighted.py", line 294, in _bidirectional_pred_succ
    raise nx.NetworkXNoPath("No path between %s and %s." % (source, target))
networkx.exception.NetworkXNoPath: No path between RoadSegmentNode(tile_index=(4, 13), dir=<Direction.LEFT: 3>, node_type=<RoadNodeType.EXIT: 1>, world_coords=(848, 281)) and RoadSegmentNode(tile_index=(7, 13), dir=<Direction.LEFT: 3>, node_type=<RoadNodeType.EXIT: 1>, world_coords=(848, 473)).

out

Zoom Functionality

Requires:

  • Bounding box around playable element to show where tiles can be added/removed
  • Min/Max zoom values
  • No breakage to existing vehicle movement

Possible:

  • Rethinking when tiles/vehicles should be rendered (if not already handled by PyGame)

4-way stop sign intersections

Checkpoint 1: Have all vehicles pause x seconds at intersection enter/exit node.
Checkpoint 2: Have intersection dictate which vehicle may pass through the intersection.

Add README

Include:

  • Description of project
  • Vision / goal
  • How to run the project
  • How to create roads (with screenshot)
  • How to modify settings

Add "tile place" indicator beneath mouse cursor

It would be helpful to see which tile is being hovered over with the mouse cursor before placing a tile.

Example:
road-example

The actual design of the highlight is up to you. You can place it above or below the road, color in the entire box, etc. So long as the intention is clear.

Bonus points:

  • Change the color of the box based on whether the highlighted tile is a valid tile placement, i.e. network.grid.get_neighbors(<params>) >= 1

Hints:

  • Check out process_mouse_button_down() in game.py for logic on processing mouse input.
  • Check out how items are rendered in RoadScreen in road/graphics.py
  • Consider adding a new sprite for this cursor. See graphics.*Sprite classes for examples on how to construct a sprite.
  • Consider adding a new layer for this cursor. See graphics.RoadScreenLayers for the different layers on the RoadScreen.
  • Consider adding a function like send_cursor() where it may make sense in graphics.py which will take a cursor input and generate and place the sprite on the RoadScreen.

Display Enter and Exit nodes when DISPLAY_ROAD_SEGMENT_NODES is set

Our RoadNetwork (network.py) is composed of the following key components:

  • TileGrid (grid.py)
  • TravelGraph (grid.py)
  • Traffic (traffic.py)

The TileGrid represents the roads (the black boxes) in the simulation.
The TravelGraph is the graph which outlines paths that Vehicles can take along the TileGrid
And Traffic handles the movement of Vehicles along the TravelGraph

Right now we can display travel edges when DISPLAY_TRAVEL_EDGES is set to True in src/settings.py. Let's add a similar flag called DISPLAY_ROAD_SEGMENT_NODES that will display the grid's RoadSegmentNodes for debugging purposes.

Color preference:

ROAD_SEGMENT_NODE_ENTER = (255, 0, 0)  # red
ROAD_SEGMENT_NODE_EXIT = (0, 0, 255)  # blue
  • add these to road.graphics.Color

RoadSegmentNodes already have world_coords, so it should be easy to draw them directly to road.graphics.RoadScreen.

We already have a layer for this: road.graphics.RoadScreenLayers.ROAD_SEGMENT_NODES, which is currently unused.

Check out the source in src/road/graphics.py for examples of how other Sprites have already been coded.

The most complex part of this project is likely figuring out how to send "updates" from the TravelGraph to the RoadScreen

See similar hints from #14 for where code may need to be added for this.

I am happy to answer any questions.

Scroll Functionality

Similar to #8, but should be simpler to implement.

Allow the user to scroll the playable grid. This does not yet include allowing the player to expand beyond the initial bounds set by game.GRID_WIDTH or game.GRID_HEIGHT.

CP1: Scroll with the arrow keys
CP2: Scroll using click+drag on the mouse

Curved Vehicle movement paths through intersections

Right now, Vehicles move strictly linearly between EXIT and ENTER RoadSegmentNodes. While this works, it's not particularly realistic to actual traffic patterns.

Adding this likely will involve a lot of math. Essentially we want to have the vehicle follow an elliptical path from one EXIT node to another ENTER node when taking a right or left turn. Problem is, there isn't an easy way to calculate the arc length of an ellipse segment. It's all approximated using an integral.

I posted about this problem here: https://stackoverflow.com/questions/59783526/move-object-a-set-distance-along-an-elliptical-path?noredirect=1#comment105711071_59783526.

Possible solutions could include:

  • Estimating points along the elliptical paths, caching them for speed (since these paths will be used in other intersections), then approximating the vehicle's next point along the path based on its speed.
  • Some modification of Kepler's Equation
  • Benzier Curves: https://www.pygame.org/wiki/BezierCurve

More research is needed to figure out which is the best solution.

I already isolated the Vehicle linear movement into physics.pathing.LinearTrajectory. Once we have a solution figured out, the logic can just go into a physics.pathing.EllipticalTrajectory and a Vehicle can swap between LinearTrajectory and EllipticalTrajectory as needed.

Z-Wave adapter

Hey, I am new to this. How do I add a Z-Wave adapter?

Rethink how we pass config values from dynaconf.settings

Dynaconf is extremely useful, but we have some values like TILE_WIDTH/HEIGHT and ROAD_WIDTH that we really don't want people modifying. Also, it seems like we're constantly passing conf throughout the project just so most objects can get these values.

Is there a better way to clean this up? Maybe we should instead just import these into common.py and reuse them that way? I'm not sure.

Test broken since adding dynaconf

$ pipenv run pytest -vv
================================ test session starts ================================
platform darwin -- Python 3.7.6, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /Users/justian/.local/share/virtualenvs/py-traffic-sim-0xsS5pXD/bin/python3.7
cachedir: .pytest_cache
rootdir: /Users/justian/scripts/py-traffic-sim
collected 0 items / 1 error

====================================== ERRORS =======================================
__________________ ERROR collecting src/road/tests/test_traffic.py __________________
src/road/tests/test_traffic.py:2: in <module>
    from road.grid import RoadSegmentNode
src/road/grid.py:14: in <module>
    from config import config
src/config.py:7: in <module>
    Validator("TILE_HEIGHT", eq=settings.TILE_WIDTH),
../../.local/share/virtualenvs/py-traffic-sim-0xsS5pXD/lib/python3.7/site-packages/dynaconf/base.py:111: in __getattr__
    return getattr(self._wrapped, name)
E   AttributeError: 'Settings' object has no attribute 'TILE_WIDTH'
!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!
================================= 1 error in 1.03s ==================================

We should be passing a mock config in test_traffic.py. Regardless, we can't get this to run until grid.py no longer has a dependency on dynaconf.

We'll need to update RoadSegmentNode to no longer require a module-level import of dynaconf.settings.

Add CollisionGrid class for detecting collisions between vehicles

Goals:

  • Efficiently detect which vehicles are colliding with one another
  • Keep the object extensible to various types of collision detection (e.g. square, circle, rectangular, rotated rectangular collision etc.)
  • Provide a form of visual debugging for these collision

Steps:

  • Create and test CollisionGrid object
    • Store objects in Collision Grid as pygame.Rects
    • Test collision logic
  • Implement CollisionGrid in traffic.py
  • Create abstract class CollisionTracker that CollisionTileGrid inherits from. Update references to CollisionTileGrid, e.g. in Traffic.init to instead request the interface instead of CollisionTileGrid. This allows us to make drop-in replacements for collision detection in case we find more a efficient method in the future.
  • Fix tests
  • Visual debugging (be sure to clean up TODOs)
    • Add Update.CHANGED_STATE
    • Add multiple states to Vehicle (1 standard, 1 collided)
  • Move VEHICLE_RADIUS into settings.py
  • Rewrite CollisionGrid to be extensible to various collision types

See https://gamedev.stackexchange.com/questions/39931/fast-accurate-2d-collision for a basic example.

Turn settings.py into a Singleton

Eventually, we'll want to make some of the settings configurable in-game. Let's set up settings.py as a singleton that can be referenced elsewhere in the code.

Let's add a way to prevent some constants from being modified once the game is run, as well, e.g TILE_WIDTH, TILE_HEIGHT, etc.

There could be some creative solutions to go about doing this elegantly.

  • Integrate settings into existing code
    • MVP
    • Use dependency injection to pass config to inner classes
    • Clean up use of settings and replace with new config module
  • Test dynaconf.update() by calling settings.RANDOMIZE_VEHICLE_COLOR directly in graphics.py, but calling dynaconf.update() in game.py in the game loop.
  • Add validation for values
  • Prevent some values from being modified Created issue for this
  • Update README with use of config.py, settings.toml, and src/.env
  • Open new Issue about lack of focus on pygame window with reference to blame commit (this PR)

Move TILE_WIDTH, TILE_HEIGHT, and ROAD_WIDTH into GameSettings

Let's move these out of road/common.py into settings.py. Several parts of the codebase will need to be refactored with this change, but it shouldn't be too difficult.

This should be tested by running the game and ensuring everything still functions correctly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.