[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Physics module status note, more things...



Peter Gebauer <peter.gebauer@xxxxxxxxxxxxxxxxxxxxx>:

Hi again!

Should have waited with my previous post, but here's a few things I don't
understand:

1) if the mass of a static body is under 1.0 it behaves as a semi-solid,
is this intentional? (i.e other bodies fall "into" the static body and with
mass reaching 0.0 they fall right through)
In test3.py, set the static body mass to 0.1, as an example.

This is due to the fact, that the current collision algorithm is not a CCD
method. Thus the collision detection highly depends on the step time, size
and speed of a body. Other systems, which do not implement a CCD, suffer from
the same issue. Zhang Fan wrote a lot about that in pgShapeObject.c.

In order to get rid of that, you have to choose matching step times, sizes
and the speed for bodies according to your simulation needs - at least as
long as there is no CCD algorithm implemented :-).

2) is there a way to get simulated bouncing? If there was a way to describe
how much energy the object retains (in new direction) after collision, a
float between 0.0 and 1.0 (0-100% energy retained, 0.01 would be a rock and
0.5 would be more of a tennis ball)?

Simulated bouncing is implemented already. The collision energy, and how it
is applied on the colliding bodies, depends on the restitution set for them.
So, whether you will receive an elastic or inelastic collision, depends on
that factor. A quick search for "Coefficient of restitution" and
"elastic collisions" will provide you tons of explanations and even some
values for different materials.
Attached you'll find a small bouncing test script.

3) can we add bouyancy? :) Body 1 is called "floater" and Body 2 is called
"water", if floater is inside water it should, depending on it'
displacement, either pop back up or sink to the bottom. We would
be able to calculate this with the already existing shape, mass and friction
attributes, but it would probably require a new boolean attribute, maybe
"solid"?

Here's how I'd do it.

* create a World with relatively high damping, the gravity vector points to
  the top (e.g. world.gravity = 0, -3).
* place body into that world with a certain damping, mass, etc.
* have fun watching the simulation.

Limiting the world's area would be left to the user. As you can have multiple
worlds, which behave completely different, you could e.g. split the screen
into "sky" and "sea", being two different worlds. If the body reaches a
certain point, you could remove it from "sea" and add it to "sky"
(which reminds of adding remove_* methods, so wait 'til the end of the
 weekend before doing that ;-).

Simulating a varying density of the world would require a slightly
different approach for worlds. Currently the world does not know anything
about its size and such, that however would be necessary, I think.

Regards
Marcus


# The python file is under test

import pygame
import physics
from pygame.locals import *

def render_body(body,surface,color):
    l = body.get_points()
    pygame.draw.polygon(surface,color,l)

def render_world(world,surface,color):
    for body in world.bodies:
        render_body(body,surface,color)
        

def init_world():
    w = physics.World()
    w.gravity = 0, 2
    
    body1 = physics.Body()
    body1.shape = physics.RectShape(30, 28, 0)
    body1.position = 400, 40
    body1.rotation = i
    body1.restitution = 0.9
    body1.mass = 20
    w.add_body(body1)
    
    body2 = physics.Body()
    body2.shape = physics.RectShape (760, 20, 0)
    body2.position = 400, 600
    body2.restitution = 1.0
    body2.mass = 1e100
    body2.static = True
    w.add_body(body2)
    return w


def main():
    """this function is called when the program starts.
       it initializes everything it needs, then runs in
       a loop until the function returns."""
#Initialize Everything
    pygame.init()
    screen = pygame.display.set_mode((800, 800))
    pygame.display.set_caption('physics test')

#Create The Backgound
    background = pygame.Surface(screen.get_size())
    background = background.convert()
    background.fill((0,0,0))


#Display The Background
    screen.blit(background, (0, 0))
    pygame.display.flip()

#Prepare Game Objects
    clock = pygame.time.Clock()
        
    #rect = pygame.Rect(0,0,20,20)
    #pointlist = [(0,10),(10,0),(0,0)]
    white = 0, 250, 250
    theta = 0
    world = init_world()
    
    
    
#Main Loop
    while 1:
        # t = clock.tick(60)
        # t = t/1000.0;
        world.update(0.02)
    #Handle Input Events
        for event in pygame.event.get():
            if event.type == QUIT:
                quit()
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                return
            elif event.type == MOUSEBUTTONDOWN:
                return
            elif event.type is MOUSEBUTTONUP:
                return
        

    #Draw Everything
        background.fill((0,0,0))
        #print world.body_list[0]
        render_world(world,background,white)
        screen.blit(background, (0, 0))
        pygame.display.flip()
        

#Game Over


#this calls the 'main' function when this script is executed
if __name__ == '__main__': main()