0
\$\begingroup\$

I'm not a game dev. However I've just created what I believe may be an original means of creating realistic-enough water or fire/smoke textures, which may perhaps in principle (and using a different language than Python) be computationally cheap.

I don't know whether this numerical cellular automaton method would be useful in principle, given the state of the art and the level of fidelity that players are demanding; however, I am curious to know what people here make of it. There may be other applications for this CA such as random number generation too.

Up front, here is my Python code, which gives you a graphical display of the automaton in action.

import numpy as np import pygame import sys class NumericalCellularAutomaton: def __init__(self, size): self.size = size # Size of the grid (size x size) self.grid = np.random.randint(0, 10, (size, size)) # Initialize grid with random values def wrap_index(self, index): """Wraps the index to ensure it stays within grid bounds.""" return index % self.size def calculate_influence(self): """Calculates the influence values for each cell.""" influence_grid = np.zeros_like(self.grid) for i in range(self.size): for j in range(self.size): count = 0 # Check all 8 neighbours plus self for di in [-1, 0, 1]: for dj in [-1, 0, 1]: ni = self.wrap_index(i + di) nj = self.wrap_index(j + dj) if self.grid[ni][nj] == self.grid[i][j]: count += 1 influence_grid[i][j] = count return influence_grid def apply_rules(self): """Applies the rules to update the grid.""" influence_grid = self.calculate_influence() new_grid = np.copy(self.grid) for i in range(self.size): for j in range(self.size): influence_value = influence_grid[i][j] distance = self.grid[i][j] # Distance is based on the cell's value # Apply influence to all orthogonal neighbours at this distance if distance > 0: for d in [-distance, distance]: ni = self.wrap_index(i+d) nj = j if self.grid[ni][nj] < influence_value and new_grid[ni][nj] < 10: new_grid[ni][nj] += 1 elif self.grid[ni][nj] > influence_value and new_grid[ni][nj] > 0: new_grid[ni][nj] -= 1 ni = i nj = self.wrap_index(j+d) if self.grid[ni][nj] < influence_value and new_grid[ni][nj] < 10: new_grid[ni][nj] += 1 elif self.grid[ni][nj] > influence_value and new_grid[ni][nj] > 0: new_grid[ni][nj] -= 1 self.grid = new_grid def run_simulation(self, iterations): """Runs the simulation for a specified number of iterations.""" pygame.init() screen_size = 600 cell_size = screen_size // self.size screen = pygame.display.set_mode((screen_size, screen_size)) clock = pygame.time.Clock() for _ in range(iterations): print("Current Grid:") print(self.grid) self.apply_rules() # Draw the grid for i in range(self.size): for j in range(self.size): colour_value = int((self.grid[i][j] / 10) * 255) # Scale to [0,255] colour = (colour_value, colour_value, colour_value) # Grayscale color pygame.draw.rect(screen, colour, (j * cell_size, i * cell_size, cell_size, cell_size)) pygame.display.flip() # Update the display clock.tick(10) # Control the speed of the simulation # Handle quitting for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if __name__ == "__main__": size = 100 # Size of the grid ca = NumericalCellularAutomaton(size) ca.run_simulation(500) # Run the simulation for 500 iterations 

Rules in English:

  1. Takes place on a square grid that wraps up, down, right and left, so every cell has 8 immediate neighbours.

  2. A given cell's "influence value" is 1 plus the sum of how many of its 8 immediate neighbours are equal in value to itself.

  3. A given cell's distance of influence is just the value in that cell.

  4. "Influence" in practice means that the 4 cells in orthogonal directions from a given cell, at the distance of influence, are incremented or decremented towards its influence value depending on whether the number in each of those cells (before any updates are made) is lower or higher than that value.

  5. All cells are updated simultaneously. Depending on the state of other cells that influence it, each cell might be incremented and/or decremented multiple times in the code before its final value is determined and displayed on the screen as a grayscale colour.

Hopefully if there's any confusion, you can read and run the code to understand better.

I am curious to hear your thoughts, positive or negative, on this general concept and any of its possible uses, including efficiency and whether anyone else has had similar ideas.

I think that the result is a moving texture with enough of the right kind of random motion in it to resemble water, fire or smoke in principle.

Also, I'll add that I tried a few different parameters and versions of this style of numerical CA and they all produced much the same effect. The specific rules I chose are somewhat arbitrary and could be changed whilst retaining the basic concept here.

\$\endgroup\$
3
  • 5
    \$\begingroup\$ While this seems like a great addition for game coding, I feel the question itself would be a better fit for codereview.stackexchange.com to get an actual review/ improvement for your code. To make this question work on this site, you could do a question in the format asking for a way to simulate water/ smoke and use your code (if it works as advertised) as the answer. (There is no problem with self answering question) \$\endgroup\$ Commented Jan 30 at 15:07
  • \$\begingroup\$ Thanks Zibelas, I wasn't sure where would be the best fit for this question and your comment is appreciated! I will repost on that area of the site. \$\endgroup\$ Commented Jan 30 at 15:15
  • 1
    \$\begingroup\$ Sounds like an interesting technique. Whether or not it's efficient enough depends on the context. Depending on their aesthetic priorities & available resources, some games will benefit in trading resources for the output & other won't. We can help you find performance bottlenecks or solutions to visual artifacts, but I don't think we can judge whether or not it's good enough in a general sense. \$\endgroup\$ Commented Jan 30 at 15:37

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.