Upload core-dump files
98
core-dump/Scripts/CurveCcwGenerator.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System.Collections.Generic;
|
||||
using AstroDX.Contexts.Gameplay.PlayerScope;
|
||||
using AstroDX.Utilities;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.SlideGenerators
|
||||
{
|
||||
public sealed class CurveCcwGenerator : SlideGenerator
|
||||
{
|
||||
private const float CurveRadius = RenderManager.CenterRadius;
|
||||
private const float RingRadius = RenderManager.PlayFieldRadius;
|
||||
private readonly float _curveLength;
|
||||
private readonly float _endForward;
|
||||
private readonly Vector2 _endPoint;
|
||||
|
||||
private readonly float _startForward;
|
||||
|
||||
private readonly float _startLength;
|
||||
|
||||
private readonly Vector2 _startPoint;
|
||||
private readonly Vector2 _tangentInPoint;
|
||||
private readonly float _tangentInRotation;
|
||||
private readonly Vector2 _tangentOutPoint;
|
||||
private readonly float _totalLength;
|
||||
|
||||
public CurveCcwGenerator(IReadOnlyList<Location> vertices)
|
||||
{
|
||||
var startRotation = GetRotation(vertices[0]);
|
||||
var endRotation = GetRotation(vertices[1]);
|
||||
|
||||
_tangentInRotation = startRotation +
|
||||
Trigonometry.GetTangentAngleDelta(CurveRadius, RingRadius, false);
|
||||
var tangentOutRotation = endRotation +
|
||||
Trigonometry.GetTangentAngleDelta(CurveRadius, RingRadius, true);
|
||||
|
||||
_startPoint = GetPositionRadial(startRotation);
|
||||
_tangentInPoint = GetPositionRadial(_tangentInRotation, CurveRadius);
|
||||
_tangentOutPoint = GetPositionRadial(tangentOutRotation, CurveRadius);
|
||||
_endPoint = GetPositionRadial(endRotation);
|
||||
|
||||
var startSegment = _tangentInPoint - _startPoint;
|
||||
_startLength = startSegment.magnitude;
|
||||
_startForward = Mathf.Atan2(startSegment.y, startSegment.x);
|
||||
|
||||
_curveLength = Trigonometry.GetAngleSpan(_tangentInRotation, tangentOutRotation,
|
||||
false) * CurveRadius;
|
||||
|
||||
var endSegment = _endPoint - _tangentOutPoint;
|
||||
var endLength = endSegment.magnitude;
|
||||
_endForward = Mathf.Atan2(endSegment.y, endSegment.x);
|
||||
|
||||
_totalLength = _startLength + _curveLength + endLength;
|
||||
}
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return _totalLength;
|
||||
}
|
||||
|
||||
public override void GetPoint(float t, out Vector2 position, out float rotation)
|
||||
{
|
||||
var distanceFromStart = t * _totalLength;
|
||||
|
||||
if (distanceFromStart < _startLength)
|
||||
{
|
||||
position = Vector2.Lerp(_startPoint,
|
||||
_tangentInPoint,
|
||||
Mathf.InverseLerp(0,
|
||||
_startLength,
|
||||
distanceFromStart));
|
||||
|
||||
rotation = _startForward;
|
||||
}
|
||||
else if (distanceFromStart < _startLength + _curveLength)
|
||||
{
|
||||
var localT = Mathf.InverseLerp(_startLength, _startLength + _curveLength, distanceFromStart);
|
||||
position = new Vector2(Mathf.Cos(_tangentInRotation + _curveLength / CurveRadius * localT) *
|
||||
CurveRadius,
|
||||
Mathf.Sin(_tangentInRotation + _curveLength / CurveRadius * localT) *
|
||||
CurveRadius);
|
||||
|
||||
var forward = position.Rotate(Trigonometry.Tau / 4);
|
||||
rotation = Mathf.Atan2(forward.y, forward.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
position = Vector2.Lerp(_tangentOutPoint,
|
||||
_endPoint,
|
||||
Mathf.InverseLerp(_startLength + _curveLength,
|
||||
_totalLength,
|
||||
distanceFromStart));
|
||||
|
||||
rotation = _endForward;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
98
core-dump/Scripts/CurveCwGenerator.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System.Collections.Generic;
|
||||
using AstroDX.Contexts.Gameplay.PlayerScope;
|
||||
using AstroDX.Utilities;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.SlideGenerators
|
||||
{
|
||||
public sealed class CurveCwGenerator : SlideGenerator
|
||||
{
|
||||
private const float CurveRadius = RenderManager.CenterRadius;
|
||||
private const float RingRadius = RenderManager.PlayFieldRadius;
|
||||
private readonly float _curveLength;
|
||||
private readonly float _endForward;
|
||||
private readonly Vector2 _endPoint;
|
||||
|
||||
private readonly float _startForward;
|
||||
|
||||
private readonly float _startLength;
|
||||
|
||||
private readonly Vector2 _startPoint;
|
||||
private readonly Vector2 _tangentInPoint;
|
||||
private readonly float _tangentInRotation;
|
||||
private readonly Vector2 _tangentOutPoint;
|
||||
private readonly float _totalLength;
|
||||
|
||||
public CurveCwGenerator(IReadOnlyList<Location> vertices)
|
||||
{
|
||||
var startRotation = GetRotation(vertices[0]);
|
||||
var endRotation = GetRotation(vertices[1]);
|
||||
|
||||
_tangentInRotation = startRotation +
|
||||
Trigonometry.GetTangentAngleDelta(CurveRadius, RingRadius, true);
|
||||
var tangentOutRotation = endRotation +
|
||||
Trigonometry.GetTangentAngleDelta(CurveRadius, RingRadius, false);
|
||||
|
||||
_startPoint = GetPositionRadial(startRotation);
|
||||
_tangentInPoint = GetPositionRadial(_tangentInRotation, CurveRadius);
|
||||
_tangentOutPoint = GetPositionRadial(tangentOutRotation, CurveRadius);
|
||||
_endPoint = GetPositionRadial(endRotation);
|
||||
|
||||
var startSegment = _tangentInPoint - _startPoint;
|
||||
_startLength = startSegment.magnitude;
|
||||
_startForward = Mathf.Atan2(startSegment.y, startSegment.x);
|
||||
|
||||
_curveLength = Trigonometry.GetAngleSpan(_tangentInRotation, tangentOutRotation,
|
||||
true) * CurveRadius;
|
||||
|
||||
var endSegment = _endPoint - _tangentOutPoint;
|
||||
var endLength = endSegment.magnitude;
|
||||
_endForward = Mathf.Atan2(endSegment.y, endSegment.x);
|
||||
|
||||
_totalLength = _startLength + _curveLength + endLength;
|
||||
}
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return _totalLength;
|
||||
}
|
||||
|
||||
public override void GetPoint(float t, out Vector2 position, out float rotation)
|
||||
{
|
||||
var distanceFromStart = t * _totalLength;
|
||||
|
||||
if (distanceFromStart < _startLength)
|
||||
{
|
||||
position = Vector2.Lerp(_startPoint,
|
||||
_tangentInPoint,
|
||||
Mathf.InverseLerp(0,
|
||||
_startLength,
|
||||
distanceFromStart));
|
||||
|
||||
rotation = _startForward;
|
||||
}
|
||||
else if (distanceFromStart < _startLength + _curveLength)
|
||||
{
|
||||
var localT = Mathf.InverseLerp(_startLength, _startLength + _curveLength, distanceFromStart);
|
||||
position = new Vector2(Mathf.Cos(_tangentInRotation - _curveLength / CurveRadius * localT) *
|
||||
CurveRadius,
|
||||
Mathf.Sin(_tangentInRotation - _curveLength / CurveRadius * localT) *
|
||||
CurveRadius);
|
||||
|
||||
var forward = position.Rotate(-Trigonometry.Tau / 4);
|
||||
rotation = Mathf.Atan2(forward.y, forward.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
position = Vector2.Lerp(_tangentOutPoint,
|
||||
_endPoint,
|
||||
Mathf.InverseLerp(_startLength + _curveLength,
|
||||
_totalLength,
|
||||
distanceFromStart));
|
||||
|
||||
rotation = _endForward;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
116
core-dump/Scripts/EdgeCurveCcwGenerator.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using System.Collections.Generic;
|
||||
using AstroDX.Contexts.Gameplay.PlayerScope;
|
||||
using AstroDX.Utilities;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.SlideGenerators
|
||||
{
|
||||
public sealed class EdgeCurveCcwGenerator : SlideGenerator
|
||||
{
|
||||
private const float CurveRadius = RenderManager.CenterRadius * 1.2f;
|
||||
private const float CenterAngularOffset = Trigonometry.Tau / 4 - Trigonometry.Tau / 16;
|
||||
private const float CenterRadialOffset = RenderManager.PlayFieldRadius * 0.4662f;
|
||||
|
||||
private readonly Vector2 _centerPosition;
|
||||
private readonly float _curveLength;
|
||||
private readonly Vector2 _endPoint;
|
||||
|
||||
private readonly float _startRotation;
|
||||
private readonly float _endRotation;
|
||||
|
||||
private readonly float _startLength;
|
||||
private readonly Vector2 _startPoint;
|
||||
private readonly Vector2 _tangentInPoint;
|
||||
private readonly float _tangentInRotation;
|
||||
private readonly Vector2 _tangentOutPoint;
|
||||
private readonly float _totalLength;
|
||||
|
||||
public EdgeCurveCcwGenerator(IReadOnlyList<Location> vertices)
|
||||
{
|
||||
var startRotation = GetRotation(vertices[0]);
|
||||
var endRotation = GetRotation(vertices[1]);
|
||||
|
||||
var centerAngle = startRotation - CenterAngularOffset;
|
||||
_centerPosition = new Vector2(CenterRadialOffset * Mathf.Cos(centerAngle),
|
||||
CenterRadialOffset * Mathf.Sin(centerAngle));
|
||||
|
||||
_startPoint = GetPositionRadial(startRotation);
|
||||
|
||||
var relativeStartRotation = Trigonometry.ToPolarAngle(_startPoint, _centerPosition);
|
||||
|
||||
var magnitude = (_centerPosition - _startPoint).magnitude;
|
||||
var startDelta = Trigonometry.GetTangentAngleDelta(CurveRadius, magnitude, false);
|
||||
|
||||
_tangentInRotation = relativeStartRotation + startDelta;
|
||||
_tangentInPoint = GetPositionRadial(_tangentInRotation, CurveRadius) +
|
||||
_centerPosition;
|
||||
|
||||
_endPoint = GetPositionRadial(endRotation);
|
||||
|
||||
var relativeEndRotation = Trigonometry.ToPolarAngle(_endPoint, _centerPosition);
|
||||
var endMagnitude = (_endPoint - _centerPosition).magnitude;
|
||||
var endDelta = Trigonometry.GetTangentAngleDelta(CurveRadius, endMagnitude, true);
|
||||
|
||||
var tangentOutRotation = relativeEndRotation + endDelta;
|
||||
_tangentOutPoint = GetPositionRadial(tangentOutRotation, CurveRadius) +
|
||||
_centerPosition;
|
||||
|
||||
var startSegment = _tangentInPoint - _startPoint;
|
||||
_startLength = startSegment.magnitude;
|
||||
_startRotation = Mathf.Atan2(startSegment.y, startSegment.x);
|
||||
|
||||
_curveLength = Trigonometry.GetAngleSpan(_tangentInRotation, tangentOutRotation,
|
||||
false, Trigonometry.Tau / 4f) * CurveRadius;
|
||||
|
||||
var endSegment = _endPoint - _tangentOutPoint;
|
||||
var endLength = endSegment.magnitude;
|
||||
_endRotation = Mathf.Atan2(endSegment.y, endSegment.x);
|
||||
|
||||
_totalLength = _startLength + _curveLength + endLength;
|
||||
}
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return _totalLength;
|
||||
}
|
||||
|
||||
public override void GetPoint(float t, out Vector2 position, out float rotation)
|
||||
{
|
||||
var distanceFromStart = t * _totalLength;
|
||||
|
||||
if (distanceFromStart < _startLength)
|
||||
{
|
||||
position = Vector2.Lerp(_startPoint,
|
||||
_tangentInPoint,
|
||||
Mathf.InverseLerp(0,
|
||||
_startLength,
|
||||
distanceFromStart));
|
||||
|
||||
rotation = _startRotation;
|
||||
}
|
||||
else if (distanceFromStart < _startLength + _curveLength)
|
||||
{
|
||||
var localT = Mathf.InverseLerp(_startLength, _startLength + _curveLength, distanceFromStart);
|
||||
position = new Vector2(Mathf.Cos(_tangentInRotation + _curveLength / CurveRadius * localT) *
|
||||
CurveRadius,
|
||||
Mathf.Sin(_tangentInRotation + _curveLength / CurveRadius * localT) *
|
||||
CurveRadius);
|
||||
|
||||
var forward = position.Rotate(Trigonometry.Tau / 4);
|
||||
rotation = Mathf.Atan2(forward.y, forward.x);
|
||||
position += _centerPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
position = Vector2.Lerp(_tangentOutPoint,
|
||||
_endPoint,
|
||||
Mathf.InverseLerp(_startLength + _curveLength,
|
||||
_totalLength,
|
||||
distanceFromStart));
|
||||
|
||||
rotation = _endRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
116
core-dump/Scripts/EdgeCurveCwGenerator.cs
Normal file
@@ -0,0 +1,116 @@
|
||||
using System.Collections.Generic;
|
||||
using AstroDX.Contexts.Gameplay.PlayerScope;
|
||||
using AstroDX.Utilities;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.SlideGenerators
|
||||
{
|
||||
public sealed class EdgeCurveCwGenerator : SlideGenerator
|
||||
{
|
||||
private const float CurveRadius = RenderManager.CenterRadius * 1.2f;
|
||||
private const float CenterAngularOffset = Trigonometry.Tau / 4 - Trigonometry.Tau / 16;
|
||||
private const float CenterRadialOffset = RenderManager.PlayFieldRadius * 0.4662f;
|
||||
|
||||
private readonly Vector2 _centerPosition;
|
||||
private readonly float _curveLength;
|
||||
private readonly Vector2 _endPoint;
|
||||
|
||||
private readonly float _startRotation;
|
||||
private readonly float _endRotation;
|
||||
|
||||
private readonly float _startLength;
|
||||
private readonly Vector2 _startPoint;
|
||||
private readonly Vector2 _tangentInPoint;
|
||||
private readonly float _tangentInRotation;
|
||||
private readonly Vector2 _tangentOutPoint;
|
||||
private readonly float _totalLength;
|
||||
|
||||
public EdgeCurveCwGenerator(IReadOnlyList<Location> vertices)
|
||||
{
|
||||
var startRotation = GetRotation(vertices[0]);
|
||||
var endRotation = GetRotation(vertices[1]);
|
||||
|
||||
var centerAngle = startRotation + CenterAngularOffset;
|
||||
_centerPosition = new Vector2(CenterRadialOffset * Mathf.Cos(centerAngle),
|
||||
CenterRadialOffset * Mathf.Sin(centerAngle));
|
||||
|
||||
_startPoint = GetPositionRadial(startRotation);
|
||||
|
||||
var relativeStartRotation = Trigonometry.ToPolarAngle(_startPoint, _centerPosition);
|
||||
|
||||
var magnitude = (_centerPosition - _startPoint).magnitude;
|
||||
var startDelta = Trigonometry.GetTangentAngleDelta(CurveRadius, magnitude, true);
|
||||
|
||||
_tangentInRotation = relativeStartRotation + startDelta;
|
||||
_tangentInPoint = GetPositionRadial(_tangentInRotation, CurveRadius) +
|
||||
_centerPosition;
|
||||
|
||||
_endPoint = GetPositionRadial(endRotation);
|
||||
|
||||
var relativeEndRotation = Trigonometry.ToPolarAngle(_endPoint, _centerPosition);
|
||||
var endMagnitude = (_endPoint - _centerPosition).magnitude;
|
||||
var endDelta = Trigonometry.GetTangentAngleDelta(CurveRadius, endMagnitude, false);
|
||||
|
||||
var tangentOutRotation = relativeEndRotation + endDelta;
|
||||
_tangentOutPoint = GetPositionRadial(tangentOutRotation, CurveRadius) +
|
||||
_centerPosition;
|
||||
|
||||
var startSegment = _tangentInPoint - _startPoint;
|
||||
_startLength = startSegment.magnitude;
|
||||
_startRotation = Mathf.Atan2(startSegment.y, startSegment.x);
|
||||
|
||||
_curveLength = Trigonometry.GetAngleSpan(_tangentInRotation, tangentOutRotation,
|
||||
true, Trigonometry.Tau / 4f) * CurveRadius;
|
||||
|
||||
var endSegment = _endPoint - _tangentOutPoint;
|
||||
var endLength = endSegment.magnitude;
|
||||
_endRotation = Mathf.Atan2(endSegment.y, endSegment.x);
|
||||
|
||||
_totalLength = _startLength + _curveLength + endLength;
|
||||
}
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return _totalLength;
|
||||
}
|
||||
|
||||
public override void GetPoint(float t, out Vector2 position, out float rotation)
|
||||
{
|
||||
var distanceFromStart = t * _totalLength;
|
||||
|
||||
if (distanceFromStart < _startLength)
|
||||
{
|
||||
position = Vector2.Lerp(_startPoint,
|
||||
_tangentInPoint,
|
||||
Mathf.InverseLerp(0,
|
||||
_startLength,
|
||||
distanceFromStart));
|
||||
|
||||
rotation = _startRotation;
|
||||
}
|
||||
else if (distanceFromStart < _startLength + _curveLength)
|
||||
{
|
||||
var localT = Mathf.InverseLerp(_startLength, _startLength + _curveLength, distanceFromStart);
|
||||
position = new Vector2(Mathf.Cos(_tangentInRotation - _curveLength / CurveRadius * localT) *
|
||||
CurveRadius,
|
||||
Mathf.Sin(_tangentInRotation - _curveLength / CurveRadius * localT) *
|
||||
CurveRadius);
|
||||
|
||||
var forward = position.Rotate(-Trigonometry.Tau / 4);
|
||||
rotation = Mathf.Atan2(forward.y, forward.x);
|
||||
position += _centerPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
position = Vector2.Lerp(_tangentOutPoint,
|
||||
_endPoint,
|
||||
Mathf.InverseLerp(_startLength + _curveLength,
|
||||
_totalLength,
|
||||
distanceFromStart));
|
||||
|
||||
rotation = _endRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
63
core-dump/Scripts/EdgeFoldGenerator.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System.Collections.Generic;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.SlideGenerators
|
||||
{
|
||||
public sealed class EdgeFoldGenerator : SlideGenerator
|
||||
{
|
||||
private readonly Vector2 _endPoint;
|
||||
private readonly Vector2 _midPoint;
|
||||
private readonly Vector2 _startPoint;
|
||||
|
||||
private readonly float _startRotation;
|
||||
private readonly float _endRotation;
|
||||
|
||||
private readonly float _startSegmentLength;
|
||||
private readonly float _totalLength;
|
||||
|
||||
public EdgeFoldGenerator(IReadOnlyList<Location> vertices)
|
||||
{
|
||||
_startPoint = GetPosition(vertices[0]);
|
||||
_midPoint = GetPosition(vertices[1]);
|
||||
_endPoint = GetPosition(vertices[2]);
|
||||
|
||||
var startSegment = _midPoint - _startPoint;
|
||||
_startSegmentLength = startSegment.magnitude;
|
||||
_startRotation = Mathf.Atan2(startSegment.y, startSegment.x);
|
||||
|
||||
var endSegment = _endPoint - _midPoint;
|
||||
var endSegmentSpan = endSegment.magnitude;
|
||||
_endRotation = Mathf.Atan2(endSegment.y, endSegment.x);
|
||||
|
||||
_totalLength = _startSegmentLength + endSegmentSpan;
|
||||
}
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return _totalLength;
|
||||
}
|
||||
|
||||
public override void GetPoint(float t, out Vector2 position, out float rotation)
|
||||
{
|
||||
var distanceFromStart = t * _totalLength;
|
||||
|
||||
if (distanceFromStart < _startSegmentLength)
|
||||
{
|
||||
position = Vector2.Lerp(_startPoint, _midPoint,
|
||||
Mathf.InverseLerp(0,
|
||||
_startSegmentLength / _totalLength,
|
||||
t));
|
||||
rotation = _startRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
position = Vector2.Lerp(_midPoint, _endPoint,
|
||||
Mathf.InverseLerp(_startSegmentLength / _totalLength,
|
||||
1,
|
||||
t));
|
||||
rotation = _endRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
327
core-dump/Scripts/FanSlideSegmentHandler.cs
Normal file
@@ -0,0 +1,327 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AstroDX.Contexts.Gameplay.Behaviours.Slide.SlideMarkers;
|
||||
using AstroDX.Contexts.Gameplay.Interactions;
|
||||
using AstroDX.Contexts.Gameplay.PlayerScope;
|
||||
using AstroDX.Contexts.Gameplay.SlideGenerators;
|
||||
using AstroDX.Globals;
|
||||
using Medicine;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.Behaviours.Slide.Handlers
|
||||
{
|
||||
public class FanSlideSegmentHandler : SlideSegmentHandler
|
||||
{
|
||||
private const int Margin = 2;
|
||||
private const int ArrowCount = 11;
|
||||
|
||||
private readonly List<FanSlideArrow> _arrows = new();
|
||||
private readonly Vector2[] _endPositions;
|
||||
|
||||
private readonly List<List<TouchInteractable>> _interactableGroups = new();
|
||||
|
||||
private readonly Vector2 _startPosition;
|
||||
private readonly Vector2[] _ups;
|
||||
|
||||
private int _interactionReceivedState;
|
||||
|
||||
private SlideStarBehaviour[] _stars;
|
||||
|
||||
public FanSlideSegmentHandler(SlideBehaviour slideBehaviour,
|
||||
SlideSegment segment,
|
||||
Location startLocation) :
|
||||
base(slideBehaviour)
|
||||
{
|
||||
var vertices = segment.vertices.ToList();
|
||||
vertices.Insert(0, startLocation);
|
||||
|
||||
_startPosition = SlideGenerator.GetPosition(vertices[0]);
|
||||
|
||||
var ccwEndLocation = startLocation;
|
||||
ccwEndLocation.index += 3;
|
||||
|
||||
var centerEndLocation = startLocation;
|
||||
centerEndLocation.index += 4;
|
||||
|
||||
var cwEndLocation = startLocation;
|
||||
cwEndLocation.index += 5;
|
||||
|
||||
_endPositions = new[]
|
||||
{
|
||||
SlideGenerator.GetPosition(ccwEndLocation),
|
||||
SlideGenerator.GetPosition(centerEndLocation),
|
||||
SlideGenerator.GetPosition(cwEndLocation)
|
||||
};
|
||||
|
||||
_ups = new[]
|
||||
{
|
||||
_endPositions[0] - _startPosition,
|
||||
_endPositions[1] - _startPosition,
|
||||
_endPositions[2] - _startPosition
|
||||
};
|
||||
|
||||
_stars = new[]
|
||||
{
|
||||
SlideManager.slideStars.Get(),
|
||||
SlideManager.slideStars.Get(),
|
||||
SlideManager.slideStars.Get()
|
||||
};
|
||||
|
||||
foreach (var star in _stars) star.Initialize(ParentPath, ParentNote.parentCollection);
|
||||
|
||||
GenerateSensors();
|
||||
GenerateArrows();
|
||||
}
|
||||
|
||||
[Inject.Single]
|
||||
private SlideManager SlideManager { get; }
|
||||
|
||||
[Inject.Single]
|
||||
private TouchManager TouchManager { get; }
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return RenderManager.PlayFieldRadius * 2;
|
||||
}
|
||||
|
||||
public override void OnUpdate(float segmentT)
|
||||
{
|
||||
if (IsJudgementTarget)
|
||||
CheckInteraction();
|
||||
|
||||
UpdateSlideStarPosition(segmentT);
|
||||
UpdateArrowOpacity();
|
||||
}
|
||||
|
||||
private void UpdateArrowOpacity()
|
||||
{
|
||||
var timeSinceNoteStart = TimeSinceSlideStart + ParentPath.delay;
|
||||
|
||||
var alpha = 0.8f;
|
||||
if (timeSinceNoteStart < 0)
|
||||
{
|
||||
var colorPoint = Mathf.InverseLerp(-Persistent.Settings.Gameplay.slideFadeInDuration,
|
||||
0,
|
||||
(float)timeSinceNoteStart);
|
||||
|
||||
alpha = Mathf.Lerp(0, 0.8f, colorPoint);
|
||||
}
|
||||
|
||||
foreach (var arrow in _arrows.Select(a => a.spriteRenderer))
|
||||
{
|
||||
var color = arrow.color;
|
||||
color.a = alpha;
|
||||
|
||||
arrow.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckInteraction()
|
||||
{
|
||||
if (_interactionReceivedState == 0)
|
||||
{
|
||||
if (!_interactableGroups[0][0].GetSlideJudgement())
|
||||
return;
|
||||
|
||||
_interactionReceivedState = 1;
|
||||
foreach (var slideArrow in _arrows
|
||||
.Where(a => a.interactionGroupIndex == 0)
|
||||
.ToList())
|
||||
{
|
||||
_arrows.Remove(slideArrow);
|
||||
slideArrow.ExitSequence();
|
||||
}
|
||||
}
|
||||
|
||||
if (_interactionReceivedState >= 3)
|
||||
{
|
||||
Cleared = true;
|
||||
return;
|
||||
}
|
||||
|
||||
for (var groupIndex = _interactionReceivedState; groupIndex < 3; groupIndex++)
|
||||
{
|
||||
foreach (var interactable in
|
||||
_interactableGroups[groupIndex]
|
||||
.Where(interactable => interactable.GetSlideJudgement())
|
||||
.ToList())
|
||||
_interactableGroups[groupIndex].Remove(interactable);
|
||||
|
||||
if (_interactableGroups[groupIndex].Count > 0 ||
|
||||
_interactionReceivedState < groupIndex)
|
||||
continue;
|
||||
|
||||
foreach (var slideArrow in _arrows
|
||||
.Where(a => a.interactionGroupIndex == _interactionReceivedState)
|
||||
.ToList())
|
||||
{
|
||||
_arrows.Remove(slideArrow);
|
||||
slideArrow.ExitSequence();
|
||||
}
|
||||
|
||||
_interactionReceivedState++;
|
||||
}
|
||||
}
|
||||
|
||||
public override float GetRemainingLength()
|
||||
{
|
||||
return (3 - _interactionReceivedState) / 3f * GetLength();
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
foreach (var slideArrow in _arrows)
|
||||
SlideManager.fanSlideArrows.Release(slideArrow);
|
||||
|
||||
foreach (var star in _stars)
|
||||
SlideManager.slideStars.Release(star);
|
||||
}
|
||||
|
||||
private void UpdateSlideStarPosition(float segmentT)
|
||||
{
|
||||
if (disposed || _stars is null)
|
||||
return;
|
||||
|
||||
for (var index = 0; index < _stars.Length; index++)
|
||||
{
|
||||
var star = _stars[index];
|
||||
|
||||
if (star == null)
|
||||
continue;
|
||||
|
||||
var transform = star.transform;
|
||||
|
||||
if (segmentT >= 1 && indexInSlide != ParentPath.segments.Count - 1)
|
||||
{
|
||||
transform.localScale = Vector3.one * Persistent.Settings.Gameplay.noteScale;
|
||||
star.Appearance.Color = new Color(1, 1, 1, 0);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var position = Vector3.Lerp(_startPosition,
|
||||
_endPositions[index],
|
||||
segmentT);
|
||||
|
||||
transform.localPosition = position;
|
||||
transform.up = _ups[index];
|
||||
|
||||
if (TimeSinceSlideStart < 0 &&
|
||||
indexInSlide == 0 &&
|
||||
ParentNote.slideMorph != SlideMorph.SuddenIn)
|
||||
{
|
||||
var interpolation =
|
||||
Mathf.InverseLerp(-ParentPath.delay, 0,
|
||||
(float)TimeSinceSlideStart);
|
||||
transform.localScale = new Vector3(interpolation, interpolation) *
|
||||
Persistent.Settings.Gameplay.noteScale;
|
||||
star.Appearance.Color = new Color(1, 1, 1, interpolation);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (segmentT < 0)
|
||||
return;
|
||||
|
||||
transform.localScale = Vector3.one * Persistent.Settings.Gameplay.noteScale;
|
||||
star.Appearance.Color = Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetJudgementVector(out Vector2 position, out float rotation)
|
||||
{
|
||||
position = _endPositions[1];
|
||||
rotation = Mathf.Atan2(_ups[1].y, _ups[1].x);
|
||||
}
|
||||
|
||||
private void GenerateSensors()
|
||||
{
|
||||
_interactableGroups.AddRange(new List<TouchInteractable>[]
|
||||
{
|
||||
new()
|
||||
{
|
||||
TouchManager.GetCollider(new Location
|
||||
{
|
||||
group = NoteGroup.ASensor,
|
||||
index = ParentNote.location.index
|
||||
})
|
||||
},
|
||||
new()
|
||||
{
|
||||
TouchManager.GetCollider(new Location
|
||||
{
|
||||
group = NoteGroup.BSensor,
|
||||
index = (ParentNote.location.index + 2) %
|
||||
8
|
||||
}),
|
||||
TouchManager.GetCollider(new Location
|
||||
{
|
||||
group = NoteGroup.BSensor,
|
||||
index = (ParentNote.location.index + 6) %
|
||||
8
|
||||
})
|
||||
},
|
||||
new()
|
||||
{
|
||||
TouchManager.GetCollider(new Location
|
||||
{
|
||||
group = NoteGroup.ASensor,
|
||||
index = (ParentNote.location.index + 5) %
|
||||
8
|
||||
}),
|
||||
TouchManager.GetCollider(new Location
|
||||
{
|
||||
group = NoteGroup.ASensor,
|
||||
index = (ParentNote.location.index + 3) %
|
||||
8
|
||||
}),
|
||||
TouchManager.GetCollider(new Location
|
||||
{
|
||||
group = NoteGroup.ASensor,
|
||||
index = (ParentNote.location.index + 4) %
|
||||
8
|
||||
})
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void GenerateArrows()
|
||||
{
|
||||
var halfMargin = Mathf.RoundToInt(Margin / 2f);
|
||||
for (var i = 0;
|
||||
i < ArrowCount;
|
||||
i++)
|
||||
{
|
||||
var position = Vector3.Lerp(_startPosition,
|
||||
_endPositions[1],
|
||||
(float)(i + halfMargin) / (ArrowCount + Margin));
|
||||
|
||||
var arrow = SlideManager.fanSlideArrows.Get();
|
||||
arrow.Initialize(position,
|
||||
_ups[1],
|
||||
ArrowCount,
|
||||
i,
|
||||
isBreak,
|
||||
isEach);
|
||||
|
||||
AssignArrows(arrow, i);
|
||||
}
|
||||
}
|
||||
|
||||
private void AssignArrows(FanSlideArrow arrow, int index)
|
||||
{
|
||||
_arrows.Add(arrow);
|
||||
|
||||
if (index < ArrowCount / 3f)
|
||||
arrow.interactionGroupIndex = 0;
|
||||
else if (index < ArrowCount * 2 / 3f)
|
||||
arrow.interactionGroupIndex = 1;
|
||||
else
|
||||
arrow.interactionGroupIndex = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
63
core-dump/Scripts/FoldGenerator.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System.Collections.Generic;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.SlideGenerators
|
||||
{
|
||||
public sealed class FoldGenerator : SlideGenerator
|
||||
{
|
||||
private readonly Vector2 _endPoint;
|
||||
private readonly float _endRotation;
|
||||
private readonly Vector2 _midPoint;
|
||||
private readonly Vector2 _startPoint;
|
||||
|
||||
private readonly float _startRotation;
|
||||
|
||||
private readonly float _startSegmentLength;
|
||||
private readonly float _totalLength;
|
||||
|
||||
public FoldGenerator(IReadOnlyList<Location> vertices)
|
||||
{
|
||||
_startPoint = GetPosition(vertices[0]);
|
||||
_endPoint = GetPosition(vertices[1]);
|
||||
_midPoint = Vector2.zero;
|
||||
|
||||
var startSegment = _midPoint - _startPoint;
|
||||
_startSegmentLength = startSegment.magnitude;
|
||||
_startRotation = Mathf.Atan2(startSegment.y, startSegment.x);
|
||||
|
||||
var endSegment = _endPoint - _midPoint;
|
||||
var endSegmentSpan = endSegment.magnitude;
|
||||
_endRotation = Mathf.Atan2(endSegment.y, endSegment.x);
|
||||
|
||||
_totalLength = _startSegmentLength + endSegmentSpan;
|
||||
}
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return _totalLength;
|
||||
}
|
||||
|
||||
public override void GetPoint(float t, out Vector2 position, out float rotation)
|
||||
{
|
||||
var distanceFromStart = t * _totalLength;
|
||||
|
||||
if (distanceFromStart < _startSegmentLength)
|
||||
{
|
||||
position = Vector2.Lerp(_startPoint, _midPoint,
|
||||
Mathf.InverseLerp(0,
|
||||
_startSegmentLength / _totalLength,
|
||||
t));
|
||||
rotation = _startRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
position = Vector2.Lerp(_midPoint, _endPoint,
|
||||
Mathf.InverseLerp(_startSegmentLength / _totalLength,
|
||||
1,
|
||||
t));
|
||||
rotation = _endRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
69
core-dump/Scripts/GameTime.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Timing
|
||||
{
|
||||
public class GameTime : MonoBehaviour
|
||||
{
|
||||
private double _lastCapturedDspTime;
|
||||
public static bool Active { get; private set; }
|
||||
public static double StartTime { get; private set; }
|
||||
public static double TimeSinceClipStart { get; private set; }
|
||||
|
||||
private static NativeLinearRegression TimePrediction { get; set; }
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!Active) return;
|
||||
|
||||
#region Smoothen DSP buffer time
|
||||
|
||||
if (AudioSettings.dspTime > _lastCapturedDspTime)
|
||||
{
|
||||
TimePrediction.Sample(new double2(Time.realtimeSinceStartupAsDouble, AudioSettings.dspTime));
|
||||
_lastCapturedDspTime = AudioSettings.dspTime;
|
||||
}
|
||||
|
||||
var smoothDspTime = TimePrediction.SampleCount < 2
|
||||
? AudioSettings.dspTime
|
||||
: TimePrediction.Predict(Time.realtimeSinceStartupAsDouble);
|
||||
|
||||
#endregion
|
||||
|
||||
TimeSinceClipStart = smoothDspTime - StartTime;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
TimePrediction.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells the time manager to start counting time
|
||||
/// </summary>
|
||||
public static void StartFrom(double startTime)
|
||||
{
|
||||
StartTime = startTime;
|
||||
TimeSinceClipStart = AudioSettings.dspTime - startTime;
|
||||
Active = true;
|
||||
|
||||
TimePrediction ??= new NativeLinearRegression();
|
||||
|
||||
TimePrediction.Clear();
|
||||
}
|
||||
|
||||
public static void Pause()
|
||||
{
|
||||
Active = false;
|
||||
}
|
||||
|
||||
public static void UnPause(double timeSinceClipStart)
|
||||
{
|
||||
TimePrediction.Clear();
|
||||
StartTime = AudioSettings.dspTime - timeSinceClipStart;
|
||||
TimeSinceClipStart = timeSinceClipStart;
|
||||
|
||||
Active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
102
core-dump/Scripts/NativeLinearRegression.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace Timing
|
||||
{
|
||||
public sealed class NativeLinearRegression : IDisposable
|
||||
{
|
||||
public int SampleCount { get; private set; }
|
||||
public int MaxSampleCount { get; }
|
||||
|
||||
private NativeArray<double2> _samples;
|
||||
|
||||
public NativeLinearRegression(int maxSampleCount = 12)
|
||||
{
|
||||
MaxSampleCount = maxSampleCount;
|
||||
_samples = new NativeArray<double2>(maxSampleCount, Allocator.Persistent);
|
||||
}
|
||||
|
||||
public void Sample(double2 plot)
|
||||
{
|
||||
if (SampleCount < MaxSampleCount)
|
||||
SampleCount++;
|
||||
else
|
||||
for (var i = 1; i < SampleCount; i++)
|
||||
_samples[i - 1] = _samples[i];
|
||||
|
||||
_samples[SampleCount - 1] = plot;
|
||||
}
|
||||
|
||||
public double Predict(in double x)
|
||||
{
|
||||
using var result = new NativeArray<double>(2, Allocator.TempJob);
|
||||
|
||||
var jobData = new LinearRegressionJob
|
||||
{
|
||||
samples = _samples.Slice(0, SampleCount),
|
||||
yInterceptAndSlope = result
|
||||
};
|
||||
|
||||
jobData.Schedule().Complete();
|
||||
|
||||
var yIntercept = result[0];
|
||||
var slope = result[1];
|
||||
|
||||
return x * slope + yIntercept;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
SampleCount = 0;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_samples.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct LinearRegressionJob : IJob
|
||||
{
|
||||
[ReadOnly]
|
||||
public NativeSlice<double2> samples;
|
||||
|
||||
[WriteOnly]
|
||||
public NativeArray<double> yInterceptAndSlope;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
double sumOfX = 0;
|
||||
double sumOfY = 0;
|
||||
double sumOfXSq = 0;
|
||||
double sumCoDeviates = 0;
|
||||
|
||||
var sampleCount = samples.Length;
|
||||
|
||||
for (var i = 0; i < sampleCount; i++)
|
||||
{
|
||||
var plot = samples[i];
|
||||
sumCoDeviates += plot.x * plot.y;
|
||||
sumOfX += plot.x;
|
||||
sumOfY += plot.y;
|
||||
sumOfXSq += plot.x * plot.x;
|
||||
}
|
||||
|
||||
var ssX = sumOfXSq - sumOfX * sumOfX / sampleCount;
|
||||
var sCo = sumCoDeviates - sumOfX * sumOfY / sampleCount;
|
||||
|
||||
var meanX = sumOfX / sampleCount;
|
||||
var meanY = sumOfY / sampleCount;
|
||||
|
||||
// y-intercept
|
||||
yInterceptAndSlope[0] = meanY - sCo / ssX * meanX;
|
||||
|
||||
// slope
|
||||
yInterceptAndSlope[1] = sCo / ssX;
|
||||
}
|
||||
}
|
||||
}
|
||||
248
core-dump/Scripts/RegularSlideSegmentHandler.cs
Normal file
@@ -0,0 +1,248 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AstroDX.Contexts.Gameplay.Behaviours.Slide.SlideMarkers;
|
||||
using AstroDX.Contexts.Gameplay.Interactions;
|
||||
using AstroDX.Contexts.Gameplay.PlayerScope;
|
||||
using AstroDX.Contexts.Gameplay.SlideGenerators;
|
||||
using AstroDX.Globals;
|
||||
using Medicine;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.Behaviours.Slide.Handlers
|
||||
{
|
||||
public class RegularSlideSegmentHandler : SlideSegmentHandler
|
||||
{
|
||||
private readonly SlideGenerator _generator;
|
||||
|
||||
private readonly
|
||||
List<(TouchInteractable relevantSensor,
|
||||
List<RegularSlideArrow> relevantArrows)> _interactionPath = new();
|
||||
|
||||
/// <summary>
|
||||
/// Used in auto judgement
|
||||
/// </summary>
|
||||
private int _initialSensorCount;
|
||||
|
||||
/// <summary>
|
||||
/// Used in auto judgement
|
||||
/// </summary>
|
||||
private int _lastCheckedClearIndex;
|
||||
|
||||
private readonly SlideStarBehaviour _slideStar;
|
||||
|
||||
public RegularSlideSegmentHandler(SlideBehaviour slideBehaviour,
|
||||
SlideSegment segment,
|
||||
Location startLocation) :
|
||||
base(slideBehaviour)
|
||||
{
|
||||
var vertices = segment.vertices.ToList();
|
||||
vertices.Insert(0, startLocation);
|
||||
|
||||
_generator = SlideManager.GetGenerator(segment.slideType, vertices);
|
||||
|
||||
_slideStar = SlideManager.slideStars.Get();
|
||||
_slideStar.Initialize(ParentPath, ParentNote.parentCollection);
|
||||
|
||||
GenerateArrows();
|
||||
}
|
||||
|
||||
[Inject.Single]
|
||||
private SlideManager SlideManager { get; }
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return _generator.GetLength();
|
||||
}
|
||||
|
||||
public override void OnUpdate(float segmentT)
|
||||
{
|
||||
if (IsJudgementTarget)
|
||||
CheckInteraction(segmentT);
|
||||
|
||||
UpdateSlideStarPosition(segmentT);
|
||||
UpdateArrowOpacity();
|
||||
}
|
||||
|
||||
private float _arrowOpacity;
|
||||
|
||||
private void UpdateArrowOpacity()
|
||||
{
|
||||
var timeSinceNoteStart = TimeSinceSlideStart + ParentPath.delay;
|
||||
|
||||
if (timeSinceNoteStart < 0)
|
||||
{
|
||||
_arrowOpacity = Mathf.InverseLerp(-Persistent.Settings.Gameplay.slideFadeInDuration,
|
||||
0,
|
||||
(float)timeSinceNoteStart);
|
||||
|
||||
_arrowOpacity = Mathf.Lerp(0, 0.8f, _arrowOpacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_arrowOpacity >= 1)
|
||||
return;
|
||||
|
||||
_arrowOpacity = 1;
|
||||
}
|
||||
|
||||
foreach (var (_, relevantArrows) in _interactionPath)
|
||||
{
|
||||
foreach (var arrow in relevantArrows)
|
||||
{
|
||||
arrow.SetAlpha(_arrowOpacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckInteraction(float segmentT)
|
||||
{
|
||||
var clearCount = GetClearCount(segmentT);
|
||||
|
||||
for (; clearCount > 0 && _interactionPath.Count > 0; clearCount--)
|
||||
{
|
||||
foreach (var slideArrow in _interactionPath[0].relevantArrows)
|
||||
slideArrow.ExitSequence();
|
||||
|
||||
_interactionPath.RemoveAt(0);
|
||||
}
|
||||
|
||||
Cleared = _interactionPath.Count == 0;
|
||||
}
|
||||
|
||||
public override float GetRemainingLength()
|
||||
{
|
||||
return (float)_interactionPath.Count / _initialSensorCount * GetLength();
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
foreach (var (_, arrows) in _interactionPath)
|
||||
foreach (var slideArrow in arrows)
|
||||
SlideManager.regularSlideArrows.Release(slideArrow);
|
||||
|
||||
SlideManager.slideStars.Release(_slideStar);
|
||||
}
|
||||
|
||||
public override void GetJudgementVector(out Vector2 position, out float rotation)
|
||||
{
|
||||
_generator.GetPoint(1, out position, out rotation);
|
||||
}
|
||||
|
||||
private void UpdateSlideStarPosition(float segmentT)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
|
||||
var starTransform = _slideStar.transform;
|
||||
|
||||
if (segmentT >= 1 && IsLastSegment)
|
||||
{
|
||||
starTransform.localScale = Vector3.one * Persistent.Settings.Gameplay.noteScale;
|
||||
_slideStar.Appearance.Color = new Color(1, 1, 1, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
_generator.GetPoint(Mathf.Clamp01(segmentT), out var position, out var rotation);
|
||||
starTransform.SetLocalPositionAndRotation(position, Quaternion.Euler(0, 0, rotation * Mathf.Rad2Deg - 90));
|
||||
|
||||
if (TimeSinceSlideStart < 0 &&
|
||||
indexInSlide == 0 &&
|
||||
ParentNote.slideMorph != SlideMorph.SuddenIn)
|
||||
{
|
||||
var interpolation =
|
||||
Mathf.InverseLerp(-ParentPath.delay, 0,
|
||||
(float)TimeSinceSlideStart);
|
||||
starTransform.localScale = new Vector3(interpolation, interpolation) *
|
||||
Persistent.Settings.Gameplay.noteScale;
|
||||
_slideStar.Appearance.Color = new Color(1, 1, 1, interpolation);
|
||||
}
|
||||
|
||||
if (segmentT < 0)
|
||||
return;
|
||||
|
||||
starTransform.localScale = Vector3.one * Persistent.Settings.Gameplay.noteScale;
|
||||
_slideStar.Appearance.Color = Color.white;
|
||||
}
|
||||
|
||||
private void GenerateArrows()
|
||||
{
|
||||
var relevantArrows = new List<RegularSlideArrow>();
|
||||
TouchInteractable relevantSensor = null;
|
||||
|
||||
var totalLength = GetLength();
|
||||
|
||||
var arrowCount = Mathf.FloorToInt(totalLength / SlideManager.ArrowDistance);
|
||||
|
||||
for (var (distance, index) = (SlideManager.ArrowDistance, 0);
|
||||
distance <= totalLength;
|
||||
distance += SlideManager.ArrowDistance)
|
||||
{
|
||||
_generator.GetPoint(distance / totalLength, out var position, out var rotation);
|
||||
|
||||
var slideArrow = SlideManager.regularSlideArrows.Get();
|
||||
slideArrow.Initialize(position, rotation,
|
||||
arrowCount, index, isBreak, isEach);
|
||||
|
||||
var sensor = slideArrow.GetClosestSensor();
|
||||
|
||||
if (relevantSensor != sensor)
|
||||
{
|
||||
if (relevantSensor != null)
|
||||
_interactionPath.Add((relevantSensor, relevantArrows));
|
||||
|
||||
relevantArrows = new List<RegularSlideArrow>();
|
||||
relevantSensor = sensor;
|
||||
}
|
||||
|
||||
relevantArrows.Add(slideArrow);
|
||||
index++;
|
||||
}
|
||||
|
||||
if (relevantArrows.Count > 0) _interactionPath.Add((relevantSensor, relevantArrows));
|
||||
|
||||
_initialSensorCount = _interactionPath.Count;
|
||||
}
|
||||
|
||||
private int GetClearCount(double segmentT)
|
||||
{
|
||||
if (Persistent.Settings.Mods.Auto && segmentT >= 0)
|
||||
{
|
||||
var clearCount = Mathf.FloorToInt((float)(segmentT * _initialSensorCount));
|
||||
|
||||
|
||||
if (_lastCheckedClearIndex >= clearCount)
|
||||
return 0;
|
||||
|
||||
var lastCheckedClearIndex = _lastCheckedClearIndex;
|
||||
_lastCheckedClearIndex = clearCount;
|
||||
return clearCount - lastCheckedClearIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
var clearCount = 0;
|
||||
var scanIndex = 0;
|
||||
var tolerance = Persistent.Settings.Judgement.slideTolerance;
|
||||
|
||||
while (tolerance >= 0 && scanIndex < _interactionPath.Count)
|
||||
{
|
||||
if (_interactionPath[scanIndex].relevantSensor.GetSlideJudgement())
|
||||
{
|
||||
tolerance = Persistent.Settings.Judgement.slideTolerance;
|
||||
clearCount = scanIndex + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tolerance--;
|
||||
}
|
||||
|
||||
scanIndex++;
|
||||
}
|
||||
|
||||
return clearCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
core-dump/Scripts/RingCcwGenerator.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Collections.Generic;
|
||||
using AstroDX.Utilities;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.SlideGenerators
|
||||
{
|
||||
public sealed class RingCcwGenerator : SlideGenerator
|
||||
{
|
||||
private readonly float _angleSpan;
|
||||
private readonly float _endRadius;
|
||||
private readonly float _length;
|
||||
|
||||
private readonly float _startRadius;
|
||||
private readonly float _startRotation;
|
||||
|
||||
public RingCcwGenerator(IReadOnlyList<Location> vertices)
|
||||
{
|
||||
var inPosition = GetPosition(vertices[0]);
|
||||
var inRadians = Trigonometry.ToPolarAngle(inPosition);
|
||||
|
||||
var outPosition = GetPosition(vertices[1]);
|
||||
var outRadians = Trigonometry.ToPolarAngle(outPosition);
|
||||
|
||||
_startRotation = inRadians;
|
||||
|
||||
_angleSpan = Trigonometry.GetAngleSpan(inRadians, outRadians, false);
|
||||
_startRadius = GetRadiusFromCenter(vertices[0]);
|
||||
_endRadius = GetRadiusFromCenter(vertices[1]);
|
||||
|
||||
_length = _angleSpan * (_startRadius + _endRadius) / 2;
|
||||
}
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return _length;
|
||||
}
|
||||
|
||||
public override void GetPoint(float t,
|
||||
out Vector2 position,
|
||||
out float rotation)
|
||||
{
|
||||
var radiusAtT = Mathf.Lerp(_startRadius, _endRadius, t);
|
||||
var rotationAtT = _startRotation + _angleSpan * t;
|
||||
|
||||
position = new Vector2(Mathf.Cos(rotationAtT) * radiusAtT,
|
||||
Mathf.Sin(rotationAtT) * radiusAtT);
|
||||
|
||||
rotation = rotationAtT + Trigonometry.Tau / 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
52
core-dump/Scripts/RingCwGenerator.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Collections.Generic;
|
||||
using AstroDX.Utilities;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.SlideGenerators
|
||||
{
|
||||
public sealed class RingCwGenerator : SlideGenerator
|
||||
{
|
||||
private readonly float _angleSpan;
|
||||
private readonly float _endRadius;
|
||||
private readonly float _length;
|
||||
|
||||
private readonly float _startRadius;
|
||||
private readonly float _startRotation;
|
||||
|
||||
public RingCwGenerator(IReadOnlyList<Location> vertices)
|
||||
{
|
||||
var inPosition = GetPosition(vertices[0]);
|
||||
var inRadians = Trigonometry.ToPolarAngle(inPosition);
|
||||
|
||||
var outPosition = GetPosition(vertices[1]);
|
||||
var outRadians = Trigonometry.ToPolarAngle(outPosition);
|
||||
|
||||
_startRotation = inRadians;
|
||||
|
||||
_angleSpan = Trigonometry.GetAngleSpan(_startRotation, outRadians, true);
|
||||
_startRadius = GetRadiusFromCenter(vertices[0]);
|
||||
_endRadius = GetRadiusFromCenter(vertices[1]);
|
||||
|
||||
_length = _angleSpan * (_startRadius + _endRadius) / 2;
|
||||
}
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return _length;
|
||||
}
|
||||
|
||||
public override void GetPoint(float t,
|
||||
out Vector2 position,
|
||||
out float rotation)
|
||||
{
|
||||
var radiusAtT = Mathf.Lerp(_startRadius, _endRadius, t);
|
||||
var rotationAtT = _startRotation - _angleSpan * t;
|
||||
|
||||
position = new Vector2(Mathf.Cos(rotationAtT) * radiusAtT,
|
||||
Mathf.Sin(rotationAtT) * radiusAtT);
|
||||
|
||||
rotation = rotationAtT - Trigonometry.Tau / 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
190
core-dump/Scripts/SlideBehaviour.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AstroDX.Contexts.Gameplay.Behaviours.Slide.Handlers;
|
||||
using AstroDX.Contexts.Gameplay.PlayerScope;
|
||||
using AstroDX.Contexts.Gameplay.SceneScope;
|
||||
using AstroDX.Globals;
|
||||
using Medicine;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
using TimeSpan = AstroDX.Models.Scoring.TimeSpan;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.Behaviours.Slide
|
||||
{
|
||||
public sealed class SlideBehaviour : MonoBehaviour, IDisposable
|
||||
{
|
||||
private readonly List<(float distance, SlideSegmentHandler handler)> _segments = new();
|
||||
private float _endRotation;
|
||||
|
||||
private Vector2 _endPosition;
|
||||
private SlideType _endSegmentType;
|
||||
private bool _judged;
|
||||
|
||||
private int _judgedSegmentCount;
|
||||
|
||||
private float _length;
|
||||
|
||||
private float _slideStartTime;
|
||||
|
||||
[Inject.Single]
|
||||
private StatisticsManager StatisticsManager { get; }
|
||||
|
||||
[Inject.Single]
|
||||
private MusicManager MusicManager { get; }
|
||||
|
||||
[Inject.Single]
|
||||
private SlideManager SlideManager { get; }
|
||||
|
||||
public SlidePath Path { get; private set; }
|
||||
public Note ParentNote { get; private set; }
|
||||
|
||||
public double TimeSinceStart => MusicManager.Time - _slideStartTime;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
UpdateSegments();
|
||||
|
||||
if (TimeSinceStart >= 0)
|
||||
CheckInteraction();
|
||||
|
||||
if (Persistent.Settings.Mods.Auto &&
|
||||
TimeSinceStart > Path.duration)
|
||||
Judge();
|
||||
else if (TimeSinceStart > Path.duration +
|
||||
TimeSpan.SlideFinish.TimingWindows[^1].lateSpan)
|
||||
Judge();
|
||||
}
|
||||
|
||||
public void Init(in SlidePath path, in Note parent)
|
||||
{
|
||||
_judgedSegmentCount = 0;
|
||||
_judged = false;
|
||||
|
||||
Path = path;
|
||||
ParentNote = parent;
|
||||
_slideStartTime = ParentNote.parentCollection.time + Path.delay;
|
||||
|
||||
GenerateHandlers(path);
|
||||
}
|
||||
|
||||
private void UpdateSegments()
|
||||
{
|
||||
var t = (float)TimeSinceStart / Path.duration * _length;
|
||||
|
||||
var isJudgementTarget = TimeSinceStart + Path.delay >= 0;
|
||||
|
||||
for (var i = 0; i < _segments.Count; i++)
|
||||
{
|
||||
var (segmentStartT, handler) = _segments[i];
|
||||
var segmentEndT = i + 1 < _segments.Count ? _segments[i + 1].distance : _length;
|
||||
|
||||
var segmentT = (t - segmentStartT) / (segmentEndT - segmentStartT);
|
||||
|
||||
handler.IsJudgementTarget = isJudgementTarget;
|
||||
handler.OnUpdate(segmentT);
|
||||
|
||||
if (!handler.Cleared)
|
||||
isJudgementTarget = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckInteraction()
|
||||
{
|
||||
while (_judgedSegmentCount < _segments.Count)
|
||||
{
|
||||
var currentHandler = _segments[_judgedSegmentCount].handler;
|
||||
|
||||
var segmentCleared = currentHandler.Cleared;
|
||||
|
||||
if (!segmentCleared)
|
||||
return;
|
||||
|
||||
_judgedSegmentCount++;
|
||||
}
|
||||
|
||||
Judge();
|
||||
}
|
||||
|
||||
private void GenerateHandlers(in SlidePath slidePath)
|
||||
{
|
||||
if (_segments.Count > 0)
|
||||
_segments.Clear();
|
||||
|
||||
var totalDistance = 0f;
|
||||
|
||||
var handlers = new List<SlideSegmentHandler>();
|
||||
|
||||
for (var i = 0; i < slidePath.segments.Count; i++)
|
||||
{
|
||||
var segment = slidePath.segments[i];
|
||||
|
||||
var startLocation = i > 0 ? slidePath.segments[i - 1].vertices[^1] : ParentNote.location;
|
||||
|
||||
var handler = SlideSegmentHandler.Recommend(this, segment, startLocation);
|
||||
handlers.Add(handler);
|
||||
}
|
||||
|
||||
var index = 0;
|
||||
foreach (var segmentHandler in handlers)
|
||||
{
|
||||
segmentHandler.SetIndex(index);
|
||||
_segments.Add((totalDistance, segmentHandler));
|
||||
totalDistance += segmentHandler.GetLength();
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
_segments[^1].handler.GetJudgementVector(out _endPosition, out _endRotation);
|
||||
_endSegmentType = Path.segments[^1].slideType;
|
||||
|
||||
_length = totalDistance;
|
||||
}
|
||||
|
||||
private void Judge()
|
||||
{
|
||||
if (_judged)
|
||||
return;
|
||||
|
||||
_judged = true;
|
||||
|
||||
var incomplete = _judgedSegmentCount < _segments.Count;
|
||||
|
||||
var startTime = ParentNote.parentCollection.time +
|
||||
Path.delay;
|
||||
|
||||
var timeFromEnd = MusicManager.Time - (startTime + Path.duration);
|
||||
|
||||
var distanceToEnd = incomplete
|
||||
? _segments[_judgedSegmentCount].handler.GetRemainingLength()
|
||||
: _length - Mathf.InverseLerp(startTime,
|
||||
startTime + Path.duration,
|
||||
(float)MusicManager.Time) * _length;
|
||||
|
||||
if (incomplete)
|
||||
{
|
||||
var multipleSegmentsRemaining = _judgedSegmentCount + 1 < _segments.Count;
|
||||
|
||||
if (multipleSegmentsRemaining)
|
||||
distanceToEnd += _length - _segments[_judgedSegmentCount + 1].distance;
|
||||
}
|
||||
|
||||
StatisticsManager.TallySlide(Path,
|
||||
distanceToEnd,
|
||||
timeFromEnd,
|
||||
_endPosition,
|
||||
_endRotation,
|
||||
_endSegmentType,
|
||||
incomplete);
|
||||
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var segment in _segments)
|
||||
segment.handler.OnDestroy();
|
||||
|
||||
SlideManager.slides.Release(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
54
core-dump/Scripts/SlideGenerator.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using AstroDX.Contexts.Gameplay.PlayerScope;
|
||||
using AstroDX.Utilities;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.SlideGenerators
|
||||
{
|
||||
public abstract class SlideGenerator
|
||||
{
|
||||
public abstract float GetLength();
|
||||
|
||||
public abstract void GetPoint(float t, out Vector2 position, out float rotation);
|
||||
|
||||
protected static float GetRotation(in Location location)
|
||||
{
|
||||
const float initialAngle = Trigonometry.Tau / 4f - Trigonometry.Tau / 16f;
|
||||
|
||||
var angle = initialAngle - Trigonometry.Tau / 8f * location.index;
|
||||
|
||||
if (location.group is NoteGroup.DSensor or NoteGroup.ESensor) angle += Trigonometry.Tau / 16f;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
public static Vector2 GetPosition(in Location location)
|
||||
{
|
||||
var radius = GetRadiusFromCenter(location);
|
||||
|
||||
return GetPositionRadial(GetRotation(location), radius);
|
||||
}
|
||||
|
||||
protected static Vector2 GetPositionRadial(in float rotationRadians,
|
||||
in float radius = RenderManager.PlayFieldRadius)
|
||||
{
|
||||
return new Vector2(Mathf.Cos(rotationRadians) * radius,
|
||||
Mathf.Sin(rotationRadians) * radius);
|
||||
}
|
||||
|
||||
protected static float GetRadiusFromCenter(Location location)
|
||||
{
|
||||
return location.group switch
|
||||
{
|
||||
NoteGroup.Tap => RenderManager.PlayFieldRadius,
|
||||
NoteGroup.ASensor => RenderManager.AreaARadius,
|
||||
NoteGroup.BSensor => RenderManager.AreaBRadius,
|
||||
NoteGroup.CSensor => 0,
|
||||
NoteGroup.DSensor => RenderManager.AreaDRadius,
|
||||
NoteGroup.ESensor => RenderManager.AreaERadius,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
70
core-dump/Scripts/SlideSegmentHandler.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System.Linq;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.Behaviours.Slide.Handlers
|
||||
{
|
||||
public abstract class SlideSegmentHandler
|
||||
{
|
||||
protected readonly bool isBreak;
|
||||
protected readonly bool isEach;
|
||||
|
||||
protected bool disposed;
|
||||
|
||||
protected int indexInSlide = -1;
|
||||
|
||||
protected SlideSegmentHandler(SlideBehaviour slideBehaviour)
|
||||
{
|
||||
disposed = false;
|
||||
|
||||
ParentSlide = slideBehaviour;
|
||||
|
||||
isEach = ParentSlide.ParentNote.parentCollection
|
||||
.Sum(n => n.slidePaths.Count) > 1;
|
||||
|
||||
isBreak = ParentSlide.Path.type == NoteType.Break;
|
||||
}
|
||||
|
||||
public bool Cleared { get; protected set; }
|
||||
|
||||
protected SlideBehaviour ParentSlide { get; }
|
||||
protected SlidePath ParentPath => ParentSlide.Path;
|
||||
protected Note ParentNote => ParentSlide.ParentNote;
|
||||
|
||||
protected double TimeSinceSlideStart => ParentSlide.TimeSinceStart;
|
||||
protected bool IsLastSegment => indexInSlide != ParentPath.segments.Count - 1;
|
||||
public bool IsJudgementTarget { get; set; }
|
||||
|
||||
public void SetIndex(int index)
|
||||
{
|
||||
indexInSlide = index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes the position and the up vector for the judgement text.
|
||||
/// </summary>
|
||||
public abstract void GetJudgementVector(out Vector2 position, out float rotation);
|
||||
|
||||
public abstract void OnUpdate(float segmentT);
|
||||
|
||||
public virtual void OnDestroy()
|
||||
{
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
public abstract float GetLength();
|
||||
|
||||
public abstract float GetRemainingLength();
|
||||
|
||||
public static SlideSegmentHandler Recommend(SlideBehaviour slideBehaviour,
|
||||
SlideSegment segment,
|
||||
Location startLocation)
|
||||
{
|
||||
return segment.slideType switch
|
||||
{
|
||||
SlideType.Fan => new FanSlideSegmentHandler(slideBehaviour, segment, startLocation),
|
||||
_ => new RegularSlideSegmentHandler(slideBehaviour, segment, startLocation)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
35
core-dump/Scripts/StraightGenerator.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Collections.Generic;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.SlideGenerators
|
||||
{
|
||||
public sealed class StraightGenerator : SlideGenerator
|
||||
{
|
||||
private readonly Vector2 _endPoint;
|
||||
private readonly float _rotation;
|
||||
private readonly float _length;
|
||||
private readonly Vector2 _startPoint;
|
||||
|
||||
public StraightGenerator(IReadOnlyList<Location> vertices)
|
||||
{
|
||||
_startPoint = GetPosition(vertices[0]);
|
||||
_endPoint = GetPosition(vertices[1]);
|
||||
|
||||
var segment = _endPoint - _startPoint;
|
||||
_length = segment.magnitude;
|
||||
_rotation = Mathf.Atan2(segment.y, segment.x);
|
||||
}
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return _length;
|
||||
}
|
||||
|
||||
public override void GetPoint(float t, out Vector2 position, out float rotation)
|
||||
{
|
||||
position = Vector2.Lerp(_startPoint, _endPoint, t);
|
||||
rotation = _rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
core-dump/Scripts/TitleManager.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Helpers;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Title
|
||||
{
|
||||
public class TitleManager : MonoBehaviour
|
||||
{
|
||||
public Text anyKeyPressed;
|
||||
|
||||
public List<string> textList;
|
||||
|
||||
private int _textIndex;
|
||||
private void Start()
|
||||
{
|
||||
textList = new List<string>
|
||||
{
|
||||
Localization.ParseAuto($"TITLE_ANYKEY"),
|
||||
Localization.ParseAuto($"TITLE_THANKS"),
|
||||
$"{Localization.ParseAuto($"TITLE_BUILDVERSION")} {Application.version}"
|
||||
};
|
||||
|
||||
StartCoroutine(CycleThroughText());
|
||||
}
|
||||
|
||||
private IEnumerator CycleThroughText()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
_textIndex = (_textIndex + 1) % textList.Count;
|
||||
anyKeyPressed.text = textList[_textIndex];
|
||||
yield return new WaitForSeconds(3);
|
||||
}
|
||||
|
||||
// ReSharper disable once IteratorNeverReturns
|
||||
}
|
||||
|
||||
public void ChangeScene()
|
||||
{
|
||||
SceneSwapper.LoadScene("ModeSelection");
|
||||
}
|
||||
}
|
||||
}
|
||||
84
core-dump/Scripts/Trigonometry.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Utilities
|
||||
{
|
||||
public static class Trigonometry
|
||||
{
|
||||
public const float Tau = Mathf.PI * 2;
|
||||
|
||||
public static Vector2 Rotate(in this Vector2 v, in float degreesRad)
|
||||
{
|
||||
var magnitude = v.magnitude;
|
||||
var originalDegrees = Mathf.Atan2(v.y, v.x);
|
||||
var newDegrees = originalDegrees + degreesRad;
|
||||
|
||||
var newX = Mathf.Cos(newDegrees) * magnitude;
|
||||
var newY = Mathf.Sin(newDegrees) * magnitude;
|
||||
|
||||
return new Vector2(newX, newY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates a point's angle relative to a center point.
|
||||
/// </summary>
|
||||
/// <param name="position">The absolute position of a point.</param>
|
||||
/// <param name="offset">The offset of the calculation's center point.</param>
|
||||
/// <returns>The relative angle of a point from the given center point.</returns>
|
||||
internal static float ToPolarAngle(in Vector2 position, in Vector2? offset = null)
|
||||
{
|
||||
if (!offset.HasValue)
|
||||
return Mathf.Atan2(position.y, position.x);
|
||||
|
||||
var difference = position - offset.Value;
|
||||
return Mathf.Atan2(difference.y, difference.x);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the angle between a line to a point on a ring
|
||||
/// and another line perpendicular from a tangent line of that point.
|
||||
/// </summary>
|
||||
/// <param name="adjacent"></param>
|
||||
/// <param name="hypotenuse"></param>
|
||||
/// <param name="clockwise"></param>
|
||||
/// <returns></returns>
|
||||
internal static float GetTangentAngleDelta(in float adjacent,
|
||||
in float hypotenuse,
|
||||
in bool clockwise)
|
||||
{
|
||||
var angleDiff = Mathf.Acos(adjacent / hypotenuse);
|
||||
return clockwise ? -angleDiff : angleDiff;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Calculates the angle between <c>startRotation</c> and <c>endRotation</c>,
|
||||
/// given its traversing direction.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="startRotation">The starting rotation.</param>
|
||||
/// <param name="endRotation">The ending rotation.</param>
|
||||
/// <param name="clockwise">Traversing direction.</param>
|
||||
/// <param name="wrapThreshold">
|
||||
/// <para>Wraps to full circle for spans smaller than this value.</para>
|
||||
/// <para><code>Tau / 4f</code> is recommended for offset circles</para>
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The span between the starting rotation and the ending rotation on a unit circle,
|
||||
/// in radians.
|
||||
/// </returns>
|
||||
public static float GetAngleSpan(in float startRotation,
|
||||
in float endRotation,
|
||||
bool clockwise,
|
||||
float wrapThreshold = Tau / 32f)
|
||||
{
|
||||
var span = clockwise
|
||||
? (startRotation - endRotation + 2 * Tau) % Tau
|
||||
: (endRotation - startRotation + 2 * Tau) % Tau;
|
||||
|
||||
if (span <= wrapThreshold)
|
||||
span += Tau;
|
||||
|
||||
return span;
|
||||
}
|
||||
}
|
||||
}
|
||||
95
core-dump/Scripts/ZigZagSGenerator.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System.Collections.Generic;
|
||||
using AstroDX.Contexts.Gameplay.PlayerScope;
|
||||
using AstroDX.Utilities;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.SlideGenerators
|
||||
{
|
||||
public sealed class ZigZagSGenerator : SlideGenerator
|
||||
{
|
||||
private readonly Vector2 _endPoint;
|
||||
private readonly Vector2 _endZagPoint;
|
||||
private readonly float _midSegmentLength;
|
||||
private readonly Vector2 _startPoint;
|
||||
|
||||
private readonly float _startRotation;
|
||||
private readonly float _midRotation;
|
||||
private readonly float _endRotation;
|
||||
|
||||
private readonly float _startSegmentLength;
|
||||
private readonly Vector2 _startZagPoint;
|
||||
private readonly float _totalLength;
|
||||
|
||||
public ZigZagSGenerator(IReadOnlyList<Location> vertices)
|
||||
{
|
||||
const float distance = RenderManager.PlayFieldRadius;
|
||||
const float inner = RenderManager.CenterRadius;
|
||||
|
||||
var startRotation = GetRotation(vertices[0]);
|
||||
var endRotation = GetRotation(vertices[1]);
|
||||
|
||||
var startZag = startRotation + Trigonometry.Tau / 4f;
|
||||
var endZag = endRotation + Trigonometry.Tau / 4f;
|
||||
|
||||
_startPoint = new Vector2(distance * Mathf.Cos(startRotation),
|
||||
distance * Mathf.Sin(startRotation));
|
||||
|
||||
_startZagPoint = new Vector2(inner * Mathf.Cos(startZag),
|
||||
inner * Mathf.Sin(startZag));
|
||||
|
||||
var startSegment = _startZagPoint - _startPoint;
|
||||
_startSegmentLength = startSegment.magnitude;
|
||||
_startRotation = Mathf.Atan2(startSegment.y, startSegment.x);
|
||||
|
||||
_endZagPoint = new Vector2(inner * Mathf.Cos(endZag),
|
||||
inner * Mathf.Sin(endZag));
|
||||
|
||||
var midSegment = _endZagPoint - _startZagPoint;
|
||||
_midSegmentLength = midSegment.magnitude;
|
||||
_midRotation = Mathf.Atan2(midSegment.y, midSegment.x);
|
||||
|
||||
_endPoint = new Vector2(distance * Mathf.Cos(endRotation),
|
||||
distance * Mathf.Sin(endRotation));
|
||||
|
||||
var endSegment = _endPoint - _endZagPoint;
|
||||
var endSegmentLength = endSegment.magnitude;
|
||||
_endRotation = Mathf.Atan2(endSegment.y, endSegment.x);
|
||||
|
||||
_totalLength = _startSegmentLength + _midSegmentLength + endSegmentLength;
|
||||
}
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return _totalLength;
|
||||
}
|
||||
|
||||
public override void GetPoint(float t, out Vector2 position, out float rotation)
|
||||
{
|
||||
var distanceFromStart = t * _totalLength;
|
||||
|
||||
if (distanceFromStart < _startSegmentLength)
|
||||
{
|
||||
position = Vector2.Lerp(_startPoint, _startZagPoint,
|
||||
Mathf.InverseLerp(0, _startSegmentLength, distanceFromStart));
|
||||
rotation = _startRotation;
|
||||
}
|
||||
else if (distanceFromStart < _startSegmentLength + _midSegmentLength)
|
||||
{
|
||||
var midLength = _startSegmentLength + _midSegmentLength;
|
||||
|
||||
position = Vector2.Lerp(_startZagPoint, _endZagPoint,
|
||||
Mathf.InverseLerp(_startSegmentLength, midLength, distanceFromStart));
|
||||
rotation = _midRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
var midLength = _startSegmentLength + _midSegmentLength;
|
||||
|
||||
position = Vector2.Lerp(_endZagPoint, _endPoint,
|
||||
Mathf.InverseLerp(midLength, _totalLength, distanceFromStart));
|
||||
rotation = _endRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
95
core-dump/Scripts/ZigZagZGenerator.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System.Collections.Generic;
|
||||
using AstroDX.Contexts.Gameplay.PlayerScope;
|
||||
using AstroDX.Utilities;
|
||||
using SimaiSharp.Structures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AstroDX.Contexts.Gameplay.SlideGenerators
|
||||
{
|
||||
public sealed class ZigZagZGenerator : SlideGenerator
|
||||
{
|
||||
private readonly Vector2 _endPoint;
|
||||
private readonly Vector2 _endZagPoint;
|
||||
private readonly float _midSegmentLength;
|
||||
private readonly Vector2 _startPoint;
|
||||
|
||||
private readonly float _startRotation;
|
||||
private readonly float _midRotation;
|
||||
private readonly float _endRotation;
|
||||
|
||||
private readonly float _startSegmentLength;
|
||||
private readonly Vector2 _startZagPoint;
|
||||
private readonly float _totalLength;
|
||||
|
||||
public ZigZagZGenerator(IReadOnlyList<Location> vertices)
|
||||
{
|
||||
const float distance = RenderManager.PlayFieldRadius;
|
||||
const float inner = RenderManager.CenterRadius;
|
||||
|
||||
var startRotation = GetRotation(vertices[0]);
|
||||
var endRotation = GetRotation(vertices[1]);
|
||||
|
||||
var startZag = startRotation - Trigonometry.Tau / 4f;
|
||||
var endZag = endRotation - Trigonometry.Tau / 4f;
|
||||
|
||||
_startPoint = new Vector2(distance * Mathf.Cos(startRotation),
|
||||
distance * Mathf.Sin(startRotation));
|
||||
|
||||
_startZagPoint = new Vector2(inner * Mathf.Cos(startZag),
|
||||
inner * Mathf.Sin(startZag));
|
||||
|
||||
var startSegment = _startZagPoint - _startPoint;
|
||||
_startSegmentLength = startSegment.magnitude;
|
||||
_startRotation = Mathf.Atan2(startSegment.y, startSegment.x);
|
||||
|
||||
_endZagPoint = new Vector2(inner * Mathf.Cos(endZag),
|
||||
inner * Mathf.Sin(endZag));
|
||||
|
||||
var midSegment = _endZagPoint - _startZagPoint;
|
||||
_midSegmentLength = midSegment.magnitude;
|
||||
_midRotation = Mathf.Atan2(midSegment.y, midSegment.x);
|
||||
|
||||
_endPoint = new Vector2(distance * Mathf.Cos(endRotation),
|
||||
distance * Mathf.Sin(endRotation));
|
||||
|
||||
var endSegment = _endPoint - _endZagPoint;
|
||||
var endSegmentLength = endSegment.magnitude;
|
||||
_endRotation = Mathf.Atan2(endSegment.y, endSegment.x);
|
||||
|
||||
_totalLength = _startSegmentLength + _midSegmentLength + endSegmentLength;
|
||||
}
|
||||
|
||||
public override float GetLength()
|
||||
{
|
||||
return _totalLength;
|
||||
}
|
||||
|
||||
public override void GetPoint(float t, out Vector2 position, out float rotation)
|
||||
{
|
||||
var distanceFromStart = t * _totalLength;
|
||||
|
||||
if (distanceFromStart < _startSegmentLength)
|
||||
{
|
||||
position = Vector2.Lerp(_startPoint, _startZagPoint,
|
||||
Mathf.InverseLerp(0, _startSegmentLength, distanceFromStart));
|
||||
rotation = _startRotation;
|
||||
}
|
||||
else if (distanceFromStart < _startSegmentLength + _midSegmentLength)
|
||||
{
|
||||
var midLength = _startSegmentLength + _midSegmentLength;
|
||||
|
||||
position = Vector2.Lerp(_startZagPoint, _endZagPoint,
|
||||
Mathf.InverseLerp(_startSegmentLength, midLength, distanceFromStart));
|
||||
rotation = _midRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
var midLength = _startSegmentLength + _midSegmentLength;
|
||||
|
||||
position = Vector2.Lerp(_endZagPoint, _endPoint,
|
||||
Mathf.InverseLerp(midLength, _totalLength, distanceFromStart));
|
||||
rotation = _endRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
122
core-dump/Shader/Note.shader
Normal file
@@ -0,0 +1,122 @@
|
||||
Shader "AstroDX/Note"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
|
||||
_GradientTex ("Gradient Texture", 2D) = "white" {}
|
||||
|
||||
_Color ("Tint", Color) = (1,1,1,1)
|
||||
_ShadowColor ("Shadow Tint", Color) = (0,0,0,1)
|
||||
_Grayscale("Grayscale", Range(0, 1)) = 0
|
||||
[MaterialToggle] _Shine ("Shine", Float) = 0
|
||||
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"Queue"="Transparent"
|
||||
"IgnoreProjector"="True"
|
||||
"RenderType"="Transparent"
|
||||
"PreviewType"="Plane"
|
||||
"CanUseSpriteAtlas"="True"
|
||||
}
|
||||
|
||||
Cull Off
|
||||
Lighting Off
|
||||
ZWrite Off
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma multi_compile _ PIXELSNAP_ON
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata_t
|
||||
{
|
||||
fixed4 vertex : POSITION;
|
||||
fixed4 color : COLOR;
|
||||
fixed2 texcoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
fixed4 vertex : SV_POSITION;
|
||||
fixed4 color : COLOR;
|
||||
fixed2 texcoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
fixed4 _Color;
|
||||
fixed _Shine;
|
||||
|
||||
v2f vert(appdata_t IN)
|
||||
{
|
||||
v2f OUT;
|
||||
OUT.vertex = UnityObjectToClipPos(IN.vertex);
|
||||
OUT.texcoord = IN.texcoord;
|
||||
OUT.color = IN.color * _Color;
|
||||
#ifdef PIXELSNAP_ON
|
||||
OUT.vertex = UnityPixelSnap (OUT.vertex);
|
||||
#endif
|
||||
|
||||
return OUT;
|
||||
}
|
||||
|
||||
sampler2D _MainTex;
|
||||
sampler2D _GradientTex;
|
||||
sampler2D _AlphaTex;
|
||||
fixed4 _ShadowColor;
|
||||
fixed _AlphaSplitEnabled;
|
||||
fixed _Grayscale;
|
||||
|
||||
fixed4 sample_sprite_texture(float2 uv)
|
||||
{
|
||||
const fixed4 color = tex2D(_MainTex, uv);
|
||||
|
||||
// setting to 0.004 and 0.996 prevents getting wrong texture edge colors
|
||||
const fixed gradient_position = lerp(0.005, 0.995, saturate(color.r * 2 - 1));
|
||||
const fixed4 gradient_map = tex2D(_GradientTex, fixed2(gradient_position, 0));
|
||||
|
||||
#if UNITY_TEXTURE_ALPHASPLIT_ALLOWED
|
||||
if (_AlphaSplitEnabled)
|
||||
{
|
||||
color.a = tex2D (_AlphaTex, uv).r;
|
||||
}
|
||||
#endif //UNITY_TEXTURE_ALPHASPLIT_ALLOWED
|
||||
|
||||
// choke starts at 0.1 higher than the gradient map threshold
|
||||
// to allow a smoother color blending (see touch)
|
||||
const fixed red_choke = smoothstep(0, 0.5, color.r);
|
||||
|
||||
const fixed3 shadow_color = fixed3(color.b * _ShadowColor.rgb);
|
||||
|
||||
fixed3 sum = gradient_map * red_choke + shadow_color * _ShadowColor.a * color.b;
|
||||
sum = color.g.xxxx + sum * (1 - color.g);
|
||||
|
||||
return fixed4(sum.rgb, color.a);
|
||||
}
|
||||
|
||||
fixed4 frag(v2f IN) : SV_Target
|
||||
{
|
||||
fixed4 c = sample_sprite_texture(IN.texcoord);
|
||||
|
||||
//Rough human eye adjusted grayscale computation
|
||||
const fixed mono_rgb = 0.299 * c.r + 0.587 * c.g + 0.114 * c.b;
|
||||
|
||||
c.rgb *= IN.color.rgb;
|
||||
|
||||
const fixed shine_multiplier = (sin(_Time.y * 16) * 0.5 + 0.5) * _Shine;
|
||||
c.rgb += shine_multiplier.rrr * 0.2;
|
||||
c.rgb *= 1 + shine_multiplier.rrr * 0.3;
|
||||
|
||||
const fixed3 out_color = lerp(c.rgb, mono_rgb.rrr, _Grayscale);
|
||||
return fixed4(out_color, c.a * IN.color.a);
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
core-dump/Sprites/IMG_GAME_HOLD_0.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
core-dump/Sprites/IMG_GAME_HOLD_1.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
core-dump/Sprites/IMG_GAME_STAR_0.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
core-dump/Sprites/IMG_GAME_STAR_1.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
core-dump/Sprites/IMG_GAME_TAP_0.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
core-dump/Sprites/IMG_GAME_TAP_1.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
core-dump/Sprites/IMG_GAME_TOUCH.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
core-dump/Sprites/IMG_GAME_TOUCH_STAR.png
Normal file
|
After Width: | Height: | Size: 18 KiB |