Xathos avatar Xathos committed c8605ac

Cleaning up...

Comments (0)

Files changed (24)

AIDemo.py

-
-import pyglet
-from pyglet.window import key
-from tanks.utilities import Point2d
-from tanks.actors import Tank, PlayerController, TankProjectile, TankAccessor
-from ai.basicAI import BasicAI
-
-window = pyglet.window.Window()
-keys = key.KeyStateHandler()
-window.push_handlers(keys)
-
-tank_projectile = TankProjectile("graphics/projectile.png", speed = 400.0)
-player_tank = Tank("graphics/tank_body.png", "graphics/tank_turret.png", speed = 100.0,
-                            controller = PlayerController(keys), projectile=tank_projectile)
-player_accessor = TankAccessor(player_tank)
-ai = BasicAI(target = player_accessor)
-ai_tank = Tank("graphics/tank_body.png", "graphics/tank_turret.png", speed = 100.0,
-                       controller = ai.ai_update, projectile = tank_projectile)
-ai_tank.move_to(Point2d(300, 200))
-
-@window.event
-def on_mouse_motion (x, y, dx, dy):
-    global player_tank
-    player_tank.target = Point2d(x, y)
-
-@window.event
-def on_draw ():
-    window.clear()
-    player_tank.draw()
-    ai_tank.draw()
-
-framerate = 24.0
-pyglet.clock.schedule_interval(player_tank.update, 1.0 / framerate)
-pyglet.clock.schedule_interval(ai_tank.update, 1.0 / framerate)
-
-pyglet.app.run()

Overview.txt

-
-Physics
-
-Graphics
-
-World:
-    Entities:
-        Actors
-            -Position, bounds (Physics)
-            -Sprite data (Graphics)
-        StaticEntities:
-            -Position, bounds
-            
-
-AI:
-    put in an external module that is imported
-    import (and inheirit from) AI framework
-        provides AI API
-        AI should ONLY be able to interface with the world through these function calls,
-        which should be wrappers for runtime functions
-        AI should NOT be able to directly access the game runtime
-    On game load:
-        Load world
-        Load AIs
-        Link AI internal function calls to game runtime
-        Create actor subclasses and attach the AI methods (create bots)
-        Spawn AI bots
-        Run game
-
-    AI API:
-        -Recieves location, stats of self, all other enemies, and bounding volumes of all entities
-        (including AIs), or tile data (if using tiles)
-        -Recieves list of all actions within time x
-        -Full access to Time API
-        -Access to part of Physics API
-        -Dispatches actions (events)
-
-Action:
-    Actor request to the game runtime.
-    If action can be completed, it is executed, and added to the event list
-    Attributes:
-        -actor reference
-        -time of action
-        -type
-        -any other data specific to type
-    Examples of Actions:
-        Bot1 moves (x, y)
-        Bot1 fires in direction (x, y)
-
-
-Movement:
-    Actors are represented by bounding spheres, w/ movement vectors (line segments);
-    Static Entities are represented by collision line segments
-    Update actors
-    Get movement requests from all actors as Vectors (x1, y1, x2, y2)
-    Check move vector intersections w/ static colliders
-        -> adjust move vector accordingly
-    Check move vectors with each other: check for collisions
-        Send message to whichever objects have triggers
-        Adjust move vector if both objects are marked for collision
-    Move actors along final movement vectors.
-    
-        
-        
-        

Readme.txt

-Tanks Game Project
-(framework for an AI competition)
-
-Note: All developers/potential developers should take a look at design/GoodCodingPractices.txt 
-
-Current state:
-    Graphics work, and everything is located in nice OOP classes.
-    No collisions, since physics system has not been implemented yet
-    (I've already explained why in great detail in TanksPrototypeIII.py)
-    Modular AIs can be built and they work! (though they will probably work differently in their final state)
-
-Files:
-    TanksDemo.py - Basic player controlled tank; minimalist code.
-    AIDemo.py - Very simple AI example (currently stationary).
-
-    TanksAIPrototype.py - More complex AI example (won't work unless you're Seiji or have access to his AI project directory ;) )
-    TanksPrototype.py - The first Tanks prototype
-    TanksPrototypeII.py - The second Tanks prototype
-    TanksPrototypeIII.py - The third Tanks prototype (TanksDemo is a simplified version of this)
-
-    Directories:
-    tanks - Contains the bulk of the tanks codebase
-        (actors.py, entities.py, and utilities.py)
-    graphics - Contains image resources used by the game
-        (projectile.png, target.png, tank_body.png, tank_turret.png, and original tank.psd file)
-        (feel free to replace these as they were done in a rush - I might eventually try modeling the
-         tank in blender and getting a render from there)
-    ai - Shared AI files: contains an example AI class and outline
-        (This directory used to be much more useful before I gutted it and pulled my custom AI code to a more secure
-         location)
-    data - Doesn't currently contain anything; level files and related data (and any other stored plaintext/binary data) should be stored here
-
-    design - A few misc. files worth tanking a look at
-
-     misc - Put miscelaneous stuff here.
-         Currently contains MathReference.txt: since it has occured to me that not all participating individuals will have the
-         same degree of mathematical knowledge, I wrote up a little math reference to try and make things a little more fair.
-         MathReference contains all of the important (relevant; not immediately obvious) mathematical knowledge that I've
-         used so far on this project (mostly trig). I'm also available as a tutor at the next meeting to bring any interested
-         individuals up to speed.

TanksAIPrototype.py

-#
-#   AI Prototype (branched from Prototype III)
-#   
-#   This example shows off two simple AI targeting systems (and how easy it is
-#   to add an AI even at this point).
-#   Two stationary AIs are introduced (these are basically just targeting systems): StupidAI and PredictiveAI
-#   Though they both try to target the player, one is very easy to dodge, while the other is not.
-#   Stupid AI simply targets the player's current position, while PredictiveAI uses motion prediction
-#   (the white crosshair shows where it is targeting)
-#   Of course, none of the projectiles do any damage, as physics and collisions haven't been implemented yet...
-#
-#   Note: it is possible to trick the Predictive AI into consistently missing (though this tactic doesn't work very
-#   well against the Stupid AI)
-#
-# Update: AIs and crosshair can be toggled. Either change the three values below, or press q, e, or r
-# while the game is running to toggle their appearance
-# q: toggles use_stupid_ai
-# e: toggles use_predictive_ai
-# r: toggles show_crosshair
-#
-
-#use_stupid_ai = True
-#use_predictive_ai = False
-#show_crosshair = False
-
-import sys
-sys.path.append ("/Users/Seiji/Programming/")
-
-import pyglet
-import math
-from pyglet.window import key
-from tanks.utilities import Point2d, StateManager, BoolState, ScalarState
-from tanks.actors import Tank, TankProjectile, PlayerController, TankAccessor
-from TankAI.simpleAI import StupidAI, PredictiveAI
-
-window = pyglet.window.Window()
-keys = key.KeyStateHandler()
-
-tank_projectile = TankProjectile("graphics/projectile.png", speed=400.0,
-                                                auto_destruct_time=2.0)
-
-# Simplifies tank making process: (I was originally doing this manually for each tank)
-# 
-def make_tank (controller, speed=100.0, starting_position=Point2d(100, 100)):
-    global tank_projectile
-    tank = Tank("graphics/tank_body.png", "graphics/tank_turret.png",
-                projectile=tank_projectile, speed = speed, controller = controller)
-    tank.move_to(starting_position)
-    return tank
-
-tank = make_tank(PlayerController(keys), 100.0, Point2d(100, 100))
-player_accessor = TankAccessor(tank)
-
-stupid_ai = StupidAI(target = player_accessor)
-stupid_tank = make_tank(stupid_ai.ai_update, 100.0, Point2d(50, 300))
-
-predictive_ai = PredictiveAI(target = player_accessor)
-predictive_tank = make_tank(predictive_ai.ai_update, 100.0, Point2d(300, 50))
-
-# State manager simplifies lots of things (handles BoolState and ScalarState objects
-# that use lambdas to check conditions and customize print statements.
-# Most importantly, it removes lots of variables from the global namespace
-# (Do NOT use globals unless you *really* need to)
-state_manager = StateManager()
-state_manager["stupid ai"] = BoolState(False,
-            condition = lambda key_: key_.symbol == key.Q)
-state_manager["predictive ai"] = BoolState(False,
-            condition = lambda key_: key_.symbol == key.E)
-state_manager["crosshair"] = BoolState(False,
-            condition = lambda key_: key_.symbol == key.R)
-state_manager["tracking limit"] = BoolState(False,
-            condition = lambda key_: key_.symbol == key.T)
-state_manager["tracking speed"] = ScalarState(tank.turret_tracking_speed, 15,
-            increment_condition = lambda key_: key_.symbol == key.H,
-            decrement_condition = lambda key_: key_.symbol == key.G)
-state_manager["game speed"] = ScalarState(1.0, 0.25,
-            increment_condition = lambda key_: key_.symbol == key.P,
-            decrement_condition = lambda key_: key_.symbol == key.O)
-# Alternate way of writing this:
-# state_manager["tracking limit"] = False
-# (or state_manager["game speed"] = 1.0)
-# state_manager["tracking limit"].condition = lambda key_: key_.symbol == key.T
-# on_enabled and on_disabled messages (also lambdas) can be customized, but default to this:
-# state_manager["tracking limit"].on_enabled = lambda name: "%s enabled."%name
-# To display something else, you could do the following:
-# (lambda doesn't have to use name, but must accept it as a parameter)
-# state_manager["tracking limit"].on_enabled = lambda name: "SOMETHING HAPPENED"
-
-
-@window.event
-def on_mouse_motion (x, y, dx, dy):
-    global tank
-    tank.target = Point2d(x, y)
-
-@window.event
-def on_draw ():
-    window.clear()
-    tank.draw()
-    if state_manager["stupid ai"].enabled:
-        stupid_tank.draw()
-    if state_manager["predictive ai"].enabled:
-        predictive_tank.draw()
-    if state_manager["crosshair"].enabled:
-        predictive_ai.debug.draw()
-
-@window.event
-def on_key_press (symbol, modifiers):
-    #Update state_manager
-    state_manager.update(symbol=symbol, modifiers=modifiers)
-    #   Apply states that are directly linked to other objects
-    # (and thus cannot be purely internally managed):
-    tank.limit_tracking = state_manager["tracking limit"].enabled
-    stupid_tank.limit_tracking = state_manager["tracking limit"].enabled
-    predictive_tank.limit_tracking = state_manager["tracking limit"].enabled
-    tank.turret_tracking_speed = state_manager["tracking speed"].value
-    stupid_tank.turret_tracking_speed = state_manager["tracking speed"].value
-    predictive_tank.turret_tracking_speed = state_manager["tracking speed"].value
-#Set this *after* on_key_press definition (using decorators overrides all other handlers)
-window.push_handlers(keys) #Add KeyHandler
-
-# GameSpeed: Experimental
-# GameSpeed acts as multiplier to delta_time and so speeds up/slows
-# down game action; game can also be paused using this (and reversed :D)
-# This should be a *very* useful feature for the AI competition, since this will
-# allow the game to be paused, slowed down, sped up, etc., as needed so
-# that AI actions and performance can be better analyzed. (speed up to get past
-# the slow parts; slow down to observe the AI's decision making process and
-# effectiveness)
-
-def update (dt):
-    dt *= state_manager["game speed"].value
-    if dt == 0:
-        return
-        # An AI could easily use dt for calculations (thus resulting in a DivideByZeroError)
-        #   (this is the case with PredictiveAI; tank-update also divides by dt when turret speed is limited)
-        # To prevent this, simply don't update AIs when dt == 0...
-    tank.update(dt)
-    if state_manager["stupid ai"].enabled:
-        stupid_tank.update(dt)
-    if state_manager["predictive ai"].enabled:
-        predictive_tank.update(dt)
-
-framerate = 24.0
-pyglet.clock.schedule_interval(update, 1.0 / framerate)
-pyglet.app.run()

TanksDemo.py

-import pyglet
-from pyglet.window import key
-from tanks.utilities import Point2d
-from tanks.actors import Tank, PlayerController, TankProjectile
-
-window = pyglet.window.Window()
-keys = key.KeyStateHandler()
-window.push_handlers(keys)
-
-tank = Tank("graphics/tank_body.png", "graphics/tank_turret.png",
-    speed = 50.0, controller = PlayerController(keys))
-
-tank.move_to(Point2d(100, 100))
-
-tank.projectile = TankProjectile("graphics/projectile.png",
-    speed=400.0, damage=2.5, auto_destruct_time=2.0)
-
-count = 0
-@window.event
-def on_mouse_motion (x, y, dx, dy):
-    global tank, count
-    tank.target =Point2d(x, y)
-
-@window.event
-def on_draw ():
-    window.clear()
-    tank.draw()
-
-framerate = 24.0
-pyglet.clock.schedule_interval(tank.update, 1.0 / framerate)
-
-pyglet.app.run()

TanksPrototype.py

-
-#
-#   First Prototype:
-#   Focused on getting the tank to move properly;
-#   worked out the trig internals to get everything to render properly
-#   (ie. move smoothly in any direction, and get the tank graphic to rotate
-#   around the *center* (not bottom left...))
-#
-
-import pyglet
-import math
-from pyglet.window import key
-from tanks.utilities import Point2d
-
-window = pyglet.window.Window()
-keys = key.KeyStateHandler() #monitors state of keys; keys are accessed via dictionary
-window.push_handlers(keys)
-
-#Tank (Actor) variables
-tank_pos = Point2d(200, 200) #Current location
-tank_rotation = 0.0 #Current rotation
-turret_rotation = 0.0
-
-tank_velocity = 0.0 #Current velocity
-
-tank_acceleration = 50.0 #acceleration speed
-tank_turn_speed = 90.0 #rotation speed
-
-tank_friction = 0.8
-
-#Graphics
-tank_base = pyglet.sprite.Sprite(pyglet.image.load("graphics/tank_body.png"), tank_pos.x, tank_pos.y)
-tank_turret = pyglet.sprite.Sprite(pyglet.image.load("graphics/tank_turret.png"), tank_pos.x, tank_pos.y)
-
-#Runtime code
-
-@window.event
-def on_mouse_motion (x, y, dx, dy):
-    #make turret follow mouse
-    global turret_rotation
-    if y > tank_pos.y:
-        turret_rotation = math.degrees(math.atan((x - tank_pos.x)/(y - tank_pos.y)))
-    elif y < tank_pos.y:
-        turret_rotation = 180 + math.degrees(math.atan((x - tank_pos.x)/(y - tank_pos.y)))
-    else: #y == tank_pos.y
-        #y - tank_pos.y would be zero, and dividing by zero is illeagal
-        #workaround:
-        if x > tank_pos.x:
-            turret_rotation = 90
-        else:
-            turret_rotation = 135
-    #turret_rotation %= 360
-    #don't need to use this since we're setting the degrees directly, not incrementing them.
-
-@window.event
-def on_draw ():
-    #Draw everything (this is called whenever the window needs to be redrawn)
-    window.clear()
-    tank_base.draw()
-    tank_turret.draw()
-
-def check_input (dt):
-    global tank_velocity, tank_rotation
-    tank_velocity = 0.0
-    if keys[key.LEFT] or keys[key.A]:
-        tank_rotation -= tank_turn_speed * dt
-    if keys[key.RIGHT] or keys[key.D]:
-        tank_rotation += tank_turn_speed * dt
-    if keys[key.UP] or keys[key.W]:
-        tank_velocity += tank_acceleration
-    if keys[key.DOWN] or keys[key.S]:
-        tank_velocity -= tank_acceleration
-    tank_rotation %= 360
-    
-def update (dt):
-    #Update function (scheduled to run once every 1/24 of a second)
-    global tank_velocity, tank_pos, tank_friction
-
-    check_input(dt)
-    
-    tank_pos.x += math.cos(math.radians(tank_rotation-90.0)) * tank_velocity * dt
-    tank_pos.y += math.sin(math.radians(tank_rotation+90.0)) * tank_velocity * dt
-    tank_velocity -= tank_velocity * tank_friction * dt
-
-    tank_base.rotation = tank_rotation
-    tank_turret.rotation = turret_rotation
-        
-    tank_base.x = tank_pos.x - math.sin(math.radians(tank_rotation+45)) * tank_base.width / 1.41
-    tank_base.y = tank_pos.y - math.cos(math.radians(tank_rotation+45)) * tank_base.height / 1.41
-    tank_turret.x = tank_pos.x - math.sin(math.radians(turret_rotation+45)) * tank_base.width / 1.41
-    tank_turret.y = tank_pos.y - math.cos(math.radians(turret_rotation+45)) * tank_base.height / 1.41
-
-#Setup, and run!
-framerate = 24.0 #Schedule our update function to be called 24 times a second
-pyglet.clock.schedule_interval(update, 1.0/framerate)
-#Run the app (pyglet runs the application loop and sends messages to user specified callback functions as they are needed)
-pyglet.app.run()

TanksPrototypeII.py

-
-#
-#   Prototype II:
-#   Complex math code from Prototype I is (mostly) internalized into the Entity class
-#   new Entity class is an extension of pyglet's Sprite class, which provides an object hierarchy
-#   and a nicer interface (ie. move(point), rotate(angle), Update(deltaTime), Draw() methods)
-#   The Entity class also rotates around its center, not the bottomLeft thanks to some trig code
-#   developed in Prototype I
-#
-
-
-import pyglet
-import math
-from pyglet.window import key
-from tanks.utilities import Point2d
-from tanks.entities import Entity
-
-window = pyglet.window.Window()
-keys = key.KeyStateHandler()
-window.push_handlers(keys)
-
-tank = Entity(pyglet.image.load("graphics/tank_body.png"))
-tank_turret = Entity(pyglet.image.load("graphics/tank_turret.png"))
-tank.add_child(tank_turret)
-tank.move(Point2d(100, 100))
-
-tank_speed = 50.0
-tank_turn_speed = 90.0
-
-@window.event
-def on_mouse_motion (x, y, dx, dy):
-    #Set the rotation of the tank turret to track the mouse cursor
-    global tank_turret
-    if y > tank_turret.y:
-        tank_turret.rotation = math.degrees(math.atan((x - tank_turret.x)/(y - tank_turret.y)))
-    elif y < tank_turret.y:
-        tank_turret.rotation = 180 + math.degrees(math.atan((x - tank_turret.x)/(y - tank_turret.y)))
-    else:
-        if x > tank_turret.x:
-            turret_rotation = 90
-        else:
-            turret_rotation = 135
-
-@window.event
-def on_draw ():
-    window.clear()
-    tank.draw()
-
-def check_input (dt):
-    global tank, tank_speed, tank_turn_speed
-    velocity = 0.0
-    rotation = 0.0
-    if keys[key.LEFT] or keys[key.A]:
-        rotation -= tank_turn_speed * dt
-    if keys[key.RIGHT] or keys[key.D]:
-        rotation += tank_turn_speed * dt
-    if keys[key.UP] or keys[key.W]:
-        velocity += tank_speed * dt
-    if keys[key.DOWN] or keys[key.S]:
-        velocity -= tank_speed * dt
-    if rotation:
-        tank.rotate(rotation)
-    if velocity:
-        tank.move(Point2d(
-            math.cos(math.radians(tank.rotation-90.0))*velocity,
-            math.sin(math.radians(tank.rotation+90.0))*velocity))
-
-def Update (dt):
-    check_input(dt)
-
-framerate = 24.0
-pyglet.clock.schedule_interval(Update, 1.0 / framerate)
-
-pyglet.app.run()
-    
-

TanksPrototypeIII.py

-#
-#   Prototype III
-#   Tanks are now self contained within the Tank class; everything is now
-#   wrapped up in a nice, easy to use interface:
-#       Tank now uses a callback function to implement player input:
-#           this is modular, and can easily be swapped for something else (eg. an AI module)
-#       Control of the tank is handled through Drive(), Turn(), and Fire() methods.
-#           Drive() moves the tank forwards or backwards relative to its current rotation
-#           Drive() and Turn() accept positive, negative, or zero values,
-#           and move according to the tank's speed and turnSpeed multiplied by deltaTime
-#
-#   Projectiles have also been implemented:
-#       TankProjectile objects stores a projectile's graphic and all other attributes (this is the interface)
-#       TankProjectile.Spawn() (called by Tank.Fire()) returns a TankProjectileInstance object, 
-#       which is stored within a TankProjectileCollection object, which handles updating, drawing, and
-#       autodestroying projectiles
-#
-#       Currently, all projectiles (located within a TankProjectileCollection) are stored within the Tank
-#       that fired them, and are updated from this object.
-#           This is NOT ideal (destroying the tank would destroy all of its projectiles), *but* it is much
-#           cleaner than storing them in a global variable within this script at the present time.
-#           (how does the Tank (located within another module) access this?) 
-#           Since this will probably need to be restructured once physics are implemented anyways,
-#           I'll just keep the projectiles stored like this until the rest of the game framework is more complete.
-#
-#   Note on Physics:
-#   I have a fairly good idea of how to implement proper physics* but I know that it will involve lots of
-#   matrix algebra -- as I haven't used matrices in a little while, physics interactions will have to wait until
-#   I've brought myself back up to speed on that subject.
-#
-#   * How I would implement physics:
-#       Objects can't be allowed to directly move themselves - instead, they send out movement requests
-#       to the physics engine.
-#       The physics engine then takes these requests and forms movement vectors for every actor (non static
-#       object) in the game.
-#       Each movement vector (line segment) is checked against every other movement vector and static
-#       collision line (culled via simple 2d checks: x1 vs x2, y1 vs y1 (sqrt is too expensive to use for this)).
-#       In the case of a collision (vectors overlap), both will be shortened to the collision point (and factoring
-#       in circle bounds), and the actors will be notified that there is a collision (and what with).
-# Other physics systems:
-#   Grid:
-#       advantages - fast collision lookup; easily adapted for pathfinding
-#       disadvantages - movement is blocky and unrealistic; not good for a realtime game
-#   Simple rectangular collision boxes:
-#       advantages - easy to implement; matrices not needed (math is greater than/less than
-#           checks between rectangle corners)
-#       disadvantages - rectangles are limiting (can't be rotated), and matrices would be needed to make
-#           actor movement work anyways (simply checking end position would mean that projectiles would
-#           frequently pass through tanks; long bounding box wouldn't work either since it couldn't be rotated).
-
-#
-# Recent addition:
-# Added to_world_space method to the Entity class, and changed bottom_right, etc., properties to pass
-# through this (so these points are now accurate - factor in rotation, etc.)
-# Added in debugging overlay to the tank to show this:
-
-#Shows debug overlay of points (top_left, center, etc.,) on tank if enabled
-#Press q while playing to toggle this
-show_debug_overlay = False
-
-import pyglet
-import math
-from pyglet.window import key
-from tanks.utilities import Point2d
-from tanks.actors import Tank, PlayerController, TankProjectile
-from tanks.entities import Entity
-
-window = pyglet.window.Window()
-keys = key.KeyStateHandler()
-
-world = Entity(pyglet.image.load("graphics/target.png"))
-
-tank = Tank("graphics/tank_body.png", "graphics/tank_turret.png",
-    controller = PlayerController(keys))
-tank.move_to(Point2d(100, 100))
-tank.projectile = TankProjectile("graphics/projectile.png",
-    speed=400.0, damage=2.5, auto_destruct_time=2.0)
-
-world.add_child(tank._body)
-
-def cam_update (dt):
-    cam_speed = 50.0
-    move_vector = Point2d()
-    if keys[key.L]:
-        move_vector.x += dt * cam_speed
-    if keys[key.J]:
-        move_vector.x -= dt * cam_speed
-    if keys[key.I]:
-        move_vector.y += dt * cam_speed
-    if keys[key.K]:
-        move_vector.y -= dt * cam_speed
-    world.move(move_vector)
-    
-
-debug_overlay = Entity(pyglet.image.load("graphics/projectile.png"))
-def draw_debug_overlay (position):
-    debug_overlay.move_to(position)
-    debug_overlay.draw()
-
-@window.event
-def on_mouse_motion (x, y, dx, dy):
-    global tank
-    tank.target =Point2d(x, y)
-
-@window.event
-def on_draw ():
-    window.clear()
-    tank.draw()
-    if show_debug_overlay:
-        debug_overlay.scale = 0.5
-        draw_debug_overlay(tank._body.bottom_left)
-        draw_debug_overlay(tank._body.bottom_right)
-        draw_debug_overlay(tank._body.top_left)
-        draw_debug_overlay(tank._body.top_right)
-        debug_overlay.scale = 0.3
-        draw_debug_overlay(tank._body.center)
-        draw_debug_overlay(tank._body.bottom_center)
-        draw_debug_overlay(tank._body.top_center)
-        draw_debug_overlay(tank._body.center_left)
-        draw_debug_overlay(tank._body.center_right)
-
-@window.event
-def on_key_press (symbol, modifiers):
-    global show_debug_overlay
-    #Toggle debug overlay
-    if symbol == key.Q:
-        if show_debug_overlay:
-            show_debug_overlay = False
-        else:
-            show_debug_overlay = True
-#This needs to be called after an on_key_press window event is defined
-# (the latter overrides the former, but not vice versa)
-window.push_handlers(keys)
-    
-framerate = 24.0
-pyglet.clock.schedule_interval(tank.update, 1.0 / framerate)
-pyglet.clock.schedule_interval(cam_update, 1.0 / framerate)
-
-pyglet.app.run()

TodoList.txt

-
-TODO LIST (as of 10.10.11):
-
-Physics/Collision and Movement core
-    Revise current movement code as necessary (if needed, move most update code from Tank and Entity
-    class to the physics update method - physics should be *secure*)
-    Necessary skills/knowledge: matrix algebra, vectors, trig, understanding of basic physics...
-
-Debug drawing utilities:
-   There needs to be drawing utilities available for debugging stuff: Draw line, point, etc.
-   Might be tricky since we're running on a sprite abstraction layer on top of opengl (should be easy
-   to do in opengl itself)
-
-Obstacle class:
-    Mechanics (pending working Physics), and Visual (could start development right away)
-    Colliders should be represented by line segments (lists of vectors)
-    Graphics should either consist of vector graphics (walls and nodes), prerendered structures
-    placed on the map (w/ physical outline determined by colliders), or filled in space (borders
-    determined by colliders) with outlines rendered as vector graphics
-
-Level Editor:
-    pending completion of Obstacle class
-    Should enable visual placement of obstacles, spawn points, and capacity to be extended to include other
-    stuff like pickups shoud they be added
-
-Obstacle Collider Editor?
-
-Physics Utilities: (For AI use)
-    Raycasting (keep last physics state in memory for this)
-    Navmesh generator ?
-        There should be *some* foundation for AI pathfinding (if included): leaving the AI to scan
-        its environment on its own would be very, *very* slow...
-
-Event system:
-    All actions should be logged and made accessible to AIs
-    Should include capability to query lists of actions given parameters (eg by actor_id, action_type,
-    or time)
-    Work on event system could start right now (though internals can't be completely mapped out
-    until Physics and AI Framework is completed)
-    
-AI Framework:
-    AI parent class should provide embedded functionality
-    AI Assembler should be able to import AI modules (python modules), attach these to tanks,
-    and then spawn the resulting actors into the game world.
-    AI API should AI's only interface to game world, and be consistently updated using latest info, consistently,
-    for every AI. (Need system for this too)
-        Events and safe world info should be fed into AI input accessors; action requests should be
-        pulled from AI output, checked for validity (evaluated, not evaluated?), and finally passed to the
-        event system to be logged (successful or not)
-    Some of this can be done now; other aspects (API) can't be done until Physics, Physics Utilities, and Events
-    are completed/planned out
-
-And if this sounds barely coherent, it's because I wrote this when I was very sleepy...
-(I thought the project needed a Todo list, so I wrote one anyways - sleepy or not).

Empty file removed.

ai/basicAI.py

-
-"""
-Basic AI example:
-
-Since AI framework doesn't exist yet, target is given directly to the AI and
-setup is done manually.
-
-Example:
-    from ai.basicAI import BasicAI
-
-    ai = BasicAI(target = player_tank)
-    bot = Tank("graphics/tank_body.png", "graphics/tank_turret.png",
-                    projectile=TankProjectile("graphics/projectile.png"),
-                    controller = ai)
-    pyglet.clock.schedule_interval(bot.ai_update, 1.0 / framerate)
-
-"""
-
-
-import sys
-sys.path.append("..")
-from tanks.utilities import Point2d, Rect, safe_atan
-import math
-import pyglet
-from tanks.entities import Entity
-
-class BasicAI:
-    """A simple AI bot."""
-    def __init__ (self, target=None):
-        """Set target to a tank/moving entity."""
-        self.target = target
-        self.flee_distance = 150.0
-        self.chase_distance = 250.0
-
-    def ai_update (self, actor, dt):
-        """Assign a tank's controller attribute to this method."""
-        if self.target is None:
-            print("No target!")
-            return
-        actor.target = self.target.position #Set the turret's target
-        delta_position = self.target.position - actor.position
-        self.move_angle = safe_atan(delta_position) * -1
-        distance = math.sqrt(delta_position.x ** 2 + delta_position.y ** 2)
-        
-        if distance < self.flee_distance:
-            self.flee(actor, dt)
-        elif distance > self.chase_distance:
-            self.chase(actor, dt)
-        else:
-            #Normal behaviour
-            actor.fire()
-
-    def flee (self, actor, dt):
-        actor.turn_towards(self.move_angle + 90)
-        actor.drive(-1)
-        actor.fire()
-
-    def chase (self, actor, dt):
-        actor.turn_towards(self.move_angle + 90)
-        actor.drive(1)
-        actor.fire()

ai/basic_ai.py

-
-"""
-Basic AI example:
-
-Since AI framework doesn't exist yet, target is given directly to the AI and
-setup is done manually.
-
-Example:
-    from ai.basicAI import BasicAI
-
-    ai = BasicAI(target = player_tank)
-    bot = Tank("graphics/tank_body.png", "graphics/tank_turret.png",
-                    projectile=TankProjectile("graphics/projectile.png"),
-                    controller = ai)
-    pyglet.clock.schedule_interval(bot.ai_update, 1.0 / framerate)
-
-"""
-
-# Add the parent directory to sys.path:
-# This gives us access to files via the same structure as if this
-# script was located in the parent directory
-import sys
-sys.path.append("..")
-from tanks.utilities import Point2d, Rect, safe_atan
-import math
-
-class BasicAI:
-    """A very basic AI bot."""
-    def __init__ (self, target=None):
-        """Set target to a tank/moving entity."""
-        self.target = target
-        self.flee_distance = 150.0
-        self.chase_distance = 250.0
-
-    def ai_update (self, actor, dt):
-        """Assign a tank's controller attribute to this method."""
-        if self.target is None:
-            # Prevent errors by returning early if target is not assigned:
-            print("No target!")
-            return
-        # Set the turret's target:
-        actor.target = self.target.position
-        # Calculate the delta position between target and self (actor):
-        delta_position = self.target.position - actor.position
-        # Use safe_atan (arc tangent, aka inverse tangent) to calculate the distance
-        # between self (actor) and target:
-        self.move_angle = safe_atan(delta_position) * -1
-        # Calculate the distane between self and target:
-        distance = math.sqrt(delta_position.x ** 2 + delta_position.y ** 2)
-        
-        if distance < self.flee_distance:
-            # Flee when the target comes too close.
-            self.flee(actor, dt)
-        elif distance > self.chase_distance:
-            # Pursue when the target moves too far away.
-            self.chase(actor, dt)
-        else:
-            # Normal behaviour:
-            # Remain stationary; fire at the target.
-            actor.fire()
-
-    def flee (self, actor, dt):
-        # Turn the tank
-        actor.turn_towards(self.move_angle + 90)
-        # Drive backwards (away)
-        actor.drive(-1)
-        # Fire (no reason not to)
-        actor.fire()
-
-    def chase (self, actor, dt):
-        #Turn the tank
-        actor.turn_towards(self.move_angle + 90)
-        # Drive forwards
-        actor.drive(1)
-        # Fire
-        actor.fire()

Binary file removed.

data/tankprofiles/player

-name = "Default Player Tank"
-controller = 

data/tankprofiles/template.tank

-name = "Tank Template"
-#Values not filled out by other tank descriptions are set by this.
-controller = PlayerController(keys)
-body = "graphics/tank_body.png"
-turret = "graphics/tank_turret.png"
-projectile = "graphics/projectile.png"
-speed = 100
-turn_speed = 180
-#...TBD

misc/MathReference.txt

-Math Reference:
-
-Note - Point2d objects makes everything easier, so use them!
-(Point2ds are essentially 2 dimensional vectors)
-
-Limit x by y:
-    x %= y
-
-Calculate displacement (difference between two points):
-    displacement = point2 - point1
-
-Calculate distance between two points:
-    distance = math.sqrt((point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2)
-
-Calculate angle between two points (radians):
-    math.atan((point1.y - point2.y) / (point1.x - point2.x))
-
-Calculate angle between two points (degrees):
-    math.degrees(math.atan((point1.y - point2.y) / (point1.x - point2.x)))
-    Note: atan can be a bit tricky since it only returns values within 180 degrees.
-            See below for safe solution
-
-Calculate position given angle and distance (r, a vs x, y):
-    position = Point2d(math.cos(a) * r, math.sin(a) * r)
-
-Calculate velocity:
-    displacement / time
-    (end_point - start_point) / time
-
-Calculate future position:
-    future_position = current_position + velocity * time
-
-Given position relative to center_position, calculate location of position after it
-has rotated 'degrees' around center_position:
-    See Entity.to_world_space()
-
-Trig Reference:
-    r = y / sin(a)
-    r = x / cos(a)
-    r = sqrt(x*x + y*y)
-    x = cos(a) * r
-    y = sin(a) * r
-    y = tan(a) * x
-    x = y / tan(a)
-    a = atan(y / x)
-    a = asin(y / r)
-    a = acos(x / r)
-
-    radians are measured in units of pi (360 degrees = 2 * pi)
-    pi = 180 degrees
-    pi / 2 = 90 degrees
-    pi / 3 = 60 degrees
-    pi / 4 = 45 degrees
-    Thus, 3 * pi / 4 = 135 degrees...
-
-Safely calculate angle between two points (radians):
-(I came up with this when writing Entity's to_world_space method (this is the same code))
-    displacement = point2 - point1
-    if displacement.y > 0:
-        if displacement.x != 0:
-            angle = math.atan(displacement.y / displacement.x)
-        else:
-            angle = math.pi / 2
-    elif displacement.y < 0:
-        if displacement.x != 0:
-            angle = math.atan(displacement.y / displacement.x) * -1
-        else:
-            angle = math.pi / 2
-    else: #y == 0
-        angle = 0.0

misc/data hiding.py

-"""Data hiding in Python:
-"""
-
-class MyClass:
-    def __init__ (self, foo, bar):
-        self.foo = foo
-        self.bar = bar
-
-
-class Accessor:
-    def __init__ (self, my_class_instance):
-        Accessor.foo = property(lambda self: my_class_instance.foo)
-        Accessor.bar = property(lambda self: my_class_instance.bar)
-        # my_class_instance reference is locked inside of function closures, so
-        # it cannot be directly accessed from any Accessor instance:
-        # the reference is not directly stored in any class or instance variable.
-        # Since it is a reference, it will mirror any changes made to the MyClass
-        # instance that it accesses.
-
-
-my_data = MyClass(10, "113")
-accessor = Accessor(my_data)
-print(accessor.foo, accessor.bar)
-
-my_data.bar = "231"
-my_data.foo = [13, 14, 15]
-print(accessor.foo, accessor.bar)

misc/python magic.py

-
-"""In Python, everything is an object.
-Thus, the following is possible:
-"""
-
-class Vector:
-    pass
-
-def add_vectors (vector1, vector2):
-    new_vector = Vector()
-    new_vector.x = vector1.x + vector2.x
-    new_vector.y = vector1.y + vector2.y
-    return new_vector
-
-Vector.__add__ = add_vectors
-del add_vectors
-
-Vector.__repr__ = lambda self: "(%0.2f, %0.2f)"%(self.x, self.y)
-
-Vector.sum = property(lambda self: self.x + self.y)
-
-def vector (x, y):
-    v = Vector()
-    v.x = x
-    v.y = y
-    return v
-
-v1 = vector(10, 11)
-v2 = vector(3, -12)
-v3 = v1 + v2
-
-print(v3)
-print(v3.sum)
-
-# Note: the lambda keyword is used to create a function closure in Python:
-# (Python lambdas can only use one line of code: anything longer than a single
-# expression should be placed in a regular function)
-#   lambda param1, param2: param1 + param2
-# vs
-#   def my_func (param1, param2):
-#       return param1 + param2
-#
-# The property keyword creates a python property: a wrapper around up to
-# three functions (get, set, and docstring) that calls these functions to behave
-# like a regular data attribute. Readonly properties can be created by only
-# specifying the first parameter (as is the case here).
Add a comment to this file

tanks/.DS_Store

Binary file removed.

Add a comment to this file

tanks/__init__.py

Empty file removed.

tanks/actors.py

-#/user/bin/env python
-
-"""Collection of actor classes (non-static entities):
-
-Tank: Self contained tank that can be controlled by a player (PlayerController) or by an AI.
-
-PlayerController: Returns a function that can be plugged into a Tank's controller attribute
-    to give it default player control. PlayerController must be given an active KeyHandler to
-    function.
-
-TankProjectile: A projectile used by Tank. spawn() returns TankProjectileInstance objects.
-
-TankProjectileInstance: Active instance of a TankProjectile; should be contained within
-    a TankProjectileCollection.
-
-TankProjectileCollection: Container for TankProjectileInstances - these are temporarily
-    located within Tank (tanks currently carry their own fired projectiles - BAD long term:
-    should be changed once Physics is completed)
-"""
-__author__ = "Seiji Emery"
-
-
-import math
-from utilities import Point2d, Rect
-from entities import Entity
-import pyglet
-from pyglet.window import key
-
-
-def PlayerController(key_input):
-    """
-    Return a function object that handles player input for a Tank.
-
-    Set key_input to an active pyglet KeyHandler.
-    Attach the input_handler function (returned value) to a tank's controller
-    attribute/init parameter.
-    Provides following controls:
-    Left/Right arrow keys and A/D keys: turn tank
-    Up/Down arrow keys and W/S keys: drive tank
-    Space key: issue a fire command to the tank
-    """
-    def input_handler (tank, dt):
-        if key_input[key.LEFT] or key_input[key.A]:
-            tank.turn(-1)
-        if key_input[key.RIGHT] or key_input[key.D]:
-            tank.turn(1)
-        if key_input[key.UP] or key_input[key.W]:
-            tank.drive(1)
-        if key_input[key.DOWN] or key_input[key.S]:
-            tank.drive(-1)
-        if key_input[key.SPACE]:
-            tank.fire()
-    return input_handler
-
-
-class TankAccessor:
-    """A readonly wrapper for a tank's public attributes.
-    (Expose this to AIs, not the tank itself)
-    This system is completely secure - position, rotation, and turret_rotation
-    are readonly properties with the tank reference stored within lambdas as a
-    local variable.
-    It is impossible to obtain a direct tank reference via this object, so yes,
-    this is a completely safe way to guard the tank instances.
-    """
-    def __init__ (self, tank):
-        #Python magic :D
-        TankAccessor.position = property(lambda self: tank.position)
-        TankAccessor.rotation = property(lambda self: tank.rotation)
-        TankAccessor.turret_rotation = property(lambda self: tank.turret_rotation)
-
-
-class Tank:
-    """A self contained tank actor.
-    Can be configured to be controlled by player input (see PlayerController), or by
-    an AI.
-    """
-    def __init__ (self, tank_img_path, turret_img_path, projectile=None,
-                      speed=75.0, turn_speed=90.0, fire_delay=0.5, limit_tracking = False, turret_tracking_speed = 180.0,
-                      controller=None):
-        """
-        Parameters:
-            tank_img_path - Path and file name of image to display for the tank's body section.
-                eg: "graphics/tank.png"
-            turret_img_path - Path and file name of image to display for the tank's turret.
-        Parameters/Data Attributes:
-            speed (float) - Tank's movement speed, in pixels per second.
-            turn_speed (float) - Tank's turn speed, in degrees per second.
-            fire_delay (float) - Delay (in seconds) between tank's shots. Determines max fire rate.
-            limit_tracking_speed (bool) - limit max turret turn speed to turret_tracking_speed if enabled.
-            turret_tracking_speed (float) - Max speed turret can track its target at (degrees / second)
-            target (Point2d) - The point in space that the tank's turret aims at.
-            controller (function reference) - Controller callback function used to issue orders to the
-                tank. Should accept one parameter (tank), and call tank.drive(), tank.turn(), and
-                tank.fire(). Intended to either use PlayerController or an AI's update method.
-            projectiles (TankProjectile) - Projectile that the tank fires.
-
-        Attribute List:
-        parameters:
-        initialization:
-            tank_img_path (string)
-            turret_img_path (string)
-        controller (function)
-        speed (float)
-        turn_speed (float)
-        target (Point2d)
-        projectile (TankProjectile)
-        fire_rate (float)
-        limit_tracking (bool)
-        turret_tracking_speed (float)
-    methods:
-        drive (direction (float))
-        turn (direction (float))
-        fire ()
-    properties:
-        position (Point2d)
-        rotation (float)
-        turret_rotation (float)
-    update:
-        update()
-        draw()
-        """
-        self._body = Entity(pyglet.image.load(tank_img_path))
-        self._turret = Entity(pyglet.image.load(turret_img_path))
-        self._body.add_child(self._turret)
-        self.speed = abs(speed)
-        self.turn_speed = abs(turn_speed)
-        self.controller = controller
-        self._move_direction = 0.0
-        self._rotate_direction = 0.0
-        self.target = Point2d(0, 0)
-        self.projectile = projectile
-        self.fire_delay = fire_delay
-        self._fire_cooldown = 0.0
-        self.projectiles = TankProjectileCollection()
-        self.limit_tracking = limit_tracking
-        self.turret_tracking_speed = turret_tracking_speed
-
-    def move_to (self, position):
-        """
-        Move the tank (basically teleportation).
-        Using this for anything other than initialization is cheating!
-        """
-        self._body.move_to(position)
-
-    def turn (self, angle):
-        """
-        Order the tank to turn.
-        A positive value will make it turn clockwise; a negative value will make it run counterclockwise.
-        """
-        #turn only sets internal input: Actual rotation is handled by update () method
-        #This ensures that movement/rotation is set to tank's movement and rotation
-        #speeds, and multiplied by deltaTime
-        self._rotate_direction = angle
-
-    def turn_towards (self, target_angle, min_turn_angle = 5.0):
-        """Order the tank to turn towards the target angle (in degrees)
-        The tank will tell itself to turn in the optimal direction to reach the target angle.
-        This makes it possible to code a simple AI bot without dealing with trigonometry.
-        
-        """
-        delta_angle = target_angle - self.rotation
-        delta_angle %= 360
-        if abs(delta_angle) < min_turn_angle:
-            return
-        if delta_angle > 0:
-            delta_angle2 = (360 - delta_angle) * -1
-        else:
-            delta_angle2 = 360 - (delta_angle * -1)
-        if abs(delta_angle) < abs(delta_angle2):
-            self._rotate_direction = delta_angle
-        else:
-            self._rotate_direction = delta_angle2
-
-    def drive (self, velocity):
-        """Order the tank to drive: Positive value indicates forward; negative indicates backwards."""
-        self._move_direction = velocity
-
-    def update (self, dt):
-        """
-        Call this method every frame with delta time as its parameter.
-
-        This method rotates and moves this tank according to input issued by the drive()
-        and turn() methods.
-        Movement and rotation is constrained by the tank's speed/turn speed and dt.
-        """
-        #Call controller handler function if it has been assigned
-        # (this shold call tank.turn() and tank.drive()
-        if self.controller:
-            self.controller(self, dt)
-        # Use input to determine movement and rotation values
-        if self._rotate_direction > 0:
-            self._rotate_direction = self.turn_speed * dt
-        elif self._rotate_direction < 0:
-            self._rotate_direction = self.turn_speed * dt * -1
-        if self._move_direction > 0:
-            self._move_direction = self.speed * dt
-        elif self._move_direction < 0:
-            self._move_direction = self.speed * dt * -1
-        #Rotate and move the tank
-        if self._rotate_direction:
-            self._body.rotate(self._rotate_direction)
-        if self._move_direction:
-            self._body.move(Point2d(
-                math.cos(math.radians(self._body.rotation - 90.0)) * self._move_direction,
-                math.sin(math.radians(self._body.rotation + 90.0)) * self._move_direction))
-        #Clear input
-        self._rotate_direction = 0.0
-        self._move_direction = 0.0
-        #Make turret point at target
-        if self.target.y > self._turret.y:
-            target_rotation = math.degrees(math.atan((self.target.x - self._turret.x)/(self.target.y - self._turret.y)))
-        elif self.target.y < self._turret.y:
-            target_rotation = 180 + math.degrees(math.atan((self.target.x - self._turret.x)/(self.target.y - self._turret.y)))
-        else:
-            if self.target.x > self._turret.x:
-                target_rotation = 90
-            else:
-                target_rotation = 135
-        if not self.limit_tracking:
-            self._turret.rotation = target_rotation
-        #Limit turret tracking...
-        else:
-            if target_rotation != self._turret.rotation:
-                target_rotation %= 360
-                self._turret.rotation %= 360
-                delta_rotation1 = target_rotation - self._turret.rotation
-                if delta_rotation1 > 0:
-                    delta_rotation2 = (360 - delta_rotation1) * -1
-                else:
-                    delta_rotation2 = 360 - (delta_rotation1 * -1)
-                if abs(delta_rotation1) < abs(delta_rotation2):
-                    if delta_rotation1 > 0:
-                        self._turret.rotation += delta_rotation1 % (self.turret_tracking_speed * dt)
-                    else:
-                        self._turret.rotation -= (delta_rotation1 * -1) % (self.turret_tracking_speed * dt)
-                else:
-                    if delta_rotation2 > 0:
-                        self._turret.rotation += delta_rotation2 % (self.turret_tracking_speed * dt)
-                    else:
-                        self._turret.rotation -= (delta_rotation2 * -1) % (self.turret_tracking_speed * dt)
-        #update firing timer
-        self._fire_cooldown -= dt
-        #update projectiles
-        self.projectiles.update(dt)
-
-    def draw (self):
-        """Draw this tank."""
-        self._body.draw()
-        self.projectiles.draw()
-
-    def fire (self):
-        """
-        Order this tank to fire.
-
-        Fire rate is limited by fire_delay.
-        """
-        if self._fire_cooldown > 0.0:
-            return
-        self._fire_cooldown = self.fire_delay
-        if self.projectile:
-            self.projectiles.add(self.projectile.spawn(self._turret.top_center, self._turret.top_center - self.position))
-
-    @property
-    def position (self):
-        return Point2d(self._body.x, self._body.y)
-
-    @property
-    def rotation (self):
-        return self._body.rotation
-
-    @property
-    def turret_rotation (self):
-        return self._turret.rotation
-
-
-class TankProjectileCollection:
-    """
-    Collection of TankProjectileInstance objects.
-    
-    draw() and update() draw/update all contained projectiles.
-    Projectiles are automatically deleted when projectiles expire
-    (set by projectile's auto_destruct_time init parameter).
-
-    Attribute List:
-    methods:
-        add (projectile (TankProjectileInstance))
-    update:
-        update()
-        draw()
-    """
-    def __init__ (self):
-        self.projectiles = []
-    def update (self, dt):
-        for i in range(len(self.projectiles)):
-            try:
-                if not self.projectiles[i].projectile_update(dt):
-                    del self.projectiles[i]
-            except IndexError:
-                pass
-    def draw (self):
-        for projectile in self.projectiles:
-            projectile.draw()
-    def add (self, projectile):
-        self.projectiles += [projectile]
-        
-
-class TankProjectile:
-    """
-    Describes a tank projectile.
-
-    spawn() returns a TankProjectileInstance; store this in a TankProjectileCollection
-
-    Attribute List:
-    parameters:
-        initialization:
-            img_path (string)
-        speed (float)
-        auto_destruct_time (float)
-        damage (float)
-    methods:
-        spawn (position (Point2d), direction (Point2d)) (TankProjectileInstance)
-    """
-    def __init__ (self, img_path, speed=150.0, damage = 2.5, auto_destruct_time = 5.0):
-        """
-        Parameters:
-        img_path - path and file name of the image to use for this projectile.
-            eg: "graphics/myprojectile.png"
-        speed - speed of the projectile.
-        damage - damage of this projectile (unused).
-        auto_destruct_time - projectile will destroy itself after this time
-        (We don't want projectiles to infinitely linger, and eat up increasingly large amounts
-        of RAM and CPU time as the game wears on).
-        """
-        self.img_path = img_path
-        self.speed = speed
-        self.damage = damage
-        self.auto_destruct_time = auto_destruct_time
-
-    def spawn (self, position, direction):
-        """
-        Spawn a projectile at position, traveling in direction.
-        Note: velocity calculated from direction is limited by speed.
-        """
-        projectile = TankProjectileInstance(self.img_path, self.speed, self.damage, position, direction, self.auto_destruct_time)
-        return projectile
-    
-
-class TankProjectileInstance:
-    def __init__ (self, img_path, speed, damage, position, direction, auto_destruct_time):
-        """
-        A projectile that travels through world space.
-
-        Spawned by TankProjectile.
-        Must be contained within a TankProjectileCollection (which itself
-        must be updated every frame and included in the drawing process)
-        """
-        self._entity = Entity(pyglet.image.load(img_path))
-        self._entity.x = position.x
-        self._entity.y = position.y
-        r = math.sqrt(direction.x **2 + direction.y ** 2)
-        self.velocity = Point2d(speed * direction.x / r, speed * direction.y / r)
-        self.damage = damage
-        self.destruct_timer = auto_destruct_time
-
-    def projectile_update (self, dt):
-        """
-        Update this projectile - called by TankProjectileCollection.update().
-        """
-        if self.destruct_timer < 0:
-            return False #destroy this object
-        self._entity.x += self.velocity.x * dt
-        self._entity.y += self.velocity.y * dt
-        self.destruct_timer -= dt
-        return True
-
-    def draw (self):
-        """Draw this projectile - called by TankProjectileCollection.draw()."""
-        self._entity.draw()

tanks/ai_framework.py

-""" AI Framework
-
-"""
-
-class Event:
-    def __init__ (self, name, value, time=0.0, tags=[]):
-        self.name = name
-        self.value = value
-        self.time = time
-        self.tags = tags
-
-class EventBundle:
-    def __init__ (self, events = [], time = 0.0):
-        pass
-
-class AIFoundation:
-    def __init__ (self):
-        pass
-
-    def ai_update (self, my_tank, dt):
-        """Use this method for updates."""
-        pass
-
-    def get_actors (self):
-        pass
-                  
-    def raycast (self, point, direction):
-        pass
-
-    def get_locations (self):
-        pass
-
-    

tanks/entities.py

-from pyglet.sprite import Sprite
-from utilities import Rect, Point2d
-import math
-from copy import copy
-
-"""
-Entity classes.
-
-Currently contains just one type of entity (Entity).
-Although Entity is dynamic, this module should generally contain static game assets (eg. obstacles;
-ColliderEntities; etc.) as opposed to the actors module (which contains non-static entities)
-
-"""
-
-class Entity (Sprite):
-    """
-    An extension of pyglet.sprite.Sprite that provides extra functionality:
-
-    Entities rotate around their center, not the bottom left corner
-    (and x, y refers to the center of the object).
-    Entities support parent-child relationships:
-        rotate(), move(), move_to(), and draw() calls are repeated in all children.
-        entities can be assigned tags; find() and find_all() searches through all children
-        for entities with matching tags.
-    A series of properties are provided to access common points on the entity (top_right,
-    bottom_left, center_left, center, etc.,). These properties return positions translated
-    into world space (based on current position, width, height, and rotation).
-
-    Added data attributes:
-    children (list)
-    tags (list)
-    
-    Attribute List:
-    parameters:
-        initialization:
-            img (pyglet image data)
-            blend_src (int)
-            blend_dest (int)
-            batch (pyglet graphics batch)
-            group (pyglet group ?)
-            usage (string)
-        x (float)
-        y (float)
-        children (list)
-        tags (list)
-    methods:
-        move (direction (Point2d))
-        move_to (position (Point2d))
-        rotate (degrees (float))
-        to_world_space (local_space (Point2d)) (Point2d)
-        add_tag (tag (string))
-        add_child (child (Entity))
-        remove_child (child (Entity))
-        find_with_tag (tag (string))
-        find_all_with_tag (tag (string))
-    properties:
-        width (float)
-        height (float)
-        rect (Rect)
-        bottom_left (Point2d)
-        bottom_center (Point2d)
-        bottom_right (Point2d)
-        center_left (Point2d)
-        center (Point2d)
-        center_right (Point2d)
-        top_left (Point2d)
-        top_center (Point2d)
-        top_right (Point2d)
-    update:
-        update()
-        draw()
-    """
-    def __init__ (self, img, x=0.0, y=0.0, blend_src = 770, blend_dest = 771, batch=None, group=None, usage='dynamic'):
-        Sprite.__init__ (self, img, x, y, blend_src, blend_dest, batch, group, usage)
-        self.children = []
-        self.tags = []
-
-    def rotate (self, degrees):
-        """Rotate this object and all children by degrees."""
-        self.rotation += degrees
-        self.rotation %= 360
-        for child in self.children:
-            try:
-                child.rotate(degrees)
-            except AttributeError: #Child doesn't have a rotate() method
-                try: #Try manually adjusting rotation
-                    child.rotation += degrees
-                except AttributeError:
-                    pass #If child has neither, ignore this child
-
-    def move (self, direction):
-        """Move this object and all children in direction (Point2d)."""
-        self.x += direction.x
-        self.y += direction.y
-        for child in self.children:
-            try:
-                child.move(direction)
-            except AttributeError: #child doesn't have a move() method
-                pass
-
-    def move_to (self, position):
-        """
-        Move this object to position (Point2d).
-
-        Relative child positions will be preserved.
-        """
-        disp = Point2d(position.x - self.x, position.y - self.y)
-        self.x = position.x
-        self.y = position.y
-        for child in self.children:
-            try:
-                child.move(disp)
-            except AttributeError: #Child doesn't have a move() method
-                pass
-
-    def draw (self):
-        """
-        Extends Sprite.draw().
-
-        Draws self and all children.
-        Offsets x and y draw position when drawing so the sprite apears to rotate around its center.
-        """
-        center_point = Point2d(self.x, self.y)
-        self.x -= math.sin(math.radians(self.rotation + 45)) * self.width / 1.41
-        self.y -= math.cos(math.radians(self.rotation + 45)) * self.height / 1.41
-        Sprite.draw(self)
-        self.x = center_point.x
-        self.y = center_point.y
-        for child in self.children:
-            child.draw()
-
-    def to_world_space (self, local_point):
-        """
-        Convert a point in local space to world space (factoring in rotation and position).
-        """
-        #Note: this is all internal, so radians are used
-        if local_point.y > 0:
-            if local_point.x != 0:
-                angle = math.atan(local_point.y / local_point.x)
-            else:
-                angle = math.pi / 2
-        elif local_point.y < 0:
-            if local_point.x != 0:
-                angle = math.atan(local_point.y / local_point.x) * -1
-            else:
-                angle = math.pi / 2 
-        else: #y == 0
-            angle = 0.0
-        r = math.sqrt(local_point.x ** 2 + local_point.y ** 2)
-        if local_point.x < 0:
-            r *= -1
-        if local_point.y < 0:
-            r *= -1
-
-        return  Point2d(self.x + r * math.cos(angle - math.radians(self.rotation)),
-                            self.y + r * math.sin(angle - math.radians(self.rotation)))
-        
-
-    def add_child (self, child):
-        """
-        Append a child to this entity's child list.
-
-        Calls to draw(), move(), and move_to() are called on all children.
-        """
-        self.children += [child]
-
-    def remove_child (self, child):
-        """Remove a child from this entity's child list."""
-        for i in range(len(self.children)):
-            if child == self.children[i]:
-                del self.children[i]
-
-    def add_tag (self, tag):
-        """Add a tag to this object's tag list."""
-        self.tags += [tag]
-
-    def find_with_tag (self, tag):
-        """Search through self and all children. Return the first object found with the matching tag (may be self)."""
-        for t in self.tags:
-            if t == tag:
-                return self
-        for child in self.children:
-            result = child.find_with_tag(tag)
-            if result:
-                return result
-        return None
-
-    def find_all_with_tag (self, tag):
-        """Search through self and all children. Return a list of all objects found with a matching tag."""
-        results = []
-        if tag in self.tags:
-            results += [self]
-        for child in self.children:
-            results += child.find_all_with_tag(tag)
-        return results
-
-    @property
-    def rect (self):
-        return Rect(self.x, self.y, self.width, self.height)
-
-    @property
-    def bottom_left (self):
-        """Return the bottom left point of this object in world space."""
-        return self.to_world_space(Point2d(self.width / -2, self.height / -2))
-        #return Point2d(self.x, self.y)
-    
-    @property
-    def bottom_center (self):
-        """Return the bottom center point of this object in world space."""
-        return self.to_world_space(Point2d(0, self.height / -2))
-        #return Point2d(self.x + self.width / 2, self.y)
-
-    @property
-    def bottom_right (self):
-        """Return the bottom right point of this object in world space."""
-        return self.to_world_space(Point2d(self.width/2, self.height / -2))
-        #return Point2d(self.x + self.width, self.y)
-
-    @property
-    def center_left (self):
-        """Return the center left point of this object in world space."""
-        return self.to_world_space(Point2d(self.width/-2, 0))
-        #return Point2d(self.x, self.y + self.height / 2)
-
-    @property
-    def center (self):
-        """Return the center point of this object in world space."""
-        return Point2d(self.x, self.y)
-        #return Point2d(self.x + self.width / 2, self.y + self.height / 2)
-
-    @property
-    def center_right (self):
-        """Return the center right point of this object in world space."""
-        return self.to_world_space(Point2d(self.width / 2, 0))
-        #return Point2d(self.x + self.width, self.y + self.height / 2)
-
-    @property
-    def top_left (self):
-        """Return the top left point of this object in world space."""
-        return self.to_world_space(Point2d(self.width / -2, self.height / 2))
-        #return Point2d(self.x, self.y + self.height)
-
-    @property
-    def top_center (self):
-        """Return the top center point of this object in world space."""
-        return self.to_world_space(Point2d(0, self.height / 2))
-        #return Point2d(self.x + self.width / 2, self.y + self.height)
-
-    @property
-    def top_right (self):
-        """Return the top right point of this object in world space."""
-        return self.to_world_space(Point2d(self.width / 2, self.height / 2))
-        #return Point2d(self.x + self.width, self.y + self.height)
-
-
-class EntitySnapshot:
-    def __init__ (self, time, x, y, rotation):
-        self.time = time
-        self.x = x
-        self.y = y
-        self.rotation = rotation
-        
-
-class Entity4dCollection:
-    """Four dimensional entity ;)
-    """
-    def __init__ (self, entity):
-        self.entity = entity
-        self.records = []
-
-    def __getitem__ (self, time):
-        return self.get_entity_at_time(time)
-
-    def __setitem__ (self, time, entity):
-        self.record(time, entity)
-
-    def record (self, time, entity):
-        self.records += [EntitySnapshot(float(time), entity.x, entity.y, entity.rotation)]
-
-    def get_entity_at_time (self, time, max_time_diff = 0.01, return_copy = False):
-        """Return an entity from the records given time.
-        If a record exists at this exact time, return that entity.
-        If a record exists within max_time_diff of this time, return that record
-        (always returns the closest record)
-        Return an interpolated result if time falls between at least two records.
-        Return an extrapolated result if time falls beyond the records.
-        Return None if insufficient records are present.
-        """
-        past_record = None
-        future_record = None
-        for record in self.records:
-            if record.time == time:
-                return self._build_entity(record)
-            if record.time > time:
-                if future_record is None:
-                    future_record = record
-                else:
-                    if record.time < future_record.time:
-                        future_record = record
-            elif record.time < time:
-                if past_record is None:
-                    past_record = record
-                else:
-                    if record.time > past_record.time:
-                        past_record = record
-        if past_record is not None and future_record is not None:
-            past_dt = time - past_record.time
-            fut_dt = future_record.time - time
-            if past_dt < fut_dt:
-                if past_dt < max_time_diff:
-                    return self._entity(past_record)
-            else:
-                if fut_dt < max_time_diff:
-                    return self._entity(future_record)
-            return self._entity(self._interpolate(past_record, future_record, time), return_copy)
-        
-        elif past_record is not None:
-            if time - past_record.time < max_time_diff:
-                return self._entity(past_record, return_copy)
-            return self._entity(self._extrapolate(past_record, time), return_copy)
-        
-        elif future_record is not None:
-            if future_record - time < max_time_diff:
-                return self._entity(future_record, return_copy)
-            return self._entity(self._extrapolate(future_record, time), return_copy)
-
-    def _interpolate (self, past_record, future_record, time):
-        delta_time = future_record.time - past_record.time
-        pblend = 1 - (time - past_record.time) / delta_time
-        fblend = 1 - (future_record.time - time) / delta_time
-        return EntitySnapshot(0,
-                    future_record.x * fblend + past_record.x * pblend,
-                    future_record.y * fblend + past_record.y * pblend,
-                    future_record.rotation * fblend + past_record.rotation * pblend)
-
-    def _extrapolate (self, record, time):
-        return record
-
-    def _entity (self, record, return_copy):
-        if return_copy:
-            return self._build_entity(record)
-        else:
-            return self._update_entity(record)
-        
-    def _update_entity (self, record):
-        self.entity.x = record.x
-        self.entity.y = record.y
-        self.entity.rotation = record.rotation
-        return self.entity
-       
-    def _build_entity (self, record):
-        entity = copy(self.entity)
-        entity.x = record.x
-        entity.y = record.y
-        entity.rotation = record.rotation
-        return entity
-
-#from utilities import Point2d
-#from pyglet import image
-#myEntity = Entity(image.load("../graphics/target.png"))
-#c = Entity4dCollection(myEntity)
-#c.record(0.0, myEntity)
-#myEntity.move(Point2d(3, 4))
-#c.record(10.0, myEntity)

tanks/utilities.py

-"""
-Game utility classes.
-
-Point2d provides a nice interface for working with x, y pairs of 2d points.
-Rect provides a similarly nice interface for working with rectangles (x, y, width, height), though
-this class should probably be avoided since the Entity class has this functionality built in...
-
-Note: 'Utility' is a bit of an understatement, since just about every class that I've written so far
-makes use of Point2d...
-
-Contents:
-
-class Point2d
-class Rect
-
-def limit (scalar, limit): 
-def optimal_rotation (rotation)
-"""
-
-import math
-
-def safe_atan (delta):
-    """Safe version of inverse tangent: return degrees(atan(delta.y / delta.x)).
-    Unlike atan, returns a value between -180 and 180, not just 0 and 180 degrees.
-    Expects Point2d (or equivalent) as the argument.
-    Example:
-        angle = safe_atan(point2 - point1)
-
-    """
-    if delta.y > 0:
-        if delta.x > 0:
-            return math.degrees(math.atan(delta.y / delta.x))
-        elif delta.x < 0:
-            return 180 + math.degrees(math.atan(delta.y / delta.x))
-        else:
-            return 90.0
-    elif delta.y < 0:
-        if delta.x > 0:
-            return math.degrees(math.atan(delta.y / delta.x))
-        elif delta.x < 0:
-            return -180 + math.degrees(math.atan(delta.y / delta.x))
-        if delta.x != 0:
-            return -90.0
-    else:
-        if delta.x > 0:
-            return 0.0
-        else:
-            return 180.0
-    
-
-def optimal_rotation (rotation):
-    """
-    TODO: write a better description for this docstring (and a better name?)
-
-    Examples:
-    optimal_rotation(112) = 112
-    optimal_rotation(225) = -135
-    optimal_rotation(-270) = 90
-    etc...
-    """
-    rotation %= 360
-    if rotation > 0:
-        rotation2 = (360 - rotation) * -1
-    else:
-        rotation2 = 360 - (rotation * -1)
-    if abs(rotation) < abs(rotation2):
-        return rotation
-    else:
-        return rotation2
-
-def limit (scalar, limit):
-    """
-    Use this instead of a modulus to limit values that may be positive or negative.
-
-    12 % 5 == 2
-    -12 % 5 == -3
-    limit(12, 5) == 2
-    limit(-12, 5) == -2
-    """
-    if scalar > 0:
-        return scalar % limit
-    else:
-        return (scalar * -1) % limit * -1
-
-class Point2d:
-    """
-    Point2d: Utility class used to represent 2d values.
-
-    parameters:
-        x (float)
-        y (float)
-    methods:
-        __repr__ () (string)
-        __add__ (other (Point2d, Rect, Entity, or 2 element tuple)) (Point2d)
-        __sub__ (other (Point2d, Rect, Entity, or 2 element tuple)) (Point2d)
-        __mul__ (scalar (float)) (Point2d)
-        __div__ (scalar (float)) (Point2d)
-        scale (x_scale (float), y_scale (float))
-    properties:
-        rect
-        tuple_
-    """
-    
-    def __init__ (self, x=0.0, y=0.0):
-        self.x = float(x)
-        self.y = float(y)
-
-    def __repr__ (self):
-        """Returns a representation of this object as a string."""
-        return "Point2d(%0.2f, %0.2f)"%(self.x, self.y)
-
-    def __add__ (self, other):
-        """Supports addition with Point2d, Rect, tuples, and lists. Invalid parameter will raise TypeError."""
-        try:
-            return Point2d(self.x + other.x, self.y + other.y)
-        except AttributeError:
-            try:
-                return Point2d(self.x + other[0], self.y + other[1])
-            except:
-                raise TypeError, "Invalid Point2d.add() parameter"
-
-    def __sub__ (self, other):
-        """Supports subtraction with Point2d, Rect, tuples, and lists. Invalid parameter will raise TypeError."""
-        try:
-            return Point2d(self.x - other.x, self.y - other.y)
-        except AttributeError:
-            try:
-                return Point2d(self.x - other[0], self.y - other[0])
-            except:
-                raise TypeError, "Invalid Point2d.sub() parameter"
-
-    def __mul__ (self, scalar):
-        """Multiply all values by a scalar. Invalid parameter will raise TypeError."""
-        try:
-            return Point2d(self.x * scalar, self.y * scalar)
-        except:
-            raise TypeError, "Invalid Point2d.mul() parameter"
-
-    def __div__ (self, scalar):
-        """Divide all values by a scalar. Invalid parameter will raise TypeError."""
-        try:
-            return Point2d(self.x / scalar, self.y / scalar)
-        except:
-            raise TypeError, "Invalid Point2d.div() parameter."
-
-    def scale (self, x_scale, y_scale):
-        """Scale x, y values independently."""
-        self.x *= xmul
-        self.y *= ymil
-
-    @property
-    def rect (self, width=0.0, height=0.0):
-        """Return this object as a Rect, with width and height as optional parameters."""
-        return Rect(self.x, self.y, width, height)
-
-    @property
-    def tuple_ (self):
-        """Return this object represented as a tuple."""
-        return (self.x, self.y)
-
-class Rect:
-    """
-    Utility class used to represent 2d rectangles.
-    
-    Rectangle is stored as (x, y, width, height)
-    x, y represent the bottom_left corner of the rectangle.
-
-    Note: This class probably isn't necessary for Tanks, so don't use it unless you really need it.
-    (Entities provide similar built in functionality)
-    """
-    
-    def __init__ (self, x=0.0, y=0.0, w=0.0, h=0.0):
-        self.x = float(x)
-        self.y = float(y)
-        self.width = w
-        self.height = h
-
-    def __repr__ (self):
-        return "Rect(%0.2f, %0.2f, width:%0.2f, height:%0.2f"%(self.x, self.y, self.width, self.height)
-
-    def __add__ (self, other):
-        try:
-            return Rect(self.x + other.x, self.y + other.y, self.width, self.height)
-        except:
-            try:
-                return Rect(self.x + other[0], self.y + other[0], self.width, self.height)
-            except:
-                raise TypeError, "Invalid Rect.add() parameter"
-
-    def __sub__ (self, other):
-        try:
-            return Rect(self.x - other.x, self.y - other.y, self.width, self.height)
-        except:
-            try:
-                return Rect(self.x - other[0], self.y - other[1], self.width, self.height)
-            except:
-                raise TypeError, "Invalid Rect.sub() parameter"
-
-    def contains_point (self, point):
-        """
-        Return true if the rectangle contains point.
-        
-        Simple collision detection: returns true if the specified point lies within this rectangle
-        The point is assumed to be a Point2d - if a Rect is used as a parameter, this will
-        just check the bottomLeft point (use <Rect>.topLeft, .topRight, .center, .bottomLeft, etc.,
-        to specify a different point).
-
-        To check if two rectangles overlap (given rect1 and rect2), use the following:
-        if rect1.Contains(rect2.topLeft) or rect1.Contains(rect2.topRight) or \
-        rect1.Contains(rect2.bottomLeft) or rect1.Contains(rect2.bottomRight):
-            overlap = True
-        else:
-            overlap = False
-
-        Note: since this method uses the > operator (and not >=), checking to see if a rectangle
-        contains its topLeft point will return false (since the values are the same): a point must be
-        *inside* the rect to register - not directly on the border or outside.
-        """
-        if self.x < point.x and self.x + self.width > point.x and self.y < point.y and self.y + self.height > point.y:
-            return True
-        return False
-
-    def scale (self, w=0.0, h=0.0):
-        """Multiply self.width, self.height by w, h. Accepts two scalars, a Point2d, or a list/tuple."""
-        try: #enables scaling by a Point2d
-            self.width *= w.x
-            self.height *= w.y
-        except:
-            try: #Enables scaling by a tuple
-                self.width *= w[0]
-                self.height *= w[1]
-            except:
-                self.width *= w
-                self.height *= h
-
-    def set_scale (self, w=0.0, h=0.0):
-        """Set self.width, self.height to w, h. Accepts two scalars, a Point2d, or a list/tuple."""
-        try: #enables use of Point2d as a parameter
-            self.width = w.x
-            self.height = w.y
-        except:
-            try: #enables use of tuple as a parameter
-                self.width = w[0]
-                self.height = w[1]
-            except:
-                self.width = w
-                self.height = h
-
-    @property
-    def tuple_ (self):
-        """Return a tuple representation of this rect. x, y correspond to the bottomLeft corner of the rectangle."""
-        return (self.x, self.y, self.width, self.height)
-
-    @property
-    def corners (self):
-        """Return the corners of this rectangle as a 4 element tuple: (left, bottom, right, top."""
-        return (self.x, self.y, self.x + self.width, self.y + self.height)
-
-    @property
-    def dimensions (self):
-        """The dimensions (width, height) of this rectangle as a Point2d"""
-        return Point2d(self.width, self.height)
-
-    @property
-    def bottom_left (self):
-        return Point2d(self.x, self.y)
-
-    @property
-    def bottom_center (self):
-        return Point2d(self.x + self.width / 2, self.y)
-
-    @property
-    def bottom_right (self):
-        return Point2d(self.x + self.width, self.y)
-
-    @property
-    def center_left (self):
-        return Point2d(self.x, self.y + self.height / 2)
-
-    @property
-    def center (self):
-        return Point2d(self.x + self.width / 2, self.y + self.height / 2)
-
-    @property
-    def center_right (self):
-        return Point2d(self.x + self.width, self.y + self.height / 2)
-
-    @property
-    def top_left (self):
-        return Point2d(self.x, self.y + self.height)
-
-    @property
-    def top_center (self):
-        return Point2d(self.x + self.width / 2, self.y + self.height)
-
-    @property
-    def top_right (self):
-        return Point2d(self.x + self.width, self.y + self.height)
-
-class BoolState:
-    """A boolean StateManager entry that is activated/deactivated when a condition is met."""
-    def __init__ (self, state, condition=None, on_enabled=None, on_disabled=None):
-        """
-        state/enabled: bool 
-        condition: lambda or function that determines when to toggle state.
-            should accept one parameter: data, whose attributes are user defined keyword
-            parameters from StateManager.update(), and return bool
-        on_enabled/on_enabled: lambda or function that is called when this is enabled.
-            should accept one parameter: name (this object's string name), and return string.
-        on_disabled/on_disabled: lambda or function that is called when this is disabled.
-            should accept one parameter: name (this object's string name), and return string.
-        """
-        self.enabled = state
-        self.condition = condition
-        if not on_enabled is None:
-            self.on_enabled = on_enabled
-        else:
-            self.on_enabled = lambda name: "%s enabled."%name
-        if not on_enabled is None:
-            self.on_disabled = on_disabled
-        else:
-            self.on_disabled = lambda name: "%s disabled."%name
-
-
-class ScalarState:
-    """A scalar StateManager entry that is modified when conditions are met."""
-    def __init__ (self, value, increment_value, increment_condition = None,
-                  decrement_condition = None, on_change = None):
-        """
-        value: float/int
-        increment_value: amound that value is modified by
-        increment_condition: lambda or function that returns true when value should be
-            incremented. Should accept one parameter: data, whose attributes are user
-            defined parameters from StateManager.update()
-        decrement_condition: lambda or function that returns true when value should be
-            decremented. Same as increment_condition.
-        on_change: lambda or function that returns a string to be printed. Should accept
-            two parameters: name and value.
-        """
-        self.value = value
-        self.increment_value = increment_value
-        self.increment_condition = increment_condition
-        self.decrement_condition = decrement_condition
-        if on_change is None:
-            self.on_change = lambda name, value: "Set %s to %0.2f"%(name, value)
-        else:
-            self.on_change = on_change
-                        
-
-class _EmptyObject:
-    pass
-
-class StateManager:
-    """
-    Use this to implement multiple togglable states that are switched when a
-    condition becomes true, and that may call actions when enabled or disabled.
-    Example use (what this was designed for): implement simple player interface
-    for switching stuff on/off in game when keys are pressed.
-    """
-    def __init__ (self):
-        self.states = {}
-
-    def update (self, **kwargs):
-        """
-        Takes a list of keyword arguments, and inserts these as attributes into
-        a (previously) empty object; this object (called data) is then passed to
-        every state's condition function/lambda.
-        """
-        data = _EmptyObject()
-        data.__dict__ = kwargs
-        for name, state in self.states.iteritems():
-            if isinstance(state, BoolState):
-                if state.condition is not None:
-                    if state.condition(data):
-                        if state.enabled:
-                            state.enabled = False
-                            if state.on_disabled is not None:
-                                print(state.on_disabled(name))
-                        else:
-                            state.enabled = True
-                            if state.on_enabled is not None:
-                                print(state.on_enabled(name))
-            elif isinstance(state, ScalarState):
-                if state.increment_condition is not None:
-                    if state.increment_condition(data):
-                        state.value += state.increment_value
-                        print(state.on_change(name, state.value))
-                if state.decrement_condition is not None:
-                    if state.decrement_condition(data):
-                        state.value -= state.increment_value
-                        print(state.on_change(name, state.value))
-
-    def __setitem__ (self, key, value):
-        if type(value) == bool:
-            if key in self.states:
-                self.states[key].enabled = value
-            else:
-                self.states[key] = BoolState(value)
-        elif type(value) == float or type(value) == int:
-            if key in self.states:
-                self.states[key].value = value
-            else:
-                self.states[key] = ScalarState(value)
-        elif isinstance(value, BoolState) or isinstance(value, ScalarState):
-            self.states[key] = value
-        else:
-            raise TypeError, "Only StateEntry objects can be added to a StateManager"
-
-    def __getitem__ (self, key):
-        return self.states[key]
-
-    def __delitem__ (self, key):
-        del self.states[key]
-
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.