Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 2 of 2
  1. #1
    Regular Coder
    Join Date
    Oct 2006
    Posts
    206
    Thanks
    1
    Thanked 0 Times in 0 Posts

    Particle System Physics

    I've been working on a particle system in JavaScript for a while, and just couldn't get the physics to work properly.

    Today, I downloaded Slingshot, a great game. I noticed that its particle physics seem to work fairly well, and downloaded the source code. Upon inspection, I found that it does not use a time based animation, as I was, but instead uses a more "step-based" system (see the update method):

    PHP Code:
    #    This file is part of Slingshot.
    #
    # Slingshot is a two-dimensional strategy game where two players attempt to shoot one
    # another through a section of space populated by planets.  The main feature of the
    # game is that the shots, once fired, are affected by the gravity of the planets.

    # Slingshot is Copyright 2007 Jonathan Musther and Bart Mak. It is released under the
    # terms of the GNU General Public License version 2, or later if applicable.

    # Slingshot is free software; you can redistribute it and/or modify it under the terms
    # of the GNU General Public License as published by the Free Software Foundation; either
    # version 2 of the License, or any later version.

    # Slingshot is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
    # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    # See the GNU General Public License for more details.

    # You should have received a copy of the GNU General Public License along with Slingshot;
    # if not, write to
    # the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 


    from settings import *
    from general import *
    import pygame
    import math
    from math import sqrt
    from random import randint

    class Particle(pygame.sprite.Sprite):
        
        
    def __init__(selfpos = (0.00.0), size 10):
            
    pygame.sprite.Sprite.__init__(self)
            if 
    size == 5:
                
    self.image Settings.particle_image5
            
    else:
                
    self.image Settings.particle_image10
            self
    .rect self.image.get_rect()
    #        self.image, self.rect = load_image("explosion-10.png", (0,0,0))
            
    self.pos pos
            self
    .impact_pos pos
            self
    .size size
            angle 
    randint(0359)
            if 
    size == 5:
                
    speed randint(Settings.PARTICLE_5_MINSPEED,Settings.PARTICLE_5_MAXSPEED)
            else:
                
    speed randint(Settings.PARTICLE_10_MINSPEED,Settings.PARTICLE_10_MAXSPEED)
            
    self.= (0.1 speed math.sin(angle), -0.1 speed math.cos(angle))
            
    self.flight Settings.MAX_FLIGHT
            
        def max_flight
    (self):
            if 
    self.flight 0:
                return 
    True
            
    else:
                return 
    False
            
        def update
    (selfplanets):
            
    self.flight self.flight 1
            
            self
    .last_pos self.pos
            
            
    for p in planets:
                
    p_pos p.get_pos()
                
    mass p.get_mass()
                
    = (self.pos[0] - p_pos[0])**+ (self.pos[1] - p_pos[1])**2
                a 
    = (Settings.mass * (self.pos[0] - p_pos[0]) / (math.sqrt(d)), Settings.mass * (self.pos[1] - p_pos[1]) / (math.sqrt(d)))
                
    self.= (self.v[0] - a[0], self.v[1] - a[1])
                
            
    self.pos = (self.pos[0] + self.v[0], self.pos[1] + self.v[1])

            
    # END OF THE ALGORITHM I QUESTION
            
            
    if not self.in_range():
                return 
    0
            
            
    for p in planets:
                
    p_pos p.get_pos()
                
    p.get_radius()
                
    = (self.pos[0] - p_pos[0])**+ (self.pos[1] - p_pos[1])**2
                
    if <= (r)**2:
                    
    self.impact_pos get_intersect(p_posrself.last_posself.pos)
                    
    self.pos self.impact_pos
                    
    return 0
            
            
    if Settings.BOUNCE:
                if 
    self.pos[0] > 799:
                    
    self.pos[0] - self.last_pos[0]
                    
    self.pos = (799self.last_pos[1] + (self.pos[1] - self.last_pos[1]) * (799 self.last_pos[0]) / d)
                    
    self.= (-self.v[0], self.v[1])
                if 
    self.pos[0] < 0:
                    
    self.last_pos[0] - self.pos[0]
                    
    self.pos = (0,self.last_pos[1] +  (self.pos[1] - self.last_pos[1]) * self.last_pos[0] / d)
                    
    self.= (-self.v[0], self.v[1])
                if 
    self.pos[1] > 599:
                    
    self.pos[1] - self.last_pos[1]
                    
    self.pos = (self.last_pos[0] + (self.pos[0] - self.last_pos[0]) * (599 self.last_pos[1]) / d599)
                    
    self.= (self.v[0], -self.v[1])
                if 
    self.pos[1] < 0:
                    
    self.last_pos[1] - self.pos[1]
                    
    self.pos = (self.last_pos[0] + (self.pos[0] - self.last_pos[0]) * self.last_pos[1] / d0)
                    
    self.= (self.v[0], -self.v[1])
    #                print self.pos
    #                print self.last_pos
            
            
    self.rect.center = (round(self.pos[0]), round(self.pos[1]))
            return 
    1
            
        def in_range
    (self):
            if 
    pygame.Rect(-800, -60024001800).collidepoint(self.pos):
                return 
    True
            
    else:
                return 
    False
            
        def visible
    (self):
            if 
    pygame.Rect(00800600).collidepoint(self.pos):
                return 
    True
            
    else:
                return 
    False
        
        def get_pos
    (self):
            return 
    self.pos

        def get_impact_pos
    (self):
            return 
    self.impact_pos
        
        def get_size
    (self):
            return 
    self.size 
    I think I know enough about Python to port this to JavaScript. However, as I was doing so, I realized that the algorithms seem to be different. Slingshot's physics is (are?) great, though. Could someone explain exactly how/why update method (up to my comment) works?

    Thanks,
    1212jtraceur
    Last edited by 1212jtraceur; 07-07-2007 at 06:51 PM.

  • #2
    New to the CF scene
    Join Date
    Jul 2007
    Posts
    1
    Thanks
    0
    Thanked 0 Times in 0 Posts
    Hi! The next block of code updates the positions (as you noticed):
    Code:
            self.last_pos = self.pos
            
            for p in planets:
                p_pos = p.get_pos()
                mass = p.get_mass()
                d = (self.pos[0] - p_pos[0])**2 + (self.pos[1] - p_pos[1])**2
                a = (Settings.g * mass * (self.pos[0] - p_pos[0]) / (d * math.sqrt(d)), Settings.g * mass * (self.pos[1] - p_pos[1]) / (d * math.sqrt(d)))
                self.v = (self.v[0] - a[0], self.v[1] - a[1])
                
            self.pos = (self.pos[0] + self.v[0], self.pos[1] + self.v[1])
    Each step, the velocity of the particles is updated with the acceleration due to gravitational force. This can be split into updates for all separate planets. For each planet, the acceleration is g*mass/(distance^2) in the direction of the planet (g can be used for tuning you system). This is where the additional 1/distance factor comes in, as the total acceleration is devided proportionally over the two elements of this vector (this is the (self.pos - p.pos)/sqrt(d) factor (note that d is distance^2)).
    With this acceleration, the velocity is updated. With the updated velocity, the position is updated.

    If you want a timebased method, you can put an extra factor before the position update to make the particle travel a bit longer or shorter into that direction. (That is, if you're keeping track of the framerate, you can adjust the distance the particles go each frame accordingly.) The reason that it works fairly well with slingshot is that we have limited the framerate to only 30. The framerate doesn't drop below 30 too easily (well, it still can...).
    EDIT: put the same factor before the velocity update as well.

    I hope it's clear. If not, I can make some graphics to illustrate where all factors come from.

    Glad you like the game!

    Bart
    Last edited by bmak; 07-10-2007 at 06:17 AM.


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •