2026.06.25 Fishing scene
This commit is contained in:
@@ -1,53 +1,255 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class FishingRewardSystem : MonoBehaviour
|
||||
{
|
||||
public enum RewardType
|
||||
[Serializable]
|
||||
public class LootEntry
|
||||
{
|
||||
Normal,
|
||||
Rare
|
||||
public FishingItemType itemType = FishingItemType.Fish;
|
||||
public string displayName = "생선";
|
||||
[Min(0f)] public float weight = 1f;
|
||||
|
||||
public LootEntry(FishingItemType itemType, string displayName, float weight)
|
||||
{
|
||||
this.itemType = itemType;
|
||||
this.displayName = displayName;
|
||||
this.weight = Mathf.Max(0f, weight);
|
||||
}
|
||||
}
|
||||
|
||||
[Header("Reward Chance")]
|
||||
[Range(0f, 100f)]
|
||||
[SerializeField] private float rareChance = 10f;
|
||||
|
||||
[Header("Reward Count")]
|
||||
[SerializeField] private int normalMemory;
|
||||
[SerializeField] private int rareMemory;
|
||||
|
||||
public int NormalMemory => normalMemory;
|
||||
public int RareMemory => rareMemory;
|
||||
|
||||
public RewardType GiveReward()
|
||||
public struct CatchResult
|
||||
{
|
||||
if (Random.value < rareChance / 100f)
|
||||
return GiveRareMemory();
|
||||
public FishingItemType ItemType;
|
||||
public string DisplayName;
|
||||
public bool CountsAsCleanupItem;
|
||||
public bool IsMemoryPiece;
|
||||
|
||||
return GiveNormalMemory();
|
||||
public CatchResult(FishingItemType itemType, string displayName, bool countsAsCleanupItem, bool isMemoryPiece)
|
||||
{
|
||||
ItemType = itemType;
|
||||
DisplayName = displayName;
|
||||
CountsAsCleanupItem = countsAsCleanupItem;
|
||||
IsMemoryPiece = isMemoryPiece;
|
||||
}
|
||||
}
|
||||
|
||||
private RewardType GiveNormalMemory()
|
||||
[Header("Loot Table - Dirty Pond")]
|
||||
[Tooltip("연못이 정화되기 전 낚이는 아이템 목록입니다. 기억의 조각은 이 테이블에 있어도 자동 제외됩니다.")]
|
||||
[SerializeField] private List<LootEntry> dirtyPondLootTable = new List<LootEntry>();
|
||||
|
||||
[Header("Loot Table - Clean Pond")]
|
||||
[Tooltip("연못이 정화된 뒤 낚이는 아이템 목록입니다. 기억의 조각을 포함할 수 있습니다.")]
|
||||
[SerializeField] private List<LootEntry> cleanPondLootTable = new List<LootEntry>();
|
||||
|
||||
[Header("Debug")]
|
||||
[SerializeField] private bool showDebugLog = true;
|
||||
|
||||
public IReadOnlyList<LootEntry> DirtyPondLootTable => dirtyPondLootTable;
|
||||
public IReadOnlyList<LootEntry> CleanPondLootTable => cleanPondLootTable;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
normalMemory++;
|
||||
|
||||
Debug.Log("ÀÏ¹Ý ±â¾ï +1");
|
||||
|
||||
return RewardType.Normal;
|
||||
SetDefaultLootTables();
|
||||
}
|
||||
|
||||
private RewardType GiveRareMemory()
|
||||
private void Awake()
|
||||
{
|
||||
rareMemory++;
|
||||
|
||||
Debug.Log("Èñ±Í ±â¾ï +1");
|
||||
|
||||
return RewardType.Rare;
|
||||
EnsureLootTables();
|
||||
}
|
||||
|
||||
public void ResetRewardCount()
|
||||
private void OnValidate()
|
||||
{
|
||||
normalMemory = 0;
|
||||
rareMemory = 0;
|
||||
EnsureLootTables();
|
||||
ClampLootTable(dirtyPondLootTable);
|
||||
ClampLootTable(cleanPondLootTable);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureLootTables()
|
||||
{
|
||||
if (dirtyPondLootTable == null)
|
||||
dirtyPondLootTable = new List<LootEntry>();
|
||||
|
||||
if (cleanPondLootTable == null)
|
||||
cleanPondLootTable = new List<LootEntry>();
|
||||
|
||||
if (dirtyPondLootTable.Count == 0)
|
||||
SetDefaultDirtyLootTable();
|
||||
|
||||
if (cleanPondLootTable.Count == 0)
|
||||
SetDefaultCleanLootTable();
|
||||
}
|
||||
|
||||
private void SetDefaultLootTables()
|
||||
{
|
||||
SetDefaultDirtyLootTable();
|
||||
SetDefaultCleanLootTable();
|
||||
}
|
||||
|
||||
private void SetDefaultDirtyLootTable()
|
||||
{
|
||||
dirtyPondLootTable = new List<LootEntry>
|
||||
{
|
||||
new LootEntry(FishingItemType.Fish, "생선", 25f),
|
||||
new LootEntry(FishingItemType.RottenFish, "상한 생선", 8f),
|
||||
new LootEntry(FishingItemType.Trash, "쓰레기", 28f),
|
||||
new LootEntry(FishingItemType.Bottle, "병", 18f),
|
||||
new LootEntry(FishingItemType.PlasticBag, "봉지", 18f),
|
||||
new LootEntry(FishingItemType.JellyfishPowder, "해파리 가루", 6f),
|
||||
new LootEntry(FishingItemType.OldCompass, "낡은 나침반", 4f)
|
||||
};
|
||||
}
|
||||
|
||||
private void SetDefaultCleanLootTable()
|
||||
{
|
||||
cleanPondLootTable = new List<LootEntry>
|
||||
{
|
||||
new LootEntry(FishingItemType.MemoryPiece, "기억의 조각", 30f),
|
||||
new LootEntry(FishingItemType.Fish, "생선", 30f),
|
||||
new LootEntry(FishingItemType.OldCompass, "낡은 나침반", 15f),
|
||||
new LootEntry(FishingItemType.JellyfishPowder, "해파리 가루", 15f),
|
||||
new LootEntry(FishingItemType.RottenFish, "상한 생선", 4f)
|
||||
};
|
||||
}
|
||||
|
||||
private void ClampLootTable(List<LootEntry> table)
|
||||
{
|
||||
if (table == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < table.Count; i++)
|
||||
{
|
||||
if (table[i] == null)
|
||||
{
|
||||
table[i] = new LootEntry(FishingItemType.Fish, "생선", 1f);
|
||||
continue;
|
||||
}
|
||||
|
||||
table[i].weight = Mathf.Max(0f, table[i].weight);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(table[i].displayName))
|
||||
table[i].displayName = GetDefaultDisplayName(table[i].itemType);
|
||||
}
|
||||
}
|
||||
|
||||
public CatchResult RollCatch(bool pondCleaned, bool forceMemoryPiece)
|
||||
{
|
||||
if (forceMemoryPiece)
|
||||
return CreateCatchResult(FishingItemType.MemoryPiece, GetDefaultDisplayName(FishingItemType.MemoryPiece));
|
||||
|
||||
List<LootEntry> table = pondCleaned ? cleanPondLootTable : dirtyPondLootTable;
|
||||
LootEntry selectedEntry = RollFromTable(table, pondCleaned);
|
||||
|
||||
if (selectedEntry == null)
|
||||
return CreateCatchResult(FishingItemType.Fish, GetDefaultDisplayName(FishingItemType.Fish));
|
||||
|
||||
return CreateCatchResult(selectedEntry.itemType, selectedEntry.displayName);
|
||||
}
|
||||
|
||||
private LootEntry RollFromTable(List<LootEntry> table, bool pondCleaned)
|
||||
{
|
||||
if (table == null || table.Count == 0)
|
||||
return null;
|
||||
|
||||
float totalWeight = 0f;
|
||||
|
||||
for (int i = 0; i < table.Count; i++)
|
||||
{
|
||||
LootEntry entry = table[i];
|
||||
|
||||
if (!IsRollableEntry(entry, pondCleaned))
|
||||
continue;
|
||||
|
||||
totalWeight += entry.weight;
|
||||
}
|
||||
|
||||
if (totalWeight <= 0f)
|
||||
return null;
|
||||
|
||||
float roll = UnityEngine.Random.Range(0f, totalWeight);
|
||||
float current = 0f;
|
||||
|
||||
for (int i = 0; i < table.Count; i++)
|
||||
{
|
||||
LootEntry entry = table[i];
|
||||
|
||||
if (!IsRollableEntry(entry, pondCleaned))
|
||||
continue;
|
||||
|
||||
current += entry.weight;
|
||||
|
||||
if (roll <= current)
|
||||
return entry;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool IsRollableEntry(LootEntry entry, bool pondCleaned)
|
||||
{
|
||||
if (entry == null)
|
||||
return false;
|
||||
|
||||
if (entry.weight <= 0f)
|
||||
return false;
|
||||
|
||||
if (!pondCleaned && entry.itemType == FishingItemType.MemoryPiece)
|
||||
return false;
|
||||
|
||||
return entry.itemType != FishingItemType.None;
|
||||
}
|
||||
|
||||
private CatchResult CreateCatchResult(FishingItemType itemType, string displayName)
|
||||
{
|
||||
string finalDisplayName = string.IsNullOrWhiteSpace(displayName) ? GetDefaultDisplayName(itemType) : displayName;
|
||||
bool countsAsCleanupItem = IsCleanupItem(itemType);
|
||||
bool isMemoryPiece = itemType == FishingItemType.MemoryPiece;
|
||||
|
||||
if (showDebugLog)
|
||||
Debug.Log($"낚시 획득: {finalDisplayName}");
|
||||
|
||||
return new CatchResult(itemType, finalDisplayName, countsAsCleanupItem, isMemoryPiece);
|
||||
}
|
||||
|
||||
public bool IsCleanupItem(FishingItemType itemType)
|
||||
{
|
||||
return itemType == FishingItemType.Trash ||
|
||||
itemType == FishingItemType.Bottle ||
|
||||
itemType == FishingItemType.PlasticBag;
|
||||
}
|
||||
|
||||
public string GetDefaultDisplayName(FishingItemType itemType)
|
||||
{
|
||||
switch (itemType)
|
||||
{
|
||||
case FishingItemType.Fish:
|
||||
return "생선";
|
||||
|
||||
case FishingItemType.RottenFish:
|
||||
return "상한 생선";
|
||||
|
||||
case FishingItemType.Trash:
|
||||
return "쓰레기";
|
||||
|
||||
case FishingItemType.Bottle:
|
||||
return "병";
|
||||
|
||||
case FishingItemType.PlasticBag:
|
||||
return "봉지";
|
||||
|
||||
case FishingItemType.JellyfishPowder:
|
||||
return "해파리 가루";
|
||||
|
||||
case FishingItemType.OldCompass:
|
||||
return "낡은 나침반";
|
||||
|
||||
case FishingItemType.MemoryPiece:
|
||||
return "기억의 조각";
|
||||
|
||||
case FishingItemType.None:
|
||||
default:
|
||||
return "없음";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user