public FluidSimulation(World world, SpriteBatch spriteBatch, SpriteFont font) { _world = world; _spriteBatch = spriteBatch; _font = font; _activeParticles = new List<int>(MAX_PARTICLES); _liquid = new FluidParticle[MAX_PARTICLES]; _liquidDelete = new FluidParticle[MAX_PARTICLES]; for (int i = 0; i < MAX_PARTICLES; i++) { _liquid[i] = new FluidParticle(Vector2.Zero, Vector2.Zero, false); _liquid[i].index = i; } _delta = new Vector2[MAX_PARTICLES]; _scaledPositions = new Vector2[MAX_PARTICLES]; _scaledVelocities = new Vector2[MAX_PARTICLES]; _grid = new Dictionary<int, Dictionary<int, List<int>>>(); _pixel = new Texture2D(_spriteBatch.GraphicsDevice, 1, 1); _pixel.SetData<Color>(new[] { Color.White }); _random = new Random(); _halfScreen = new Vector2( _spriteBatch.GraphicsDevice.Viewport.Width, _spriteBatch.GraphicsDevice.Viewport.Height) / 2f; _simulationAABB.LowerBound.X = -(_halfScreen.X + 100f); _simulationAABB.LowerBound.Y = -(_halfScreen.Y + 100f); _simulationAABB.UpperBound.X = _halfScreen.X + 100f; _simulationAABB.UpperBound.Y = _halfScreen.Y + 100f; }
private void findNeighbors(FluidParticle particle) { particle.neighborCount = 0; Dictionary<int, List<int>> gridX; List<int> gridY; for (int nx = -1; nx < 2; nx++) { for (int ny = -1; ny < 2; ny++) { int x = particle.ci + nx; int y = particle.cj + ny; if (_grid.TryGetValue(x, out gridX) && gridX.TryGetValue(y, out gridY)) { for (int a = 0; a < gridY.Count; a++) { if (gridY[a] != particle.index) { particle.neighbors[particle.neighborCount] = gridY[a]; particle.neighborCount++; if (particle.neighborCount >= MAX_NEIGHBORS) return; } } } } } }
public void update() { MouseState mouseState = Mouse.GetState(); _halfScreen = new Vector2( _spriteBatch.GraphicsDevice.Viewport.Width, _spriteBatch.GraphicsDevice.Viewport.Height) / 2f; //_mouse = (new Vector2(mouseState.X, mouseState.Y) - _halfScreen) / Game1.scale; //_mouse = new Vector2(Game1.mouseTruePos.X*Game1.scale, Game1.mouseTruePos.Y*Game1.scale); _mouse = new Vector2(Game1.mouseTruePos.X, Game1.mouseTruePos.Y); if (mouseState.LeftButton == ButtonState.Pressed && !Game1.strafeMode) createParticle(); // Prepare simulation Parallel.For(0, _numActiveParticles, i => { prepareSimulation(_activeParticles[i]); }); // Prepare collisions prepareCollisions(); // Calculate pressures Parallel.For(0, _numActiveParticles, i => { calculatePressure(_activeParticles[i]); }); // Calculate forces Parallel.For( 0, _numActiveParticles, () => new Vector2[MAX_PARTICLES], (i, state, accumulatedDelta) => calculateForce(_activeParticles[i], accumulatedDelta), (accumulatedDelta) => { lock (_calculateForcesLock) { for (int i = _numActiveParticles - 1; i >= 0; i--) { int index = _activeParticles[i]; _delta[index] += accumulatedDelta[index] / MULTIPLIER; } } } ); // Resolve collisions Parallel.For(0, _numActiveParticles, i => resolveCollision(_activeParticles[i])); /*for (int i = 0; i < _numActiveParticles; i++) { FluidParticle particle = _liquid[_activeParticles[i]]; //_spriteBatch.Draw(_pixel, new Vector2(2400,1800), new Rectangle(0, 0, 20, 20), Color.Black, 0f, new Vector2(1, 1), 1f, SpriteEffects.None, 0f); //Game1.checkGridLiquid(new Vector2(((float)particle.position.X + (particle.position.X-particle.oldPosition.X)/10)*Game1.scale, ((float)particle.position.Y + (particle.position.Y - particle.oldPosition.Y)/10))*Game1.scale); Game1.checkGridLiquid(new Vector2(((float)particle.position.X + (particle.position.X - particle.oldPosition.X)), ((float)particle.position.Y + (particle.position.Y - particle.oldPosition.Y)))); //Game1.checkGridLiquid(new Vector2((float)particle.position.X, (float)particle.position.Y)); //_spriteBatch.Draw(_pixel, (particle.position) * Game1.scale, new Rectangle(0, 0, 2, 2), Color.DarkBlue, 0f, new Vector2(1, 1), 1f, SpriteEffects.None, 0f); }*/ foreach (KeyValuePair<int, Dictionary<int, List<int>>> row1 in _grid) { foreach (KeyValuePair<int, List<int>> row2 in row1.Value) { Game1.checkGridLiquid(new Vector2((float)row1.Key * CELL_SIZE, (float)row2.Key * CELL_SIZE)); } } bool delete; for (int i = 0; i < _numActiveParticles; i++) { FluidParticle particle = _liquid[_activeParticles[i]]; delete = Game1.checkParticle(new Vector2(((float)particle.position.X + (particle.position.X - particle.oldPosition.X)), ((float)particle.position.Y + (particle.position.Y - particle.oldPosition.Y)))); if (delete) { particle.velocity = new Vector2(0, 0); //particle.position = particle.oldPosition; } //if(particle.position.X } // Update particle cells for (int i = 0; i < _numActiveParticles; i++) moveParticle(_activeParticles[i]); if (clearParticles) { //_activeParticles.Clear(); _activeParticles = new List<int>(MAX_PARTICLES); _liquid = new FluidParticle[MAX_PARTICLES]; for (int i = 0; i < MAX_PARTICLES; i++) { _liquid[i] = new FluidParticle(Vector2.Zero, Vector2.Zero, false); _liquid[i].index = i; } _delta = new Vector2[MAX_PARTICLES]; _scaledPositions = new Vector2[MAX_PARTICLES]; _scaledVelocities = new Vector2[MAX_PARTICLES]; _grid = new Dictionary<int, Dictionary<int, List<int>>>(); _numActiveParticles = 0; clearParticles = false; } }