LADXHD/InGame/GameObjects/Enemies/EnemyFloorLayer.cs
2023-12-14 17:21:22 -05:00

235 lines
8.7 KiB
C#

using Microsoft.Xna.Framework;
using ProjectZ.InGame.GameObjects.Base;
using ProjectZ.InGame.GameObjects.Base.Components;
using ProjectZ.InGame.GameObjects.Base.CObjects;
using ProjectZ.InGame.GameObjects.Base.Components.AI;
using ProjectZ.InGame.Map;
using ProjectZ.InGame.SaveLoad;
using ProjectZ.InGame.Things;
using ProjectZ.InGame.Controls;
using System.Collections.Generic;
using ProjectZ.InGame.GameObjects.Things;
namespace ProjectZ.InGame.GameObjects.Enemies
{
// not sure why I called it an enemy...
internal class EnemyFloorLayer : GameObject
{
private readonly List<GameObject> _deactivatedGameObjects = new List<GameObject>();
private readonly List<EnemyFloorLayerFloor> _spawnedTiles = new List<EnemyFloorLayerFloor>();
private readonly BodyComponent _body;
private readonly AiComponent _aiComponent;
private Vector2 _spawnPosition;
private Vector2 _startPosition;
private Vector2 _endPosition;
private Vector2 _moveDirection;
private float _soundCounter;
private float _moveCounter;
private int _moveIndex;
private string _fullKey;
private int _minMoveCount;
private const float MoveSpeed = 0.5f;
public EnemyFloorLayer() : base("floor layer") { }
public EnemyFloorLayer(Map.Map map, int posX, int posY, int count, string fullKey) : base(map)
{
EntityPosition = new CPosition(posX + 8, posY + 14, 0);
EntitySize = new Rectangle(-8, -16, 16, 16);
_minMoveCount = count;
_fullKey = fullKey;
_spawnPosition = EntityPosition.Position;
_body = new BodyComponent(EntityPosition, -8, -14, 16, 14, 8)
{
IgnoreHoles = true,
CollisionTypes =
Values.CollisionTypes.Normal |
Values.CollisionTypes.Player,
FieldRectangle = map.GetField(posX, posY)
};
var sprite = new CSprite(EntityPosition);
var animator = AnimatorSaveLoad.LoadAnimator("Enemies/floor layer");
animator.Play("idle");
var animatorComponent = new AnimationComponent(animator, sprite, new Vector2(0, 2));
_aiComponent = new AiComponent();
var stateIdle = new AiState() { Init = InitIdle };
var stateMove = new AiState(UpdateMoving);
var stateDead = new AiState(UpdateDead) { Init = InitDead };
_aiComponent.States.Add("idle", stateIdle);
_aiComponent.States.Add("move", stateMove);
_aiComponent.States.Add("dead", stateDead);
AddComponent(BodyComponent.Index, _body);
AddComponent(BaseAnimationComponent.Index, animatorComponent);
AddComponent(AiComponent.Index, _aiComponent);
AddComponent(CollisionComponent.Index, new BodyCollisionComponent(_body, Values.CollisionTypes.Enemy));
AddComponent(PushableComponent.Index, new PushableComponent(_body.BodyBox, OnPush) { InertiaTime = 250 });
AddComponent(DrawComponent.Index, new BodyDrawComponent(_body, sprite, Values.LayerPlayer));
AddComponent(DrawShadowComponent.Index, new DrawShadowCSpriteComponent(sprite) { Height = 1.0f, Rotation = 0.1f });
_aiComponent.ChangeState("idle");
}
private void InitIdle()
{
SetActive(true);
}
private void InitDead()
{
SetActive(false);
}
private void SetActive(bool active)
{
((BodyCollisionComponent)Components[CollisionComponent.Index]).IsActive = active;
((DrawComponent)Components[DrawComponent.Index]).IsActive = active;
((DrawShadowComponent)Components[DrawShadowComponent.Index]).IsActive = active;
}
private void UpdateDead()
{
// remove the floor when the player leaves the room and not all tiles where layed
if (!_body.FieldRectangle.Contains(MapManager.ObjLink.EntityPosition.Position) && _moveIndex != _minMoveCount + 1)
Reactivate();
}
private void Reactivate()
{
_moveIndex = 0;
EntityPosition.Set(_spawnPosition);
_aiComponent.ChangeState("idle");
((PushableComponent)Components[PushableComponent.Index]).IsActive = true;
// despawn the tiles
foreach (var tile in _spawnedTiles)
{
// reactivate holes
tile.SetHoleState(true);
Map.Objects.DeleteObjects.Add(tile);
// spawn the explosion effect
var splashAnimator = new ObjAnimator(Map, (int)tile.EntityPosition.X,
(int)tile.EntityPosition.Y, 0, 0, Values.LayerTop, "Particles/spawn", "run", true);
Map.Objects.SpawnObject(splashAnimator);
}
_spawnedTiles.Clear();
}
private bool OnPush(Vector2 direction, PushableComponent.PushType type)
{
if (type != PushableComponent.PushType.Continues)
return false;
StartMoving(direction);
return false;
}
private void StartMoving(Vector2 direction)
{
_aiComponent.ChangeState("move");
((PushableComponent)Components[PushableComponent.Index]).IsActive = false;
_moveDirection = direction;
_startPosition = EntityPosition.Position;
_endPosition = EntityPosition.Position;
SetNewPosition(false);
}
private void UpdateMoving()
{
MapManager.ObjLink.FreezePlayer();
_soundCounter -= Game1.DeltaTime;
if (_soundCounter < 0)
{
_soundCounter += 55;
Game1.GameManager.PlaySoundEffect("D360-62-3E", false);
}
// get the new direction the player is pushing
var vecDirection = ControlHandler.GetMoveVector2();
if (vecDirection != Vector2.Zero)
{
var newDirection = AnimationHelper.GetDirection(vecDirection);
_moveDirection = AnimationHelper.DirectionOffset[newDirection];
}
_moveCounter += Game1.DeltaTime;
// finished moving to the next segment?
var time = 16 / (60 * MoveSpeed) * 1000;
if (_moveCounter > time)
{
_moveCounter -= time;
SetNewPosition(true);
}
// calculate the new position
var percentage = _moveCounter / time;
var newPercentage = Vector2.Lerp(_startPosition, _endPosition, percentage);
EntityPosition.Set(newPercentage);
}
private void SetNewPosition(bool spawnFloor)
{
_moveIndex++;
_startPosition = _endPosition;
_endPosition = _startPosition + _moveDirection * 16;
// spawn the floor
if (spawnFloor)
{
var objFloor = new EnemyFloorLayerFloor(Map, (int)_startPosition.X - 8, (int)_startPosition.Y - 14);
Map.Objects.SpawnObject(objFloor);
_spawnedTiles.Add(objFloor);
}
// stop moving if there is no hole at next position
if (!CheckForHole((int)_endPosition.X - 8, (int)_endPosition.Y - 14))
{
Game1.GameManager.PlaySoundEffect("D360-47-2F");
// spawn the explosion effect
var splashAnimator = new ObjAnimator(Map, (int)EntityPosition.X - 8,
(int)EntityPosition.Y - 14, 0, 0, Values.LayerTop, "Particles/spawn", "run", true);
Map.Objects.SpawnObject(splashAnimator);
if (_moveIndex > _minMoveCount && !string.IsNullOrEmpty(_fullKey))
Game1.GameManager.SaveManager.SetString(_fullKey, "1");
_aiComponent.ChangeState("dead");
}
}
private bool CheckForHole(int posX, int posY)
{
_deactivatedGameObjects.Clear();
Map.Objects.GetObjectsOfType(_deactivatedGameObjects, typeof(ObjHole), posX, posY, 16, 16);
Map.Objects.GetObjectsOfType(_deactivatedGameObjects, typeof(ObjLava), posX, posY, 16, 16);
foreach (var gameObject in _deactivatedGameObjects)
if (gameObject.IsActive &&
gameObject.EntityPosition.Position == new Vector2(posX, posY))
return true;
return false;
}
}
}