Search code examples
pythonpygamephysicsgame-physics

Fluid-like characteristics with Pygame


So I'm trying to write a little simulator thing with pygame, but im stuck

I'm trying to make particles that fall and settle but i want them to stack and stop when they hit a wall

This may sound confusing so here is an example:

http://www.coolmath-games.com/0-sugar-sugar/

I want to make particles that resemble the sugar in the game above:

I started by trying:

if pygame.sprite.spritecollideany(self, self.game.block_list):
    self.rect.x += 0
    self.rect.y += 0

but then the particles just stop and they don't roll down sloped surfaces

also I need to know how to check if a sprite collides with any other sprite in its group

So if anyone knows how I can duplicate this liquid like particle movement in pygame that would be awesome!

Thank You!


Solution

  • As I stated above, I tried to write the exactly same game with pygame too but left it uncompleted.
    First of all, I preferred NOT to store these particles as different objects. Instead I used a dictionary to store their coordinates. I made it so because there are HUNDREDS of them and you have to check for collisions ~50 times per second for each of them. If you try to make them all different objects, it may go out of hand at some point.
    After you detect a collision, in order to make them roll down sloped surface, let them move diagonally too. First check for the cell below, if that cell is not empty, check for the cells at bottom left and bottom right of the particle.
    Btw, I found my function that moves the particles but it is not really readable.

    def spawnSugar(spawnPoint) :
        global sugarList,mapDict
        mapDict[spawnPoint] = 1
        sugarList.append(spawnPoint)
    
    def moveAll() :
        global mapDict,sugarList
        sugarListTmp = sugarList
        sugarList = []
        for sugarX,sugarY in sugarListTmp :
                # m stands for the vertical movement (1 for down, 0 for staying still)
                # k stands for horizontal movement (-1 for left, +1 for right)
                m = 1
                if mapDict[( sugarX , (sugarY+1)%mapSizeY )]==0:
                # checks whether the coordinate below this particle is empty
                    k = randint( -(mapDict[((sugarX-1)%mapSizeX , (sugarY+1)%mapSizeY)]==0) , mapDict[((sugarX+1)%mapSizeX , (sugarY+1)%mapSizeY)]==0 )
                    # If it is empty; randomly chooses 1 of the 3 coordinates below the particle (1 of them is just below and the other 2 are diagonally below)
                elif mapDict[((sugarX-1)%mapSizeX,(sugarY+1)%mapSizeY)]==0 and mapDict[((sugarX-1)%mapSizeX,(sugarY)%mapSizeY)]==0 and mapDict[((sugarX+1)%mapSizeX,(sugarY+1)%mapSizeY)]==0 and mapDict[((sugarX+1)%mapSizeX,(sugarY)%mapSizeY)]==0:
                # If the coordinate below the particle is not empty but other 2 diagonals are empty
                    k = -1 if randint(0,1) else 1 #chooses 1 of them randomly
    
                else : # If at most 1 of these 2 diagonal coordinates are empty
                    k = (mapDict[((sugarX+1)%mapSizeX,(sugarY+1)%mapSizeY)]==0 and mapDict[((sugarX+1)%mapSizeX,(sugarY)%mapSizeY)]==0) or -(mapDict[((sugarX-1)%mapSizeX,(sugarY+1)%mapSizeY)]==0 and mapDict[((sugarX-1)%mapSizeX,(sugarY)%mapSizeY)]==0)
                    if not k: # If none of them are empty
                        m = 0
                mapDict[(sugarX,sugarY)] = 0
                mapDict[((sugarX+k)%mapSizeX,(sugarY+m)%mapSizeY)] = 1
                sugarList.append(((sugarX+k)%mapSizeX,(sugarY+m)%mapSizeY))
    
    
    
    
    # Values to assign before entering the main loop
    mapDict = {}
    sugarList = []
    for x in range(mapSizeX):
        for y in range(mapSizeY):
            mapDict[(x,y)] = 0