void Propagate() { // propagate heat to neighbor squares simDir = (simDir + 1) % 2; ParticleMap partMap = gameMap.GetParticleMap(); int _y; int _x; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (simDir == 0) // dir switching { _x = x; _y = y; } else { _x = (width - 1) - x; _y = y; } // Get positions of current cell Point cellPos = new Point(_x, _y); if (partMap.Type(cellPos) == ElementID.WALL) { continue; // skip WALLS } // Get positions of neigbor cells Point neighPos; Point[] neighborPoints = FindNeighbor(cellPos); // cell/neighbor HT = heatTransfer amount float cellHT = Element.elements[partMap.Type(cellPos)].HeatTrans; float neighHT; for (int i = 0; i < 4; i++) { neighPos = neighborPoints[i]; if (neighPos.X == -1 || partMap.Type(neighPos) == ElementID.WALL) { continue; // Out of bounds / WALL } neighHT = Element.elements[partMap.Type(neighPos)].HeatTrans; float flow = map[neighPos.X, neighPos.Y] - map[cellPos.X, cellPos.Y]; if (flow > 0.0f) { flow *= neighHT; } else { flow *= cellHT; } if (i == 0 && flow < 0) // favors upward hot air motion { flow *= flowConstant * 50; } else { flow *= flowConstant; } map[neighPos.X, neighPos.Y] -= flow / neighHT; map[cellPos.X, cellPos.Y] += flow / cellHT; // kill temperature oscilations (can be really confusing) if ((flow > 0.0f && map[neighPos.X, neighPos.Y] < map[cellPos.X, cellPos.Y]) || ( flow <= 0.0f && map[neighPos.X, neighPos.Y] > map[cellPos.X, cellPos.Y])) { float total = (cellHT * map[cellPos.X, cellPos.Y]) + (neighHT * map[neighPos.X, neighPos.Y]); float avg = total / (cellHT + neighHT); map[neighPos.X, neighPos.Y] = avg; map[cellPos.X, cellPos.Y] = avg; } } } } }
public Point UpdatePosition(Point pos, ParticleMap partMap) { if (!this.move) { return(pos); } Point INVALID = new Point(-1, -1); List <Point> possiblePos = new List <Point>(); if (state == 0) // solids { Point DOWN = new Point(pos.X, pos.Y + 1); ElementID typeDOWN = partMap.Type(DOWN); if ((typeDOWN == ElementID.AIR) || (Element.elements[typeDOWN].weight < this.weight)) // heavier sinks { if (MainGame.random.NextDouble() <= 0.9f) // random sideways movement { return(DOWN); } else { Point DOWNLEFT = new Point(pos.X - 1, pos.Y + 1); DOWNLEFT = (partMap.Type(DOWNLEFT) == ElementID.AIR) ? DOWNLEFT : INVALID; Point DOWNRIGHT = new Point(pos.X + 1, pos.Y + 1); DOWNRIGHT = (partMap.Type(DOWNRIGHT) == ElementID.AIR) ? DOWNRIGHT : INVALID; if (DOWNLEFT == INVALID && DOWNRIGHT == INVALID) { return(DOWN); } else if (DOWNLEFT != INVALID && DOWNRIGHT != INVALID) { if (MainGame.random.NextDouble() <= 0.5f) { return(DOWNLEFT); } else { return(DOWNRIGHT); } } else if (DOWNLEFT != INVALID) { return(DOWNLEFT); } else { return(DOWNRIGHT); } } } Point testPos = new Point(); ElementID typeTestPos; for (int _y = 1; _y < 2; _y++) { for (int _x = -1; _x < 2; _x++) { testPos.X = pos.X + _x; testPos.Y = pos.Y + _y; typeTestPos = partMap.Type(testPos); if ((typeTestPos == ElementID.AIR) || (Element.elements[typeTestPos].weight < this.weight)) { possiblePos.Add(testPos); } } } } else if (state == 1) // LIQUID { Point DOWN = new Point(pos.X, pos.Y + 1); ElementID typeDOWN = partMap.Type(DOWN); if ((typeDOWN == ElementID.AIR) || (Element.elements[typeDOWN].weight < this.weight)) // heavier sinks { if (MainGame.random.NextDouble() <= 0.9f) // random sideways movement { return(DOWN); } else { Point DOWNLEFT = new Point(pos.X - 1, pos.Y + 1); DOWNLEFT = (partMap.Type(DOWNLEFT) == ElementID.AIR) ? DOWNLEFT : INVALID; Point DOWNRIGHT = new Point(pos.X + 1, pos.Y + 1); DOWNRIGHT = (partMap.Type(DOWNRIGHT) == ElementID.AIR) ? DOWNRIGHT : INVALID; if (DOWNLEFT == INVALID && DOWNRIGHT == INVALID) { return(DOWN); } else if (DOWNLEFT != INVALID && DOWNRIGHT != INVALID) { if (MainGame.random.NextDouble() <= 0.5f) { return(DOWNLEFT); } else { return(DOWNRIGHT); } } else if (DOWNLEFT != INVALID) { return(DOWNLEFT); } else { return(DOWNRIGHT); } } } Point testPos = new Point(); ElementID typeTestPos; for (int _y = 0; _y < 2; _y++) { for (int _x = -1; _x < 2; _x++) { testPos.X = pos.X + _x; testPos.Y = pos.Y + _y; typeTestPos = partMap.Type(testPos); if ((typeTestPos == ElementID.AIR) || (Element.elements[typeTestPos].weight < this.weight)) { possiblePos.Add(testPos); } } } } else if (state == 2) // GAS { Point UP = new Point(pos.X, pos.Y - 1); ElementID typeUP = partMap.Type(UP); if ((typeUP == ElementID.AIR) || (Element.elements[typeUP].weight < this.weight)) // lighter sinks { if (MainGame.random.NextDouble() <= 0.8f) // random sideways movement { return(UP); } else { Point UPLEFT = new Point(pos.X - 1, pos.Y - 1); UPLEFT = (partMap.Type(UPLEFT) == ElementID.AIR) ? UPLEFT : INVALID; Point UPRIGHT = new Point(pos.X + 1, pos.Y - 1); UPRIGHT = (partMap.Type(UPRIGHT) == ElementID.AIR) ? UPRIGHT : INVALID; if (UPLEFT == INVALID && UPRIGHT == INVALID) { return(UP); } else if (UPLEFT != INVALID && UPRIGHT != INVALID) { if (MainGame.random.NextDouble() <= 0.5f) { return(UPLEFT); } else { return(UPRIGHT); } } else if (UPLEFT != INVALID) { return(UPLEFT); } else { return(UPRIGHT); } } } Point testPos = new Point(); ElementID typeTestPos; for (int _y = 0; _y > -2; _y--) { for (int _x = -1; _x < 2; _x++) { testPos.X = pos.X + _x; testPos.Y = pos.Y + _y; typeTestPos = partMap.Type(testPos); if ((typeTestPos == ElementID.AIR) || (Element.elements[typeTestPos].weight < this.weight)) { possiblePos.Add(testPos); } } } } if (possiblePos.Count != 0) // choose random from possible positions { return(possiblePos[MainGame.random.Next(0, possiblePos.Count)]); } else { return(pos); } }
public bool Eval(Point pos, ParticleMap partMap, out List <ElementID> result, out Point destroy) // true if reaction occured and out is the result element { result = new List <ElementID>() { FROM }; destroy = new Point(-1, -1); if (NEED == ElementID.VOID) // time/prob based reactions { if (random.NextDouble() <= probability) { result = TO; return(true); } } else if (NEED != ElementID.MOLTEN) // element based reactions { int occurence = 0; Point testPos = new Point(); ElementID type; for (int y = -1; y < 2; y++) { for (int x = -1; x < 2; x++) { testPos.X = pos.X + x; testPos.Y = pos.Y + y; type = partMap.Type(testPos); if (type == NEED) { occurence++; if (destroyOther) { destroy = testPos; } } } } if (occurence >= minNEEDAmount) { if (random.NextDouble() <= probability) { result = TO; return(true); } } } else // special reaction with molten elements { ElementID moltenElement = ElementID.VOID; int occurence = 0; Point testPos = new Point(); ElementID type; for (int y = -1; y < 2; y++) { for (int x = -1; x < 2; x++) { testPos.X = pos.X + x; testPos.Y = pos.Y + y; type = partMap.Type(testPos); if (type == ElementID.COPPERMELT || type == ElementID.TINMELT || type == ElementID.BRONZEMELT) { occurence++; moltenElement = type; if (destroyOther) { destroy = testPos; } } } } if (occurence >= minNEEDAmount) { if (random.NextDouble() <= probability) { if (TO[0] == ElementID.MOLTEN) { result = new List <ElementID>() { moltenElement } } ; else { result = TO; } return(true); } } } return(false); }
public ElementID UpdateReaction(Point pos, int lifeTime, bool stable, ParticleMap partMap, TemperatureMap tempMap) { if (!stable) { foreach (Reaction r in this.reactions) // evaluate all possible reactions { if (r.Eval(pos, partMap, out List <ElementID> result, out Point destroy)) { //spawn other results around this particle for (int i = 1; i < result.Count; i++) { if (partMap.Type(new Point(pos.X, pos.Y - 1)) == ElementID.AIR) { partMap.SpawnLater(result[i], new Point(pos.X, pos.Y - 1), 1); } else if (partMap.Type(new Point(pos.X, pos.Y + 1)) == ElementID.AIR) { partMap.SpawnLater(result[i], new Point(pos.X, pos.Y + 1), 1); } else if (partMap.Type(new Point(pos.X - 1, pos.Y)) == ElementID.AIR) { partMap.SpawnLater(result[i], new Point(pos.X - 1, pos.Y), 1); } else if (partMap.Type(new Point(pos.X + 1, pos.Y)) == ElementID.AIR) { partMap.SpawnLater(result[i], new Point(pos.X + 1, pos.Y), 1); } } if (partMap.InBounds(destroy)) { partMap.DeleteLater(destroy, 0); } return(result[0]); } } } // evaluate preset transitional reactons if (lowLevelTempTransition != null && tempMap.Get(pos) <= lowLevelTemp) { if (lowLevelTempTransition.Eval(pos, partMap, out List <ElementID> result, out Point destroy)) { tempMap.Set(pos, 0, tempMap.Get(pos) * 1.05f); return(result[0]); } } if (highLevelTempTransition != null && tempMap.Get(pos) >= highLevelTemp) { if (highLevelTempTransition.Eval(pos, partMap, out List <ElementID> result, out Point destroy)) { tempMap.Set(pos, 0, tempMap.Get(pos) * 0.95f); return(result[0]); } } if (endOfLifeTransition != null && lifeTime > this.maxLifeTime) { if (endOfLifeTransition.Eval(pos, partMap, out List <ElementID> result, out Point destroy)) { return(result[0]); } } return(this.ID); }
void Propagate() { simDir = (simDir + 1) % 2; ParticleMap partMap = gameMap.GetParticleMap(); int _y; int _x; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (simDir == 0) // dir switching { _x = x; _y = y; } else { _x = (width - 1) - x; _y = y; } // Get positions of current cell Point cellPos = new Point(_x, _y); if (partMap.Type(cellPos) == ElementID.WALL) { continue; // skip WALLS } float remainingMass = map[cellPos.X, cellPos.Y]; // Get positions of neigbor cells Point neighPos; Point[] neighborPoints = FindNeighbor(cellPos); for (int i = 0; i < 4; i++) { float flow = 0; neighPos = neighborPoints[i]; if (neighPos.X == -1) { continue; // out of bounds } if (partMap.Type(neighPos) == ElementID.WALL) { continue; // skip WALLS } if (remainingMass <= 0) { break; } if (i == 0) // below { flow = GetStable(remainingMass + map[neighPos.X, neighPos.Y]) - map[neighPos.X, neighPos.Y]; } else if (i == 1 || i == 2) // left/right { flow = (map[cellPos.X, cellPos.Y] - map[neighPos.X, neighPos.Y]) / 2; } else if (i == 3) // upwards { flow = remainingMass - GetStable(remainingMass + map[neighPos.X, neighPos.Y]); } /* if (flow > MinFlow) */ /* flow *= 0.5f; */ // constrain flow if (flow < 0) { flow = 0; } if (flow > remainingMass) { flow = remainingMass; } remainingMass -= flow; map[cellPos.X, cellPos.Y] -= flow; map[neighPos.X, neighPos.Y] += flow; } } } for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { /* map[x,y] += newMap[x,y]; */ newMap[x, y] = 0; if (map[x, y] > MinMass) { elementMap[x, y] = ElementID.WATER; } else { elementMap[x, y] = ElementID.AIR; map[x, y] = 0; } } } }