def __init__(self, filename, view): Model.__init__(self, filename, view) TriangleMesh.__init__(self, filename) # Create rigid body tvia = TriangleIndexVertexArray() tvia.addIndexedMesh(self.mesh) shape = BvhTriangleMeshShape(tvia) shape.buildOptimizedBvh() transform = Transform() transform.setIdentity() transform.setOrigin(bVector3(0, 0, 0)) motion = DefaultMotionState() motion.setWorldTransform(transform) self.body = RigidBody.fromConstructionInfo(motion, # MotionState motion shape, # CollisionShape shape 0.0, # btScalar mass bVector3(0, 0, 0), # Vector3 inertia transform, # Transform worldTransform 0.0, # btScalar linearDamping 0.0, # btScalar angularDamping 0.75, # btScalar friction 0.95, # btScalar restitution 0.0, # btScalar linearSleepingThreshold 0.0) # btScalar angularSleepingThreshold self.motion = motion self.body.setContactProcessingThreshold(0)
def internal_tick_callback(self, timeStep): if self._cue_ball_rest(): disp = self.world.getDispatcher() n = disp.getNumManifolds() for i in xrange(n): cm = disp.getManifoldByIndexInternal(i) contacts = cm.getNumContacts() for c in xrange(contacts): obA = cm.getBody0().getUserPointer() obB = cm.getBody1().getUserPointer() if obA == 'Cue' and obB == 'Cue Ball' \ or obA == 'Cue Ball' and obB == 'Cue': p = cm.getContactPoint(c) if p.getDistance() < 0.0: # test for penetration # The cue's strike force is calculated from actual # linear velocity applied to the cues orientation vector b = self.cue.body.getLinearVelocity() v = eVector3(b.x, b.y, b.z) d = self.cue.direction if hasattr(self.cue, 'direction') \ else self.view.dir # get force impuls = v.magnitude() * SCALE_FACTOR * 25. force = bVector3(d.x * impuls, d.y * impuls, 0.0) # span offset to [0..1] offset = eVector3(self.cue.dx * 4., 0., self.cue.dy * 4.) # calculate offset from cue's position [convert from eye into object space] # TODO: (rewrite this in compact form of vector vs. matrix multiplication) moffset = self.view.orient.inverse() * Matrix4.new_translate(*offset) offset = eVector3(moffset.d, moffset.h, moffset.l) cue = self.ball['cue'] cue.body.clearForces() cue.body.applyGravity() cue.body.applyForce(force, bVector3(offset.x, offset.y, offset.z)) # Restore cue self._reset_cue() def ball_cant_fly(ball): # check for flying pos = ball.motion.getWorldTransform().getOrigin() if pos.z > ball.radius: ball.body.applyCentralForce(bVector3(0, 0, -15 * SCALE_FACTOR)) # check for ball speed v = ball.body.getLinearVelocity() vel = eVector3(v.x, v.y, v.z) if vel.magnitude_squared() > PoolWindow.BALL_MAX_SPEED: ball.body.setLinearVelocity(v * 0.9) for ball in self.ball.values(): ball_cant_fly(ball)
def __init__(self, filename, view, mass, position=eVector3()): super(CueBall, self).__init__(filename, view) self.radius = self.model.dimension.z / 2.0 self.mass = mass # Update z pos from radius position.z = self.radius # Init Transform transform = Transform() self.position = position self.do_transformation_matrix() self.mnumpy = array(self.m, 'f') transform.setFromOpenGLMatrix(self.mnumpy) # The Rigid Body mass = self.mass * SCALE_FACTOR shape = SphereShape(self.radius) i = shape.getLocalInertia(mass) * 0.65 self.motion = DefaultMotionState() self.motion.setWorldTransform(transform) self.body = RigidBody.fromConstructionInfo(self.motion, # MotionState motion shape, # CollisionShape shape mass, # btScalar mass bVector3(i.x, i.y, i.z), # Vector3 inertia transform, # Transform worldTransform 0.2, # btScalar linearDamping 0.65, # btScalar angularDamping 0.25, # btScalar friction 0.7, # btScalar restitution 1.5, # btScalar linearSleepingThreshold 1.5) # btScalar angularSleepingThreshold self.body.setContactProcessingThreshold(0) self.body.setCcdMotionThreshold(0) self.body.setHitFraction(0.1 * SCALE_FACTOR)
def ball_cant_fly(ball): # check for flying pos = ball.motion.getWorldTransform().getOrigin() if pos.z > ball.radius: ball.body.applyCentralForce(bVector3(0, 0, -15 * SCALE_FACTOR)) # check for ball speed v = ball.body.getLinearVelocity() vel = eVector3(v.x, v.y, v.z) if vel.magnitude_squared() > PoolWindow.BALL_MAX_SPEED: ball.body.setLinearVelocity(v * 0.9)
def __init__(self, filename, view, cball_radius): super(CueStick, self).__init__(filename, view) self.half = self.model.dimension / 2.0 self.tip_radius = self.half.x self.pivot = eVector3(0, 0, self.half.z + cball_radius) self.org_pivot = eVector3(*self.pivot) shape = CapsuleShapeZ(self.tip_radius, self.model.dimension.z - self.tip_radius * 2) #shape = CylinderShapeZ(bVector3(*self.half)) transform = Transform() transform.setIdentity() self.motion = CSMotionState() self.motion.cue = self self.delta = 0. self.dx = 0. self.dy = 0. self.motion.setWorldTransform(transform) self.body = RigidBody.fromConstructionInfo(self.motion, # MotionState motion shape, # CollisionShape shape 0.0, # btScalar mass bVector3(0, 0, 0), # Vector3 inertia transform, # Transform worldTransform 0.0, # btScalar linearDamping 0.0, # btScalar angularDamping 0.0, # btScalar friction 0.71, # btScalar restitution 0.0, # btScalar linearSleepingThreshold 0.0) # btScalar angularSleepingThreshold self.body.setContactProcessingThreshold(0) self.body.setCcdMotionThreshold(0) self.body.setHitFraction(0.1 * SCALE_FACTOR) self.body.setGravity(bVector3(0, 0, 0)) # Make it kinematic body with collision contacts generation but no response impulses flags = self.body.getCollisionFlags() | CueStick.CF_KINEMATIC_OBJECT | CueStick.CF_NO_CONTACT_RESPONSE self.body.setCollisionFlags(flags) self.body.setActivationState(DISABLE_DEACTIVATION)
def __init__(self, *args, **kwargs): super(PoolWindow, self).__init__(*args, **kwargs) self.set_size(1680, 1000) #self.set_fullscreen() self.keys = key.KeyStateHandler() self.push_handlers(self.keys) # Setup GL self.set_vsync(True) glClearColor(.15, .15, .15, 1) glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) glShadeModel(GL_SMOOTH) self.lpos1 = (0, 0.5 * SCALE_FACTOR, 1 * SCALE_FACTOR, 0) self.lpos2 = (0, -0.5 * SCALE_FACTOR, 1 * SCALE_FACTOR, 0) glLightfv(GL_LIGHT0, GL_POSITION, vec(*self.lpos1)) glLightfv(GL_LIGHT1, GL_POSITION, vec(*self.lpos2)) glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE) glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) glEnable(GL_LIGHT1) # Scroll zoom self.wheel_step = PoolWindow.ZOOM_SCROLL_STEP # Setup view self.view = View(eye=(0, -3 * SCALE_FACTOR, .75 * SCALE_FACTOR), center=(0, 0, -SCALE_FACTOR)) self.view.set_distance(SCALE_FACTOR) # The scene self.table = Table('obj/table.obj', self.view) self.rails = Rails('obj/rails.obj', self.view) self.ball = {} self.ball['cue'] = CueBall('obj/ball.obj', self.view, .260) self.ball['red'] = CueBall('obj/red.obj', self.view, .260, eVector3(0, 0.5 * SCALE_FACTOR, 0)) self.ball['yellow'] = CueBall('obj/yellow.obj', self.view, .260, eVector3(0, -0.5 * SCALE_FACTOR, 0)) self.cue = CueStick('obj/cue.obj', self.view, self.ball['cue'].radius) self.table.body.setUserPointer("Table") self.rails.body.setUserPointer("Rails") self.cue.body.setUserPointer("Cue") self.ball['cue'].body.setUserPointer("Cue Ball") self.ball['red'].body.setUserPointer("Red") self.ball['yellow'].body.setUserPointer("Yellow") # Set view center pos = self.ball['cue'].motion.getWorldTransform().getOrigin() self.view.set_center(eVector3(pos.x, pos.y, pos.z)) # Setup cue (position and orient) self._reset_cue() # Initialize physics self.world = DiscreteDynamicsWorld() self.debug = DebugDraw() self.world.setDebugDrawer(self.debug) self.world.addRigidBody(self.table.body) self.world.addRigidBody(self.cue.body) self.world.addRigidBody(self.rails.body) for ball in self.ball.values(): self.world.addRigidBody(ball.body) self.world.setGravity(bVector3(0, 0, -9.81 * SCALE_FACTOR)) # Register call-backs # A 1/60 call-back to run physics (the same as render) pyglet.clock.schedule(self._step) # Physic clock callback (usually few times faster than render clock) self.world.setInternalTickCallback(self.internal_tick_callback, True) self._setup_pan() self.topview = False self.helper = True self.push_handlers(on_key_press=self._on_key_press)