Implement score combo multiplier with animated HUD text
Подробный список изменений: - В IPlayerController.cs и JumpPlayerController.cs добавлено событие LandedOnNormalPlatform, срабатывающее при обычном автопрыжке. - В GameplaySession.cs внедрено свойство CurrentCombo. Очки при сборе монет и убийстве врагов умножаются на текущий комбо-множитель, который растет с каждым набором очков. Сброс комбо в 1 происходит по событию приземления на обычную платформу, при смерти или сбросе сессии. - В GameplayHud.uxml добавлен элемент ComboValue с оранжевым стилем и тенью. - В GameplayHudController.cs реализовано отображение комбо с анимацией пульсации scale.
This commit is contained in:
parent
19ac082fed
commit
15adf94b21
@ -31,6 +31,11 @@ namespace DanroJump.Gameplay
|
||||
|
||||
public string SessionId { get; private set; } = CreateSessionId();
|
||||
|
||||
/// <summary>
|
||||
/// Текущий комбо-множитель очков (увеличивается при сборе монет/врагах, сбрасывается на платформах).
|
||||
/// </summary>
|
||||
public int CurrentCombo { get; private set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Итоговые очки текущего забега: игровые начисления плюс бонус за максимальную высоту.
|
||||
/// </summary>
|
||||
@ -122,11 +127,33 @@ namespace DanroJump.Gameplay
|
||||
{
|
||||
this.player.Died += HandlePlayerDied;
|
||||
this.player.Respawned += HandlePlayerRespawned;
|
||||
this.player.LandedOnNormalPlatform += ResetCombo;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавляет очки в текущий забег.
|
||||
/// Увеличивает комбо-множитель.
|
||||
/// </summary>
|
||||
public void IncrementCombo()
|
||||
{
|
||||
CurrentCombo++;
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Сбрасывает комбо-множитель в 1.
|
||||
/// </summary>
|
||||
public void ResetCombo()
|
||||
{
|
||||
if (CurrentCombo != 1)
|
||||
{
|
||||
CurrentCombo = 1;
|
||||
Changed?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавляет очки в текущий забег (с учетом комбо-множителя).
|
||||
/// </summary>
|
||||
public void AddScore(int amount)
|
||||
{
|
||||
@ -135,7 +162,8 @@ namespace DanroJump.Gameplay
|
||||
return;
|
||||
}
|
||||
|
||||
baseScore += amount;
|
||||
baseScore += amount * CurrentCombo;
|
||||
CurrentCombo++;
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
@ -165,6 +193,7 @@ namespace DanroJump.Gameplay
|
||||
DeathCount = 0;
|
||||
RemainingLives = startingLives;
|
||||
State = GameplaySessionState.Running;
|
||||
CurrentCombo = 1;
|
||||
player?.ResetRun();
|
||||
Changed?.Invoke();
|
||||
}
|
||||
@ -186,6 +215,7 @@ namespace DanroJump.Gameplay
|
||||
sceneFlow?.CancelGameOverReturn();
|
||||
RemainingLives = ContinueGameLives;
|
||||
State = GameplaySessionState.Respawning;
|
||||
CurrentCombo = 1;
|
||||
|
||||
if (player != null)
|
||||
{
|
||||
@ -215,6 +245,7 @@ namespace DanroJump.Gameplay
|
||||
|
||||
player.Died -= HandlePlayerDied;
|
||||
player.Respawned -= HandlePlayerRespawned;
|
||||
player.LandedOnNormalPlatform -= ResetCombo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -226,6 +257,8 @@ namespace DanroJump.Gameplay
|
||||
DeathCount++;
|
||||
RemainingLives = Mathf.Max(0, RemainingLives - 1);
|
||||
State = RemainingLives > 0 ? GameplaySessionState.Respawning : GameplaySessionState.GameOver;
|
||||
CurrentCombo = 1;
|
||||
|
||||
if (State == GameplaySessionState.GameOver)
|
||||
{
|
||||
audioService?.Play(GameAudioEvent.GameOver);
|
||||
|
||||
@ -9,6 +9,7 @@ namespace DanroJump.Gameplay
|
||||
{
|
||||
event System.Action<IPlayerController> Died;
|
||||
event System.Action<IPlayerController> Respawned;
|
||||
event System.Action LandedOnNormalPlatform;
|
||||
|
||||
Transform Transform { get; }
|
||||
float HighestY { get; }
|
||||
|
||||
@ -186,6 +186,7 @@ namespace DanroJump.Gameplay
|
||||
|
||||
public event System.Action<IPlayerController> Died;
|
||||
public event System.Action<IPlayerController> Respawned;
|
||||
public event System.Action LandedOnNormalPlatform;
|
||||
|
||||
public Transform Transform => transform;
|
||||
|
||||
@ -949,6 +950,7 @@ namespace DanroJump.Gameplay
|
||||
if (!suppressAutoJump)
|
||||
{
|
||||
Bounce(autoJumpVelocity);
|
||||
LandedOnNormalPlatform?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -52,6 +52,7 @@ namespace DanroJump.UI.Gameplay
|
||||
private Label coinsLabel;
|
||||
private Label deathsLabel;
|
||||
private Label stateLabel;
|
||||
private Label comboLabel;
|
||||
private CancellationTokenSource refreshCancellation;
|
||||
private CancellationTokenSource qrTimeoutCancellation;
|
||||
private CancellationTokenSource physicalDispenseCancellation;
|
||||
@ -185,6 +186,7 @@ namespace DanroJump.UI.Gameplay
|
||||
coinsLabel = FindLabel(root, coinsLabelName);
|
||||
deathsLabel = FindLabel(root, deathsLabelName);
|
||||
stateLabel = FindLabel(root, stateLabelName);
|
||||
comboLabel = FindLabel(root, "ComboValue");
|
||||
}
|
||||
|
||||
private void BindPrizeOverlay()
|
||||
@ -248,9 +250,48 @@ namespace DanroJump.UI.Gameplay
|
||||
SetLabel(coinsLabel, session.Coins.ToString());
|
||||
SetLabel(deathsLabel, session.DeathCount.ToString());
|
||||
SetLabel(stateLabel, FormatState(session.State));
|
||||
|
||||
if (comboLabel != null)
|
||||
{
|
||||
if (session.CurrentCombo > 1)
|
||||
{
|
||||
var comboText = $"x{session.CurrentCombo} COMBO!";
|
||||
if (comboLabel.text != comboText)
|
||||
{
|
||||
comboLabel.text = comboText;
|
||||
comboLabel.style.display = DisplayStyle.Flex;
|
||||
PulseComboLabel();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
comboLabel.style.display = DisplayStyle.None;
|
||||
}
|
||||
}
|
||||
|
||||
RefreshContinueOverlay();
|
||||
}
|
||||
|
||||
private void PulseComboLabel()
|
||||
{
|
||||
if (comboLabel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
comboLabel.style.scale = new StyleScale(new Scale(new Vector3(1.4f, 1.4f, 1f)));
|
||||
ResetComboScaleAsync().Forget();
|
||||
}
|
||||
|
||||
private async UniTaskVoid ResetComboScaleAsync()
|
||||
{
|
||||
await UniTask.Delay(TimeSpan.FromMilliseconds(80));
|
||||
if (comboLabel != null)
|
||||
{
|
||||
comboLabel.style.scale = new StyleScale(new Scale(new Vector3(1.0f, 1.0f, 1f)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Безопасно обновляет текст label, если элемент найден в UXML.
|
||||
/// </summary>
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement class="hud-icon hud-icon-crystal hud-icon-crystal-right" style="padding-left: 32px; padding-right: 64px; display: none;"/>
|
||||
</ui:VisualElement>
|
||||
<ui:Label name="ComboValue" text="x2 COMBO!" style="position: absolute; bottom: -80px; align-self: center; font-size: 54px; -unity-font-definition: url("project://database/Assets/Fonts/RifficFree-Bold.ttf?fileID=12800000&guid=63991fec8a53abe4d9a7907ef7f0db77&type=3#RifficFree-Bold"); color: rgb(255, 140, 0); -unity-text-outline-width: 3px; -unity-text-outline-color: rgb(0, 0, 0); text-shadow: 3px 3px 0px rgba(0,0,0,0.5); display: none; transition-property: scale; transition-duration: 0.08s; transition-timing-function: ease-out;" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="RightStats" class="hud-column hud-column-right">
|
||||
<ui:VisualElement class="hud-stat-list">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user