/// <summary> /// Tries to generate particles. May return null if the generator is eiher empty /// or the random attempt failed /// </summary> /// <returns></returns> public Particle[] Generate(TableDepositor system, double counter) { GeneratorSettings settings = (settings_allowed) ? this.settings : this.baseSettings; generatingStep++; if (generatingStep > (PhysicSettings.Instance().DEFAULT_GENERATING_SPEED - settings.generatingSpeed)) { // coefficient of regularity int coeff = settings.Regular_generating ? 1 : (CommonAttribService.apiRandom.Next(5) + 1); int arrayLength = (int)((settings.generatingSpeed / coeff) * ((A_Rock)this).Intensity / 100); if (arrayLength <= 0) { return(null); } Particle[] output = new Particle[arrayLength]; for (int i = 0; i < output.Length; i++) { output[i] = GenerateParticle(counter); // start over generatingStep = 0; } generatingNumber++; return(output); } else { return(null); } }
/// <summary> /// Renders stones as tiny squares (mainly for debugging and polishing) /// </summary> /// <param name="objects"></param> private void DrawRocks(TableDepositor objects) { foreach (Graviton grv in objects.gravitons) { FPoint pos = new FPoint(grv.Position.X + CommonAttribService.ACTUAL_TABLE_WIDTH / 2, grv.Position.Y + CommonAttribService.ACTUAL_TABLE_HEIGHT / 2); pos.X *= ratioX; pos.Y *= ratioY; DrawSquare((int)pos.X, (int)pos.Y, 5, color_graviton); } foreach (Magneton grv in objects.magnetons) { FPoint pos = new FPoint(grv.Position.X + CommonAttribService.ACTUAL_TABLE_WIDTH / 2, grv.Position.Y + CommonAttribService.ACTUAL_TABLE_HEIGHT / 2); pos.X *= ratioX; pos.Y *= ratioY; DrawSquare((int)pos.X, (int)pos.Y, 5, color_magneton); } foreach (BlackHole grv in objects.blackHoles) { FPoint pos = new FPoint(grv.Position.X + CommonAttribService.ACTUAL_TABLE_WIDTH / 2, grv.Position.Y + CommonAttribService.ACTUAL_TABLE_HEIGHT / 2); pos.X *= ratioX; pos.Y *= ratioY; DrawSquare((int)pos.X, (int)pos.Y, 8, color_blackHole); } foreach (Generator grv in objects.generators) { FPoint pos = new FPoint(grv.Position.X + CommonAttribService.ACTUAL_TABLE_WIDTH / 2, grv.Position.Y + CommonAttribService.ACTUAL_TABLE_HEIGHT / 2); pos.X *= ratioX; pos.Y *= ratioY; DrawSquare((int)pos.X, (int)pos.Y, 5, color_generator); } }
/// <summary> /// Renders the system /// </summary> /// <param name="objects"></param> public void Repaint(TableDepositor objects) { if (CommonAttribService.OUTPUT_DRAW_ALLOWED) { BitmapSource bmp = null; if (GraphicsSettings.Instance().OUTPUT_TABLE_SIZE_DEPENDENT) { bmp = tableDrawingManager.CreateBitmap(objects, true); } else { if (((int)tableDrawingManager.actual_size.X) != CommonAttribService.ACTUAL_OUTPUT_WIDTH) { tableDrawingManager.Resize(CommonAttribService.ACTUAL_OUTPUT_WIDTH, (int)(CommonAttribService.ACTUAL_TABLE_HEIGHT * (((double)CommonAttribService.ACTUAL_OUTPUT_WIDTH) / CommonAttribService.ACTUAL_TABLE_WIDTH))); } bmp = tableDrawingManager.CreateBitmap(objects, false); } if (bmp != null) { tableImage.Source = bmp; tableImage.Width = ActualWidth; tableImage.Height = ActualHeight; } } }
/// <summary> /// Renders the system into the window /// </summary> /// <param name="objects"></param> public void Repaint(TableDepositor objects) { if (CommonAttribService.SIMULATION_DRAW_ALLOWED) { BitmapSource bmp = null; // if both outputs are enabled, let's just take the picture from the OpenGL window if (CommonAttribService.OUTPUT_DRAW_ALLOWED && !CommonAttribService.MODE_2D) { bmp = CommonAttribService.LAST_BITMAP; } else { bmp = tableDrawingManager.CreateBitmap(objects, true); } if (bmp != null) { if (tableImage == null) { tableImage = new Image(); } tableImage.Source = bmp; tableImage.Width = ActualWidth; tableImage.Height = ActualHeight; tableImage.HorizontalAlignment = HorizontalAlignment.Left; tableImage.VerticalAlignment = VerticalAlignment.Top; if (!tableGrid.Children.Contains(tableImage)) { tableGrid.Children.Add(tableImage); } } } }
private static void DeleteBufferedParticles(TableDepositor system) { foreach (Particle part in deletedParticles) { system.particles.Remove(part); } deletedParticles.Clear(); }
/// <summary> /// Processes gravitons for one particle /// </summary> /// <param name="system"></param> /// <param name="part"></param> public static void ProcessGravitons(TableDepositor system, Particle part) { temp.X = 0; temp.Y = 0; foreach (Graviton ig in system.gravitons) { GravitonSettings settings = (ig.Settings_Allowed) ? ig.Settings : system.table.Settings.gravitonSettings; double length = (part.Position.X - ig.Position.X) * (part.Position.X - ig.Position.X) + (part.Position.Y - ig.Position.Y) * (part.Position.Y - ig.Position.Y); //================================================= // GRAVITY: // g = CONST*M/(radius/11 + 14), //================================================= // fix treshold double acc = (PhysicSettings.Instance().DEFAULT_GRAVITY_CONSTANT *ig.Settings.weigh) / (length / 114 + 14) * (((A_Rock)ig).Intensity / 100); double sqrt_length = Math.Sqrt(length); if (sqrt_length < 20) { acc *= -Math.Log(sqrt_length - Math.Min(20, sqrt_length - 2)); } // pulsar if (settings.Energy_pulsing) { acc /= (1 + Math.Tan(settings.Energy_pulse_speed) / 10); } // calculate velocity if (PhysicsSettings.gravitationMode == GravitationMode.ADITIVE) { temp.Add(acc * ((ig.Position.X - part.Position.X) / Math.Sqrt(length)), acc * ((ig.Position.Y - part.Position.Y) / Math.Sqrt(length))); } else if (PhysicsSettings.gravitationMode == GravitationMode.AVERAGE) { temp.Add(1 / (acc * ((ig.Position.X - part.Position.X) / Math.Sqrt(length))), 1 / (acc * ((ig.Position.Y - part.Position.Y) / Math.Sqrt(length)))); } else if (PhysicsSettings.gravitationMode == GravitationMode.MULTIPLY) { temp.Add(acc * ((ig.Position.X - part.Position.X) / Math.Log(length)), acc * ((ig.Position.Y - part.Position.Y) / Math.Log(length))); } } if (PhysicsSettings.gravitationMode == GravitationMode.AVERAGE) { temp.Invert(); } part.Vector_Acceleration.Add(temp); }
/// <summary> /// Transforms the system from to another state /// </summary> /// <param name="system"></param> public static void TransformSystem(TableDepositor system) { counter++; try { if (system.table.Settings.generatorSettings.enabled) { ProcessGenerators(system); // generate new particles } ProcessParticles(system); // process particles } catch { // .... no-op here } }
/// <summary> /// Processes all particles /// </summary> private static void ProcessParticles(TableDepositor system) { double tableWidth = CommonAttribService.ACTUAL_TABLE_WIDTH; double tableHeight = CommonAttribService.ACTUAL_TABLE_HEIGHT; foreach (Particle part in system.particles) { // size change if (PhysicsSettings.particle_sizeChanging_allowed) { FixParticleSizeChange(part, system); } // reset acceleration - it will be recalculated part.Vector_Acceleration.X = 0; part.Vector_Acceleration.Y = 0; // process stones ProcessParticleStoneInterraction(part, system); // set all new values part.Position = new FPoint(part.Position.X + part.Vector_Velocity.X, part.Position.Y + part.Vector_Velocity.Y); // table gravity if (system.table.Settings.gravity_allowed) { part.Vector_Acceleration.X += 0.1 * system.table.Settings.gravity.X; part.Vector_Acceleration.Y += 0.1 * system.table.Settings.gravity.Y; } part.Vector_Velocity.Add(part.Vector_Acceleration); // loosing energy if (system.table.Settings.energy_loosing || system.table.Settings.energy_loosing) { FixParticleEnergyLoosing(part, system); } // collision with the borders of the table if (system.table.Settings.interaction) { FixParticleTableInterraction(part, system, tableWidth, tableHeight); } } // delete particles that are to be deleted DeleteBufferedParticles(system); }
/// <summary> /// Processes all particle generators /// </summary> /// <param name="system"></param> private static void ProcessGenerators(TableDepositor system) { foreach (Generator ab in system.generators) { Particle[] obj = ab.Generate(system, counter); // try to generate new particles if (obj != null) // add new particles to the system { for (int i = 0; i < obj.Length; i++) { system.particles.Add(obj[i]); } } } }
/// <summary> /// Change particle energy /// </summary> /// <param name="part"></param> /// <param name="system"></param> private static void FixParticleEnergyLoosing(Particle part, TableDepositor system) { // if the value is -1, we will use global settings if (system.table.Settings.energy_loosing_speed != -1) { part.Vector_Velocity.Mult(1 - system.table.Settings.energy_loosing_speed / PhysicSettings.Instance().DEFAULT_ENERGY_TABLE_LOOSING_SPEED_MAX, 1 - system.table.Settings.energy_loosing_speed / PhysicSettings.Instance().DEFAULT_ENERGY_TABLE_LOOSING_SPEED_MAX); } else { part.Vector_Velocity.Mult(1 - system.table.Settings.energy_loosing_speed / PhysicSettings.Instance().DEFAULT_ENERGY_TABLE_LOOSING_SPEED_MAX, 1 - system.table.Settings.energy_loosing_speed / PhysicSettings.Instance().DEFAULT_ENERGY_TABLE_LOOSING_SPEED_MAX); } }
/// <summary> /// Process interaction between particles and stones /// </summary> private static void ProcessParticleStoneInterraction(Particle part, TableDepositor system) { if (system.table.Settings.blackHoleSettings.enabled) { ProcessBlackHoles(system, part); } if (system.table.Settings.gravitonSettings.enabled) { ProcessGravitons(system, part); } if (system.table.Settings.magnetonSettings.enabled) { ProcessMagnetons(system, part); } }
/// <summary> /// Processes magnetons for one particle /// </summary> public static void ProcessMagnetons(TableDepositor system, Particle part) { temp.X = 0; temp.Y = 0; foreach (Magneton ig in system.magnetons) { MagnetonSettings settings = (ig.Settings_Allowed) ? ig.Settings : system.table.Settings.magnetonSettings; // calculate distance between the particle and the stone double length = (part.Position.X - ig.Position.X) * (part.Position.X - ig.Position.X) + (part.Position.Y - ig.Position.Y) * (part.Position.Y - ig.Position.Y); double acc = (PhysicSettings.Instance().DEFAULT_MAGNETON_CONSTANT *ig.Settings.force) / (length / 114 + 14) * (((A_Rock)ig).Intensity / 100); // pulsar if (settings.Energy_pulsing) { acc /= (1 + Math.Tan(counter * settings.Energy_pulse_speed) / 10); } if (PhysicsSettings.magnetismMode == MagnetismMode.ADITIVE) { temp.Add(-acc * ((ig.Position.X - part.Position.X) / Math.Sqrt(length)), -acc * ((ig.Position.Y - part.Position.Y) / Math.Sqrt(length))); } else if (PhysicsSettings.magnetismMode == MagnetismMode.AVERAGE) { temp.Add(1 / (-acc * ((ig.Position.X - part.Position.X) / Math.Sqrt(length))), 1 / (-acc * ((ig.Position.Y - part.Position.Y) / Math.Sqrt(length)))); } else if (PhysicsSettings.magnetismMode == MagnetismMode.MULTIPLY) { temp.Add(-acc * ((ig.Position.X - part.Position.X) / Math.Log(length)), -acc * ((ig.Position.Y - part.Position.Y) / Math.Log(length))); } } if (PhysicsSettings.magnetismMode == MagnetismMode.AVERAGE) { temp.Invert(); } part.Vector_Acceleration.Add(temp); }
/// <summary> /// Change particle velocity if it interacts with borders of the table /// </summary> private static void FixParticleTableInterraction(Particle part, TableDepositor system, double tableWidth, double tableHeight) { if (part.Position.X < -tableWidth / 2 && part.Vector_Velocity.X < 0) { part.Vector_Velocity.Mult(-1, 1); } if (part.Position.X > tableWidth / 2 && part.Vector_Velocity.X > 0) { part.Vector_Velocity.Mult(-1, 1); } if (part.Position.Y < -tableHeight / 2 && part.Vector_Velocity.Y < 0) { part.Vector_Velocity.Mult(1, -1); } if (part.Position.Y > tableHeight / 2 && part.Vector_Velocity.Y > 0) { part.Vector_Velocity.Mult(1, -1); } }
/// <summary> /// Change particle sizes due various attributse /// </summary> private static void FixParticleSizeChange(Particle part, TableDepositor system) { if (PhysicsSettings.particle_sizeMode == ParticleSizeMode.GRAVITY) { part.Settings.size = 1 + (part.Vector_Acceleration.X * part.Vector_Acceleration.X + part.Vector_Acceleration.Y * part.Vector_Acceleration.Y); } else if (PhysicsSettings.particle_sizeMode == ParticleSizeMode.VELOCITY) { part.Settings.size = 1 + part.Vector_Velocity.Size(); } else if (PhysicsSettings.particle_sizeMode == ParticleSizeMode.WEIGH) { part.Settings.size = part.Settings.weigh * 2; } else if (PhysicsSettings.particle_sizeMode == ParticleSizeMode.NONE) { part.Settings.size = part.Settings.originSize; } }
public RealTableManager(TableDepositor system) { this.system = system; }
/// <summary> /// Draws a grid that determines gravity force /// </summary> /// <param name="objects"></param> private void DrawLines(TableDepositor objects) { DateTime pk = DateTime.Now; int row_pixel = (((int)(CommonAttribService.ACTUAL_TABLE_HEIGHT * ratioY)) / 20); int col_pixel = row_pixel; for (int i = 0; i < ((int)(ratioY * CommonAttribService.ACTUAL_TABLE_HEIGHT)); i += row_pixel) { for (int j = 0; j < ((int)(ratioX * CommonAttribService.ACTUAL_TABLE_WIDTH)); j += col_pixel) { int orig_col = j; int orig_row = i; // original position of the point int orig_position_x = orig_col - ((int)(ratioX * CommonAttribService.ACTUAL_TABLE_WIDTH)) / 2; int orig_position_y = orig_row - ((int)(ratioY * CommonAttribService.ACTUAL_TABLE_HEIGHT)) / 2; double temp_position_x = orig_position_x; double temp_position_y = orig_position_y; double shift_x = 0; double shift_y = 0; foreach (Graviton gr in objects.gravitons) { // calc distance between the original point and the graviton double length = Math.Sqrt((temp_position_x - gr.Position.X) * (temp_position_x - gr.Position.X) + (temp_position_y - gr.Position.Y) * (temp_position_y - gr.Position.Y)); // calculate potential double acc = (PhysicSettings.Instance().DEFAULT_GRAVITY_CONSTANT *gr.Settings.weigh) / ((length * length / 100 + 10)); // shift the grid point shift_x += acc * (gr.Position.X - temp_position_x) / (0.1 * gr.Settings.weigh); shift_y += acc * (gr.Position.Y - temp_position_y) / (0.1 * gr.Settings.weigh); temp_position_x = orig_position_x + shift_x; temp_position_y = orig_position_y + shift_y; } foreach (Magneton mg in objects.magnetons) { double length = Math.Sqrt((temp_position_x - mg.Position.X) * (temp_position_x - mg.Position.X) + (temp_position_y - mg.Position.Y) * (temp_position_y - mg.Position.Y)); double acc = (PhysicSettings.Instance().DEFAULT_GRAVITY_CONSTANT *mg.Settings.force) / ((length * length / 100 + 10)); shift_x -= acc * (mg.Position.X - temp_position_x); shift_y -= acc * (mg.Position.Y - temp_position_y); temp_position_x = orig_position_x + shift_x; temp_position_y = orig_position_y + shift_y; } foreach (BlackHole mg in objects.blackHoles) { double length = Math.Sqrt((temp_position_x - mg.Position.X) * (temp_position_x - mg.Position.X) + (temp_position_y - mg.Position.Y) * (temp_position_y - mg.Position.Y)); double acc = (PhysicSettings.Instance().DEFAULT_GRAVITY_CONSTANT * 80) / ((length * length / 100 + 10)); shift_x += acc * (mg.Position.X - temp_position_x); shift_y += acc * (mg.Position.Y - temp_position_y); temp_position_x = orig_position_x + shift_x; temp_position_y = orig_position_y + shift_y; } // shift the position of the grid point int other_position_x = (int)(orig_col + shift_x); int other_position_y = (int)(orig_row + shift_y); int posX = (int)other_position_x; int posY = (int)other_position_y; DrawRectangle((int)posX, (int)posY, 1, 3, 0xFF333333); DrawRectangle((int)posX, (int)posY, 3, 1, 0xFF333333); } } }
private DateTime last_render = DateTime.Now; // time of the last render public TableManager() { this.tableDepositor = new TableDepositor(); inputManager = new InputManager(this); }
/// <summary> /// Process black holes for one particle /// </summary> public static void ProcessBlackHoles(TableDepositor system, Particle part) { foreach (BlackHole blackH in system.blackHoles) { BlackHoleSettings settings = (blackH.Settings_Allowed) ? blackH.Settings : system.table.Settings.blackHoleSettings; // distance between the particle and the stone double length = Math.Sqrt((part.Position.X - blackH.Position.X) * (part.Position.X - blackH.Position.X) + (part.Position.Y - blackH.Position.Y) * (part.Position.Y - blackH.Position.Y)); // if the distance is within the treshold, we will remove it if (length < blackH.Radius) { if (PhysicsSettings.absorptionMode == AbsorptionMode.BLACKHOLE) { deletedParticles.Add(part); } else if (PhysicsSettings.absorptionMode == AbsorptionMode.RECYCLE) { // if the recycling is enabled, just find an appropriate generator and give it the deleted particle if (system.generators.Count > 0) { system.generators.ElementAt(CommonAttribService.apiRandom.Next(system.generators.Count - 1)).generatingNumber--; deletedParticles.Add(part); } } else if (PhysicsSettings.absorptionMode == AbsorptionMode.SELECT) { if (CommonAttribService.apiRandom.Next(50) == 40) { deletedParticles.Add(part); } } return; } // creepy gravity acceleration double acc = (PhysicSettings.Instance().DEFAULT_GRAVITY_CONSTANT *settings.weigh) / (Math.Log(length * length) / 114 + 14) * (((A_Rock)blackH).Intensity / 100); double dist_x = (blackH.Position.X - part.Position.X); double dist_y = (blackH.Position.Y - part.Position.Y); double celk = length * 1.5; // pulsar if (settings.Energy_pulsing) { acc /= (1 + Math.Tan(counter * settings.Energy_pulse_speed) / (4 + 4 * Math.Log10(length))); } part.Vector_Acceleration.Add(0.5 * acc * ((dist_x) / length), 0.5 * acc * ((dist_y) / length)); // this is really creepy but it works if (dist_x > 0 && (-dist_y) > 0) { dist_y *= length / 4; } else if (dist_x > 0 && (-dist_y) < 0) { dist_x *= length / 4; } else if (dist_x < 0 && (-dist_y) > 0) { dist_x *= length / 4; } else if (dist_x < 0 && (-dist_y) < 0) { dist_y *= length / 4; } // add gravityy acceleration part.Vector_Acceleration.Add((-dist_y / celk) / 30, (dist_x / celk) / 30); } }
/// <summary> /// Creates an image of a table system /// </summary> /// <returns></returns> public BitmapSource CreateBitmap(TableDepositor objects, Boolean isTableSized) { try { renderCounter++; // used for garbage collector // invoke GC if (renderCounter > 30) { renderCounter = 0; GC.Collect(); } ratioX = actual_size.X / CommonAttribService.ACTUAL_TABLE_WIDTH; ratioY = actual_size.Y / CommonAttribService.ACTUAL_TABLE_HEIGHT; color_particle = 0x00000000 + (uint)(255 << 24 | GraphicsSettings.Instance().DEFAULT_PARTICLE_COLOR_R << 16 | GraphicsSettings.Instance().DEFAULT_PARTICLE_COLOR_G << 8 | GraphicsSettings.Instance().DEFAULT_PARTICLE_COLOR_B); // check resizing if (isTableSized) { if (pixelData.Length != (int)(CommonAttribService.ACTUAL_TABLE_HEIGHT * CommonAttribService.ACTUAL_TABLE_WIDTH)) { pixelData = new UInt32[(int)(CommonAttribService.ACTUAL_TABLE_HEIGHT * CommonAttribService.ACTUAL_TABLE_WIDTH)]; actual_size.X = CommonAttribService.ACTUAL_TABLE_WIDTH; actual_size.Y = CommonAttribService.ACTUAL_TABLE_HEIGHT; } } // remove pixel buffer for (int i = 0; i < pixelData.Length; i++) { pixelData[i] = 0xFF000000; } if (GraphicsSettings.Instance().DEFAULT_GRID_ENABLED) { DrawLines(objects); // draw grid } // draw particles foreach (Particle part in objects.particles) { DrawParticle(part); } // draw stones if (GraphicsSettings.Instance().DEFAULT_OUTPUT_ROCK_DISPLAY) { DrawRocks(objects); } // create a bitmap for pixel array BitmapSource bmp = BitmapSource.Create((int)actual_size.X, (int)actual_size.Y, 96, 96, PixelFormats.Bgra32, null, pixelData, ((((int)actual_size.X * 32 + 31) & ~31) / 8)); CommonAttribService.LAST_BITMAP = bmp; return(bmp); } catch { // no-op here } return(null); }