C# Variable Scope Question, and Text-based RPG Attempt - c#

I am trying to write a text-based RPG in C#. I am having issues understanding how I could make the character data accessible to many other objects in an effective manner.
I am fairly new to programming, and I certainly lack information. I've been reading guides and questions online and it got me so far, but I feel like I am either thinking about this the wrong way or missing something completely.
I am trying to write everything as flexible as possible since I am planning on adding a lot to this project if I can get past this stage. But it seems difficult for me to allow all of these objects to actively communicate with each other. Would using Unity help with this? I am mostly doing this to learn the language so I can later use it w/ Unity, but I wanted to learn the language directly so I opted out of starting with Unity. If there are any suggested resources to learn about the language I could really use recommendations.
I am sorry if the question is too open ended, but I can't really find anything regarding the mindset behind how I should be building a system like this. The last thing I've learned is ref but I feel like that isn't the best answer.
namespace GameMain
{
public class Game
{
static void Main()
{
MainMenu Game = new MainMenu();
Game.Menu();
return;
}
}
public class MainMenu
{
Character CurrentPlayer = new Character();
public void Menu()
{
Music MusicPlayer = new Music();
LocationEngine Location = new LocationEngine();
Tester Testman = new Tester();
MusicPlayer.Track("0");
while (true)
{
Menu:
Console.WriteLine("Welcome to the main menu. Enter 'create' to create a character and begin the game. Enter 'play' to log in.\r\nSaving features are to be implemented.\r\n");
while (true)
{
string MenuSelection = Console.ReadLine();
if (MenuSelection == "create")
{
CurrentPlayer.Creation();
goto Menu;
}
else if (MenuSelection == "play")
{
if (CurrentPlayer.CharacterPass != "")
{
Console.Write("\r\nEnter your password: ");
string Password = Console.ReadLine();
bool Check = CurrentPlayer.Login(Password);
if (Check == true)
{
Console.WriteLine("\r\nAdd transition to location here.");
break;
}
else
{
break;
}
}
else
{
Console.WriteLine("Please create a character first.\r\n");
break;
}
}
}
while (true)
{
Console.WriteLine("\r\nPress any key to continue.\r\n");
Console.ReadKey();
string TownSelection = "";
Console.WriteLine("\r\nYou are in Town.\r\n\r\nYou can 'explore' for encounters\r\nYou can use 'stats' to check your character\r\nOr you can 'sleep' to return to the main menu\r\n");
TownSelection = Console.ReadLine();
if (TownSelection == "sleep")
{
Console.WriteLine("");
break;
}
else if (TownSelection == "stats")
{
CurrentPlayer.CharacterStats();
}
}
}
}
}
}
I don't know how I can make the CurrentPlayer object accessible to the other objects such as Location. Is it better to pass every relevant bit as reference all the way down the rabbit hole?
I have posted the entire thing on github here if you are feeling extra patient: https://github.com/Slocknog/rpgproject
...and thank you for the help. Please do comment on anything else that you think I should be doing differently or reading up on.

I would take a step back and make sure you understand the purpose of each class you write. (This may sound patronizing, but it's really not trying to be. This is a difficult part of design.)
The purpose of each class should be clear and constrained: it should be reasonably obvious whether any piece of functionality belongs in a particular class or not, and no class should take on too much responsibility. I'd encourage you to write documentation comments on each class to explain its purpose - this will make it easier for you to come back and ask yourself whether some aspect of state and functionality really makes sense for that class.
Next, think about three ways data can be available to the class:
Through static variables. This is effectively global state, and is best restricted to natural constants. Global state should usually be immutable (unless it's something like a cache) as otherwise it can make testing and reasoning about your code fairly difficult.
Through instance variables. This is the state for an instance of the class (an object). It should be state that feels like it naturally belongs to an instance for its whole lifetime.
Through method parameters. This is information that is useful just for the duration of a single method call. For example, I don't think a LocationEngine should really know about the Character as part of global or instance state, but it might make sense to pass a Character reference into a method. (It might make more sense to pass a Location reference into the method, which might be obtained from a Character - it's hard to say without effectively trying to do a large portion of design for you.)
It's definitely worth putting significant thought into these decisions early on - although you should still expect to make mistakes. If you find yourself having to write code that feels ugly quite a lot of the time, in terms of how it accesses information, think about whether that information currently "lives" in the right place.
(Oh, and you're wise to separate "learning C#" from "learning Unity" in my view. Quite a lot of Unity uses idioms/techniques/conventions that would raise eyebrows in other C# codebases. Learning about them only when you move into Unity means you're less likely to carry them over to writing C# code elsewhere. Additionally, debugging "regular" C# code, particularly console applications, is somewhat simpler than having to worry about the Unity editor etc.)

you could have all those "other objects" Constructors accept a Character object to which you'll provide CurrentPlayer
supposing you have the following Character class
class Character
{
public string Name { get; set; }
}
then your LocationEngine class would be:
class LocationEngine
{
Character _player;
public LocationEngine(Character player)
{
_player = player;
}
public void SomeMethod()
{
string playerName = _player.Name;
}
}
and in your MainMenu class you'd code:
public class MainMenu
{
Character CurrentPlayer = new Character();
LocationEngine location = new LocationEngine(CurrentPlayer);
...
}

Related

Encapsulation and data security

I am trying to understand Object oriented programming. With respect to Encapsulation, I understood it like this.
"Encapsulation, refers to an object's ability to hide data and behavior that are not necessary to other classes& assemblies.
With the help of encapsulation, a class can change the internal implementation without hurting the overall functionality of the system.
Prevents code (data) from accidental corruption due to programming errors
Encapsulation enables a group of properties, methods and other members to be considered a single unit or object."
So, when it comes to data hiding/security with encapsulation, I understand it like securing the data from other programmers in the team as there are chances that the data can be corrupted due to programming errors
My question here is, "Is my understanding about data security/data hiding with respect to encapsulation is correct? Or, whether it is not limited to securing data from programmers alone and it enables securing data from hackers as well ?"
The encapsulation has nothing to do with outside hackers, it's not a data security concept, it's more about programming model. Here is an example:
class Engine
{
public bool Running { get; private set; }
public void Start()
{
this.Running = true;
}
public void Stop()
{
this.Running = false;
}
}
It's a simple model, Engine can Start/Stop by its instance methods, which essentially changes the Running property. If you want to start/stop an Engine, just invoke the corresponding method. We can say the behaviors of Engine is well encapsulated.
Let's change the code
class Engine
{
public bool Running { get; set; } //set is changed to public
}
Now the code is shorter and simpler, if we want to start an engine just set Running to true (or false when you want to stop). As the project grows, you will have several methods that will change Running property to start an engine.
Here comes a new case1: sometimes the engine is out-of-control then it can't be started/stopped. If you are using the old version, it's easy to change the code to:
class Engine
{
public bool Running { get; private set; }
public bool OutOfControl { get; private set; }
public void Start()
{
if (this.OutOfControl) return;
this.Running = true;
}
public void Stop()
{
if (this.OutOfControl) return;
this.Running = false;
}
public void SomeOperation()
{
//inside the method sometimes OutOfControl is set to true
}
}
The callers of Engine.Start and Engine.Stop will not be affected. What about the "simpler" version? You need to change 10+(or 100+) callers, checking OutOfControl property before changing Running property.
And then here comes a new case2, case3...the "simpler" version is becoming harder and harder to maintain. Because it exposes the implementation details to callers. Every time the start/stop implementation changes, the first version (well-encapsulated version) only needs to change the start/stop method, because it's the only place that performs the behavior.
Encapsulation is more of logic perspective on writing code rather than people perspective. Encapsulation is the act of hiding the details which are not relevant.
For example, you use a Computer. But you don't see what CPU looks like. Its sort of encapsulated or hidden behind all plastic stuff.
In Object oriented programming, one usually have this kind of code:
CLASS {
METHOD {
// some code
}
}
An example of "encapsulation" would be having a METHOD that the regular user can't see (example: private).
Encapsulation:- Information hiding.
Real life examples of encapsulation:
Capsule
Wallet
Box

Checking a private value in another class [C#]

I'm making a simple dart game in the console for an assignment where I am to practice using private lists and variables everywhere. The basic flow of the program for some context is as follows:
User lands in a menu
User chooses from 1-4. (1 = Add player, 2 = Add CPU, 3 = Start game, 4 = Quit)
Game starts. Players manually add their 3 throws per turn, and CPU gets theirs randomly.
When a player or CPU reaches 301 score, the loop ends and you now see every throw made by the winner.
UML diagram for class structure context: https://i.imgur.com/bL5pZV5.png
Everything is pretty much complete. I've made the program to such an extent that both players and CPUs are getting random values (are treated as CPU players), it prints out everything correctly and follows the flow to the end.
My issue now is that I want to be able to reach the is_CPU variable which is private in the Player class from the Game class and use it in an IF check, directing whether or not the values are manually added or randomly generated.
Pseudo-code:
FOREACH (var player in player_list)
IF (is_CPU == TRUE)
THEN Assign random values
ELSE
THEN Manually enter values
I tried messing around with the get-set stuff, but I don't fully understand how to use them and how they work. I have looked around on here and still don't see how I should be using them in this case, if at all.
I can think of one way to work around this and that is by making a method just for this where it checks that value and returns true/false, but that seems like a 'lazy' or improper way to do this, and comes with several downsides. I feel like there should be a better way to do this, one that won't come back to bite me in the ass later. Hopefully there is, and I can learn it by asking here.
EDIT: The variables and lists HAVE to be private. It is part of the exercise where we learn how to handle these.
I think you just want a get property on your player class.
public bool IsCpu { get { return is_CPU; }}
See also c# properties
In order to access private members of a class instance, you either have to define properties on that class with a public getter, as follows:
public class Player
{
private Boolean m_IsCPU;
public Boolean IsCPU
{
get { return m_IsCPU; }
}
// ...
}
or to change these members in order to make them public, as follows:
public class Player
{
public Boolean IsCPU;
// ...
}
Whatever you choose (I suggest you to go for the first approach), in any part of your code in which you have to check the IsCPU property/member for each instance of the Player class, you can just do as follows:
foreach (Player player in players)
{
if (player.IsCPU)
// Do Something...
else
// Do Something Else...
}
Some interesting links:
Access Modifiers
C# Properties
Why prefer Properties to public variables?
Redesign your app like this:
Class Game
List<IPlayer> Players
ShowMenu()
AddPlayer()
StartGame()
IsGameOver(): boolean
Interface IPlayer
Turn() : Score
CpuPlayer: IPlayer
Player: IPlayer
Split your logic into two different classes: you dont need to check. Treat every player the same in the game. Later if you come up with 'NetworkPlayer', 'AIPlayer', 'SuperPlayer' you can easily add to your system.
In your menu:
switch (userInput) {
case AddUser:
AddPlayer(new Player());
break;
case AddCpuPlayer:
AddPlayer(new CpuPlayer());
break;
In your gameplay:
while (!IsGameOver)
{
var nextPlayer = ... next player
nextPlayer.Turn() ...
}

Passing a class that use a method as a member

I've been learning C# for the past 6 months or so and am currently stuck on a turn-based battle system for a game.
I have tried a couple of different things and watched loads of videos about it but I didn't find what I was looking for. Maybe it's impossible but here it is. Also, I'm not looking for someone to write the code or anything, I am mainly looking for pointers.
switch (currentBattleState)
{
case (BattleState.WAIT):
{
if (heroesToManage.Count > 0)
currentBattleState = BattleState.ACTION_SELECT;
break;
}
case (BattleState.ACTION_SELECT):
{
foreach(Button button in buttons)
button.interactable = true;
break;
}
}
This is the current status of the battle state machine. I have two buttons at the moment, one that will attack and one that will open a spellbook to choose which spell to cast.
What I would need is something like this pseudocode:
void OnClicked()
{
ChooseSpell(); // If it's the "magic" button
ChooseTarget();
// And this Action will pass the target to the Attack() or Cast()
// function on the HeroStateMachine
listOfActions.Add(new Action(origin, target, Attack() or Cast())
}
and then when each Action is processed by the BattleStateMachine, like so, again in pseudocode because I have no idea how to do it:
void ProcessAction(Function action, int index = 0)
{
// This would result in Cast(origin, target) or Attack(origin, target)
action(listOfAction[index].origin, listOfAction[index].target);
}
// And then call it like this ?
ProcessAction(listOfActions[0].function)
we remove it from the list so, basically, this would be a first-in first-out type of thing.
The issue is that I haven't found a way to do that. So far, the videos I've watched are creating a derived class for every single type of attack, spell or item (all derived from a BaseAction)... Which I don't want to do since this seems like really wet code... Also, I wouldn't want to create a whole new class every time I want to add something to the game...
As I said, I'm not looking for full code but so far you've all been helpful so maybe just a pointer to what I could use to do what I want? Or just tell me if I'm approaching this whole thing from the wrong angle.

How to avoid casting from interface to class

In trying to design a collision detection component for a game, I came up with the following solution. I define an interface ICollideable that looks something like:
interface ICollideable
{
Sprite Sprite { get; }
int Damage { get; }
void HandleCollision(ICollideable collidedWith);
}
Basically, any game objects that want to participate in collision detection have to implement this interface, then register themselves with the detector, which maintains a list of ICollideables. When it detects a collision, it calls the HandleCollision method on the object and passes in a reference to the object it collided with.
I like this, because it lets me keep all my collision algorithms in one place, and lets the game objects themselves decide how to handle the collision. But because of the latter, I find I am having to check the underlying object type. For example, I don't want Players to collide with each other, so in the Player class there might be something like:
void HandleCollision(ICollideable collidedWith)
{
if (!(collidedWith is Player)) { // do stuff }
}
and so on, and I am wondering if this is telling me that I have a bad design and what the alternatives might be.
Second question, further along the lines of the first. For scoring purposes, if an Enemy is destroyed by a Projectile, someone needs to know the "Owning Player" member of the Projectile class. However, none of my other collideables have or need this property, so I find myself wanting to do (in the Enemy HandleCollision):
void HandleCollision(ICollideable collidedWith)
{
if (collidedWith is Projectile) {
Health -= collidedWith.Damage;
if (Health <= 0) {
Player whoDestroyedMe = (collidedWith as Projectile).FiredBy
// ...
}
}
}
I haven't a clue as to how to handle this with a better design. Any insights would be appreciated.
EDIT: I wanted to pull focus towards the second question, because my gut tells me a way of handling this will solve the first question. As for the first question, I thought of a way to abstract this behavior. I could define an enum:
enum Team
{
Player,
Enemy,
Neither
}
and have ICollideables implement this property. Then the collision detector simply doesn't register collisions between collideables on the same "Team". So, Player and Player Projectiles would be on one team, Enemy and Enemy Projectiles on the other, and the environment (which can damage both) can be on neither. It doesn't have to be an enum, could be an int or a string or anything, with the idea that objects with the same value for this property do not collide with each other.
I like this idea of modeling behavior with a simple attribute. For instance, if I want to turn "allow friendly fire" on, all I have to do is create Projectiles with a Team value other than the Player's Team value. However, I still may have cases where this is not enough. For example, a Player may have shields that are temporarily impervious to projectiles but will not protect against a direct collision with an enemy, and so on.
I think you're going the wrong way altogether in handling the collision inside of the class of one of the colliders. I would put this logic into a third object, outside of the entity objects. You could do all of the checking of the types in this third object, and even handle most of the logic there too. Why should a Ship or a Projectile have a monopoly over the logic that happens when one hits the other?
The following is how I might handle this, although it means using an object for each style of collision (Ship vs Ship, Ship vs Projectile, Ship vs Asteroid, etc.) You might be more comfortable putting all that logic into a single object, or even a single method on that object.
public interface ICollisionHandler
{
bool HandleCollision(Entity first, Entity second);
}
public class PlayerShipVsProjectile : ICollisionHandler
{
private GameOptions options;
public PlayersOwnShipHandler(GameOptions options)
{
this.options = options;
}
public bool HandleCollision(Entity first, Entity second)
{
// Exactly how you go about doing this line, whether using the object types
// or using a Type property, or some other method, is not really that important.
// You have so much more important things to worry about than these little
// code design details.
if ((!first is Ship) || (!second is Projectile)) return false;
Ship ship = (Ship)first;
Projectile projectile = (Projectile)second;
// Because we've decided to put this logic in it's own class, we can easily
// use a constructor parameter to get access to the game options. Here, we
// can have access to whether friendly fire is turned on or not.
if (ship.Owner.IsFriendlyWith(projectile.Shooter) &&
!this.options.FriendlyFire) {
return false;
}
if (!ship.InvulnerableTypes.Contains(InvulnerableTypes.PROJECTILE))
{
ship.DoDamage(projectile.Damage);
}
return true;
}
}
Like this, you can then do...
// Somewhere in the setup...
CollisionMapper mapper = new CollisionMapper();
mapper.AddHandler(new ShipVsProjectile(gameOptions));
mapper.AddHandler(new ShipVsShip(gameOptions));
// Somewhere in your collision handling...
mapper.Resolve(entityOne, entityTwo);
The implementation of CollisionMapper is left as an exercise for the reader. Remember that you might need to have Resolve call the ICollisionHandler's "Handle" method twice, with the second time reversing the entities (otherwise your collision handler objects will need to check for the reverse situation, which might be ok as well).
I feel this makes the code easier to read. A single object describes exactly what will happen when two entities collide, rather than trying to put all this info into one of the entity objects.
For the first case, I would add the following extra method to ICollidable:
bool CanCollideWith(ICollidable collidedWith)
As the name suggests, it would return true or false depending upon whether it can collide with the passed in object.
Your Player.HandleCollision method would just do its stuff because the calling method could do that test and not even call the method if it wasn't required.
How about something like this?
Collidable.cs
abstract class Collidable
{
public Sprite Sprite { get; protected set; }
public int Damage { get; protected set; }
protected delegate void CollisionAction(Collidable with);
protected Dictionary<Type, CollisionAction> collisionTypes = new Dictionary<Type, CollisionAction>();
public void HandleCollision(Collidable with)
{
Type collisionTargetType = with.GetType();
CollisionAction action;
bool keyFound = collisionTypes.TryGetValue(collisionTargetType, out action);
if (keyFound)
{
action(with);
}
}
}
Bullet.cs
class Bullet: Collidable
{
public Bullet()
{
collisionTypes.Add(typeof(Player), HandleBulletPlayerCollision);
collisionTypes.Add(typeof(Bullet), HandleBulletBulletCollision);
}
private void HandleBulletPlayerCollision(Collidable with)
{
Console.WriteLine("Bullet collided with {0}", with.ToString());
}
private void HandleBulletBulletCollision(Collidable with)
{
Console.WriteLine("Bullet collided with {0}.", with.ToString());
}
}
Player.cs
class Player : Collidable
{
public Player()
{
collisionTypes.Add(typeof(Bullet), HandlePlayerBulletCollision);
collisionTypes.Add(typeof(Player), HandlePlayerPlayerCollision);
}
private void HandlePlayerBulletCollision(Collidable with)
{
Console.WriteLine("Player collided with {0}.", with.ToString());
}
private void HandlePlayerPlayerCollision(Collidable with)
{
Console.WriteLine("Player collided with {0}.", with.ToString());
}
}
I think this is a good question #idlewire and I have to say that I don't think there is anything fundamentally wrong with your original solution. In asking whether object Foo should be allowed to cast the ICollideable to a Bar, the important question is only: is undesirable to have Foo knowing anything at all about Bar? If the answer is 'no' because Foo already knows about Bars (for behaviours other than collisions, perhaps) then I see no problem in the cast and, as you say, it allows you to better encapsulate the behaviour of both.
Where you need to be wary is only where this would introduces a dependency between two things you'd like kept apart - which would make re-use of either without the other (in a different game application for example) impossible. There you might want to either have more specific sub-interfaces from ICollideable (e.g. IElastic and IInelastic), or use properties on the interface as you have proposed with the Enum.
In short, I think your original posting shows good evidence of OO thinking, not bad.
Sometimes the simplest method is the best method. Unless you want to separate your collision interactions into numerous subtypes, you could instead place a bool IsPlayer property within the Interface.
The upside here is that you have a cheaper, and type safe method of determination over casting.
If (isplayer == true)
{
Handlethisway;
}
The downside is that you're still having to do some sort of state checking, but this is more efficient.
To avoid any state checks, you'd need to do the following: Make an ICollidablePlayer Interface which accepts generic Icollideable and handles them differently. Since the Icollideable is your injected dependency, the ICollideablePlayer dependencies are inherent. The objects of Icollideable would have no knowledge of this separate process, and interact with each other in the same manner.
ICollideablePlayer:ICollideable
{
//DependenciesHere
HandlePlayerCollision(ICollideable)
{
HandleDifferently
{
}
ICollideable
{
//DependenciesHere
HandleCollision(ICollideable)
}
}
}
In an interaction, the ICollideable will treat the player as any other ICollideable, but the ICollideablePlayer will reject the interaction when it does the check itself.
For things like shields and all that, You're talking about state changes which implies that those such things should be properties within either of those Interfaces such that something like bool ColliderOff to temporarily change the state.

OOD and subject-object confusion

Suppose I have a definition for a door:
class Door
{
public void Lock()
{
// lock the door
}
}
This appeared to make sense to me, at least for awhile. But now, I'm not so sure. If I had a Person object that wanted to lock a Door, he would call aDoor.Lock(). But in real life, we do not lock doors by telling the door to lock itself.
It seems like a more accurate model of the situation would be the person being able to directly modify the state of aDoor, provided he has sufficient power to lock doors. For example, aCat should not be able to set aDoor.IsLocked = true. I could see how to do this with properties, if they supported parameters:
class Person
{
public void LockDoor(Door door)
{
door.IsLocked(this) = true;
}
}
class Door
{
bool isLocked;
public bool IsLocked(Person person)
{
set
{
if(person != null) // ensure there is a real person trying to lock the door
{
this.isLocked = value;
}
}
}
}
static void Main()
{
Person personFromThinAir = new Person();
Door doorFromThinAir = new Door();
personFromThinAir.LockDoor(doorFromThinAir);
}
Instead, what we can do is this:
class Person
{
public void LockDoor(Door door)
{
door.SetLocked(this, true);
}
}
class Door
{
bool isLocked;
public void SetLocked(Person person, bool locked)
{
if(person != null)
{
this.isLocked = locked;
}
}
}
Obviously these two classes are strongly coupled and both would probably have interfaces extracted in actual code, but that's not what I'm getting at. My question is, is this a better way to model the relationship between the two objects? Is there an even better way than this? The more I think about it, the less sense of aDoor.Lock() I can make; it seems to violate object-oriented design.
Although the person "locks" the door, in reality the person is toggling (or frobbing) on an element of the door (the lock handle) and that manipulation causes the lock to lock the door. You can think of this where, although the person is moving the deadbolt, the deadbolt is what is locking the door - not the person. So a better representation might be that a door has a lock, and the person calls lock.lock(), which then sets the lock being closed (locked).
The basic premise here is that, although the person is manipulating the lock, that is external (the function call). The lock's internal changes (the code inside the function) is what is actually causing the door to lock. The person is not taking off the handle and manipulating the inside to lock the door every time - they are simply toggling a state on the outside and expecting the machinery internal to handle it.
OOP isn't really about modelling how things work in the "real world". Its more about managing complexity. Considering this, it is perfectly acceptable for the door to lock itself. Even in the real world, a person locking a door doesn't need to know anything about how the lock works other than turning the knob or the key.
Hiding the details of a complex idea behind an abstraction is what makes OOP so useful. The abstractions you use differ with the problem domain. In the example you gave the Person shouldn't need to know anything about the door other than how to operate it:
class Door
{
public bool Open(){}
public bool Close(){}
public void Lock(){}
public void Unlock(){}
}
The most interesting design issue here to me is how to handle the coupling between the locker and the lockee since there are requirements which must be met for the locking/unlocking to be allowed. I look at this question and imagine a game where a player might sometimes be a human but other times be a cat (per the example given), and maybe is_human is the only requirement for locking/unlocking. But you might also want to have doors which require the matching key to be in the player's possesion in order for locking/unlocking to happen. If so, you have to add that to the criteria. Perhaps some doors can only be locked from one side and not the other, so the player's location must be added to the criteria. You could further add a lockpicking skill which some players might have (cat burglars, no doubt) to allow them to have a chance to unlock (but not lock) a door even if they didn't have the key. Etc. etc.
One can envision a conversation between the objects like:
Player: "I am trying to unlock you."
Lock: "Do you meet requirement A?"
Player: "Yes"
Lock: "Do you meet requirement B?" // Only some doors would ask this.
Player: "Yes"
Lock: "OK, you succeed. I am unlocked!"
But, you probably don't want to expose the involved fields publicly or clutter up the Player interface seen by objects that don't need to know about locking/unlocking requirements.
I am not a C# programmer, and it has been a while since I did Java, but I think an approach in Java which may also apply in C# would be to have the Player object pass an instance of a lock_unlock_credentials inner class as a parameter to the get_locked/get_unlocked methods of the Door object (or Lock object as has been suggested.) The lock_unlock_credentials object would have callback methods which, by virtue of its being an inner class of Player, could access relevant fields of the Player object, but those fields would otherwise not be exposed outside of Player. The Lockable object could then use those callback methods to check to see if the requirements it cares about are met. You can't avoid the coupling resulting from the requirements, but this way keeps the details internal to the interaction between the Player and the Lockable object.
Not sure if the same inner class approach applies to C#, but presenting this as something to think about.

Categories

Resources