Talk:Physics Jam/Help

From OLPC
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

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