开发者

Pygame, simple physics engine, how to hold points between planes?

开发者 https://www.devze.com 2023-02-24 22:02 出处:网络
I\'m trying to write this tutorial in Pygame(Python) and having problems about holding points between planes.

I'm trying to write this tutorial in Pygame(Python) and having problems about holding points between planes.

My code is: fiz2.py

Vector class: vector.py

If you move mouse on the Pygame screen, the planes will rotate. And when the planes are rotating, points are passing through planes and going outside.

I tried to fix points' positions on every iteration but they still passed the planes. I have no idea about where should I fix their positions.

NOTE: I know my code is a little bit messy, this is my first 2开发者_JAVA百科d program and I had really hard times getting used to Pygame's coordinate plane and vectors. I will re-write when I solve this.

NOTE2: Yes, I wrote the comment about how to hold points between planes on the tutorial, I understand the way he fixes positions but have no idea about how(and where, in code) to implement it.

Thanks.


I can't tell looking at the code. My guess is a variable-timestep, causing instability. But I can't verify if the math is right. Although, I have useful information :

Vectors

You can simplify code, by using vectors as a class vs list/tuple. (velocity, acceleration, location) are treated as one object, verses separate .x and .y values.

# example:
pos[0] += vel[0]
pos[1] += vel[1]

# vs
pos += vel

There is a python-only implementation: euclid.py You can use to compare with your vector.py.

Or use NumPy [ used for 3d graphics, in openGL. ] Is a popular, mature lib.

physics

(It looks like you want to learn by writing your own physics), but check out PyMunk

colors

You can use: pygame.Color

import pygame
from pygame import Color
color = Color('white')
color2 = Color('lightgray')
color3 = Color(0,128,128)

collisions

Look at pygame.sprite.*collide , and pygame.Rect.*collide

pygame Game loop with numpy vector's

Boilerplate I wrote

""" Pygame boilerplate. <ninmonkey>2011/04
        pygame main Game() loop, and numpy for vector math.
        
note:
        this might not be the most effecient way to use numpy as vectors, but it's an intro.
        
        And this does not force fixed-timesteps. If you want a stable simulation, you need to use a fixed timestep.
        see: http://gafferongames.com/game-physics/fix-your-timestep/

Keys:
    ESC : exit
    Space : game_init()
"""

import pygame
from pygame.locals import * 
from pygame import Color, Rect

import numpy as np

def get_screen_size():
    """return screen (width, height) tuple"""
    screen = pygame.display.get_surface()
    return screen.get_size()

class Actor():
    """basic actor, moves randomly.
    
    members:
        loc = position vector
        velocity = velocity vector
        width, height        
    """
    def __init__(self, loc=None, velocity=None):
        """optional initial loc and velocity vectors"""
        self.width = 50
        self.height = 50
        
        # if loc or velocity are not set: use random
        if loc is None: self.rand_loc()
        else: self.loc = loc
                
        if velocity is None: self.rand_velocity()
        else: self.velocity = velocity
        
    def update(self):
        """update movement""" 
        self.loc += self.velocity
        
    def rand_velocity(self):
        """set a random vector , based on random direction. Using unit circle:        
                x = cos(deg) * speed
        """
        rad = np.radians( np.random.randint(0,360) )
        speed = np.random.randint(1,15)
        x = np.cos(rad)
        y = np.sin(rad)
        velocity = np.array( [x,y])
        velocity *= speed
        self.velocity = velocity 
        
    def rand_loc(self):
        """random location onscreen"""
        width,height = get_screen_size()
        x = np.random.randint(0,width)
        y = np.random.randint(0,height)
        self.loc = np.array([x,y])

    def is_onscreen(self):
        """test is screen.colliderect(actor) true?"""
        x,y = self.loc
        w,h = get_screen_size()
        
        screen = Rect(0, 0, w, h)
        actor = Rect(x, y, self.width, self.height)
        
        if screen.colliderect(actor): return True
        else: return False

class GameMain():
    """game Main entry point. handles intialization of game and graphics."""
    done = False
    debug = False
    color_gray = Color('lightgray')
    
    def __init__(self, width=800, height=600, color_bg=None):
        """Initialize PyGame"""        
        pygame.init()
        self.width, self.height = width, height
        self.screen = pygame.display.set_mode(( self.width, self.height ))
        pygame.display.set_caption( "boilerplate : pygame" )        

        self.clock = pygame.time.Clock()
        self.limit_fps = True
        self.limit_fps_max = 60  
        
        if color_bg is None: color_bg = Color(50,50,50)       
        self.color_bg = color_bg
        
        self.game_init()
        
    def game_init(self):
        """new game/round"""
        self.actors = [Actor() for x in range(10)]

    def loop(self):
        """Game() main loop"""
        while not self.done:
            self.handle_events()
            self.update()
            self.draw()
             
            if self.limit_fps: self.clock.tick( self.limit_fps_max )
            else: self.clock.tick()
    
    def update(self):        
        """update actors, handle physics"""
        for a in self.actors:
            a.update()
                                
            if not a.is_onscreen():
                a.rand_loc()
            
    def handle_events(self):
        """handle regular events. """        
        events = pygame.event.get()
        # kmods = pygame.key.get_mods() # key modifiers
        
        for event in events:
            if event.type == pygame.QUIT: sys.exit()
            elif event.type == KEYDOWN:
                if (event.key == K_ESCAPE): self.done = True
                elif (event.key == K_SPACE): self.game_init()

    def draw(self):
        """render screen"""
        # clear screen
        self.screen.fill( self.color_bg )
        
        # Actor: draw
        for a in self.actors:
            x,y = a.loc
            w,h = a.width, a.height
            r = Rect(x, y, w, h)
            self.screen.fill(self.color_gray, r)
            
        # will call update on whole screen Or flip buffer.
        pygame.display.flip()

if __name__ == '__main__':
    g = GameMain()
    g.loop()
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号