Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion Core/AchievementSystem/AchievementSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,17 @@ public partial class AchievementSystem : Node

private GameSaveData saveData;

private AudioStreamPlayer _achievementSound;

public override void _Ready()
{
saveData = SaveController.GameData;

_achievementSound = new AudioStreamPlayer();
_achievementSound.Stream = ResourceLoader.Load<AudioStream>("res://sounds/unlock_achievement.mp3");

AddChild(_achievementSound);

foreach (var achievement in AllAchievements)
{
achievement.IsUnlocked =
Expand Down Expand Up @@ -59,6 +66,12 @@ private void UnlockAchievement(AchievementData achievement)

achievement.IsUnlocked = true;

if (_achievementSound != null)
{
_achievementSound.Play();
GD.Print(achievement.AchievementName);
}

if (saveData != null && !saveData.Achievements.Contains(achievement.Id))
{
saveData.Achievements.Add(achievement.Id);
Expand All @@ -73,7 +86,7 @@ private void UnlockAchievement(AchievementData achievement)
}
}

private void CheckAchievements(AchievementType type, int value = 1)
public void CheckAchievements(AchievementType type, int value = 1)
{
foreach (var achievement in AllAchievements)
{
Expand Down
16 changes: 15 additions & 1 deletion Core/AchievementSystem/Achievements.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,22 @@
[ext_resource type="Resource" uid="uid://w8ijl5xmjo8y" path="res://resources/achievements/FirstSet.tres" id="3_qtoig"]
[ext_resource type="Resource" uid="uid://bwfcy42k2nmt8" path="res://resources/achievements/FirstGame.tres" id="4_qtoig"]
[ext_resource type="Resource" uid="uid://df185apnjqyui" path="res://resources/achievements/Points_1000.tres" id="5_l8182"]
[ext_resource type="Resource" uid="uid://dsmnkn5rtudbs" path="res://resources/achievements/NoMistakes.tres" id="6_bjm61"]
[ext_resource type="Resource" uid="uid://c0khsml6efaq" path="res://resources/achievements/TotalSets_10.tres" id="7_g78ka"]
[ext_resource type="Resource" uid="uid://35cjnbw2xnvw" path="res://resources/achievements/TotalSets_50.tres" id="8_y5vsq"]
[ext_resource type="Resource" uid="uid://bbetvxo00tbv2" path="res://resources/achievements/TotalSets_100.tres" id="9_y5vsq"]
[ext_resource type="Resource" uid="uid://6nu02w1jojm6" path="res://resources/achievements/TotalSets_500.tres" id="10_ls5uk"]
[ext_resource type="Resource" uid="uid://b47joqpxeutb4" path="res://resources/achievements/Sets25_NoMistakes.tres" id="11_ls5uk"]
[ext_resource type="Resource" uid="uid://ci0gh7m10e81h" path="res://resources/achievements/Set_sec_5.tres" id="12_6dm4i"]
[ext_resource type="Resource" uid="uid://dx6j4hc5a4x6s" path="res://resources/achievements/Series_5.tres" id="12_slb81"]
[ext_resource type="Resource" uid="uid://bjowubeeylxw6" path="res://resources/achievements/Series_10.tres" id="13_hlqj6"]
[ext_resource type="Resource" uid="uid://c4okwdq8fvn6o" path="res://resources/achievements/Series_20.tres" id="14_fffem"]
[ext_resource type="Resource" uid="uid://dqnoxgli30dom" path="res://resources/achievements/Set_10_per_minute.tres" id="16_8vpy1"]
[ext_resource type="Resource" uid="uid://la6qbi3b3qnr" path="res://resources/achievements/Sets_3_per_15_sec.tres" id="17_qqku5"]
[ext_resource type="Resource" uid="uid://dhppdc71vdtci" path="res://resources/achievements/Mode_on_time.tres" id="18_gddjv"]
[ext_resource type="Resource" uid="uid://beq8k6w0saixe" path="res://resources/achievements/All_achievements.tres" id="19_v8q2g"]

[node name="AchievementSystem" type="Node" unique_id=1380662846]
script = ExtResource("1_cke4p")
AllAchievements = Array[ExtResource("2_8ygst")]([ExtResource("3_qtoig"), ExtResource("4_qtoig"), ExtResource("5_l8182")])
AllAchievements = Array[ExtResource("2_8ygst")]([ExtResource("3_qtoig"), ExtResource("4_qtoig"), ExtResource("6_bjm61"), ExtResource("12_6dm4i"), ExtResource("5_l8182"), ExtResource("7_g78ka"), ExtResource("8_y5vsq"), ExtResource("9_y5vsq"), ExtResource("10_ls5uk"), ExtResource("12_slb81"), ExtResource("13_hlqj6"), ExtResource("14_fffem"), ExtResource("11_ls5uk"), ExtResource("16_8vpy1"), ExtResource("17_qqku5"), ExtResource("18_gddjv"), ExtResource("19_v8q2g")])
metadata/_custom_type_script = "uid://c047evqheeiiv"
107 changes: 95 additions & 12 deletions Core/Controllers/GameController/GameController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,22 @@ public partial class GameController : Node
{
[Signal] public delegate void SetCheckSuccessEventHandler(Godot.Collections.Array<CardData> checkedCards);
[Signal] public delegate void SetCheckFailedEventHandler();
[Signal] public delegate void TimeChangedEventHandler(int remainingTime);
[Signal] public delegate void GameFinishedEventHandler();

[Export] public int ScoreForOneSet { get; set; } = 0;
[Export] public int GameDuration { get; set; } = 300;

public int RemainingTime { get; private set; }

private bool _isTimerPaused = false;

[Export] public Score GameScore { get; set; }
[Export] public Streak GameStreak { get; set; }
[Export] public Timer GameTimer { get; set; }

public int SetsThisGame { get; private set; } = 0;
public int MistakesThisGame { get; private set; } = 0;

[Export] public BaseCardValidator CardValidator { get; set; }
[Export] public BaseStreakStrategy StreakStrategy { get; set; }
Expand All @@ -30,13 +41,17 @@ public override void _Ready()
gameAchievementSystem = GetNode<AchievementSystem>("/root/Achievements");

gameAchievementSystem.Initialize(GameScore, GameStreak);

GameTimer.Timeout += OnTimerTimeout;

StartGameTimer();
}

public void ProcessSelectedSet(List<CardData> cards)
{
if (cards == null || cards.Count != 3)
{
GD.PrintErr($"[GameController]: Ошибка! Проверяясь должно быть 3 карты, получено: {(cards?.Count ?? 0)}");
GD.PrintErr($"[GameController]: The number of cards is insufficient to check for a set. Cards transferred: {(cards?.Count ?? 0)}");
return;
}

Expand All @@ -58,18 +73,26 @@ private void HandleSuccessfulSet(List<CardData> cards)
int streakBonus = StreakStrategy.CalculateScore(GameScore, GameStreak);
GameScore.Modify(ScoreForOneSet + streakBonus);

SetsThisGame++;
SaveData.TotalSets++;

gameAchievementSystem.CheckTotalSets(SaveData.TotalSets);
gameAchievementSystem.CheckScore(GameScore.CurrentValue);
gameAchievementSystem.CheckStreak(GameStreak.CurrentValue);

if (SaveData.TotalSets == 1)
{
gameAchievementSystem.UnlockByType(AchievementType.FirstSet);
}

SaveData.BestScore = Math.Max(SaveData.BestScore, GameScore.HighScore);
SaveData.BestStreak = Math.Max(SaveData.BestStreak, GameStreak.MaxStreak);
SaveController.SaveGameData(SaveData);
if (RemainingTime >= (GameDuration - 5))
{
gameAchievementSystem.CheckAchievements(AchievementType.FastSet);
}
if (RemainingTime >= (GameDuration - 15))
{
gameAchievementSystem.CheckAchievements(AchievementType.FastSet, SetsThisGame);
}

var cardArray = new Godot.Collections.Array<CardData>(cards);
EmitSignal(SignalName.SetCheckSuccess, cardArray);
Expand All @@ -81,39 +104,99 @@ private void HandleFailedSet()
GameScore.Modify(-penalty);
GameStreak.ResetCurrentValue();

MistakesThisGame++;
SaveData.TotalMistakes++;
SaveController.SaveGameData(SaveData);

EmitSignal(SignalName.SetCheckFailed);
}

public (bool scoreRecord, bool streakRecord) FinishGame()
public (bool scoreRecord, bool streakRecord, bool PatternsRecord) FinishGame()
{
bool scoreRecord = GameScore.CurrentValue > SaveData.BestScore;
bool streakRecord = GameStreak.MaxStreak > SaveData.BestStreak;
bool patternsRecord = SetsThisGame > SaveData.BestPatterns;

SaveData.TotalGames++;
SaveData.TotalScore += GameScore.CurrentValue;

if (scoreRecord)
SaveData.BestScore = GameScore.CurrentValue;

if (streakRecord)
SaveData.BestStreak = GameStreak.MaxStreak;

if (patternsRecord)
SaveData.BestPatterns = SetsThisGame;

SaveData.BestScore = Math.Max(SaveData.BestScore, GameScore.CurrentValue);
SaveData.BestStreak = Math.Max(SaveData.BestStreak, GameStreak.MaxStreak);
SaveData.BestPatterns = Math.Max(SaveData.BestPatterns, SetsThisGame);

if (SaveData.TotalGames >= 1)
{
gameAchievementSystem.UnlockByType(AchievementType.FirstGame);
GD.Print($"[GameController] unlock first game achievement");
}

if (MistakesThisGame == 0)
{
gameAchievementSystem.UnlockByType(AchievementType.NoMistakes);
}

SaveController.SaveGameData(SaveData);
return (scoreRecord, streakRecord);
return (scoreRecord, streakRecord, patternsRecord);
}

private void ValidateDependencies()
{
if (GameScore == null) GD.PrintErr($"[GameController] Ошибка: Не прикреплен узел Score в инспекторе {Name}");
if (GameStreak == null) GD.PrintErr($"[GameController] Ошибка: Не прикреплен узел Streak в инспекторе {Name}");
if (CardValidator == null) GD.PrintErr($"[GameController] Ошибка: Не прикреплен узел CardValidator в инспекторе {Name}");
if (StreakStrategy == null) GD.PrintErr($"[GameController] Ошибка: Не прикреплен узел StreakStrategy в инспекторе {Name}");
if (PenaltyStrategy == null) GD.PrintErr($"[GameController] Ошибка: Ме прикреплен узел PenaltyStrategy в инспекторе {Name}");
if (GameScore == null) GD.PrintErr($"[GameController] Error: Score node not connected in the Inspector {Name}");
if (GameStreak == null) GD.PrintErr($"[GameController] Error: Streak node not connected in the Inspector {Name}");
if (CardValidator == null) GD.PrintErr($"[GameController] Error: CardValidator node not connected in the Inspector {Name}");
if (StreakStrategy == null) GD.PrintErr($"[GameController] Error: StreakStrategy node not connected in the Inspector {Name}");
if (PenaltyStrategy == null) GD.PrintErr($"[GameController] Error: PenaltyStrategy node not connected in the Inspector {Name}");
}
public void StartGameTimer()
{
RemainingTime = GameDuration;

GameTimer.Start();

EmitSignal( SignalName.TimeChanged, RemainingTime);
}

private void OnTimerTimeout()
{
RemainingTime--;

if (RemainingTime <= 0)
{
RemainingTime = 0;
GameTimer.Stop();

EmitSignal(SignalName.TimeChanged, RemainingTime);

EmitSignal(SignalName.GameFinished);
return;
}

EmitSignal(SignalName.TimeChanged, RemainingTime);
}

public void PauseGameTimer()
{
if (GameTimer == null || GameTimer.IsStopped())
return;

_isTimerPaused = true;
GameTimer.Paused = true;
}

public void ResumeGameTimer()
{
if (GameTimer == null)
return;

_isTimerPaused = false;
GameTimer.Paused = false;
}
}
1 change: 1 addition & 0 deletions Core/Controllers/SaveController/GameSaveData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public partial class GameSaveData : Resource
{
[Export] public int BestScore { get; set; } = 0;
[Export] public int BestStreak { get; set; } = 0;
[Export] public int BestPatterns { get; set; } = 0;

[Export] public int TotalScore { get; set; } = 0;

Expand Down
18 changes: 9 additions & 9 deletions Core/StreakStrategy/LinearStreakStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
[GlobalClass]
public partial class LinearStreakStrategy : BaseStreakStrategy
{
[Export] public int PointsPerStreakStep { get; set; } = 5;
[Export] public int MaxMultiplier { get; set; } = 5;
[Export] public int PointsPerStreakStep { get; set; } = 5;
[Export] public int MaxMultiplier { get; set; } = 5;

public override int CalculateScore(Score score, Streak streak)
{
if(streak.CurrentValue < 1) return score.CurrentValue;
public override int CalculateScore(Score score, Streak streak)
{
if(streak.CurrentValue <= 1) return score.CurrentValue;

int resultMultiplier = Mathf.Clamp(streak.CurrentValue, 1, MaxMultiplier);
int resultMultiplier = Mathf.Clamp(streak.CurrentValue, 1, MaxMultiplier);

return score.CurrentValue + (PointsPerStreakStep * resultMultiplier);
}
}
return PointsPerStreakStep * resultMultiplier;
}
}
2 changes: 1 addition & 1 deletion PatternShift.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Godot.NET.Sdk/4.7.1">
<Project Sdk="Godot.NET.Sdk/4.7.0">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net9.0</TargetFramework>
Expand Down
7 changes: 7 additions & 0 deletions PatternShift.csproj.old.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Godot.NET.Sdk/4.7.1">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net9.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>
</Project>
14 changes: 14 additions & 0 deletions resources/achievements/All_achievements.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[gd_resource type="Resource" script_class="AchievementData" format=3 uid="uid://beq8k6w0saixe"]

[ext_resource type="Script" uid="uid://dlp73yl0k544o" path="res://Core/AchievementSystem/AchievementData.cs" id="1_3pplh"]
[ext_resource type="Texture2D" uid="uid://byfxnc1xfv5pi" path="res://assets/images/achievements/legend.png" id="1_vya30"]

[resource]
script = ExtResource("1_3pplh")
Id = "all_achievements"
AchievementName = "Легенда"
AchievementDescription = "Открыть все дизайны карточек и получить все остальные достижения"
Type = 12
TargetValue = 1
Icon = ExtResource("1_vya30")
metadata/_custom_type_script = "uid://dlp73yl0k544o"
14 changes: 14 additions & 0 deletions resources/achievements/First_skin.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[gd_resource type="Resource" script_class="AchievementData" format=3 uid="uid://bm3dsp7iq4ng3"]

[ext_resource type="Script" uid="uid://dlp73yl0k544o" path="res://Core/AchievementSystem/AchievementData.cs" id="1_aycrh"]
[ext_resource type="Texture2D" uid="uid://c7fi1oxpfclbc" path="res://assets/images/achievements/collector.png" id="1_cygcu"]

[resource]
script = ExtResource("1_aycrh")
Id = "first_skin"
AchievementName = "Коллекционер"
AchievementDescription = "Открыть первый дизайн карточек"
Type = 6
TargetValue = 1
Icon = ExtResource("1_cygcu")
metadata/_custom_type_script = "uid://dlp73yl0k544o"
14 changes: 14 additions & 0 deletions resources/achievements/Mode_on_time.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[gd_resource type="Resource" script_class="AchievementData" format=3 uid="uid://dhppdc71vdtci"]

[ext_resource type="Texture2D" uid="uid://bucojbroaxmt2" path="res://assets/images/achievements/against_time.png" id="1_duiko"]
[ext_resource type="Script" uid="uid://dlp73yl0k544o" path="res://Core/AchievementSystem/AchievementData.cs" id="1_pgknf"]

[resource]
script = ExtResource("1_pgknf")
Id = "mode_on_time"
AchievementName = "Время"
AchievementDescription = "Выиграть режим \"На время\""
Type = 11
TargetValue = 1
Icon = ExtResource("1_duiko")
metadata/_custom_type_script = "uid://dlp73yl0k544o"
13 changes: 13 additions & 0 deletions resources/achievements/NoMistakes.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[gd_resource type="Resource" script_class="AchievementData" format=3 uid="uid://dsmnkn5rtudbs"]

[ext_resource type="Script" uid="uid://dlp73yl0k544o" path="res://Core/AchievementSystem/AchievementData.cs" id="1_d7sre"]
[ext_resource type="Texture2D" uid="uid://su540gappm7v" path="res://assets/images/achievements/flawless.png" id="1_v6jhb"]

[resource]
script = ExtResource("1_d7sre")
Id = "no_mistakes"
AchievementName = "Без ошибок"
AchievementDescription = "Закончить игру без единой ошибки"
Type = 2
Icon = ExtResource("1_v6jhb")
metadata/_custom_type_script = "uid://dlp73yl0k544o"
14 changes: 14 additions & 0 deletions resources/achievements/Series_10.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[gd_resource type="Resource" script_class="AchievementData" format=3 uid="uid://bjowubeeylxw6"]

[ext_resource type="Script" uid="uid://dlp73yl0k544o" path="res://Core/AchievementSystem/AchievementData.cs" id="1_8jng8"]
[ext_resource type="Texture2D" uid="uid://bxij4eev2d8lq" path="res://assets/images/achievements/streak_x10.png" id="1_vrsk4"]

[resource]
script = ExtResource("1_8jng8")
Id = "series_10"
AchievementName = "Серия ×10"
AchievementDescription = "Сделать серию из 10 правильных ответов"
Type = 7
TargetValue = 10
Icon = ExtResource("1_vrsk4")
metadata/_custom_type_script = "uid://dlp73yl0k544o"
Loading