Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/elements/elements.py
diff options
context:
space:
mode:
Diffstat (limited to 'elements/elements.py')
-rw-r--r--elements/elements.py307
1 files changed, 165 insertions, 142 deletions
diff --git a/elements/elements.py b/elements/elements.py
index 4033688..06d43cc 100644
--- a/elements/elements.py
+++ b/elements/elements.py
@@ -9,7 +9,7 @@ Home: http://elements.linuxuser.at
IRC: #elements on irc.freenode.org
Code: http://www.assembla.com/wiki/show/elements
- svn co http://svn2.assembla.com/svn/elements
+ svn co http://svn2.assembla.com/svn/elements
License: GPLv3 | See LICENSE for the full text
This program is free software: you can redistribute it and/or modify
@@ -23,9 +23,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
+along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-__version__= '0.11'
+__version__ = '0.11'
__contact__ = '<elements@linuxuser.at>'
# Load Box2D
@@ -34,8 +34,8 @@ try:
except:
print 'Could not load the pybox2d library (Box2D).'
print 'Please run "setup.py install" to install the dependencies.'
- print
- print 'Alternatively, recompile pybox2d for your system and python version.'
+ print
+ print 'Or recompile pybox2d for your system and python version.'
print "See http://code.google.com/p/pybox2d"
exit()
@@ -53,90 +53,97 @@ import callbacks
import camera
# Main Class
+
+
class Elements:
"""The class which handles all interaction with the box2d engine
"""
# Settings
- run_physics =True # Can pause the simulation
- element_count =0 # Element Count
- renderer =None # Drawing class (from drawing.py)
- input =INPUT_PIXELS # Default Input in Pixels! (can change to INPUT_METERS)
- line_width =0 # Line Width in Pixels (0 for fill)
- listener =None
-
- screen_offset = (0, 0) # Offset screen from world coordinate system (x, y) [meter5]
- screen_offset_pixel = (0, 0) # Offset screen from world coordinate system (x, y) [pixel]
-
+ run_physics = True # Can pause the simulation
+ element_count = 0 # Element Count
+ renderer = None # Drawing class (from drawing.py)
+ # Default Input in Pixels! (can change to INPUT_METERS)
+ input_unit = INPUT_PIXELS
+ line_width = 0 # Line Width in Pixels (0 for fill)
+ listener = None
+
+ # Offset screen from world coordinate system (x, y) [meter5]
+ screen_offset = (0, 0)
+ # Offset screen from world coordinate system (x, y) [pixel]
+ screen_offset_pixel = (0, 0)
+
# The internal coordination system is y+=up, x+=right
# But it's possible to change the input coords to something else,
# they will then be translated on input
- inputAxis_x_left = False # positive to the right by default
- inputAxis_y_down = True # positive to up by default
+ inputAxis_x_left = False # positive to the right by default
+ inputAxis_y_down = True # positive to up by default
mouseJoint = None
- def __init__(self, screen_size, gravity=(0.0,-9.0), ppm=100.0, renderer='pygame'):
+ def __init__(self, screen_size, gravity=(0.0, -9.0), ppm=100.0,
+ renderer='pygame'):
""" Init the world with boundaries and gravity, and init colors.
-
+
Parameters:
screen_size .. (w, h) -- screen size in pixels [int]
gravity ...... (x, y) in m/s^2 [float] default: (0.0, -9.0)
ppm .......... pixels per meter [float] default: 100.0
- renderer ..... which drawing method to use (str) default: 'pygame'
+ renderer ..... which drawing method to use (str) default:
+ 'pygame'
Return: class Elements()
"""
self.set_screenSize(screen_size)
self.set_drawingMethod(renderer)
-
+
# Create Subclasses
self.add = add_objects.Add(self)
self.callbacks = callbacks.CallbackHandler(self)
self.camera = camera.Camera(self)
-
+
# Set Boundaries
- self.worldAABB=box2d.b2AABB()
+ self.worldAABB = box2d.b2AABB()
self.worldAABB.lowerBound = (-100.0, -100.0)
self.worldAABB.upperBound = (100.0, 100.0)
-
+
# Gravity + Bodies will sleep on outside
self.gravity = gravity
self.doSleep = True
-
+
# Create the World
self.world = box2d.b2World(self.worldAABB, self.gravity, self.doSleep)
- # Init Colors
+ # Init Colors
self.init_colors()
-
+
# Set Pixels per Meter
self.ppm = ppm
- def set_inputUnit(self, input):
+ def set_inputUnit(self, input_unit):
""" Change the input unit to either meter or pixels
-
+
Parameters:
input ... INPUT_METERS or INPUT_PIXELS
-
+
Return: -
"""
- self.input = input
-
+ self.input_unit = input_unit
+
def set_inputAxisOrigin(self, left=True, top=False):
""" Change the origin of the input coordinate system axis
-
+
Parameters:
left ... True or False -- x = 0 is at the left?
top .... True or False -- y = 0 is at the top?
-
+
Return: -
- """
+ """
self.inputAxis_x_left = not left
self.inputAxis_y_down = top
def set_drawingMethod(self, m, *kw):
""" Set a drawing method (from drawing.py)
-
+
Parameters:
m .... 'pygame' or 'cairo'
*kw .. keywords to pass to the initializer of the drawing method
@@ -144,86 +151,89 @@ class Elements:
Return: True if ok, False if no method identifier m found
"""
try:
- self.renderer = getattr(drawing, "draw_%s" % m) (*kw)
+ self.renderer = getattr(drawing, "draw_%s" % m)(*kw)
return True
except AttributeError:
return False
-
+
def set_screenSize(self, size):
""" Set the current screen size
-
- Parameters:
+
+ Parameters:
size ... (int(width), int(height)) in pixels
-
+
Return: -
"""
self.display_width, self.display_height = size
def init_colors(self):
""" Init self.colors with a fix set of hex colors
-
- Return: -
+
+ Return: -
"""
self.fixed_color = None
self.cur_color = 0
self.colors = [
- "#737934", "#729a55", "#040404", "#1d4e29", "#ae5004", "#615c57",
- "#6795ce", "#203d61", "#8f932b"
+ "#737934", "#729a55", "#040404", "#1d4e29", "#ae5004", "#615c57",
+ "#6795ce", "#203d61", "#8f932b"
]
shuffle(self.colors)
def set_color(self, clr):
- """ Set a fixed color for all future Elements (until reset_color() is called)
-
- Parameters:
+ """ Set a fixed color for all future Elements (until reset_color()
+ is called)
+
+ Parameters:
clr ... Hex '#123123' or RGB ((r), (g), (b))
-
+
Return: -
"""
self.fixed_color = clr
-
+
def reset_color(self):
""" All Elements from now on will be drawn in random colors
-
- Return: -
+
+ Return: -
"""
self.fixed_color = None
def get_color(self):
- """ Get a color - either the fixed one or the next from self.colors
-
- Return: clr = ((R), (G), (B))
+ """ Get a color - either the fixed one or the next from self.colors
+
+ Return: clr = ((R), (G), (B))
"""
- if self.fixed_color != None:
+ if self.fixed_color is not None:
return self.fixed_color
-
- if self.cur_color == len(self.colors):
+
+ if self.cur_color == len(self.colors):
self.cur_color = 0
shuffle(self.colors)
-
+
clr = self.colors[self.cur_color]
if clr[0] == "#":
clr = tools.hex2rgb(clr)
-
+
self.cur_color += 1
return clr
-
+
def update(self, fps=50.0, vel_iterations=10, pos_iterations=8):
""" Update the physics, if not paused (self.run_physics)
-
+
Parameters:
fps ............. fps with which the physics engine shall work
- vel_iterations .. velocity substeps per step for smoother simulation
- pos_iterations .. position substeps per step for smoother simulation
-
+ vel_iterations .. velocity substeps per step for smoother
+ simulation
+ pos_iterations .. position substeps per step for smoother
+ simulation
+
Return: -
"""
if self.run_physics:
self.world.Step(1.0 / fps, vel_iterations, pos_iterations)
def translate_coord(self, point):
- """ Flips the coordinates in another coordinate system orientation, if necessary
- (screen <> world coordinate system)
+ """ Flips the coordinates in another coordinate system orientation,
+ if necessary (screen <> world coordinate system)
"""
x, y = point
@@ -232,46 +242,49 @@ class Elements:
if self.inputAxis_y_down:
y = self.display_height - y
-
+
return (x, y)
-
+
def translate_coords(self, pointlist):
- """ Flips the coordinates in another coordinate system orientation, if necessary
- (screen <> world coordinate system)
- """
- p_out = []
+ """Flips the coordinates in another coordinate system orientation, if
+ necessary (screen <> world coordinate system)
+ """
+ p_out = []
for p in pointlist:
p_out.append(self.translate_coord(p))
return p_out
def to_world(self, pos):
- """ Transfers a coordinate from the screen to the world coordinate system (pixels)
+ """ Transfers a coordinate from the screen to the world
+ coordinate system (pixels)
+
- Change to the right axis orientation
- Include the offset: screen -- world coordinate system
- - Include the scale factor (Screen coordinate system might have a scale factor)
+ - Include the scale factor (Screen coordinate system might have
+ a scale factor)
"""
dx, dy = self.screen_offset_pixel
-
+
x = pos[0] / self.camera.scale_factor
y = pos[1] / self.camera.scale_factor
-
+
x, y = self.translate_coord((round(x), round(y)))
- return (x+dx, y+dy)
-
+ return(x + dx, y + dy)
+
def to_screen(self, pos):
- """ Transfers a coordinate from the world to the screen coordinate system (pixels)
- and by the screen offset
+ """Transfers a coordinate from the world to the screen coordinate
+ system (pixels) and by the screen offset
"""
dx, dy = self.screen_offset_pixel
x = pos[0] - dx
y = pos[1] - dy
-
+
sx, sy = self.translate_coord((x, y))
return (sx * self.camera.scale_factor, sy * self.camera.scale_factor)
-
+
def meter_to_screen(self, i):
return i * self.ppm * self.camera.scale_factor
-
+
def get_bodies_at_pos(self, search_point, include_static=False, area=0.01):
""" Check if given point (screen coordinates) is inside any body.
If yes, return all found bodies, if not found return False
@@ -280,11 +293,11 @@ class Elements:
sx /= self.ppm
sy /= self.ppm
- f = area/self.camera.scale_factor
+ f = area / self.camera.scale_factor
- AABB=box2d.b2AABB()
- AABB.lowerBound = (sx-f, sy-f)
- AABB.upperBound = (sx+f, sy+f)
+ AABB = box2d.b2AABB()
+ AABB.lowerBound = (sx - f, sy - f)
+ AABB.upperBound = (sx + f, sy + f)
amount, shapes = self.world.Query(AABB, 2)
@@ -297,101 +310,110 @@ class Elements:
if not include_static:
if body.IsStatic() or body.GetMass() == 0.0:
continue
-
+
if s.TestPoint(body.GetXForm(), (sx, sy)):
bodylist.append(body)
return bodylist
-
+
def draw(self):
""" If a drawing method is specified, this function passes the objects
to the module in pixels.
-
+
Return: True if the objects were successfully drawn
False if the renderer was not set or another error occurred
"""
self.callbacks.start(CALLBACK_DRAWING_START)
-
- # No need to run through the loop if there's no way to draw
- if not self.renderer:
+
+ # No need to run through the loop if there's no way to draw
+ if not self.renderer:
return False
if self.camera.track_body:
# Get Body Center
- p1 = self.camera.track_body.GetWorldCenter()
-
+ p1 = self.camera.track_body.GetWorldCenter()
+
# Center the Camera There, False = Don't stop the tracking
- self.camera.center(self.to_screen((p1.x*self.ppm, p1.y*self.ppm)), stopTrack=False)
-
+ self.camera.center(self.to_screen((p1.x * self.ppm,
+ p1.y * self.ppm)),
+ stopTrack=False)
+
# Walk through all known elements
self.renderer.start_drawing()
-
+
for body in self.world.bodyList:
xform = body.GetXForm()
shape = body.GetShapeList()
angle = body.GetAngle()
-
+
if shape:
userdata = body.GetUserData()
- clr = userdata['color']
-
- for shape in body.shapeList:
+ if 'color' in userdata:
+ clr = userdata['color']
+ else:
+ clr = self.colors[0]
+
+ for shape in body.shapeList:
type = shape.GetType()
-
+
if type == box2d.e_circleShape:
position = box2d.b2Mul(xform, shape.GetLocalPosition())
-
- pos = self.to_screen((position.x*self.ppm, position.y*self.ppm))
- self.renderer.draw_circle(clr, pos, self.meter_to_screen(shape.radius), angle)
+
+ pos = self.to_screen((position.x * self.ppm,
+ position.y * self.ppm))
+
+ self.renderer.draw_circle(
+ clr, pos, self.meter_to_screen(shape.radius), angle)
elif type == box2d.e_polygonShape:
points = []
for v in shape.vertices:
pt = box2d.b2Mul(xform, v)
- x, y = self.to_screen((pt.x*self.ppm, pt.y*self.ppm))
+ x, y = self.to_screen((pt.x * self.ppm,
+ pt.y * self.ppm))
points.append([x, y])
self.renderer.draw_polygon(clr, points)
-
+
else:
- print " unknown shape type:%d" % shape.GetType()
-
+ print "unknown shape type:%d" % shape.GetType()
for joint in self.world.jointList:
p2 = joint.GetAnchor1()
- p2 = self.to_screen((p2.x*self.ppm, p2.y*self.ppm))
-
+ p2 = self.to_screen((p2.x * self.ppm, p2.y * self.ppm))
+
p1 = joint.GetAnchor2()
- p1 = self.to_screen((p1.x*self.ppm, p1.y*self.ppm))
-
+ p1 = self.to_screen((p1.x * self.ppm, p1.y * self.ppm))
+
if p1 == p2:
- self.renderer.draw_circle((255,255,255), p1, 2, 0)
+ self.renderer.draw_circle((255, 255, 255), p1, 2, 0)
else:
- self.renderer.draw_lines((0,0,0), False, [p1, p2], 3)
+ self.renderer.draw_lines((0, 0, 0), False, [p1, p2], 3)
self.callbacks.start(CALLBACK_DRAWING_END)
self.renderer.after_drawing()
-
- return True
+ return True
def mouse_move(self, pos):
pos = self.to_world(pos)
x, y = pos
x /= self.ppm
y /= self.ppm
-
+
if self.mouseJoint:
- self.mouseJoint.SetTarget((x,y))
+ self.mouseJoint.SetTarget((x, y))
def pickle_save(self, fn, additional_vars={}):
import cPickle as pickle
self.add.remove_mouseJoint()
-
+
if not additional_vars and hasattr(self, '_pickle_vars'):
- additional_vars=dict((var, getattr(self, var)) for var in self._pickle_vars)
+ additional_vars = dict((var, getattr(self, var))
+ for var in self._pickle_vars)
- save_values = [self.world, box2d.pickle_fix(self.world, additional_vars, 'save')]
+ save_values = [self.world, box2d.pickle_fix(self.world,
+ additional_vars, 'save')]
try:
pickle.dump(save_values, open(fn, 'wb'))
@@ -411,13 +433,13 @@ class Elements:
try:
world, variables = pickle.load(open(fn, 'rb'))
world = world._pickle_finalize()
- variables = box2d.pickle_fix(world, variables, 'load')
+ variables = box2d.pickle_fix(world, variables, 'load')
except Exception, s:
print 'Error while loading world: ', s
return
-
+
self.world = world
-
+
if set_vars:
# reset the additional saved variables:
for var, value in variables.items():
@@ -461,7 +483,8 @@ class Elements:
if shapename == "b2CircleShape":
modelshape['type'] = 'circle'
modelshape['radius'] = shape.radius
- modelshape['localPosition'] = shape.localPosition.tuple()
+ modelshape['localPosition'] = \
+ shape.localPosition.tuple()
if shapename == "b2PolygonShape":
modelshape['type'] = 'polygon'
modelshape['vertices'] = shape.vertices
@@ -528,19 +551,19 @@ class Elements:
def json_load(self, path, serialized=False):
import json
- self.world.GetGroundBody().userData = {"saveid" : 0}
+ self.world.GetGroundBody().userData = {"saveid": 0}
f = open(path, 'r')
worldmodel = json.loads(f.read())
f.close()
- #clean world
+ # clean world
for joint in self.world.GetJointList():
self.world.DestroyJoint(joint)
for body in self.world.GetBodyList():
if body != self.world.GetGroundBody():
self.world.DestroyBody(body)
- #load bodys
+ # load bodies
for body in worldmodel['bodylist']:
bodyDef = box2d.b2BodyDef()
bodyDef.position = body['position']
@@ -550,7 +573,7 @@ class Elements:
#_logger.debug(newBody)
newBody.angularVelocity = body['angularVelocity']
newBody.linearVelocity = body['linearVelocity']
- if body.has_key('shapes'):
+ if 'shapes' in body:
for shape in body['shapes']:
if shape['type'] == 'polygon':
polyDef = box2d.b2PolygonDef()
@@ -565,7 +588,7 @@ class Elements:
circleDef.density = shape['density']
circleDef.restitution = shape['restitution']
circleDef.friction = shape['friction']
- circleDef.localPosition = shape['localPosition']
+ circleDef.localPosition = shape['localPosition']
newBody.CreateShape(circleDef)
newBody.SetMassFromShapes()
@@ -577,7 +600,7 @@ class Elements:
body2 = self.getBodyWithSaveId(joint['body2'])
anch2 = joint['anchor2']
jointDef.collideConnected = joint['collideConnected']
- jointDef.Initialize(body1,body2,anch1,anch2)
+ jointDef.Initialize(body1, body2, anch1, anch2)
jointDef.SetUserData(joint['userData'])
self.world.CreateJoint(jointDef)
if joint['type'] == 'revolute':
@@ -585,7 +608,7 @@ class Elements:
body1 = self.getBodyWithSaveId(joint['body1'])
body2 = self.getBodyWithSaveId(joint['body2'])
anchor = joint['anchor']
- jointDef.Initialize(body1,body2,anchor)
+ jointDef.Initialize(body1, body2, anchor)
jointDef.SetUserData(joint['userData'])
jointDef.enableMotor = joint['enableMotor']
jointDef.motorSpeed = joint['motorSpeed']
@@ -594,17 +617,17 @@ class Elements:
self.additional_vars = {}
addvars = {}
- for (k,v) in worldmodel['additional_vars'].items():
+ for (k, v) in worldmodel['additional_vars'].items():
addvars[k] = v
if serialized and 'trackinfo' in addvars:
trackinfo = addvars['trackinfo']
for key, info in trackinfo.iteritems():
if not info[3]:
- addvars['trackinfo'][key][0] = \
- self.getBodyWithSaveId(info[0])
- addvars['trackinfo'][key][1] = \
- self.getBodyWithSaveId(info[1])
+ addvars['trackinfo'][key][0] = \
+ self.getBodyWithSaveId(info[0])
+ addvars['trackinfo'][key][1] = \
+ self.getBodyWithSaveId(info[1])
else:
addvars['trackinfo'][key][0] = None
addvars['trackinfo'][key][1] = None
@@ -612,9 +635,9 @@ class Elements:
self.additional_vars = addvars
for body in self.world.GetBodyList():
- del body.userData['saveid'] #remove temporary data
+ del body.userData['saveid'] # remove temporary data
- def getBodyWithSaveId(self,saveid):
+ def getBodyWithSaveId(self, saveid):
for body in self.world.GetBodyList():
if body.userData['saveid'] == saveid:
return body