So I'm working on a game and I'd like some recommendations for how to sort items for easy, legible, coding reference in Unity. I know my current method is flawed, and really I'd just like some guidance.
So what I'm doing is using classes to separate item categories and their items.
For example, here's an idea of a setup for a script :
public class Items {
public class Equipment {
public class Weapons {
public Item Sword = new Item();
Sword.name = "Sword";
Sword.cost = 1;
}
}
}
then a basic Item class for example
public class Item {
public string name;
public int cost;
}
I can tell this is terrible practice, especially based on the problems I've been having, but I like the idea of using a reference like Items.Equipment.Weapons.Sword and I've grown accustomed to using that from an API I previously used.
I'm open to completely changing everything, I just want some tips. Thanks.
I guess my main question is (was), what's the best way to organize nested classes so they can be references from other scripts easily?
The answer I found was that instead of nesting classes, in my case, it's better to use namespaces to separate items into categories. Thanks a million.
I recommend using ScriptableObjects to create your items, armor, and weapons. You'll have to spend an hour or two learning them, but I think you'll be much happier with your design if you go that route.
Think of a ScriptableObject as a set of properties (item name, cost, attack power, defense power, etc.). For each item you have in your game, you create an instance of a ScriptableObject. Those ScriptableObject instances then become assets in your Unity project, just like a prefab or a sprite. That means you can drag them around in your project, and assign them to the fields on your MonoBehaviours. That'll result in you being able to assign equipment to a character by dragging it from your Project view into the Inspector.
Here's an example of how it'll look
Item.cs
public class Item : ScriptableObject
{
public string name;
public int cost;
public Sprite image;
}
Equipment.cs
public class Equipment : Item
{
public Slots slot;
}
public enum Slots
{
Body,
DoubleHanded,
Hands,
Head,
Feet,
Legs,
LeftHand,
RightHand
}
Weapon.cs
// CreateAssetMenu is what lets you create an instance of a Weapon in your Project
// view. Make a folder for your weapons, then right click inside that folder (in the
// Unity project view) and there should be a menu option for Equipment -> Create Weapon
[CreateAssetMenu(menuName = "Equipment/Create Weapon")]
public class Weapon : Equipment
{
public int attackPower;
public int attackSpeed;
public WeaponTypes weaponType;
}
public enum WeaponTypes
{
Axe,
Bow,
Sword
}
Armor.cs
[CreateAssetMenu(menuName = "Equipment/Create Armor")]
public class Armor : Equipment
{
public int defensePower;
}
Now create a bunch of weapons and armor in your project.
One thing that makes ScriptableObjects nice is you can edit them in your Inspector, rather than having to do it through code (although you can do that too).
Now on your "character" MonoBehaviour, add some properties for that character's equipment.
public class Character : MonoBehaviour
{
public Armor bodyArmor;
public Armor headArmor;
public Weapon weapon;
}
Now you can assign your weapons and armor to your character in the Inspector
You'll probably want something more customized to your needs than my example, but those are the basics. I recommend spending some time looking at ScriptableObjects. Read the Unity docs I linked earlier, or watch some videos on YouTube.
One of Unity's strengths is that it lets you do a lot of design and configuration through the editor rather than through code, and ScriptableObjects reinforce that.
Related
Work with me now, I'm a confused lost little child at this point.
Intro
I have an inventory that allows me to place items into a gear slot, instantiating that item in my players hand/ on body. For example, I have a simple rifle, I put it in my gear slot and it is created. My player can now run around shoot, kill, and unequip it too! BUUUT I can not figure out how to save my modified variables.
Problem Lore
All my items are Scriptable Objects while in the inventory, so I can easily create different items. The Scriptable Object holds; some text data, other things, and the actual prefab of the weapon I want to instantiate. The problem is, when I unequip the item from the gear slot it deletes the prefab, as it should, I don't want to see or use it anymore while in game. I can easily create an upgrade system, but saving those changed variables is a problem. I'm deleting it when I unequip it and instantiating a new copy when I equip it. My game allows the player to pickup the same weapon until the inventory is full too.
Overall Problems
How do I go about saving multiple modified prefabs instantiated from the same scriptable object?
Should I figure out how to create a unique Id that represents the weapon and allows the scriptable object to instantiate this unique Id?
I'm not sure if the second question is possible, but I think you might get the gist of the problem, any solutions are helpful, if I should recreate my inventory, I'd cry for sure, but I really want a weapon upgrade system in my game, so I'LL HECKIN DO IT! Thank you guys.
Problem
I will have a lot of various classes, which is very similar("simple sword", "diamond sword", "giga sword"...)
Solution
Strategy pattern, instead of creation whole new object, i will change the property of this object
Example
interface IHandle
{
public int Speed { get; set; }
}
class SimpleHandle : IHandle
{
public int Speed { get; set; }
public SimpleHandle()
{
Speed = 5;
}
}
interface IBlade
{
public int Damage { get; set; }
}
class SimpleBlade : IBlade
{
public int Damage { get; set; }
public SimpleBlade()
{
Damage = 5;
}
}
class Sword
{
private IHandle _handle { get; set; }
private IBlade _blade { get; set; }
public void ChangeHandle(IHandle handle)
{
_handle = handle;
}
public void ChangeBlade(IBlade blade)
{
_blade = blade;
}
}
I am developing a small nuclear reactor simulator game. I have a bunch of reactor component classes: HeatVent, HeatExchanger, UraniumCell etc. They are not deriving from MonoBehaviour since they don't have any Unity logic, but they do implement a shared interface IReactorComponent. What I want to do is to be able to create prefabs of such components (simple heat vent, advanced heat vent, doubled uranium cell etc.) The prefabs would have different sprites and something like that, but the main issue is to define what reactor component class the prefab is related to, because I can't just drag'n'drop a non-MonoBehaviour script on inspector. Also, I want to be able to set settings in the inspector (for example, HeatVent has CoolAmount and HeatCapacity properties, UraniumCell has FuelAmount, HeatProduce and PowerProduce properties).
I have read about factory method pattern and as I understood, I have to create a fabric class that derives from MonoBehaviour for each reactor component class like HeatVentBehaviour, HeatExchangerBehaviour etc. Yes, that completely solves my issue with prefabs but is there any way to not create an additional MonoBehaviour wrap for each class? If I had 15 IReactorComponent classes, I would need to create 15 fabrics which feels like not the greatest solution.
Sounds like what you are looking for is ScriptableObject!
Instances of those are assets so they don't live in a scene but in the Assets folder and basically behave a little bit like prefabs except: They already exist and do not need to be instantiated anymore.
Mostly they are used as just configurable data containers. They have an Inspector so you can easily fill them with your desired data and references to other assets (e.g. the related prefab in your case).
But in addition you can as well let them implement behavior like your interface and thereby change the behavior of your scene objects by using different implementations of a method from different ScriptableObjects!
For the factory you then only need to figure out for which method to use which ScriptableObject instance e.g. either by having different methods or by having a Dictionary where you fill in your SO references.
Just as an example how this might look like (make sure each MonoBehaviour and ScriptableObject has its individual script file with matching name)
SpawnManager.cs
public class SpawnManager : MonoBehaviour
{
[SerializeField] private ReactorComponentBehaviour _behaviourPrefab;
[SerializeField] private BaseReactorComponent[] _components;
public bool TrySpawn<T>(out T component, out ReactorComponentBehaviour componentBehaviour) where T : IReactorComponent
{
component = default(T);
componentBehaviour = default;
var foundComponent = components.FirstOrDefault(c => c.GetType() == typeof(T));
if(foundComponent == null)
{
Debug.LogError($"No component found of type {T.GetType().Name}!");
return false;
}
// Here Instantiate doesn't spawn anything into the scene but
// rather creates a copy of the ScriptableObject asset
// This is just to avoid that any changes in the fields during the game
// would change the original ScriptableObject asset and thereby ALL related behavior instances
component = Instantiate ( (T) foundComponent);
// This now indeed spawns the related MonoBehaviour + GameOver
componentBehaviour = Instantiate (behaviourPrefab);
componentBehaviour.Init(component);
return true;
}
}
BaseReactorComponent.cs
public abstract class BaseReactorComponent : ScriptableObject, IReactorComponent
{
public abstract void WhateverIReactorComponentNeeds();
// Common fields and methods e.g.
public Sprite Icon;
}
HeatVent.cs
[CreateAssetMenu]
public class HeatVent : BaseReactorComponent
{
public int CoolAmount;
public int HeatCapacity;
public override void WhateverIReactorComponentNeeds ()
{
// Do something
}
}
UraniumCell.cs
[CreateAssetMenu]
public class UraniumCell : BaseReactorComponent
{
public int FuelAmount;
public int HeatProduce;
public int PowerProduce;
public override void WhateverIReactorComponentNeeds ()
{
// Do something
}
}
And finally you need only one base prefab with the
ReactorComponentBehavior.cs
public class ReactorComponentBehavior : MonoBehaviour
{
[SerializeField] private Image _image;
private IReactorComponent _component;
public void Init(IReactorComponent component)
{
_componemt = component;
// Do other stuff like e.g. adjust visuals according to the component etc
_image.sprite = component.Icon;
}
// And then use whatever this behavior should do with the assigned component
}
So in the end you would use that like e.g.
if(spawManagerReference.TrySpawn<HeatVent>(out var component, out var componentBehaviour)
{
// Do something with the behavior e.g. set its position, parent etc
}
else
{
Debug.LogError($"Failed to get a {nameof(HeatVent)}!");
}
If then at some point you still want different additional behaviours you could let them inherit from the common ReactorComponentBehavior and rather reference the prefabs inside the BaseReactorComponent itself .. then every component can bring its own prefab but still have a common core behaviour
I've been reading many articles online about how to set up a unit test, and most of all it seems pretty straight forward: you create a Test directory using Test Running in Unity. According to this post here, if you run into a namespace issue, then you create an assembly definition file in your scripts directly, reference it in your test.asmdef file, and boom you can start running tests successfully.
My problem is I've inherited a project with 34 of these Scripts directories, and the moment I add an assembly definition file to one, it creates a namespace issue with all other namespaces/objects. Logical conclusion is I create an .asmdef in each of these files and create references where they are needed. Unfortunately this program was designed in such a way that this creates a cyclical dependency among the assembly definition files. This circular dependency is not an issue in the general usage of the program. Without restructuring the code base, is there a way to make this code testable?
Simple solution would be to add the asmdef to the top folder of your 34 script folders.
If they are all across Assets folder then you can create that Script folder and move them all in there. That should not break your project as Unity will update all connections.
The long term solution you may have to go for is creating abstract/interface in assembly that current code would implement.
Say you have script Player in player.asmdef and you want to test it. But it has a dependency to Inventory which is not in any asmdef. You could move Inventory but it also has its set of dependencies and so on.
Instead of moving Inventory, you create a base inventory as abstract and interface in the manager.asmdef and add this one to player.asmdef. Assuming Player.cs uses
List<Item> Inventory.GetInventory();
void Inventory.SetItem(Item item);
Your IInventory.cs could look like so
public abstract class InventoryBase : MonoBehaviour, IInventory
{
// if those methods were self contained, meaning they don't use any outside code
// the implementation could be moved here
public abstract List<Item> GetInventory();
public abstract void SetItem(Item item);
}
public interface IInventory
{
List<Item> GetInventory();
void SetItem(Item item);
}
public class Item
{
public string id;
public int amount;
public string type;
}
Then the Inventory class
public class Inventory : InventoryBase
{
// Implementation is already there since it was used
// but requires the override on the methods
}
It may feel like adding extra useless layers but this adds a second advantage of major importance, you can mock the IInventory object in your player test:
[Test]
public void TestPlayer()
{
// Using Moq framework but NSubstitute does same with different syntax
Mock<IInventory> mockInventory = new Mock<IInventory>();
Mock<IPlayer> mockPlayer= new Mock<IPlayer>();
PlayerLogic player = new PlayerLogic(mockPlayer.Object, mockInventory.Object);
mock.Setup(m=> m.GetInventory).Returns(new List<Item>());
}
This assumes the Player class is decoupled between the MonoBehaviour and the logic:
public class Player : MonoBehaviour ,IPlayer
{
[SerializedField] private InventoryBase m_inventory;
PlayerLogic m_logic;
void Awake()
{
m_logic = new PlayerLogic(this, m_inventory);
}
}
public interface IPlayer{}
public class PlayerLogic
{
IPlayer m_player;
IInventory m_inventory
public PlayerLogic(IPlayer player, IInventory inventory)
{
m_player = player;
m_inventory = inventory;
}
// Do what you need with dependencies
// Test will use the mock objects as if they were real
}
Notice that Player uses InventoryBase since it cannot see Inventory not being in an assembly. But as you drop in the Inventory object, the compiler will use the code down there even if Player type is not aware of Inventory type.
If you were to use another method from Inventory into Player, then you'd need to add the abstract to the base class and the declaration in the interface for testing.
PlayerLogic uses the interface instead of the base type to make the testing possible.
I'm a noob, and a rusty one at that, so bear with me here. I want to make a digital implementation of an old, obscure card game. I have a Card type with properties such as name, rarity, classification, etc. Then there's more specific stuff that not all cards have, such as attack power, resource cost, etc. A fate card doesn't have a power stat, a planet card doesn't have an influence stat, and so forth.
I want to subclass Card out into these various kinds of cards with the appropriate properties that only they have, but I don't want to give up having a single "new Card(string name)" constructor. My idea was to have the Card constructor call a subclass's constructor with arguments for the general properties, but I read that you can't return anything from a constructor other than the type being constructed. Any way to do this cleanly?
If I understand well, what you want to have in the end would be something like this:
Card planetCard = new Card("Planet");
Card fateCard = new Card("Fate");
Your plan of using inheritance won't work this way, as a base class cannot call a constructor of the inherited class from its own costructor. It can only happen the other way around. The two simpler options to solve this would be:
1- Instantiate the propper class as you need it.
Given two classes like this:
public class PlanetCard : Card
{
///--- Attributes of planet here
public PlanetCard() : base("Planet"){}
}
public class FateCard : Card
{
///--- Attributes of fate here
public FateCard() : base("Fate"){}
}
You can now create the cards as follows (which is kind of similar to what you wanted to achieve in the first place):
Card planetCard = new PlanetCard();
Card fateCard = new FateCard();
2- Using Components instead of inheritance.
The use of components instead of inheritance is very common nowadays when it comes to games. The idea is having only one Card class, but each card, depending on what it really is, would have different components to use:
interface IComponent{}
public class PlanetComponent : IComponent
{
///--- Attributes of Planet
}
public class FateComponent : IComponent
{
///--- Attributes of Fate
}
public class Card
{
List<IComponent> components;
public Card(string cardName)
{
///--- Fill components according to the name
}
public T GetComponent<T>()
{
///--- return the component of the type T in the list, or null
}
}
And now you can create cards like in the first place (although the use later will be a bit different):
Card planetCard = new Card("Planet");
Card fateCard = new Card("Fate");
///--- Using the planet card
PlanetComponent planetComp=planetCard.GetComponent<PlanetComponent>();
if (planetComp!=null)
{
///--- you can use here the planet attributes
}
This solution is much more flexible, as it allows you to combine the components at will (you clud have a "FatePlanet" card with both components if you wanted). You will need though, some way of matching the name of the card with the components you want it to have.
Hope it helps!
I'm writing a HandConverter of a poker hand. This is my first project and I'm trying to do it right from the beginning.
I got already the most parts, like lists of players, their position, stack sizes, cards for different boards, what game is being played and so on, but I struggle with the representation of the betting, especially the different raises, bets and multiple calls from the same player.
I found some cases where my naive case based solution does not work, and it's really complicated and I dislike it. As it currently works for NL Hold'em I think I'll have more workarounds to do if I want to implement games like Stud, Razz and so on altough the betting structure is likely the same.
For now I use this representation and I would like to improve especially the Round and Action classes. Do you have some suggestions for me?
public class HandHistory
{
public GameInfo GameInfo;
public TableInfo TableInfo;
public List<Player> Players;
public List<Round> Rounds;
public string rawtext;
public bool withHero;
}
public Round
{
public List<Action> Action;
public string Name;
public decimal Potsize;
public ulong Cards; //usually would have used a custom class,
//but I need them in a ulong mask for some library I use
}
public class Action
{
public Player Player;
public string Type;
public decimal Amount;
}
P.S. I'm also using a List to store the different rounds, is there better way like inheriting the round class for Flop, Turn and River e.g?
Instead of a string for your Action.Type, you could use an enum:
enum BettingAction
{
Check,
Bet,
Call,
Raise,
Fold
}
When you say first project what do you mean? I am guessing you are a student or new to programming.
Under that assumption I would suggest picking something simpler and than a poker hand history. As in game programming it is unreasonable to think on your first shot of programming a game you create the latest Call of Duty. You start with breakout and move up from there.
If you do not wish to start smaller than I suggest never jump into coding. When you do that you will spend more time just spinning your wheels rather than getting something done.
For instance you should first spend time designing what your program will do and what it will not do. Try to be as complete as possible. This can be done from something as complicated using a UML program or as simple as pen and paper.
I would flow out how you want a hand to progress. Information you want to track. Once you really understand this your data structures will start to come to life.
Since you are new to programming, I would start to write proof of concept code. Then move it to your final project. What I mean by proof of concept is code that you are just testing an idea to see how it works. For example, how would hand history work? Can you create some 'mock' history and set them up? Ideally you would unit test, but lets start a little smaller.
It is important to know that you are constructing a program, just like a house. You need to know what you want it to do and not do (blue prints). What each step is. And you build upon other pieces slowly. It is a process that takes time, but in the end is well worth it.
Cards could have a better name, but I am assuming you mean the community cards. I would make it a list of Cards, then the turn and river subclasses would just only ever have one card in the list. I would also suggest representing the cards in a way that makes sense to you and then doing a conversion when you need to interface with the library.
Not really a programming related answer; but the betting styles for Razz or Stud is different from Hold 'em in several ways.
1.) There are no blinds; rather antes
2.) The person opening can either bring-in or complete the bet
3.) There are more rounds of betting
You have a pretty good start. You'd probably want to create a List<Hands> which has List<Rounds> inside it. Otherwise you'll have a huge list of rounds without being able to tell when one hand started/ended and another one began.
I think you probably need to define out your action types, and then things will probably start to fall into place. Here's what I would have for types:
Check
Bet
Fold
Call
Raise (essentially a call and bet)
Might also want to think about implementing something like "Prior Action" on your action class; as each player is reacting to the action before them.
You'd also want to address some nuances of the game; where player a bets 500 and player b goes all in for 250; since except in this instance, the call needs to match the prior bet.
The term Round is a little ambiguous. BettingRound makes it more obvious.
I don't see the need to have cards, name and potsize here. Potsize is a function of the actions and changes throughout the betting round.
Seats represent the game a little better than a list of players does as this allows you to represent the game state (stack sizes etc.) a little more obviously.
I don't see the need to make the flop, river cards explicitly assigned to rounds - just use a list of cards and some conventions. e.g. first three cards = flop... first betting round = flop. Use some extension methods for convenience of referring to the flop for holdem.
Use the ulong version of cards via conversion when you need to use it rather than cluttering your domain model.
This is how I see the model of a particular individual Game (i.e. 1 flop, river, turn etc.). There's still a bunch of work to do to model all games (e.g. limit games use small bet / big bet instead of blinds to define the stakes).
public class Card
{
public Suit Suit;
public Rank Rank;
public ulong ToCardMask();
}
public enum Suit
{
Clubs,
Diamonds,
Hearts,
Spades
}
public enum Rank
{
Ace,
Deuce,
Trey,
//...
Jack,
Queen,
King
}
public class Game
{
public GameInfo GameInfo;
public TableInfo TableInfo;
public List<BettingRound> BettingRounds;
public List<Card> CommunityCards;
public string Rawtext;
public bool WithHero; //??
}
public static class GameExtensions
{
public static BettingRound Flop(this Game game)
{
return game.BettingRounds[0];
}
public static List<Card> FlopCards(this Game game)
{
return game.CommunityCards.Take(3).ToList();
}
}
public class GameInfo
{
public GameType GameType;
public GameBettingStructure BettingStructure; // Limit, PotLimit, NoLimit
public Stakes Stakes; // e.g. { $1, $2 }
public long Id;
public List<Seat> Seats;
}
enum GameType // prob change to a class for extensibility
{
HoldEm,
Razz,
StudHi,
StudHiLo,
OmahaHi,
OmahaHiLo
}
enum GameBettingStructure
{
Limit,
PotLimit,
NoLimit
}
class Stakes // probably needs some tweeking for stud games (e.g. bring-in ...)
{
public Money Ante;
public List<Money> Blinds;
}
public class Seat
{
public Player Player;
public Money InitialStackAmount;
public Money FinalStackAmount; // convienience field can be calculated
public List<Card> Hand;
}
class Money
{
public decimal Amount;
public Unit Unit;
}
enum Unit
{
USD,
EUR,
AUD,
TournamentDollars
}
public class Player
{
public string Name;
}
public class TableInfo
{
public string Name;
}
public class BettingRound
{
public List<BettingAction> BettingActions;
}
public class BettingAction
{
public abstract Money PotSizeAfter();
public byte SeatNumber;
}
public class Fold : BettingAction { }
public class Call : BettingAction { }
public class BringIn : BettingAction { }
public class Complete : BettingAction { }
public class Bet : BettingAction
{
public Money Amount;
}
public class Raise : Bet { }
instead of SubClassing Round into FlopRound TurnRound etc, I would use a Street attribute within round, and within Action as well.
static public enum Street {PREFLOP, FLOP, TURN, RIVER};
...