#!/usr/bin/env python # -*- coding: utf-8 -*- # # C++ version Copyright (c) 2006-2007 Erin Catto http://www.box2d.org # Python version by Ken Lauer / sirkne at gmail dot 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. from .framework import (Framework, Keys, main) from Box2D import (b2CircleShape, b2EdgeShape, b2FixtureDef, b2PolygonShape, b2Vec2, b2_pi) # Original inspired by a contribution by roman_m # Dimensions scooped from APE (http://www.cove.org/ape/index.htm) class TheoJansen (Framework): name = "Theo Jansen" description = "Keys: left = a, brake = s, right = d, toggle motor = m" motorSpeed = 2 motorOn = True offset = (0, 8) def __init__(self): super(TheoJansen, self).__init__() # ball_count = 40 pivot = b2Vec2(0, 0.8) # The ground ground = self.world.CreateStaticBody( shapes=[ b2EdgeShape(vertices=[(-50, 0), (50, 0)]), b2EdgeShape(vertices=[(-50, 0), (-50, 10)]), b2EdgeShape(vertices=[(50, 0), (50, 10)]), ] ) box = b2FixtureDef( shape=b2PolygonShape(box=(0.5, 0.5)), density=1, friction=0.3) circle = b2FixtureDef( shape=b2CircleShape(radius=0.25), density=1) # Create the balls on the ground for i in range(ball_count): self.world.CreateDynamicBody( fixtures=circle, position=(-40 + 2.0 * i, 0.5), ) # The chassis chassis_fixture = b2FixtureDef( shape=b2PolygonShape(box=(2.5, 1)), density=1, friction=0.3, groupIndex=-1) self.chassis = self.world.CreateDynamicBody( fixtures=chassis_fixture, position=pivot + self.offset) # Chassis wheel wheel_fixture = b2FixtureDef( shape=b2CircleShape(radius=1.6), density=1, friction=0.3, groupIndex=-1) self.wheel = self.world.CreateDynamicBody( fixtures=wheel_fixture, position=pivot + self.offset) # Add a joint between the chassis wheel and the chassis itself self.motorJoint = self.world.CreateRevoluteJoint( bodyA=self.wheel, bodyB=self.chassis, anchor=pivot + self.offset, collideConnected=False, motorSpeed=self.motorSpeed, maxMotorTorque=400, enableMotor=self.motorOn) wheelAnchor = pivot + (0, -0.8) self.CreateLeg(-1, wheelAnchor) self.CreateLeg(1, wheelAnchor) self.wheel.transform = (self.wheel.position, 120.0 * b2_pi / 180) self.CreateLeg(-1, wheelAnchor) self.CreateLeg(1, wheelAnchor) self.wheel.transform = (self.wheel.position, -120.0 * b2_pi / 180) self.CreateLeg(-1, wheelAnchor) self.CreateLeg(1, wheelAnchor) def CreateLeg(self, s, wheelAnchor): p1, p2 = b2Vec2(5.4 * s, -6.1), b2Vec2(7.2 * s, -1.2) p3, p4 = b2Vec2(4.3 * s, -1.9), b2Vec2(3.1 * s, 0.8) p5, p6 = b2Vec2(6.0 * s, 1.5), b2Vec2(2.5 * s, 3.7) # Use a simple system to create mirrored vertices if s > 0: poly1 = b2PolygonShape(vertices=(p1, p2, p3)) poly2 = b2PolygonShape(vertices=((0, 0), p5 - p4, p6 - p4)) else: poly1 = b2PolygonShape(vertices=(p1, p3, p2)) poly2 = b2PolygonShape(vertices=((0, 0), p6 - p4, p5 - p4)) body1 = self.world.CreateDynamicBody( position=self.offset, angularDamping=10, fixtures=b2FixtureDef( shape=poly1, groupIndex=-1, density=1), ) body2 = self.world.CreateDynamicBody( position=p4 + self.offset, angularDamping=10, fixtures=b2FixtureDef( shape=poly2, groupIndex=-1, density=1), ) # Using a soft distance constraint can reduce some jitter. # It also makes the structure seem a bit more fluid by # acting like a suspension system. # Now, join all of the bodies together with distance joints, # and one single revolute joint on the chassis self.world.CreateDistanceJoint( dampingRatio=0.5, frequencyHz=10, bodyA=body1, bodyB=body2, anchorA=p2 + self.offset, anchorB=p5 + self.offset, ) self.world.CreateDistanceJoint( dampingRatio=0.5, frequencyHz=10, bodyA=body1, bodyB=body2, anchorA=p3 + self.offset, anchorB=p4 + self.offset, ) self.world.CreateDistanceJoint( dampingRatio=0.5, frequencyHz=10, bodyA=body1, bodyB=self.wheel, anchorA=p3 + self.offset, anchorB=wheelAnchor + self.offset, ) self.world.CreateDistanceJoint( dampingRatio=0.5, frequencyHz=10, bodyA=body2, bodyB=self.wheel, anchorA=p6 + self.offset, anchorB=wheelAnchor + self.offset, ) self.world.CreateRevoluteJoint( bodyA=body2, bodyB=self.chassis, anchor=p4 + self.offset, ) def Keyboard(self, key): if key == Keys.K_a: self.motorJoint.motorSpeed = -self.motorSpeed elif key == Keys.K_d: self.motorJoint.motorSpeed = self.motorSpeed elif key == Keys.K_s: self.motorJoint.motorSpeed = 0 elif key == Keys.K_m: self.motorJoint.motorEnabled = not self.motorJoint.motorEnabled if __name__ == "__main__": main(TheoJansen)