Untitled Game
by FlashMaker22765 lines20.2 KB
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class BorderOpsPrototype : MonoBehaviour
{
public static BorderOpsPrototype Instance { get; private set; }
public CurrencyManager currency;
public InventoryManager inventory;
public TradeManager trade;
public OperatorManager operators;
public GunsmithManager gunsmith;
public RangeManager range;
public HeadquartersManager headquarters;
public ServerAuthority server;
[Header("主界面面板")]
public GameObject mainPanel;
public GameObject inventoryPanel;
public GameObject tradePanel;
public GameObject rangePanel;
public GameObject gunsmithPanel;
public GameObject operatorPanel;
public GameObject headquartersPanel;
[Header("主界面文本")]
public Text hafuCoinText;
public Text actionPointsText;
public Text currentOperatorText;
[Header("仓库")]
public Transform warehouseListParent;
public GameObject warehouseItemPrefab;
public Text warehouseHint;
[Header("交易行")]
public InputField tradeSearchInput;
public Transform marketListParent;
public Transform myListingsParent;
public GameObject tradeListingPrefab;
public Text tradeBalanceText;
[Header("靶场")]
public Text rangeStatusText;
public Button staticTargetButton;
public Button movingTargetButton;
public Button damageTestButton;
public Button exitRangeButton;
[Header("改枪台")]
public Transform gunsmithBuildListParent;
public GameObject gunsmithBuildPrefab;
public Text gunsmithHint;
[Header("干员")]
public Transform operatorListParent;
public GameObject operatorEntryPrefab;
public Text currentOperatorDetailText;
[Header("特勤处")]
public Text headquartersLevelText;
public Transform departmentListParent;
public GameObject departmentEntryPrefab;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
currency = GetComponent<CurrencyManager>() ?? gameObject.AddComponent<CurrencyManager>();
inventory = GetComponent<InventoryManager>() ?? gameObject.AddComponent<InventoryManager>();
trade = GetComponent<TradeManager>() ?? gameObject.AddComponent<TradeManager>();
operators = GetComponent<OperatorManager>() ?? gameObject.AddComponent<OperatorManager>();
gunsmith = GetComponent<GunsmithManager>() ?? gameObject.AddComponent<GunsmithManager>();
range = GetComponent<RangeManager>() ?? gameObject.AddComponent<RangeManager>();
headquarters = GetComponent<HeadquartersManager>() ?? gameObject.AddComponent<HeadquartersManager>();
server = GetComponent<ServerAuthority>() ?? gameObject.AddComponent<ServerAuthority>();
}
private void Start()
{
RefreshMainInfo();
currency.onHafuCoinChanged.AddListener(_ => RefreshMainInfo());
currency.onActionPointsChanged.AddListener(_ => RefreshMainInfo());
operators.onOperatorChanged.AddListener(op =>
{
if (currentOperatorText != null && op != null)
currentOperatorText.text = op.operatorName;
});
inventory.onInventoryChanged.AddListener(RefreshWarehouse);
trade.onMarketUpdated.AddListener(RefreshMarket);
trade.onMyListingsUpdated.AddListener(RefreshMyListings);
currency.onHafuCoinChanged.AddListener(UpdateTradeBalance);
range.onRangeStateChanged.AddListener(_ => UpdateRangeStatus());
headquarters.onHeadquartersUpdated.AddListener(RefreshHeadquarters);
RefreshWarehouse();
RefreshMarket();
RefreshMyListings();
UpdateTradeBalance(currency.hafuCoin);
UpdateRangeStatus();
RefreshHeadquarters();
RefreshOperators();
RefreshGunsmithBuilds();
}
public void RefreshMainInfo()
{
if (hafuCoinText != null)
hafuCoinText.text = $"哈夫币:{currency.hafuCoin}";
if (actionPointsText != null)
actionPointsText.text = $"行动点:{currency.actionPoints}";
var op = operators.currentOperator;
if (currentOperatorText != null && op != null)
currentOperatorText.text = op.operatorName;
}
public void OpenInventory()
{
SetActivePanel(inventoryPanel);
RefreshWarehouse();
}
public void OpenTrade()
{
SetActivePanel(tradePanel);
RefreshMarket();
RefreshMyListings();
UpdateTradeBalance(currency.hafuCoin);
}
public void OpenRange()
{
SetActivePanel(rangePanel);
range.EnterRange();
}
public void OpenGunsmith()
{
SetActivePanel(gunsmithPanel);
RefreshGunsmithBuilds();
}
public void OpenOperators()
{
SetActivePanel(operatorPanel);
RefreshOperators();
}
public void OpenHeadquarters()
{
SetActivePanel(headquartersPanel);
RefreshHeadquarters();
}
public void StartOperation()
{
Debug.Log("进入对局:搜打撤模式");
}
public void BackToMain()
{
mainPanel?.SetActive(true);
inventoryPanel?.SetActive(false);
tradePanel?.SetActive(false);
rangePanel?.SetActive(false);
gunsmithPanel?.SetActive(false);
operatorPanel?.SetActive(false);
headquartersPanel?.SetActive(false);
range.ExitRange();
}
private void SetActivePanel(GameObject panel)
{
mainPanel?.SetActive(false);
inventoryPanel?.SetActive(false);
tradePanel?.SetActive(false);
rangePanel?.SetActive(false);
gunsmithPanel?.SetActive(false);
operatorPanel?.SetActive(false);
headquartersPanel?.SetActive(false);
if (panel != null)
panel.SetActive(true);
}
public void RefreshWarehouse()
{
if (warehouseListParent == null) return;
foreach (Transform child in warehouseListParent)
Destroy(child.gameObject);
foreach (var item in inventory.warehouse)
{
if (item.item == null) continue;
var entry = CreateEntry(warehouseListParent, warehouseItemPrefab);
var text = entry.GetComponentInChildren<Text>();
if (text != null)
text.text = $"{item.item.itemName} x{item.count}";
}
if (warehouseHint != null)
warehouseHint.text = $"仓库物品数:{inventory.warehouse.Count}";
}
public void RefreshMarket()
{
FillTradeList(marketListParent, trade.marketListings, true);
}
public void RefreshMyListings()
{
FillTradeList(myListingsParent, trade.myListings, false);
}
private void FillTradeList(Transform parent, List<TradeListing> listings, bool isBuy)
{
if (parent == null || listings == null) return;
foreach (Transform child in parent)
Destroy(child.gameObject);
foreach (var listing in listings)
{
if (listing.item == null) continue;
var entry = CreateEntry(parent, tradeListingPrefab);
var text = entry.GetComponentInChildren<Text>();
var button = entry.GetComponentInChildren<Button>();
if (text != null)
text.text = $"{listing.item.itemName} x{listing.count} 单价:{listing.pricePerUnit}";
if (button != null && isBuy)
{
string id = listing.listingId;
button.onClick.AddListener(() => trade.TryBuy(id));
}
}
}
public void TradeSearch()
{
string keyword = tradeSearchInput != null ? tradeSearchInput.text : "";
var results = trade.Search(keyword);
FillTradeList(marketListParent, results, true);
}
private void UpdateTradeBalance(int coin)
{
if (tradeBalanceText != null)
tradeBalanceText.text = $"哈夫币:{coin}";
}
public void UpdateRangeStatus()
{
if (rangeStatusText != null)
rangeStatusText.text = range.inRange ? "靶场训练中" : "未在靶场";
}
public void EnterStaticTarget()
{
Debug.Log("靶场:静态靶已开启");
}
public void EnterMovingTarget()
{
Debug.Log("靶场:移动靶已开启");
}
public void EnterDamageTest()
{
Debug.Log("靶场:伤害测试已开启");
}
public void ExitRange()
{
range.ExitRange();
BackToMain();
}
public void RefreshGunsmithBuilds()
{
if (gunsmithBuildListParent == null) return;
foreach (Transform child in gunsmithBuildListParent)
Destroy(child.gameObject);
foreach (var build in gunsmith.savedBuilds)
{
if (build.gun == null) continue;
var entry = CreateEntry(gunsmithBuildListParent, gunsmithBuildPrefab);
var text = entry.GetComponentInChildren<Text>();
if (text != null)
text.text = $"{build.buildName} - {build.gun.gunName}";
}
if (gunsmithHint != null)
gunsmithHint.text = $"已保存方案:{gunsmith.savedBuilds.Count}";
}
public void RefreshOperators()
{
if (operatorListParent == null) return;
foreach (Transform child in operatorListParent)
Destroy(child.gameObject);
foreach (var op in operators.allOperators)
{
if (op == null) continue;
var entry = CreateEntry(operatorListParent, operatorEntryPrefab);
var text = entry.GetComponentInChildren<Text>();
var button = entry.GetComponentInChildren<Button>();
if (text != null)
text.text = $"{op.operatorName} [{op.operatorClass}]";
if (button != null)
{
var selected = op;
button.onClick.AddListener(() =>
{
operators.SelectOperator(selected);
if (currentOperatorDetailText != null)
currentOperatorDetailText.text = $"{selected.operatorName}\n{selected.description}";
});
}
}
}
public void RefreshHeadquarters()
{
if (headquartersLevelText != null)
headquartersLevelText.text = $"特勤处等级:{headquarters.headquartersLevel}";
if (departmentListParent == null) return;
foreach (Transform child in departmentListParent)
Destroy(child.gameObject);
var depts = new[]
{
headquarters.commandCenter,
headquarters.trainingCenter,
headquarters.rangeDept,
headquarters.workshop,
headquarters.gunsmithDept,
headquarters.warehouseDept
};
foreach (var dept in depts)
{
if (dept == null) continue;
var entry = CreateEntry(departmentListParent, departmentEntryPrefab);
var text = entry.GetComponentInChildren<Text>();
var button = entry.GetComponentInChildren<Button>();
if (text != null)
text.text = $"{dept.name} Lv.{dept.level} 升级消耗:{dept.upgradeCost}";
if (button != null)
{
var selected = dept;
button.onClick.AddListener(() =>
{
if (headquarters.TryUpgrade(selected))
RefreshHeadquarters();
});
}
}
}
private static GameObject CreateEntry(Transform parent, GameObject prefab)
{
if (prefab != null)
return Instantiate(prefab, parent);
var obj = new GameObject("Entry");
obj.transform.SetParent(parent, false);
return obj;
}
}
[Serializable]
public class InventoryItem
{
public ItemData item;
public int count = 1;
public int durability = 100;
}
[Serializable]
public class TradeListing
{
public string listingId;
public ItemData item;
public int count;
public int pricePerUnit;
public string sellerId;
public long createTime;
}
[Serializable]
public class GunBuild
{
public GunData gun;
public List<ItemData> attachments = new List<ItemData>();
public string buildName;
}
[Serializable]
public class SkillData
{
public string skillName;
public string description;
public float cooldown;
}
[Serializable]
public class Department
{
public string name;
public int level = 1;
public int maxLevel = 10;
public int upgradeCost = 1000;
}
public enum ItemType
{
Ammo,
Armor,
Helmet,
Medic,
Material,
Keycard,
Collectible,
Attachment,
Gun,
Backpack,
ChestRig,
SafeBox
}
public enum GunType
{
AR,
SMG,
Sniper,
Shotgun,
DMR,
LMG,
Pistol
}
public enum OperatorClass
{
Assault,
Support,
Recon,
Engineer
}
[CreateAssetMenu(menuName = "BorderOps/ItemData")]
public class ItemData : ScriptableObject
{
public string id;
public string itemName;
public ItemType type;
public int stackSize = 1;
public bool tradable = true;
public bool bound = false;
public int basePrice = 0;
public Sprite icon;
}
[CreateAssetMenu(menuName = "BorderOps/GunData")]
public class GunData : ScriptableObject
{
public string id;
public string gunName;
public GunType gunType;
public float damage;
public float fireRate;
public float recoil;
public float adsSpeed;
public float mobility;
public int magazineSize;
public Sprite icon;
}
[CreateAssetMenu(menuName = "BorderOps/OperatorData")]
public class OperatorData : ScriptableObject
{
public string id;
public string operatorName;
public OperatorClass operatorClass;
public string description;
public Sprite portrait;
public SkillData passive;
public SkillData tactical1;
public SkillData tactical2;
public SkillData ultimate;
}
public class CurrencyManager : MonoBehaviour
{
public int hafuCoin = 10000;
public int actionPoints = 5;
public UnityAction<int> onHafuCoinChanged;
public UnityAction<int> onActionPointsChanged;
public void AddHafuCoin(int amount)
{
hafuCoin += amount;
onHafuCoinChanged?.Invoke(hafuCoin);
}
public bool TrySpendHafuCoin(int amount)
{
if (hafuCoin < amount) return false;
hafuCoin -= amount;
onHafuCoinChanged?.Invoke(hafuCoin);
return true;
}
public bool TrySpendActionPoints(int amount)
{
if (actionPoints < amount) return false;
actionPoints -= amount;
onActionPointsChanged?.Invoke(actionPoints);
return true;
}
}
public class InventoryManager : MonoBehaviour
{
public List<InventoryItem> warehouse = new List<InventoryItem>();
public List<InventoryItem> safeBox = new List<InventoryItem>();
public List<InventoryItem> equippedGear = new List<InventoryItem>();
public UnityAction onInventoryChanged;
public void AddItem(ItemData item, int count = 1)
{
if (item == null) return;
if (item.stackSize > 1)
{
var existing = warehouse.Find(x => x.item == item);
if (existing != null)
{
existing.count += count;
}
else
{
warehouse.Add(new InventoryItem { item = item, count = count });
}
}
else
{
for (int i = 0; i < count; i++)
{
warehouse.Add(new InventoryItem { item = item, count = 1 });
}
}
onInventoryChanged?.Invoke();
}
public bool RemoveItem(ItemData item, int count = 1)
{
if (item == null) return false;
var existing = warehouse.Find(x => x.item == item && x.count >= count);
if (existing == null) return false;
existing.count -= count;
if (existing.count <= 0)
{
warehouse.Remove(existing);
}
onInventoryChanged?.Invoke();
return true;
}
public List<InventoryItem> GetTradableItems()
{
return warehouse.FindAll(x => x.item != null && x.item.tradable && !x.item.bound);
}
}
public class TradeManager : MonoBehaviour
{
public List<TradeListing> marketListings = new List<TradeListing>();
public List<TradeListing> myListings = new List<TradeListing>();
public float feeRate = 0.05f;
public int maxListings = 10;
public UnityAction onMarketUpdated;
public UnityAction onMyListingsUpdated;
public bool TryList(InventoryItem inventoryItem, int count, int pricePerUnit)
{
if (inventoryItem == null || inventoryItem.item == null) return false;
if (!inventoryItem.item.tradable) return false;
if (myListings.Count >= maxListings) return false;
if (pricePerUnit <= 0) return false;
if (count <= 0 || count > inventoryItem.count) return false;
if (!BorderOpsPrototype.Instance.inventory.RemoveItem(inventoryItem.item, count))
return false;
var listing = new TradeListing
{
listingId = Guid.NewGuid().ToString(),
item = inventoryItem.item,
count = count,
pricePerUnit = pricePerUnit,
sellerId = "player",
createTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
};
myListings.Add(listing);
marketListings.Add(listing);
onMyListingsUpdated?.Invoke();
onMarketUpdated?.Invoke();
return true;
}
public bool TryBuy(string listingId)
{
var listing = marketListings.Find(x => x.listingId == listingId);
if (listing == null) return false;
int total = listing.pricePerUnit * listing.count;
if (!BorderOpsPrototype.Instance.currency.TrySpendHafuCoin(total)) return false;
BorderOpsPrototype.Instance.inventory.AddItem(listing.item, listing.count);
marketListings.Remove(listing);
if (listing.sellerId == "player")
{
myListings.Remove(listing);
onMyListingsUpdated?.Invoke();
}
onMarketUpdated?.Invoke();
return true;
}
public List<TradeListing> Search(string keyword, ItemType? type = null)
{
var result = marketListings;
if (!string.IsNullOrEmpty(keyword))
{
result = result.FindAll(x =>
x.item != null &&
x.item.itemName.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0);
}
if (type.HasValue)
{
result = result.FindAll(x => x.item != null && x.item.type == type.Value);
}
return result;
}
}
public class OperatorManager : MonoBehaviour
{
public List<OperatorData> allOperators = new List<OperatorData>();
public OperatorData currentOperator;
public UnityAction<OperatorData> onOperatorChanged;
public void SelectOperator(OperatorData op)
{
if (op == null) return;
currentOperator = op;
onOperatorChanged?.Invoke(currentOperator);
}
}
public class GunsmithManager : MonoBehaviour
{
public List<GunBuild> savedBuilds = new List<GunBuild>();
public void SaveBuild(GunBuild build)
{
if (build == null || build.gun == null) return;
var existing = savedBuilds.Find(x => x.buildName == build.buildName);
if (existing != null)
{
existing.gun = build.gun;
existing.attachments = new List<ItemData>(build.attachments);
}
else
{
savedBuilds.Add(build);
}
}
public void RemoveBuild(string buildName)
{
savedBuilds.RemoveAll(x => x.buildName == buildName);
}
}
public class RangeManager : MonoBehaviour
{
public bool inRange = false;
public UnityAction<bool> onRangeStateChanged;
public void EnterRange()
{
inRange = true;
onRangeStateChanged?.Invoke(true);
Debug.Log("已进入靶场");
}
public void ExitRange()
{
inRange = false;
onRangeStateChanged?.Invoke(false);
Debug.Log("已退出靶场");
}
}
public class HeadquartersManager : MonoBehaviour
{
public int headquartersLevel =
[(doc_common_card_1)]
Game Source: Untitled Game
Creator: FlashMaker22
Libraries: none
Complexity: complex (765 lines, 20.2 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: untitled-game-flashmaker22" to link back to the original. Then publish at arcadelab.ai/publish.