# Filename: A16a_BodyTypes.py # Written by: James D. Miller # This file is based on the test_BodyTypes.py file in the examples directory of the # pybox2d distribution. This depends on the pygame framework in that distribution so # all the framework files must be in the same directory as this file. #!/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 * from math import cos, sin, pi class BodyTypes (Framework): name="Body Types, Guns, and Slingshot." description="Change body type keys: (d)dynamic, (s)static, (k)kinematic.\n(p)pyramid, (l)load, (c)circle.\nShoot gun: g or b. b has variable speed based on mouse string.\nSlingshot: shift and mouse drag." speed = 3 # platform speed def __init__(self): super(BodyTypes, self).__init__() self.time = 0 # A list for keeping track of the age of the bullets. self.bullet_list = [] # Collision masking (also see test_CollisionFiltering.py) # This positive (+5) non_bullets group index insures collisions in this group. self.non_bullets = 5 # Categories self.gunCategory = 0x0002 self.bulletCategory = 0x0004 # Masks self.gunMask = 0xFFFF # An exclusive OR to keep bullets from colliding with the gun parts. self.bulletMask = 0xFFFF ^ self.gunCategory # The ground ground = self.world.CreateBody( shapes=b2EdgeShape(vertices=[(-30,0),(30,0)]) ) # The attachment attachment_fixture = b2FixtureDef( shape=b2PolygonShape(box=(0.5,2)), density=2.0, filter = b2Filter( groupIndex = self.non_bullets, categoryBits = self.gunCategory, maskBits = self.gunMask ) ) self.attachment=self.world.CreateDynamicBody( position=(0,3), fixtures=attachment_fixture, ) # The platform fixture=b2FixtureDef( shape=b2PolygonShape(box=(4,0.5)), density=2, friction=0.6, filter = b2Filter( groupIndex = self.non_bullets, categoryBits = self.gunCategory, maskBits = self.gunMask ) ) self.platform=self.world.CreateDynamicBody( position=(0,5), fixtures=fixture, ) # The joints joining the attachment/platform and ground/platform self.RJ = self.world.CreateRevoluteJoint( bodyA=self.attachment, bodyB=self.platform, anchor=(0,5), maxMotorTorque=50, enableMotor=True ) self.PJ = self.world.CreatePrismaticJoint( bodyA=ground, bodyB=self.platform, anchor=(0,5), axis=(1,0), maxMotorForce = 1000, enableMotor = True, lowerTranslation = -10, upperTranslation = 10, enableLimit = True ) def newpayload(self): # And the payload that initially sits upon the platform in the original demo. # Reusing the fixture we previously defined above. payload_fixture=b2FixtureDef( shape=b2PolygonShape(box=(0.75, 0.75)), density=2, friction=0.6, filter = b2Filter( groupIndex = self.non_bullets, categoryBits = self.bulletCategory, maskBits = self.bulletMask ) ) self.payload=self.world.CreateDynamicBody( position=(0,8), fixtures=payload_fixture, ) def newCircle(self): # Some circles for testing contact normals. circle_fixture=b2FixtureDef( shape=b2CircleShape(radius=2.0), density=2, friction=0.6, filter = b2Filter( groupIndex = self.non_bullets, categoryBits = self.bulletCategory, maskBits = self.bulletMask ) ) self.circle=self.world.CreateDynamicBody( position=(0,8), fixtures=circle_fixture, ) def newpyramid(self): # Pyramid on the ground box_half_size = (0.5, 0.5) box_density = 5.0 box_rows = 20 x=b2Vec2(-27, 0.75) deltaX=(0.5625, 1.25) deltaY=(1.125, 0) for i in range(box_rows): y = x.copy() for j in range(i, box_rows): self.world.CreateDynamicBody( position=y, fixtures=b2FixtureDef( shape=b2PolygonShape(box=box_half_size), density=box_density) ) y += deltaY x += deltaX def newbullet(self, location_init, angle_radians_init, speed_control): # Speed v = 30 # Note: angle_degrees = angle_radians_init * 180/pi # Scale the bullet speed by the length of the mouse vector. if self.mouseJoint and (speed_control == "on"): joint_vector = self.mouseJoint.anchorB - self.mouseJoint.target joint_vector_length = (joint_vector.x**2 + joint_vector.y**2)**0.5 #print joint_vector_length v = v * joint_vector_length/2.0 # Cut this by a factor of 2... v_x = v * cos(pi/2- angle_radians_init) v_y = v * sin(pi/2- angle_radians_init) bullet_fixture = b2FixtureDef(shape=b2PolygonShape(box=(0.25, 0.25)), density=100.0) #restitution=1.0 bullet_fixture.filter.groupIndex = 0 bullet_fixture.filter.categoryBits = self.bulletCategory bullet_fixture.filter.maskBits = self.bulletMask self.bullet=self.world.CreateDynamicBody( position=location_init, bullet=True, fixtures=bullet_fixture, linearVelocity=(v_x, v_y) ) # Put the bullet into a list for clean-up (deletion) later. Tag it with # a birth-time stamp so can calculate age later. self.bullet_list.append([self.bullet, self.time]) # print "self.time =", self.time def Keyboard(self, key): if key==Keys.K_d: self.platform.type=b2_dynamicBody elif key==Keys.K_s: self.platform.type=b2_staticBody elif key==Keys.K_k: self.platform.type=b2_kinematicBody self.platform.linearVelocity=(-self.speed, 0) self.platform.angularVelocity=0 elif (key==Keys.K_g) or (key==Keys.K_b): if (key==Keys.K_b): speed_control = "on" else: speed_control = "off" bullet_angle_init = self.RJ.angle #print "angle =", bullet_angle_init # Get the world position of the tip (0,2) of the gun barrel. bullet_xy_init = self.attachment.transform * (0,2) #print "world point = ", bullet_xy_init self.newbullet(bullet_xy_init, bullet_angle_init, speed_control) elif key==Keys.K_p: self.newpyramid() elif key==Keys.K_l: self.newpayload() elif key==Keys.K_c: self.newCircle() def Step(self, settings): super(BodyTypes, self).Step(settings) # Move the platform if it's kinematic. if self.platform.type==b2_kinematicBody: p = self.platform.transform.position if ((p.x < -10) or (p.x > 10)): self.platform.linearVelocity *= -1 # Every step (or second if use commented value), check the age of each bullet in the list. self.time += 1.0/60.0 if (self.stepCount % 1)==0: # change the 1 to 60 to delay check to every second. #print "--------------------", self.time, "--------------------" # Copy the list so you are not deleting in the list used by the for loop. bullet_list_copy = self.bullet_list[:] for bullet in bullet_list_copy: bullet_age = self.time - bullet[1] if (bullet_age) > 10.0: #print "age of bullet =", bullet_age # Delete the bullet self.world.DestroyBody(bullet[0]) # Delete the sub-list element in the main list. self.bullet_list.remove(bullet) # Delete the copy of the list. del bullet_list_copy if __name__=="__main__": main(BodyTypes)