public override void RunTick() { if (this.behavior is Behavior) { this.behavior.RunTick(); } // Standard Physics this.physics.RunPhysicsTick(); // Animations, if applicable. if (this.animate is Animate) { this.animate.RunAnimationTick(Systems.timer); } // Check if the enemy is about to run off of a cliff: if (Systems.timer.IsTickFrame && this.physics.touch.toFloor) { if (this.FaceRight) { if (!CollideTile.IsBlockingCoord(this.room.tilemap, this.posX + this.bounds.Right + 8, this.posY + this.bounds.Bottom + 10, DirCardinal.Down)) { this.SetDirection(false); } } else { if (!CollideTile.IsBlockingCoord(this.room.tilemap, this.posX + this.bounds.Left - 8, this.posY + this.bounds.Bottom + 10, DirCardinal.Down)) { this.SetDirection(true); } } } }
private void DetermineSlamDistance() { TilemapLevel tilemap = this.actor.room.tilemap; // We know the slammer's starting position. short gridX = this.actor.GridX; short gridY = this.actor.GridY; this.viewY = this.actor.posY + ((byte)TilemapEnum.TileHeight * 2); this.viewHeight = 0; // Scan for solid tiles beneath the slammer, up to 17 below (for a full screen) for (short testY = (short)(gridY + 2); testY < gridY + 19; testY++) { if (testY > tilemap.YCount + (byte)TilemapEnum.GapUp) { return; } // If there is a blocking tile at this height below the slammer, we can determine it's final Y-position after a slam: if (CollideTile.IsBlockingSquare(tilemap, gridX, testY, DirCardinal.Up) || CollideTile.IsBlockingSquare(tilemap, (short)(gridX + 1), testY, DirCardinal.Up)) { this.endY = testY * (byte)TilemapEnum.TileHeight; this.viewHeight = (short)(this.endY - this.viewY - 10); break; } } }
public void DropItem() { if (this.objHeld == null) { return; } Item item = this.objHeld; item.intangible = Systems.timer.Frame + 7; // Check what Main Layer has present at the throw-release tile: TilemapLevel tilemap = this.character.room.tilemap; bool isBlocked = false; bool faceRight = this.character.FaceRight; isBlocked = CollideTile.IsBlockingSquare(tilemap, faceRight ? item.GridX2 : item.GridX, item.GridY, DirCardinal.Up); // If the drop tiles are blocked, see if we can drop it in the tile below. if (isBlocked) { int limitY = item.GridY * (byte)TilemapEnum.TileHeight + (byte)TilemapEnum.TileHeight; int dist = limitY - (item.posY + item.bounds.Top); // If we only have to drop it 24 pixels (or less), we can just lower the item slightly. if (dist < 24) { item.physics.MoveToPosY(limitY - item.bounds.Top); isBlocked = CollideTile.IsBlockingSquare(tilemap, faceRight ? item.GridX2 : item.GridX, item.GridY, DirCardinal.Up); } } // If the tile is still blocked, then a Y-reposition didn't work. We'll have to move it to character's tile. if (isBlocked) { int limitX; // NOTE: MUST have it like this. I don't understand the nuanced difference here, but it works. if (faceRight) { limitX = item.GridX2 * (byte)TilemapEnum.TileWidth; } else { limitX = item.GridX * (byte)TilemapEnum.TileWidth + (byte)TilemapEnum.TileWidth; } item.physics.MoveToPosX(limitX - (faceRight ? item.bounds.Right : item.bounds.Left)); } // Assign Minimal Drop Physics (to smooth natural look) item.physics.velocity.X = FInt.Create(this.character.physics.velocity.X.RoundInt / 3); item.physics.velocity.Y = FInt.Create(-1.5); // Play Drop Sound this.character.room.PlaySound(Systems.sounds.wooshSubtle, 0.5f, this.character.posX + 16, this.character.posY + 16); this.ResetHeldItem(); }
private void DoTeleport() { CharacterStatus status = this.character.status; // End the Teleport Action (to prevent re-teleportation) this.character.status.action.EndAction(this.character); // Get X, Y Coordinates from Distance and Radian float trueRotation = Radians.Normalize(status.actionFloat1); int xCoord = (int)Radians.GetXFromRotation(trueRotation, status.actionNum1) + character.posX + character.bounds.MidX; int yCoord = (int)Radians.GetYFromRotation(trueRotation, status.actionNum1) + character.posY + character.bounds.MidY; // Make sure teleportation is within world bounds. if (yCoord < (byte)TilemapEnum.GapUpPixel || yCoord > this.character.room.Height + (byte)TilemapEnum.GapUpPixel || xCoord < (byte)TilemapEnum.GapLeftPixel || xCoord > this.character.room.Width + (byte)TilemapEnum.GapRightPixel) { this.character.room.PlaySound(Systems.sounds.disableCollectable, 0.5f, this.character.posX + 16, this.character.posY + 16); return; } TilemapLevel tilemap = character.room.tilemap; // Make sure teleportation is to a valid open area. Blocking tiles will prevent teleportation. int xMid = xCoord - this.character.bounds.MidX; int yMid = yCoord - this.character.bounds.MidY; bool upLeft = CollideTile.IsBlockingCoord(tilemap, xMid + character.bounds.Left, yMid + character.bounds.Top - 1, DirCardinal.None); bool upRight = CollideTile.IsBlockingCoord(tilemap, xMid + character.bounds.Right, yMid + character.bounds.Bottom - 1, DirCardinal.None); bool downLeft = CollideTile.IsBlockingCoord(tilemap, xMid + character.bounds.Left, yMid + character.bounds.Top - 1, DirCardinal.None); bool downRight = CollideTile.IsBlockingCoord(tilemap, xMid + character.bounds.Right, yMid + character.bounds.Bottom - 1, DirCardinal.None); // If all positions are blocked, prevent teleport. if (upLeft && upRight && downLeft && downRight) { this.character.room.PlaySound(Systems.sounds.disableCollectable, 0.5f, this.character.posX + 16, this.character.posY + 16); return; } // If some positions are blocked, adjust position: if (upLeft && downLeft) { xMid += 12; } if (upRight && downRight) { xMid -= 12; } if (upLeft && upRight) { yMid += 12; } if (downLeft && downRight) { yMid -= 12; } this.character.room.PlaySound(Systems.sounds.pop, 1f, this.character.posX + 16, this.character.posY + 16); // Teleport Character this.character.physics.MoveToPos(xMid, yMid); }
public override bool RunImpact(RoomScene room, GameObject actor, short gridX, short gridY, DirCardinal dir) { // Characters interact with Chest: if (actor is Character) { byte subType = room.tilemap.GetMainSubType(gridX, gridY); // If the chest is open, no interactions are allowed: if (subType == (byte)ChestSubType.Open) { return(false); } Character character = (Character)actor; // Make sure the character is fully within the chest tile. if (!CollideTile.IsWithinTile(character, gridX, gridY)) { return(false); } // The Character must be pressing the interaction key to open the chest. if (!character.input.isPressed(IKey.YButton)) { return(false); } // If the chest is locked, must have a key: if (subType == (byte)ChestSubType.Locked) { // Remove the Key, Unlock the Chest. if (!character.trailKeys.RemoveKey()) { room.PlaySound(Systems.sounds.click3, 1f, gridX * (byte)TilemapEnum.TileWidth, gridY * (byte)TilemapEnum.TileHeight); return(false); } room.PlaySound(Systems.sounds.unlock, 1f, gridX * (byte)TilemapEnum.TileWidth, gridY * (byte)TilemapEnum.TileHeight); } else { room.PlaySound(Systems.sounds.click2, 0.5f, gridX * (byte)TilemapEnum.TileWidth, gridY * (byte)TilemapEnum.TileHeight); } this.OpenChest(room, gridX, gridY); } return(false); }
public override bool Activate() { // Make sure the power can be activated if (!this.CanActivate()) { return(false); } // References Character character = this.character; // Determine Starting Position of Projectile relative to Character int posX = character.posX + character.bounds.MidX + (character.FaceRight ? 10 : -30); int posY = character.posY + character.bounds.Top + 5; // Play Sound character.room.PlaySound(this.sound, 1f, posX, posY); // Check if the tile placement is blocked: TilemapLevel tilemap = this.character.room.tilemap; bool isBlocked = CollideTile.IsBlockingCoord(tilemap, posX + 10 + (character.FaceRight ? 6 : -6), posY + 10, character.FaceRight ? DirCardinal.Right : DirCardinal.Left); // Prevent Throw if (isBlocked) { return(false); } // Prepare Velocity FInt velX = character.FaceRight ? this.xVel : this.xVel.Inverse; FInt velY = this.yVel; // Affect the Y-Velocity of the projectile if holding UP or DOWN this.AffectByInput(ref velX, ref velY); // Apply Character's Momentum (if applicable) if (this.multMomentum > 0) { velX += character.physics.velocity.X * this.multMomentum; velY += character.physics.velocity.Y * this.multMomentum * FInt.Create(0.5); } // Launch Projectile this.Launch(posX, posY, velX, velY); return(true); }
// Returns TRUE if the character can phase to the horizontal location. public bool TestPhasingHorizontal(Character character, TilemapLevel tilemap, short toX, DirCardinal dir) { bool blocking = CollideTile.IsBlockingSquare(tilemap, toX, character.GridY, dir); if (blocking) { return(false); } if (character.GridY != character.GridY2) { blocking = CollideTile.IsBlockingSquare(tilemap, toX, character.GridY2, dir); } return(!blocking); }
// Returns TRUE if the character can phase to the vertical location. public bool TestPhasingVertical(Character character, TilemapLevel tilemap, short toY, DirCardinal dir) { bool blocking = CollideTile.IsBlockingSquare(tilemap, character.GridX, toY, dir); if (blocking) { return(false); } if (character.GridX != character.GridX2) { blocking = CollideTile.IsBlockingSquare(tilemap, character.GridX2, toY, dir); } return(!blocking); }
public void SolidTileCollision() { Character ch = this.character; Physics phys = ch.physics; // Create Tiles in diamond pattern. this.tilemap.SetMainTile(10, 8, (byte)TileEnum.Brick, 0); // Position at 480, 384 this.tilemap.SetMainTile(9, 9, (byte)TileEnum.Brick, 0); // Position at 432, 432 this.tilemap.SetMainTile(10, 10, (byte)TileEnum.Brick, 0); // Position at 480, 480 this.tilemap.SetMainTile(11, 9, (byte)TileEnum.Brick, 0); // Position at 528, 432 // --- Simultaneous Up AND Right Tile Collisions; not corner --- // phys.SetGravity(FInt.Create(0)); // End Gravity phys.MoveToPos(480 - ch.bounds.Right - 3, 480); phys.velocity = FVector.Create(6, -4); // Character moving up-right. this.VerifyGridPos(ch, 9, 10, 9, 10); phys.RunPhysicsTick(); ch.RunTick(); CollideTile.RunTileCollision(ch); Debug.Assert(ch.posX + ch.bounds.Right == 480, "Character posX should be 480."); Debug.Assert(ch.posY + ch.bounds.Top == 480, "Character posY should be 480."); // --- Simultaneous Down AND Left Tile Collisions; not corner --- // phys.MoveToPos(528 - ch.bounds.Left + 2, 432 - ch.bounds.Bottom - 2); phys.velocity = FVector.Create(-5, 7); // Character moving down-left. this.VerifyGridPos(ch, 11, 8, 11, 8); phys.RunPhysicsTick(); ch.RunTick(); CollideTile.RunTileCollision(ch); Debug.Assert(ch.posX + ch.bounds.Left == 528, "Character posX should be 528."); Debug.Assert(ch.posY + ch.bounds.Bottom == 432, "Character posY should be 432."); // Delete Tiles this.tilemap.ClearMainLayer(10, 8); this.tilemap.ClearMainLayer(9, 9); this.tilemap.ClearMainLayer(10, 10); this.tilemap.ClearMainLayer(11, 9); }
public override bool Activate() { // Make sure the power can be activated if (!this.CanActivate()) { return(false); } // References Character character = this.character; // Determine Starting Position of Projectile relative to Character int posX = character.posX + character.bounds.MidX + (character.FaceRight ? 6 : -30); int posY = character.posY + character.bounds.Top + 5; // Play Sound character.room.PlaySound(this.sound, 1f, posX, posY); // Check if the tile placement is blocked (only applies to bolts that collide with tiles). if (this is BoltBlue) { TilemapLevel tilemap = this.character.room.tilemap; bool isBlocked = CollideTile.IsBlockingCoord(tilemap, posX + (character.FaceRight ? 10 : 4), posY, character.FaceRight ? DirCardinal.Right : DirCardinal.Left); // Prevent Throw if (isBlocked) { return(false); } } // Prepare Velocity FInt velX = character.FaceRight ? FInt.Create(this.xVel) : FInt.Create(-this.xVel); FInt velY = FInt.Create(this.yVel); // Affect the Y-Velocity of the projectile if holding UP or DOWN this.AffectByInput(ref velX, ref velY); // Launch Projectile this.Launch(character, posX, posY, velX, velY); return(true); }
public void ThrowItem(bool useXMomentum = false) { if (this.objHeld == null) { return; } Item item = this.objHeld; // Item will release in the direction the character does. item.SetDirection(this.character.FaceRight); // Check what Main Layer has present at the throw-release tile: TilemapLevel tilemap = this.character.room.tilemap; bool isBlocked = CollideTile.IsBlockingSquare(tilemap, item.GridX, item.GridY, DirCardinal.Up); if (!isBlocked && item.GridX != item.GridX2) { isBlocked = CollideTile.IsBlockingSquare(tilemap, item.GridX2, item.GridY, DirCardinal.Up); } // Prevent Throw if (isBlocked) { this.DropItem(); return; } // Assign Item Physics + Thrown Properties item.intangible = Systems.timer.Frame + 5; item.releasedMomentum = useXMomentum ? (sbyte)Math.Round(this.character.physics.velocity.X.RoundInt / 2.5) : (sbyte)0; item.physics.velocity.X = FInt.Create(item.releasedMomentum); item.physics.velocity.Y = FInt.Create(-item.ThrowStrength); // Play Throw Sound this.character.room.PlaySound(Systems.sounds.wooshSubtle, 1f, this.character.posX + 16, this.character.posY + 16); // No longer holding object: this.ResetHeldItem(); }
private void PlaceDetectorsAbove(RoomScene room, short gridX, short gridY) { TilemapLevel tilemap = room.tilemap; // Scan for solid tiles above the flag, up to 18 above (for a full screen) for (short testY = (short)(gridY - 1); testY > gridY - 18; testY--) { if (testY < (byte)TilemapEnum.GapUp) { return; } // If there is a blocking tile at this grid sqare, stop placements. if (CollideTile.IsBlockingSquare(tilemap, gridX, testY, DirCardinal.Down)) { return; } // Otherwise, add a Detector. room.tilemap.SetMainTile(gridX, testY, (byte)TileEnum.DetectCheckpointPass, 0); } }