mirror of
https://github.com/Phantop/LADXHD.git
synced 2025-09-01 03:14:56 +00:00
630 lines
22 KiB
C#
630 lines
22 KiB
C#
using System;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using ProjectZ.Base;
|
|
using ProjectZ.InGame.GameObjects.Base;
|
|
using ProjectZ.InGame.GameObjects.Base.CObjects;
|
|
using ProjectZ.InGame.GameObjects.Base.Components;
|
|
using ProjectZ.InGame.GameObjects.Base.Components.AI;
|
|
using ProjectZ.InGame.GameObjects.Things;
|
|
using ProjectZ.InGame.Map;
|
|
using ProjectZ.InGame.SaveLoad;
|
|
using ProjectZ.InGame.Things;
|
|
|
|
namespace ProjectZ.InGame.GameObjects.Bosses
|
|
{
|
|
class BossSlimeEel : GameObject
|
|
{
|
|
private readonly Animator _animator;
|
|
private readonly AnimationComponent _animationComponent;
|
|
private readonly BodyComponent _body;
|
|
private readonly AiComponent _aiComponent;
|
|
private readonly CSprite _sprite;
|
|
private readonly DamageFieldComponent _damageField;
|
|
private readonly AiDamageState _aiDamageState;
|
|
|
|
private readonly Animator _explosionAnimator;
|
|
|
|
private readonly BossSlimeEelSpawn _eelSpawner;
|
|
|
|
// parts are used to deal damage and have a hittable box
|
|
private readonly BossSlimeEelTail[] _tailParts = new BossSlimeEelTail[5];
|
|
|
|
private readonly DictAtlasEntry _spriteTail;
|
|
private readonly DictAtlasEntry _spriteTailEnd;
|
|
private readonly DictAtlasEntry _spriteHeart0;
|
|
private readonly DictAtlasEntry _spriteHeart1;
|
|
|
|
private readonly Vector2 _centerPosition;
|
|
|
|
private Vector2 _startPosition;
|
|
|
|
private Vector2 _hockshotPosition;
|
|
private Vector2 _hookshotOffset;
|
|
private float _pullSound;
|
|
|
|
private double _retreatCount;
|
|
private float _moveSpeed;
|
|
private int _moveDirection = 1;
|
|
|
|
private bool _attackOut;
|
|
private bool _isFullyOut;
|
|
|
|
private float _moveRotation;
|
|
private float _rotationDir = 1;
|
|
|
|
private const float MoveSpeed = 0.75f;
|
|
|
|
private readonly float[] _tailDistance = { 10.0f, 8f, 9f };
|
|
private readonly Vector2[] _savedPosition = new Vector2[30];
|
|
private readonly Vector2[] _tailPositions = new Vector2[3];
|
|
|
|
private string _saveKey;
|
|
|
|
private bool _attackSound;
|
|
|
|
private float _saveInterval = 33;
|
|
private float _saveCounter;
|
|
private int _saveIndex;
|
|
|
|
public BossSlimeEel(Map.Map map, Vector2 centerPosition, BossSlimeEelSpawn eelSpawner, string saveKey) : base(map)
|
|
{
|
|
Tags = Values.GameObjectTag.Enemy;
|
|
|
|
_centerPosition = centerPosition;
|
|
_eelSpawner = eelSpawner;
|
|
|
|
_saveKey = saveKey;
|
|
|
|
EntityPosition = new CPosition(centerPosition.X, centerPosition.Y, 0);
|
|
EntitySize = new Rectangle(-16, -16, 32, 32);
|
|
|
|
_body = new BodyComponent(EntityPosition, -8, -8, 16, 16, 8)
|
|
{
|
|
MoveCollision = OnCollision,
|
|
IgnoreHoles = true
|
|
};
|
|
|
|
_spriteTail = Resources.GetSprite("eel_tail_0");
|
|
_spriteTailEnd = Resources.GetSprite("eel_tail_2");
|
|
_spriteHeart0 = Resources.GetSprite("eel_heart_0");
|
|
_spriteHeart1 = Resources.GetSprite("eel_heart_1");
|
|
|
|
for (var i = 0; i < _tailParts.Length; i++)
|
|
{
|
|
if (i == 0)
|
|
_tailParts[i] = new BossSlimeEelTail(Map, EntityPosition.Position, 0, OnHitHeart);
|
|
else
|
|
_tailParts[i] = new BossSlimeEelTail(Map, EntityPosition.Position, 0, null);
|
|
|
|
_tailParts[i].SetActive(false);
|
|
|
|
Map.Objects.SpawnObject(_tailParts[i]);
|
|
}
|
|
|
|
_explosionAnimator = AnimatorSaveLoad.LoadAnimator("Objects/explosion");
|
|
|
|
_animator = AnimatorSaveLoad.LoadAnimator("Nightmares/slime eel");
|
|
|
|
_sprite = new CSprite(EntityPosition);
|
|
_animationComponent = new AnimationComponent(_animator, _sprite, Vector2.Zero);
|
|
|
|
_aiComponent = new AiComponent();
|
|
|
|
var stateSpawn = new AiState { Init = InitSpawn };
|
|
var stateSpawnAttack = new AiState(UpdateSpawnAttack);
|
|
var stateHidden = new AiState { Init = InitHidden };
|
|
stateHidden.Trigger.Add(new AiTriggerCountdown(1000, null, EndHidden));
|
|
var stateAttack = new AiState(UpdateAttack) { Init = InitAttack };
|
|
var statePulled = new AiState(UpdatePulled) { Init = InitPulled };
|
|
var stateRetreat = new AiState(UpdateRetreat) { Init = InitRetreat };
|
|
var stateJumpingOut = new AiState(UpdateJumpingOut) { Init = InitJumpingOut };
|
|
var statePulledOut = new AiState(UpdatePulledOut) { Init = InitPulledOut };
|
|
statePulledOut.Trigger.Add(new AiTriggerRandomTime(ChangeDirection, 650, 1000));
|
|
statePulledOut.Trigger.Add(new AiTriggerCountdown(1600, null, () => _aiComponent.ChangeState("blink")));
|
|
var stateBlink = new AiState { Init = InitBlink };
|
|
stateBlink.Trigger.Add(new AiTriggerCountdown(AiDamageState.CooldownTime, TickBlink, Explode));
|
|
var stateExplode = new AiState(UpdateExplode) { Init = InitExplode };
|
|
|
|
_aiComponent.States.Add("spawn", stateSpawn);
|
|
_aiComponent.States.Add("spawnAttack", stateSpawnAttack);
|
|
_aiComponent.States.Add("hidden", stateHidden);
|
|
_aiComponent.States.Add("attack", stateAttack);
|
|
_aiComponent.States.Add("pulled", statePulled);
|
|
_aiComponent.States.Add("retreat", stateRetreat);
|
|
_aiComponent.States.Add("jumpingOut", stateJumpingOut);
|
|
_aiComponent.States.Add("pulledOut", statePulledOut);
|
|
_aiComponent.States.Add("blink", stateBlink);
|
|
_aiComponent.States.Add("explode", stateExplode);
|
|
_aiDamageState = new AiDamageState(this, _body, _aiComponent, _sprite, 8, false, false)
|
|
{
|
|
HitMultiplierX = 0,
|
|
HitMultiplierY = 0,
|
|
ExplosionOffsetY = 16,
|
|
BossHitSound = true
|
|
};
|
|
_aiDamageState.AddBossDamageState(OnDeath);
|
|
|
|
_aiComponent.ChangeState("spawn");
|
|
|
|
var damageCollider = new CBox(EntityPosition, -6, -6, 0, 12, 12, 8);
|
|
var hittableBox = new CBox(EntityPosition, -6, -6, 0, 12, 12, 8);
|
|
|
|
AddComponent(AiComponent.Index, _aiComponent);
|
|
AddComponent(BodyComponent.Index, _body);
|
|
AddComponent(BaseAnimationComponent.Index, _animationComponent);
|
|
AddComponent(HittableComponent.Index, new HittableComponent(hittableBox, OnHit));
|
|
AddComponent(DrawComponent.Index, new DrawComponent(Draw, Values.LayerBottom, EntityPosition));
|
|
AddComponent(DamageFieldComponent.Index, _damageField = new DamageFieldComponent(damageCollider, HitType.Enemy, 2) { IsActive = false });
|
|
}
|
|
|
|
public void SpawnAttack(int positionIndex)
|
|
{
|
|
SetAttackPosition(positionIndex);
|
|
|
|
_attackSound = false;
|
|
_sprite.IsVisible = true;
|
|
_animator.Play("attack_spawn");
|
|
_aiComponent.ChangeState("spawnAttack");
|
|
}
|
|
|
|
public void ToSpawned()
|
|
{
|
|
_aiComponent.ChangeState("hidden");
|
|
}
|
|
|
|
private void InitSpawn()
|
|
{
|
|
_sprite.IsVisible = false;
|
|
}
|
|
|
|
private void UpdateSpawnAttack()
|
|
{
|
|
if (!_attackSound && _animator.CurrentFrameIndex == 2)
|
|
{
|
|
_attackSound = true;
|
|
Game1.GameManager.PlaySoundEffect("D370-22-16");
|
|
}
|
|
|
|
if (!_animator.IsPlaying)
|
|
{
|
|
_aiComponent.ChangeState("spawn");
|
|
}
|
|
}
|
|
|
|
private void InitExplode()
|
|
{
|
|
Game1.GameManager.PlaySoundEffect("D378-12-0C");
|
|
_explosionAnimator.Play("idle");
|
|
|
|
_isFullyOut = false;
|
|
_sprite.IsVisible = false;
|
|
}
|
|
|
|
private void UpdateExplode()
|
|
{
|
|
var collisionRect = _explosionAnimator.CollisionRectangle;
|
|
if (collisionRect != Rectangle.Empty)
|
|
{
|
|
var collisionBox = new Box(
|
|
EntityPosition.X + collisionRect.X,
|
|
EntityPosition.Y + collisionRect.Y, 0,
|
|
collisionRect.Width, collisionRect.Height, 16);
|
|
|
|
if (collisionBox.Intersects(MapManager.ObjLink._body.BodyBox.Box))
|
|
MapManager.ObjLink.HitPlayer(collisionBox, HitType.Bomb, 4);
|
|
}
|
|
|
|
_explosionAnimator.Update();
|
|
if (!_explosionAnimator.IsPlaying)
|
|
_aiComponent.ChangeState("hidden");
|
|
}
|
|
|
|
private void InitBlink()
|
|
{
|
|
_damageField.IsActive = false;
|
|
_body.VelocityTarget = Vector2.Zero;
|
|
}
|
|
|
|
private void TickBlink(double counter)
|
|
{
|
|
_sprite.SpriteShader = (AiDamageState.CooldownTime - counter) % (AiDamageState.BlinkTime * 2) <
|
|
AiDamageState.BlinkTime ? Resources.DamageSpriteShader0 : null;
|
|
}
|
|
|
|
private void Explode()
|
|
{
|
|
_aiComponent.ChangeState("explode");
|
|
}
|
|
|
|
private void InitJumpingOut()
|
|
{
|
|
Game1.GameManager.PlaySoundEffect("D370-22-16");
|
|
|
|
_animator.Play("head_0");
|
|
_body.VelocityTarget = _moveDirection * new Vector2(0, 1) * 1.5f;
|
|
_moveRotation = _moveDirection != 1 ? MathF.PI : 0;
|
|
_isFullyOut = true;
|
|
|
|
for (var i = 0; i < _savedPosition.Length; i++)
|
|
_savedPosition[i] = _startPosition;
|
|
}
|
|
|
|
private void UpdateJumpingOut()
|
|
{
|
|
var distance = Math.Abs(_startPosition.Y - EntityPosition.Y);
|
|
var tailState = 1 - Math.Clamp(distance / 48, 0, 1);
|
|
|
|
_eelSpawner.SetTailState(tailState);
|
|
|
|
if (distance > 48)
|
|
_aiComponent.ChangeState("pulledOut");
|
|
|
|
UpdateTailPositions();
|
|
}
|
|
|
|
private void ChangeDirection()
|
|
{
|
|
_rotationDir = -_rotationDir;
|
|
}
|
|
|
|
private void OnCollision(Values.BodyCollision collision)
|
|
{
|
|
_moveRotation += MathF.PI;
|
|
}
|
|
|
|
private void InitPulledOut()
|
|
{
|
|
}
|
|
|
|
private void UpdatePulledOut()
|
|
{
|
|
_moveRotation += _rotationDir * Game1.TimeMultiplier * 0.1f;
|
|
|
|
var newVelocity = new Vector2(-MathF.Sin(_moveRotation), MathF.Cos(_moveRotation)) * MoveSpeed;
|
|
_body.VelocityTarget = newVelocity;
|
|
|
|
UpdateTailPositions();
|
|
|
|
while (_moveRotation < MathF.PI * 2)
|
|
_moveRotation += MathF.PI * 2;
|
|
|
|
// update the animation
|
|
var animationIndex = (int)((_moveRotation + Math.PI / 8) / (MathF.PI / 4)) % 8;
|
|
|
|
if (animationIndex % 2 == 0)
|
|
{
|
|
if (animationIndex == 0 || animationIndex == 4)
|
|
_animator.Play("head_0");
|
|
else
|
|
_animator.Play("head_2");
|
|
}
|
|
else
|
|
{
|
|
_animationComponent.MirroredH = animationIndex > 4;
|
|
_animationComponent.MirroredV = animationIndex != 1 && animationIndex != 7;
|
|
_animator.Play("head_1");
|
|
}
|
|
}
|
|
|
|
private void OnDeath()
|
|
{
|
|
// spawn a heart
|
|
var objItem = new ObjItem(Map, (int)EntityPosition.X - 8, (int)EntityPosition.Y - 8, "j", "d5_nHeart", "heartMeterFull", null);
|
|
Map.Objects.SpawnObject(objItem);
|
|
|
|
Game1.GameManager.SaveManager.SetString(_saveKey, "1");
|
|
|
|
// stop boss music
|
|
Game1.GameManager.SetMusic(-1, 2);
|
|
|
|
DespawnObjects();
|
|
}
|
|
|
|
private void DespawnObjects()
|
|
{
|
|
// delete the head
|
|
Map.Objects.DeleteObjects.Add(this);
|
|
|
|
// delete the tail
|
|
for (var i = 0; i < _tailParts.Length; i++)
|
|
Map.Objects.DeleteObjects.Add(_tailParts[i]);
|
|
}
|
|
|
|
private void UpdateTail()
|
|
{
|
|
var distance = Math.Abs(_startPosition.Y - EntityPosition.Y);
|
|
var tailState = 1 - Math.Clamp(distance / 80, 0, 1);
|
|
|
|
_eelSpawner.SetTailState(tailState);
|
|
}
|
|
|
|
private void InitRetreat()
|
|
{
|
|
_retreatCount = 0;
|
|
_moveSpeed = 1 / 16f;
|
|
_animator.Play("head_open");
|
|
}
|
|
|
|
private void UpdateRetreat()
|
|
{
|
|
_retreatCount += Game1.DeltaTime;
|
|
|
|
var direction = _startPosition - EntityPosition.Position;
|
|
|
|
if (_retreatCount > 1500)
|
|
{
|
|
_moveSpeed = AnimationHelper.MoveToTarget(_moveSpeed, 1, 0.05f * Game1.TimeMultiplier);
|
|
}
|
|
|
|
var moveDistance = _moveSpeed * Game1.TimeMultiplier;
|
|
|
|
if (direction.Length() > moveDistance)
|
|
{
|
|
direction.Normalize();
|
|
EntityPosition.Offset(direction * moveDistance);
|
|
}
|
|
else
|
|
{
|
|
_attackOut = false;
|
|
EntityPosition.Set(_startPosition);
|
|
_aiComponent.ChangeState("hidden");
|
|
}
|
|
|
|
UpdateTail();
|
|
}
|
|
|
|
private void InitPulled()
|
|
{
|
|
_damageField.IsActive = false;
|
|
_attackOut = true;
|
|
_pullSound = 0;
|
|
|
|
_animator.Play("head_0");
|
|
}
|
|
|
|
private void UpdatePulled()
|
|
{
|
|
// finished pull
|
|
if (!MapManager.ObjLink.Hookshot.IsMoving)
|
|
{
|
|
FinishPull();
|
|
}
|
|
|
|
UpdateTail();
|
|
|
|
_pullSound += Game1.DeltaTime;
|
|
if (_pullSound > 75)
|
|
{
|
|
_pullSound -= 75;
|
|
Game1.GameManager.PlaySoundEffect("D360-41-29");
|
|
}
|
|
}
|
|
|
|
private void FinishPull()
|
|
{
|
|
MapManager.ObjLink.Hookshot.HookshotPosition.PositionChangedDict.Remove(typeof(BossSlimeEel));
|
|
|
|
_aiComponent.ChangeState("retreat");
|
|
}
|
|
|
|
private void InitAttack()
|
|
{
|
|
SetAttackPosition(Game1.RandomNumber.Next(0, 4));
|
|
|
|
// activate damage
|
|
for (var i = 0; i < _tailParts.Length; i++)
|
|
_tailParts[i].SetActive(true);
|
|
|
|
_damageField.IsActive = true;
|
|
_sprite.IsVisible = true;
|
|
_animator.Play("attack");
|
|
}
|
|
|
|
private void SetAttackPosition(int index)
|
|
{
|
|
_moveDirection = index < 2 ? 1 : -1;
|
|
|
|
var spawnPosition = new Vector2(
|
|
_centerPosition.X + (index % 2 == 0 ? -32 : 32),
|
|
_centerPosition.Y + (index < 2 ? -56 : 56));
|
|
|
|
_animationComponent.MirroredV = index >= 2;
|
|
_animationComponent.MirroredH = index >= 2;
|
|
|
|
EntityPosition.Set(spawnPosition);
|
|
_startPosition = spawnPosition;
|
|
}
|
|
|
|
private void UpdateAttack()
|
|
{
|
|
if (!_attackSound && _animator.CurrentFrameIndex == 3)
|
|
{
|
|
_attackSound = true;
|
|
Game1.GameManager.PlaySoundEffect("D370-22-16");
|
|
}
|
|
|
|
// finished attacking?
|
|
if (!_animator.IsPlaying)
|
|
{
|
|
_aiComponent.ChangeState("hidden");
|
|
}
|
|
}
|
|
|
|
private void InitHidden()
|
|
{
|
|
_sprite.IsVisible = false;
|
|
_eelSpawner.SetTailIsMoving(true);
|
|
}
|
|
|
|
private void EndHidden()
|
|
{
|
|
_attackSound = false;
|
|
_aiComponent.ChangeState("attack");
|
|
}
|
|
|
|
private void Draw(SpriteBatch spriteBatch)
|
|
{
|
|
// change the draw effect
|
|
if (_sprite.SpriteShader != null)
|
|
{
|
|
spriteBatch.End();
|
|
ObjectManager.SpriteBatchBegin(spriteBatch, _sprite.SpriteShader);
|
|
}
|
|
|
|
// draw the tail
|
|
if (_attackOut)
|
|
for (var i = 0; i < 5; i++)
|
|
{
|
|
var centerPosition = new Vector2(EntityPosition.X, EntityPosition.Y + (14 + i * 14) * -_moveDirection);
|
|
var position = new Vector2(centerPosition.X - 8, centerPosition.Y - 8);
|
|
_tailParts[i].EntityPosition.Set(centerPosition);
|
|
|
|
if (_moveDirection == 1 && position.Y + 16 < _startPosition.Y ||
|
|
_moveDirection == -1 && position.Y > _startPosition.Y)
|
|
continue;
|
|
|
|
var sprite = _spriteTail;
|
|
// draw the part with the heart
|
|
if (i == 0)
|
|
sprite = Game1.TotalGameTime % (32000 / 60f) < (16000 / 60f) ? _spriteHeart0 : _spriteHeart1;
|
|
|
|
DrawHelper.DrawNormalized(spriteBatch, sprite, position, Color.White);
|
|
}
|
|
|
|
// draw the tail while moving around outside
|
|
if (_isFullyOut)
|
|
{
|
|
for (var i = _tailPositions.Length - 1; i >= 0; i--)
|
|
{
|
|
var sprite = i == 2 ? _spriteTailEnd : _spriteTail;
|
|
var position = new Vector2(_tailPositions[i].X - 8, _tailPositions[i].Y - 8);
|
|
DrawHelper.DrawNormalized(spriteBatch, sprite, position, Color.White);
|
|
}
|
|
}
|
|
|
|
// draw the head
|
|
_sprite.Draw(spriteBatch);
|
|
|
|
// change the draw effect
|
|
if (_sprite.SpriteShader != null)
|
|
{
|
|
spriteBatch.End();
|
|
ObjectManager.SpriteBatchBegin(spriteBatch, null);
|
|
}
|
|
|
|
// draw the explosion
|
|
if (_explosionAnimator.IsPlaying)
|
|
_explosionAnimator.Draw(spriteBatch, EntityPosition.Position, Color.White);
|
|
}
|
|
|
|
public Values.HitCollision OnHitHeart(GameObject originObject, Vector2 direction, HitType type, int damage, bool pieceOfPower)
|
|
{
|
|
// can not get attacked while not visible
|
|
if (!_attackOut || (type & HitType.Sword) == 0)
|
|
return Values.HitCollision.None;
|
|
|
|
var wasAlive = _aiDamageState.CurrentLives > 0;
|
|
var hitReturn = _aiDamageState.OnHit(originObject, direction, type, damage, false);
|
|
|
|
if (_aiDamageState.CurrentLives <= 0 && wasAlive)
|
|
{
|
|
Game1.GameManager.StartDialogPath("slime_eel_1");
|
|
_eelSpawner.ToDespawn();
|
|
}
|
|
|
|
return hitReturn;
|
|
}
|
|
|
|
private Values.HitCollision OnHit(GameObject originObject, Vector2 direction, HitType type, int damage, bool pieceOfPower)
|
|
{
|
|
// can get pulled out by the hookshot at animation frame 1, 2 and 3
|
|
if (_aiComponent.CurrentStateId == "attack" && 0 < _animator.CurrentFrameIndex && _animator.CurrentFrameIndex < 4 && type == HitType.Hookshot)
|
|
{
|
|
_hockshotPosition = MapManager.ObjLink.Hookshot.HookshotPosition.Position;
|
|
_hookshotOffset = EntityPosition.Position - _hockshotPosition;
|
|
|
|
//TODO: not sure what the real condition for this is
|
|
if (_aiDamageState.CurrentLives <= 4 && Game1.RandomNumber.Next(0, 10) < 5)
|
|
_aiComponent.ChangeState("jumpingOut");
|
|
else
|
|
{
|
|
MapManager.ObjLink.Hookshot.HookshotPosition.AddPositionListener(typeof(BossSlimeEel), OnPositionChange);
|
|
_aiComponent.ChangeState("pulled");
|
|
}
|
|
|
|
_eelSpawner.SetTailIsMoving(false);
|
|
_eelSpawner.ChangeRotation();
|
|
|
|
return Values.HitCollision.Blocking;
|
|
}
|
|
|
|
if (_aiComponent.CurrentStateId == "attack")
|
|
return Values.HitCollision.RepellingParticle;
|
|
|
|
if (!_isFullyOut && !_attackOut)
|
|
return Values.HitCollision.None;
|
|
|
|
return Values.HitCollision.RepellingParticle;
|
|
}
|
|
|
|
private void OnPositionChange(CPosition position)
|
|
{
|
|
// head gets pulled out of the hole
|
|
var newPosition = position.Position + _hookshotOffset;
|
|
EntityPosition.Set(newPosition);
|
|
}
|
|
|
|
private void UpdateTailPositions()
|
|
{
|
|
SavePosition();
|
|
|
|
var indexCount = _saveIndex + (_saveCounter / _saveInterval);
|
|
var timeDiff = _saveCounter + _saveInterval * 1000;
|
|
|
|
for (var i = 0; i < _tailPositions.Length; i++)
|
|
{
|
|
indexCount -= _tailDistance[i];
|
|
if (indexCount < 0)
|
|
indexCount += _savedPosition.Length;
|
|
|
|
timeDiff -= _tailDistance[i] * _saveInterval;
|
|
var index = (int)indexCount;
|
|
|
|
_tailPositions[i] = Vector2.Lerp(
|
|
_savedPosition[index], _savedPosition[(index + 1) % _savedPosition.Length],
|
|
(timeDiff % _saveInterval) / _saveInterval);
|
|
}
|
|
}
|
|
|
|
// TODO: make this better; does not work correctly
|
|
private void SavePosition()
|
|
{
|
|
var position = EntityPosition.Position + _body.VelocityTarget * (Game1.DeltaTime / 16.6667f);
|
|
_saveCounter += Game1.DeltaTime;
|
|
var diff = _saveCounter % _saveInterval;
|
|
|
|
var updateSteps = (int)(_saveCounter / _saveInterval);
|
|
_saveIndex = (_saveIndex + updateSteps) % _savedPosition.Length;
|
|
var index = _saveIndex;
|
|
|
|
var currentDirection = _moveRotation;
|
|
|
|
while (_saveCounter >= _saveInterval)
|
|
{
|
|
_saveCounter -= _saveInterval;
|
|
|
|
index--;
|
|
if (index < 0)
|
|
index = _savedPosition.Length - 1;
|
|
|
|
var vecDir = new Vector2((float)Math.Sin(currentDirection), (float)Math.Cos(currentDirection));
|
|
_savedPosition[index] = position - vecDir * (diff / 16.6667f);
|
|
|
|
position = _savedPosition[index];
|
|
diff = _saveInterval;
|
|
currentDirection -= _moveDirection * 0.025f * (_saveInterval / 16.6667f);
|
|
}
|
|
}
|
|
}
|
|
} |