// Projects the powerup position downwards to rest on the ground public void ProjectDownwards(BlockWorld world) { // Don't project downwards if not falling anymore! if (!isFalling) { return; } // Speed and gravity fall if (Type != PowerupType.Speed && Type != PowerupType.Gravity) { return; } // Get nearest two horizontal indices int i1 = World.XToI(X - 64.0f); // HACK: Powerup size better not change int i2 = i1 + 1; // Increase y until hit ground float y = World.FloorLevel; for (int j = 0; j < World.BlocksHeight; j++) { if (world.CheckGroundByIndex(i1, j) || world.CheckGroundByIndex(i2, j)) { break; } y += World.BlockSize; } }
override public bool Level2GoalFunction(BlockWorld blockWorld) { int playerI = blockWorld.Player.I; int playerJ = blockWorld.Player.J; int opponentI = Level2DangerZone.SourceI; int opponentJ = Level2DangerZone.SourceJ; // Check distance if (Util.ManhattanDistance(playerI, playerJ, opponentI, opponentJ) <= RunAwayBlockDistance) { return(false); } // Enforce no ground above bool groundAbove = false; for (int j = playerJ; j >= 0; j--) { if (blockWorld.CheckGroundByIndex(playerI, j)) { groundAbove = true; break; } } if (groundAbove) { return(false); } // Enforce no danger if (Level2DangerZone.CheckDanger(playerI, playerJ) != 0.0f) { return(false); } return(true); }
// Recursively add danger to the 2D array void addDangerToBlockAndNeighbors(int i, int j, WeaponType type, float probability, int ammo, bool facingRight, BlockWorld blockWorld, bool isFalling = false) { // Base cases if (probability < epsilon) { return; } if (ammo == 0) { return; // Master mode has negative ammo - do not return } // Blow out ground if there is any at the current position. If there is if (blockWorld.CheckGroundByIndex(i, j)) { // Another base case for immutable ground bool immutable = blockWorld.CheckGroundImmutableByIndex(i, j); if (immutable) { return; // End of the line } // Blow out ground otherwise blockWorld.SetGroundByIndex(i, j, false); addDangerToBlockAndNeighbors(i, j, type, probability * groundBlowoutFactor, ammo - 1, facingRight, blockWorld); return; } else { int normalized = facingRight ? -1 : 1; switch (type) { case WeaponType.Rockets: { addDanger(i, j, probability * RocketsDangerWeight); addDangerToBlockAndNeighbors(i + normalized, j, type, probability, ammo, facingRight, blockWorld); break; } case WeaponType.Bombs: { addDanger(i, j, probability * BombsDangerWeight); addDangerToBlockAndNeighbors(i, j + 1, type, probability, ammo, facingRight, blockWorld); break; } case WeaponType.Minions: { addDanger(i, j, probability * MinionsDangerWeight); bool groundDown = blockWorld.CheckGroundByIndex(i, j + 1); bool groundRight = blockWorld.CheckGroundByIndex(i + normalized, j); bool goRight = false; bool goDown = false; // Do natural motion - right first unless hasn't fallen if (!groundRight && !groundDown) { if (isFalling && blockWorld.CheckGroundByIndex(i + normalized, j + 1)) { goRight = true; } else { goDown = true; } } else if (!groundRight && groundDown) { goRight = true; } else if (groundRight && !groundDown) { goDown = true; } else { // Block worlds diverge, so make a new one BlockWorld newBlockWorld = blockWorld.Clone(); // Go both directions addDangerToBlockAndNeighbors(i + normalized, j, type, probability / 2.0f, ammo, facingRight, blockWorld, false); addDangerToBlockAndNeighbors(i, j + 1, type, probability / 2.0f, ammo, facingRight, newBlockWorld, true); } // Do sole motions if (goRight) { addDangerToBlockAndNeighbors(i + normalized, j, type, probability, ammo, facingRight, blockWorld, false); return; } if (goDown) { addDangerToBlockAndNeighbors(i, j + 1, type, probability, ammo, facingRight, blockWorld, true); return; } break; } } } }
// Computes a belief distribution for the projectile sources void computeSourceBeliefs(int playerNum, World world) { // Find player World.Player player = playerNum == 1 ? world.Player1 : world.Player2; int playerI = World.XToI(player.X); int playerJ = World.YToJ(player.Y); sourceI = playerI; sourceJ = playerJ; // The initial source is at the player ProjectileSourceBelief initial = new ProjectileSourceBelief(1.0f, player.Ammo, player.Weapon); sourceBeliefs.Add(new IJCoords(playerI, playerJ), initial); // Compute distribution of projectile sources for (int iter = 0; iter < DistributionSteps; iter++) { Dictionary <IJCoords, ProjectileSourceBelief> newBeliefs = new Dictionary <IJCoords, ProjectileSourceBelief>(); float newBeliefsTotal = 0.0f; // Advance our belief state, except keep the old one around for efficiency foreach (KeyValuePair <IJCoords, ProjectileSourceBelief> entry in sourceBeliefs) { ProjectileSourceBelief belief = entry.Value; int i = entry.Key.I; int j = entry.Key.J; float prior = belief.Probability; // Determine possible directions bool upPossible = false; bool leftPossible = false; bool rightPossible = false; bool downPossible = false; bool stayPossible = false; int numPossibleDirections = 0; bool supported = blockWorld.CheckPositionSupported(i, j); if (!supported) { // Can only move down from unsupported positions numPossibleDirections++; downPossible = true; } else { stayPossible = true; numPossibleDirections++; if (!blockWorld.CheckGroundByIndex(i, j + 1)) { downPossible = true; numPossibleDirections++; } if (!blockWorld.CheckGroundByIndex(i + 1, j)) { leftPossible = true; numPossibleDirections++; } if (!blockWorld.CheckGroundByIndex(i - 1, j)) { rightPossible = true; numPossibleDirections++; } if (!blockWorld.CheckGroundByIndex(i, j - 1)) { upPossible = true; numPossibleDirections++; } } // Compute chance of each direction - uniform float chance = 1.0f / numPossibleDirections; float derivedChance = chance * prior; // Update beliefs based on possible directions // Staying in place is always an option if (stayPossible) { addBeliefUsingWorld(newBeliefs, i, j, belief, derivedChance, ref newBeliefsTotal); } if (upPossible) { addBeliefUsingWorld(newBeliefs, i, j - 1, belief, derivedChance, ref newBeliefsTotal); } if (downPossible) { addBeliefUsingWorld(newBeliefs, i, j + 1, belief, derivedChance, ref newBeliefsTotal); } if (leftPossible) { addBeliefUsingWorld(newBeliefs, i + 1, j, belief, derivedChance, ref newBeliefsTotal); } if (rightPossible) { addBeliefUsingWorld(newBeliefs, i - 1, j, belief, derivedChance, ref newBeliefsTotal); } } // Normalize our new belief state foreach (KeyValuePair <IJCoords, ProjectileSourceBelief> entry in newBeliefs) { entry.Value.Probability /= newBeliefsTotal; } // Update sourceBeliefs = newBeliefs; } }