Talk:Physics Jam/Help

From OLPC
Jump to navigation Jump to search

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])