Grid/Base/GridMovement.cs
using Sandbox;
using Sandbox.Sboku;
using SWB.Demo;
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Numerics;
public sealed class GridMovement : Component
{
[Property] public float GridSize { get; set; } = 128f;
[Property] public float MoveDuration { get; set; } = 0.15f;
[Property] public float TurnDuration { get; set; } = 0.1f;
[Property] public float StepCooldown { get; set; } = 0.15f;
[Property] public float SnapBackDuration { get; set; } = 0.1f;
[Property] public bool IgnoreInput { get; set; } = false;
private GridMap GridMap;
private DemoPlayer Player;
private Component mover;
private GameTransform moverTransform;
private Vector3 moveFrom;
private Vector3 moveTo;
private float moveT;
private Rotation turnFrom;
private Rotation turnTo;
private float turnT;
private bool isTurning;
private float stepTimer;
private Vector3 safeGridPosition;
private float safeYaw;
private bool snapInProgress;
private Vector3 snapStartPos;
private float snapStartYaw;
private float snapT;
private float moveStartYaw;
private float moveTargetYaw;
protected override void OnStart()
{
Player = Components.Get<DemoPlayer>();
if (Player == null)
{
Enabled = false; // 🔑 älä käytä GridMovementia botille
return;
}
GridMap = Scene.GetComponentInChildren<GridSpawner>()?.Map;
moverTransform = Player.Transform;
safeGridPosition = moverTransform.Position;
safeYaw = moverTransform.Rotation.Angles().yaw;
}
protected override void OnUpdate()
{
if (stepTimer > 0f) stepTimer -= Time.Delta;
if (snapInProgress) { AnimateSnapBack(); return; }
if (isTurning) { AnimateTurn(); return; }
if (moveT > 0f) { AnimateMove(); return; }
if (Player != null && !Player.IsProxy && !Player.IsBot)
HandlePlayerInput();
}
public bool Move(Vector2Int dir, bool shouldTurn)
{
if (stepTimer > 0f || dir == Vector2Int.Zero)
return false;
StartMove(new Vector3(dir.x, dir.y, 0), shouldTurn);
stepTimer = StepCooldown;
return true;
}
private void HandlePlayerInput()
{
if (IgnoreInput) return;
Vector3 dir = Vector3.Zero;
bool shouldTurn = false;
if (Input.Pressed("forward")) { dir = GetCameraGridForward(); shouldTurn = true; }
else if (Input.Pressed("backward")) { dir = -GetCameraGridForward(); }
else if (Input.Pressed("left")) { dir = -GetCameraGridRight(); }
else if (Input.Pressed("right")) { dir = GetCameraGridRight(); }
if (dir != Vector3.Zero)
Move(new Vector2Int((int)dir.x, (int)dir.y), shouldTurn);
if (Input.Pressed("turnleft")) TurnBy(90);
if (Input.Pressed("turnright")) TurnBy(-90);
}
private void StartMove(Vector3 dir, bool shouldTurn)
{
var currentGrid = GridMap.WorldToGrid(moverTransform.Position);
int gx = currentGrid.x + (int)dir.x;
int gy = currentGrid.y + (int)dir.y;
moveFrom = GridMap.GridToWorld(currentGrid.x, currentGrid.y, moverTransform.Position.z);
if (!CanMoveTo(gx, gy))
{
snapStartPos = moverTransform.Position;
snapStartYaw = moverTransform.Rotation.Angles().yaw;
snapT = 0f;
snapInProgress = true;
moveTo = safeGridPosition;
moveTargetYaw = snapStartYaw;
return;
}
moveTo = GridMap.GridToWorld(gx, gy, moverTransform.Position.z);
moveStartYaw = moverTransform.Rotation.Angles().yaw;
moveTargetYaw = shouldTurn ? MathF.Atan2(dir.y, dir.x) * 180f / MathF.PI : moveStartYaw;
moveT = 0.001f;
}
private bool CanMoveTo(int x, int y)
{
if (!GridMap.InBounds(x, y))
return false;
// Seinät estävät aina liikkumisen
if (GridMap.IsWall(x, y))
return false;
// Tarkistetaan onko ruudussa ovi
var door = Scene.GetAllComponents<DoorComponent>()
.FirstOrDefault(d => d.GridX == x && d.GridY == y);
if (GridMap.IsDoor(x, y))
return door != null && door.State == DoorComponent.DoorState.Open; // Liikkuu vain jos ovi on auki
// 🔹 Tarkistetaan onko ruudussa aktivoitu ansa
var trap = Scene.GetAllComponents<TrapComponent>()
.FirstOrDefault(t => t.GridX == x && t.GridY == y);
if (trap != null && trap.IsActive) // lisätään IsActive property TrapComponentiin
return false;
// Tyhjät ruudut ja painikkeet läpäiseviä
return true;
}
private void AnimateMove()
{
moveT = MathF.Min(moveT + Time.Delta / MoveDuration, 1f);
SetPosition(Vector3.Lerp(moveFrom, moveTo, moveT));
float yaw = moveStartYaw + DeltaAngle(moveStartYaw, moveTargetYaw) * moveT;
moverTransform.Rotation = Rotation.FromYaw(yaw);
if (moveT >= 1f)
{
moveT = 0f;
safeGridPosition = moveTo;
safeYaw = moveTargetYaw;
}
}
private void AnimateTurn()
{
turnT += Time.Delta / TurnDuration;
turnT = MathF.Min(turnT, 1f);
moverTransform.Rotation = Rotation.Slerp(turnFrom, turnTo, turnT);
if (Player != null)
{
Player.EyeAngles = moverTransform.Rotation.Angles();
}
if (turnT >= 1f)
{
isTurning = false;
// varmista lopullinen synkka
if (Player != null)
Player.EyeAngles = moverTransform.Rotation.Angles();
}
}
private void AnimateSnapBack()
{
snapT = MathF.Min(snapT + Time.Delta / SnapBackDuration, 1f);
SetPosition(Vector3.Lerp(snapStartPos, moveTo, snapT));
moverTransform.Rotation = Rotation.FromYaw(
snapStartYaw + DeltaAngle(snapStartYaw, moveTargetYaw) * snapT
);
if (snapT >= 1f) snapInProgress = false;
}
private void TurnBy(float degrees)
{
if (isTurning) return;
turnFrom = moverTransform.Rotation;
turnTo = Rotation.FromYaw(turnFrom.Angles().yaw + degrees);
turnT = 0f;
isTurning = true;
}
private Vector3 GetCameraGridForward()
{
float yaw = Player != null ? Player.EyeAngles.yaw : moverTransform.Rotation.Angles().yaw;
yaw = MathF.Round(yaw / 90f) * 90f;
float rad = yaw * MathF.PI / 180f;
return new Vector3(MathF.Round(MathF.Cos(rad)), MathF.Round(MathF.Sin(rad)), 0);
}
private Vector3 GetCameraGridRight()
{
var fwd = GetCameraGridForward();
return new Vector3(fwd.y, -fwd.x, 0);
}
private float DeltaAngle(float a, float b)
{
float delta = (b - a) % 360f;
if (delta > 180f) delta -= 360f;
if (delta < -180f) delta += 360f;
return delta;
}
private void SetPosition(Vector3 pos)
{
var cc = Components.Get<CharacterController>();
if (cc != null) cc.WorldPosition = pos;
else moverTransform.Position = pos;
}
public void SnapToGrid()
{
if (GridMap == null)
return;
var g = GridMap.WorldToGrid(moverTransform.Position);
var snapped = GridMap.GridToWorld(g.x, g.y, moverTransform.Position.z);
SetPosition(snapped);
safeGridPosition = snapped;
safeYaw = moverTransform.Rotation.Angles().yaw;
}
public Vector2Int GetCurrentGrid()
{
var g = GridMap.WorldToGrid(moverTransform.Position);
return new Vector2Int(g.x, g.y);
}
public void EnterFreeMode()
{
IgnoreInput = true;
// Katkaise kaikki grid-animaatiot
moveT = 0f;
turnT = 0f;
isTurning = false;
snapInProgress = false;
}
public void EnterGridMode()
{
IgnoreInput = false;
// Pakota takaisin gridiin
SnapToGrid();
// Lukitse yaw 90° välein
float yaw = moverTransform.Rotation.Angles().yaw;
yaw = MathF.Round(yaw / 90f) * 90f;
moverTransform.Rotation = Rotation.FromYaw(yaw);
if (Player != null)
Player.EyeAngles = moverTransform.Rotation.Angles();
// Nollaa liike
moveT = 0f;
turnT = 0f;
isTurning = false;
snapInProgress = false;
}
}