Non-screen flipping graphics
import pygame
from pygame.locals import *
from pygame.color import *
import Box2D2 as box2d
from math import *
global SCENERY
global ROLLCAT_WHEEL
global ROLLCAT_BODY
(SCENERY, ROLLCAT_WHEEL, ROLLCAT_BODY) = (0,1,2)
global contactList
contactList = []
class X2OGame:
def __init__(self, screen):
self.pixelsPerMeter = 20
self.updateList = []
self.screen = screen
# get everything set up
self.clock = pygame.time.Clock()
#self.font = pygame.font.Font(None, 24) # font object
#self.canvas = olpcgames.ACTIVITY.canvas
#self.joystickobject = None
self.debug = True
self.initializeWorld()
self.screen.fill((0,0,0))
self.leftLPress = False
self.leftRPress = False
# create the name --> instance map for components
def worldToScreen(self, worldX, worldY):
return (worldX * self.pixelsPerMeter, - worldY * self.pixelsPerMeter)
def screenToWorld(self, screenX, screenY):
return (screenX / self.pixelsPerMeter, - screenY / self.pixelsPerMeter)
def initializeWorld(self):
worldAABB = box2d.b2AABB()
worldAABB.lowerBound.Set(- 100, - 100)
worldAABB.upperBound.Set(100, 100)
gravity = box2d.b2Vec2(0, - 10)
doSleep = True
self.world = box2d.b2World(worldAABB, gravity, doSleep)
bodyDef2 = box2d.b2BodyDef()
bodyDef2.position.Set(10, - 20)
body2 = self.world.CreateBody(bodyDef2)
shapeDef2 = box2d.b2PolygonDef()
shapeDef2.SetAsBox(50, .2)
body2.CreateShape(shapeDef2)
body2.SetXForm(body2.GetXForm().position,-.02)
BodySprite(body2, 'pic2.png',100,.4,0,0,self.worldToScreen, self.screenToWorld)
body2.type = SCENERY
self.updateList.append(RollCat(self,(10,0)))
self.updateList.append(RollCat(self,(13,0)))
self.updateList.append(RollCat(self,(16,0)))
self.updateList.append(RollCat(self,(19,0)))
self.updateList.append(RollCat(self,(22,0)))
self.updateList.append(RollCat(self,(25,0)))
print body2.type
def run(self):
self.running = True
while self.running:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
self.running = False
if (event.type == KEYDOWN and event.key == K_a):
self.leftLPress = True
if (event.type == KEYUP and event.key == K_a):
self.leftLPress = False
if (event.type == KEYDOWN and event.key == K_d):
self.leftRPress = True
if (event.type == KEYUP and event.key == K_d):
self.leftRPress = False
#self.currentTool.handleEvents(event)
# Clear Display
#self.screen.fill((0,0,0)) #255 for white
contactList = []
self.world.Step(1.0/60,10)
for updatable in self.updateList:
updatable.update()
#Print all the text on the screen
#text = self.font.render("Current Tool: "+self.currentTool.name, True, (0,0,0))
#textpos = text.get_rect(left=700,top=7)
#self.screen.blit(text,textpos)
for char in BodySprite.bodySpriteList:
char.update()
for char in BodySprite.bodySpriteList:
self.screen.blit(char.blank, char.old)
for char in BodySprite.bodySpriteList:
self.screen.blit(char.image, char.rect)
for char in BodySprite.bodySpriteList:
pygame.display.update([char.old, char.rect])
# Flip Display
#pygame.display.flip()
# Try to stay at 30 FPS
self.clock.tick(60) # originally 50
class BodySprite(pygame.sprite.Sprite):
blankColor = (0, 0, 0)
bodySpriteList = []
def __init__(self, body, imageName, imageWidthMeters, imageHeightMeters, imageOffsetXMeters, imageOffsetYMeters, worldToScreenFunction, screenToWorldFunction):
pygame.sprite.Sprite.__init__(self)
BodySprite.bodySpriteList.append(self)
# Save a copy of the screen's rectangle
self.screen = pygame.display.get_surface().get_rect()
self.w2s = worldToScreenFunction
self.s2w = screenToWorldFunction
self.body = body
newWidth = self.w2s(imageWidthMeters, imageHeightMeters)[0] - self.w2s(0, 0)[0]
newHeight = self.w2s(imageWidthMeters, imageHeightMeters)[1] - self.w2s(0, 0)[1]
self.offsetX = imageOffsetXMeters
self.offsetY = imageOffsetYMeters
if newWidth < 0:
newWidth *= - 1
if newHeight < 0:
newHeight *= - 1
# Create a variable to store the previous position of the sprite
self.old = (0, 0, 0, 0)
self.angle = 0
self.originalImage = pygame.transform.scale(pygame.image.load(imageName).convert_alpha(), (newWidth, newHeight))
self.image = pygame.transform.rotate(self.originalImage, self.angle)
self.rect = self.image.get_rect()
# Create a Surface the size of our character
self.blank = pygame.Surface((self.rect.width * 2, self.rect.height * 2), 0, self.screen)
self.blank.fill(BodySprite.blankColor)
self.alreadyRendered = False
# self.
def update(self):
if ((self.body.IsStatic() or self.body.IsSleeping()) and self.alreadyRendered):
return
self.alreadyRendered = True
# Make a copy of the current rectangle for use in erasing
self.old = self.rect
angle = self.body.GetAngle()
self.image = pygame.transform.rotate(self.originalImage, angle * 180 / 3.1415)
# Move the rectangle by the specified amount
self.rect = self.image.get_rect()
cosAngle = cos(- angle)
sinAngle = sin(- angle)
vrotx = - (cosAngle * self.offsetX - sinAngle * self.offsetY)
vroty = (sinAngle * self.offsetX + cosAngle * self.offsetY)
(self.x, self.y) = self.w2s(self.body.GetXForm().position.x + vrotx, self.body.GetXForm().position.y + vroty)
self.rect.center = (self.x, self.y)
class myContactListener(box2d.b2ContactListener):
def __init__(self): super(myContactListener, self).__init__()
def Add(self, point):
pass
def Persist(self, point):
contact
def Remove(self, point):
pass
def Result(self, point):
pass
class RollCat:
def __init__(self, game, location):
self.game = game
self.world = game.world
bodyDef = box2d.b2BodyDef()
bodyDef.position.Set(location[0], location[1]+1)
#bodyDef.fixedRotation = True
body = self.world.CreateBody(bodyDef)
shapeDef = box2d.b2PolygonDef()
shapeDef.SetAsBox(1, 1)
shapeDef.density = 1
shapeDef.restitution = 0.5
shapeDef.friction = 1.0
body.CreateShape(shapeDef)
body.SetMassFromShapes()
self.torso = body
self.torso.type = ROLLCAT_BODY
bodyDef3 = box2d.b2BodyDef()
bodyDef3.position.Set(location[0],location[1])
body3 = self.world.CreateBody(bodyDef3)
shapeDef3 = box2d.b2CircleDef()
shapeDef3.radius = 1.0
shapeDef3.density = 1
shapeDef3.restitution = 0.5
shapeDef3.friction = 1.0
body3.CreateShape(shapeDef3)
body3.SetMassFromShapes()
self.wheel = body3
self.wheel.type = ROLLCAT_WHEEL
sensorDef = box2d.b2CircleDef()
sensorDef.radius = 0.5
sensorDef.isSensor = True
sensorDef.localPosition = box2d.b2Vec2(0,-2)
sensorShape = self.torso.CreateShape(sensorDef)
jd = box2d.b2RevoluteJointDef()
jd.Initialize(body, body3, box2d.b2Vec2(location[0],location[1]))
revJoint = self.world.CreateJoint(jd).getAsType()
self.axle = revJoint
revJoint.EnableMotor(True)
revJoint.SetMotorSpeed(0)
revJoint.SetMaxMotorTorque(5000)
self.motorSpeed = 0
self.targetAngle = 0
BodySprite(body3,'Rollcats_bottom.png',2, 2, 0, 0, self.game.worldToScreen, self.game.screenToWorld)
BodySprite(body,'Rollcats_top.png',2, 2, 0, 0,self.game.worldToScreen, self.game.screenToWorld)
#def canJump(self):
def update(self):
moveSpeed = .1
moveForce = 100
angle = self.torso.GetAngle() - self.targetAngle
angVel = self.torso.GetAngularVelocity()
if (self.game.leftLPress):
self.targetAngle = .95*self.targetAngle + .05 * .4
self.wheel.ApplyForce(box2d.b2Vec2(-moveForce,0),self.wheel.GetWorldCenter())
elif (self.game.leftRPress):
self.targetAngle = .95*self.targetAngle - .05 * .4
self.wheel.ApplyForce(box2d.b2Vec2(moveForce,0),self.wheel.GetWorldCenter())
else:
vx = self.wheel.GetLinearVelocity().x
self.targetAngle = .9*self.targetAngle
self.wheel.ApplyForce(box2d.b2Vec2(-.1*moveForce*vx,0),self.wheel.GetWorldCenter())
while (angle > 3.1415):
angle -= 2*3.1415
while (angle < -3.1415):
angle += 2*3.1415
correctionFactor = 2
correctionDragFactor = .1
#torque = -correctionFactor*angle - correctionDragFactor*angVel
#self.torso.ApplyTorque(torque)
self.motorSpeed += correctionFactor*angle + correctionDragFactor*angVel
self.axle.SetMotorSpeed(self.motorSpeed)
def main():
pygame.init()
pygame.display.init()
x, y = (1200,800)#pygame.display.list_modes()[0]
#toolbarheight = 10
#tabheight = 10
screen = pygame.display.set_mode((x, y))
# create an instance of the game
game = X2OGame(screen)
# start the main loop
game.run()
# function for loading sounds (mostly borrowed from Pete Shinners pygame tutorial)
def loadSound(name):
# if the mixer didn't load, then create an empy class that has an empty play method
# this way the program will run if the mixer isn't present (sans sound)
class NoneSound:
def play(self): pass
def set_volume(self): pass
if not pygame.mixer:
return NoneSound()
try:
sound = pygame.mixer.Sound(name)
except:
print "error with sound: " + name
return NoneSound()
return sound
# make sure that main get's called
if __name__ == '__main__':
main()
Binding sprites and bodies:
import pygame
from Box2D2 import *
import sys
from math import *
class BodySprite(pygame.sprite.Sprite):
blankColor = (0, 0, 0)
bodySpriteList = []
def __init__(self, body, imageName, imageWidthMeters, imageHeightMeters, imageOffsetXMeters, imageOffsetYMeters, worldToScreenFunction, screenToWorldFunction):
pygame.sprite.Sprite.__init__(self)
BodySprite.bodySpriteList.append(self)
# Save a copy of the screen's rectangle
self.screen = pygame.display.get_surface().get_rect()
self.w2s = worldToScreenFunction
self.s2w = screenToWorldFunction
self.body = body
newWidth = self.w2s(imageWidthMeters,imageHeightMeters)[0] - self.w2s(0,0)[0]
newHeight = self.w2s(imageWidthMeters,imageHeightMeters)[1] - self.w2s(0,0)[1]
self.offsetX = imageOffsetXMeters
self.offsetY = imageOffsetYMeters
if newWidth < 0:
newWidth *= -1
if newHeight < 0:
newHeight *= -1
# Create a variable to store the previous position of the sprite
self.old = (0, 0, 0, 0)
self.angle = 0
self.originalImage = pygame.transform.scale(pygame.image.load(imageName).convert_alpha(),(newWidth,newHeight))
self.image = pygame.transform.rotate(self.originalImage,self.angle)
self.rect = self.image.get_rect()
# Create a Surface the size of our character
self.blank = pygame.Surface((self.rect.width*2, self.rect.height*2),0,screen)
self.blank.fill(BodySprite.blankColor)
# self.
def update(self):
# Make a copy of the current rectangle for use in erasing
self.old = self.rect
angle = self.body.GetAngle()
self.image = pygame.transform.rotate(self.originalImage,angle * 180 / 3.1415)
# Move the rectangle by the specified amount
self.rect = self.image.get_rect()
cosAngle = cos(-angle)
sinAngle = sin(-angle)
vrotx = -(cosAngle * self.offsetX - sinAngle * self.offsetY)
vroty = (sinAngle * self.offsetX + cosAngle * self.offsetY)
(self.x, self.y) = self.w2s(self.body.GetXForm().position.x + vrotx, self.body.GetXForm().position.y + vroty)
self.rect.center = (self.x, self.y)
global pixelsPerMeter
pixelsPerMeter = 20
#screen to world conversion
def s2w(screenX, screenY):
return (screenX / pixelsPerMeter, -screenY / pixelsPerMeter)
#world to screen conversion
def w2s(worldX, worldY):
return (worldX * pixelsPerMeter, -worldY * pixelsPerMeter)
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption('Body + Sprite Example')
screen.fill((159, 182, 205))
worldAABB = b2AABB()
worldAABB.lowerBound.Set(-100,-100)
worldAABB.upperBound.Set(100,100)
gravity = b2Vec2(0, -10)
doSleep = True
world = b2World(worldAABB, gravity, doSleep)
bodyDef = b2BodyDef()
bodyDef.position.Set(10,-10)
bodyDef.fixedRotation = True
body = world.CreateBody(bodyDef)
body.SetLinearVelocity(b2Vec2(1.0,0.0))
shapeDef = b2PolygonDef()
shapeDef.SetAsBox(1, 1)
shapeDef.density = 1
shapeDef.restitution = 0.5
shapeDef.friction = 1.0
body.CreateShape(shapeDef)
body.SetMassFromShapes()
bodyDef2 = b2BodyDef()
bodyDef2.position.Set(10,-20)
body2 = world.CreateBody(bodyDef2)
shapeDef2 = b2PolygonDef()
shapeDef2.SetAsBox(50,.2)
body2.CreateShape(shapeDef2)
bodyDef3 = b2BodyDef()
bodyDef3.position.Set(10,-11)
body3 = world.CreateBody(bodyDef3)
shapeDef3 = b2CircleDef()
shapeDef3.radius = 1.0
shapeDef3.density = 1
shapeDef3.restitution = 0.5
shapeDef3.friction = 1.0
body3.CreateShape(shapeDef3)
body3.SetMassFromShapes()
jd = b2RevoluteJointDef()
jd.Initialize(body, body3, b2Vec2(10,-11))
revJoint = world.CreateJoint(jd)
BodySprite(body3,'wheel.png',2, 2, 0, 0, w2s, s2w)
BodySprite(body,'pic2.png',2, 2, 0, 0,w2s,s2w)
BodySprite(body2, 'pic2.png',100,.4,0,0,w2s,s2w)
pygame.display.update()
while True:
count = 0
world.Step(1.0/60.0, 10)
for event in pygame.event.get():
0
for char in BodySprite.bodySpriteList:
char.update()
# Erase the old position by putting our blank Surface on it
for char in BodySprite.bodySpriteList:
screen.blit(char.blank, char.old)
for char in BodySprite.bodySpriteList:
screen.blit(char.image, char.rect)
for char in BodySprite.bodySpriteList:
pygame.display.update([char.old, char.rect])