File: demos.py

package info (click to toggle)
python-box2d 2.0.2%2Bsvn20100109.244-1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd, squeeze, wheezy
  • size: 2,864 kB
  • ctags: 3,280
  • sloc: cpp: 11,679; python: 10,103; xml: 477; makefile: 85; sh: 8
file content (233 lines) | stat: -rw-r--r-- 8,249 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#!/usr/bin/python
#
# C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
# Python version Copyright (c) 2008 kne / sirkne at gmail dot com
# 
# Implemented using the pybox2d SWIG interface for Box2D (pybox2d.googlecode.com)
# 
# This software is provided 'as-is', without any express or implied
# warranty.  In no event will the authors be held liable for any damages
# arising from the use of this software.
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.

import os
import pygame
import Box2D as box2d
from pygame.locals import *
from settings import fwSettings
from pgu import gui
from test_main import fwDebugDraw

from distutils import sysconfig

global width, height
width, height = 640, 480

def main():
    # Initialize pygame
    screen = pygame.display.set_mode((width,height))

    caption= "Python Box2D Testbed Demos"
    pygame.display.set_caption(caption)

    # Initialize the GUI
    theme = gui.Theme("default")
    app = gui.Desktop(theme=theme)

    app.connect(gui.QUIT,app.quit,None)

    main = gui.Container(width=width, height=height)

    # Label at the top left
    main.add(gui.Label("Box2D Testbed Demos", cls="h1"), 20, 20)

    # The dimensions of the list of the demos
    list_size= (width / 2, height / 2)
    list_pos = (width/2 - list_size[0]/2, height/2 - list_size[1]/2)

    # Create the actual widget
    demolist = gui.List(width=list_size[0], height=list_size[1])
    main.add(demolist, list_pos[0], list_pos[1])

    # Add all the demos found in the directory to the list
    add_demos(demolist)

    
    buttonw = (list_size[0]/2-20)        # width of the buttons
    bottom = list_pos[1]+list_size[1]+20 # the y-location of the bottom of the list

    # Create a Run button, calling run_demo on click
    b = gui.Button("Run", width=buttonw)
    main.add(b, list_pos[0], bottom)
    b.connect(gui.CLICK, run_demo, demolist)

    # Create a Quit button
    b = gui.Button("Quit", width=buttonw)
    main.add(b, list_pos[0]+buttonw+30, bottom)
    b.connect(gui.CLICK, lambda x:pygame.event.post(pygame.event.Event(pygame.QUIT)), None)

    # box2d initialization
    z=10 #scale (10 pixels/physics unit)

    # Since we're taking the debug draw implementation from the testbed, it requires a bit
    # of ugliness to set it up properly.
    renderer = fwDebugDraw()
    renderer.surface = screen
    renderer.viewZoom=z
    renderer.viewCenter=box2d.b2Vec2(0,0)
    renderer.width, renderer.height = width, height
    renderer.viewOffset = renderer.viewCenter - box2d.b2Vec2(width, height)/2
    renderer.SetFlags(box2d.b2DebugDraw.e_shapeBit) # we only want shapes to be drawn
    renderer.DrawSolidPolygon = lambda a,b,c: 0 # make it not draw the polygons!
    renderer.DrawPolygon = lambda a,b,c: 0      #

    # Create the world
    worldAABB=box2d.b2AABB()
    worldAABB.lowerBound = (-100.0, -100.0)
    worldAABB.upperBound = ( 100.0, 100.0)
    gravity = (0.0, -10.0)

    world = box2d.b2World(worldAABB, gravity, True)
    world.SetDebugDraw(renderer)

    # Create the ground
    bd = box2d.b2BodyDef()
    bd.position = (0.0, 0.0)
    ground = world.CreateBody(bd)
    
    # The borders of the screen
    sd = box2d.b2PolygonDef()
    sd.SetAsBox(1, height/z, (-width/(2*z)-1, 0), 0)
    ground.CreateShape(sd)
    sd.SetAsBox(1, height/z, (width/(2*z)+1, 0), 0)
    ground.CreateShape(sd)
    sd.SetAsBox(width/z, 1, (0,-height/(2*z)-1), 0)
    ground.CreateShape(sd)
    sd.SetAsBox(width/z, 1, (0,height/(2*z)+1), 0)
    ground.CreateShape(sd)

    # The shape for the file list
    sd.SetAsBox(list_size[0]/(2*z), list_size[1]/(2*z))
    ground.CreateShape(sd)

    # Create a few balls to bounce around the screen
    for i in range(10):
        bd = box2d.b2BodyDef()
        bd.allowSleep = True
        bd.position = (box2d.b2Random(-width/(2*z), width/(2*z)), box2d.b2Random(-height/(2*z), height/(2*z)))
        bd.isBullet = True
        bomb = world.CreateBody(bd)
        bomb.SetLinearVelocity(-5.0 * bd.position)

        sd = box2d.b2CircleDef()
        sd.radius = 1
        sd.density = 1.0
        sd.restitution = 0.7
        bomb.CreateShape(sd)
        
        bomb.SetMassFromShapes()

    app.init(main)
    main_loop(world, screen, demolist, app)

def get_shapes(world):
    for body in world.bodyList:
        shape = body.GetShapeList()
        while shape:
            yield (body, shape.getAsType())
            shape=shape.GetNext()

def update_shapes(world):
    # Check to see if any objects are sleeping or coming to a stop. 
    # Then give them a little push.
    for body in world.bodyList:
        v = body.GetLinearVelocity()
        if body.IsSleeping() or v.LengthSquared() < 0.2:
            i = body.GetWorldVector((box2d.b2Random(-200,200), box2d.b2Random(-200,200)))
            p = body.GetWorldPoint((0.0, 0.0))
            body.ApplyImpulse(i, p)
       
def main_loop(world, screen, demolist, app):
    # Create a surface to draw the GUI onto
    app_surface = pygame.Surface((width,height), SWSURFACE)
    hz = 60.0
    clock = pygame.time.Clock()
    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
                return
            elif event.type == KEYDOWN:
                if event.key == K_RETURN:
                    run_demo(demolist)
            elif event.type == MOUSEBUTTONDOWN:
                if event.button ==3:
                    run_demo(demolist)
                elif event.button ==4:
                    demolist.set_vertical_scroll(demolist.vscrollbar.value-100)
                elif event.button ==5:
                    demolist.set_vertical_scroll(demolist.vscrollbar.value+100)

            app.event(event)

        # Tell the GUI to update itself, then blit it to the screen
        app.update(app_surface) # pygame 1.8.1/pgu problem? 1.8.0 works fine
        screen.blit(app_surface, (0,0))

        # Wake up non/slow-moving shapes
        update_shapes(world)

        # Step the world 
        # (calls the debugdraw functions, so this is where the balls are drawn)
        world.Step(1/hz, 10, 8)

        clock.tick(hz)        
        #fps = clock.get_fps()
        pygame.display.flip()

def add_demos(demolist):
    # I don't feel like maintaining a list of demos.
    # So just glob to see what test_*.py files are in the current
    # directory and add them to the demo list.
    import glob

    ignore_list=("main")

    for f in glob.glob("test_*.py"):
        name = f[5:-3]
        if name.lower() in ignore_list:
            continue
        demolist.add(name,value=f)

def run_demo(demolist):
    # Run the currently selected demo (the widget itself is passed as an argument)
    if demolist.value == None: return

    print "Running: ", demolist.value
    from sys import executable as python_interpreter
    from platform import system as sys_platform

    if sys_platform() == "Windows":
        # Just in case we're in some directory with a space in it, use quotes
        # around the path.
        cmd = '"%s" -OO %s' % (python_interpreter, demolist.value)
    else:
        cmd = "%s -OO %s" % (python_interpreter, demolist.value)

    print "-> %s" % cmd

    ret = os.system(cmd)

    if ret == 10 or ret/256 == 10: # user hit reload (somehow the retval on linux is *256)
        run_demo(demolist) 

if __name__=="__main__":
    main()