I'm currently trying to learn the SOLID design principles along with behavior driven development, but am having quite the hard time getting my head around the Single Responsibility Principle. I've tried to find a good tutorial for c# that uses test driven development, but haven't been able to find anything worthwhile in that vein. Anyway, after spending a few days reading about it, I decided the best way to learn is by experience, so I started creating a small app using those principles best I can.
It's a simple bowling score calculator. I figured the best way to go about it was to work from the simplest part up, so I started at the ball (or throw) level. Right now I have created tests and an interface and class for dealing with ball(throw) scores, which makes sure they aren't invalid, ie. <10 or >0. After implementing this I realized that the ball class is basically just a nullable integer, so maybe I don't even need it... but for now it's there.
Following the ball, I decided the next logical thing to add was a frame interface and class. This is where I have gotten stuck. Here is where I'm at:
namespace BowlingCalc.Frames
{
public interface IFrame : BowlingCalc.Generic.ICheckValid
{
void AddThrow(int? score);
int? GetThrow(int throw_number);
}
}
namespace BowlingCalc.Frames
{
public class Frame : IFrame
{
private List<Balls.IBall> balls;
private Balls.IBall ball;
private int frame_number;
public Frame(Balls.IBall ball, int frame_number)
{
this.ball = ball;
this.frame_number = frame_number;
balls = new List<Balls.IBall>();
check_valid();
}
public void AddThrow(int? score)
{
var current_ball = ball;
current_ball.Score = score;
balls.Add(current_ball);
}
public int? GetThrow(int throw_number)
{
return balls[throw_number].Score;
}
public void check_valid()
{
if (frame_number < 0 || frame_number > 10)
{
throw (new Exception("InvalidFrameNumberException"));
}
}
}
}
The frame uses my previously implemented ball class through dependency injection to add ball scores to the frame. It also implements a way to return the score for any given ball in the frame.
What I want to do, and where I'm stuck, is I want to add a way to make sure the frame score is valid. (For the moment just the simple case of frames 1-9, where the combined score of both balls must be 10 or less. I will move on to the much more complicated frame 10 case later.)
The problem is I have no idea how to implement this in a SOLID way. I was thinking of adding the logic into the class, but that seems to go against the single responsibility principle. Then I thought to add it as a separate interface/class and then call that class on each frame when its score updates. I also thought of creating a separate interface, IValidator or something like that, and implementing that in the Frame class. Unfortunately, I have no idea which, if any, of these is the best/SOLID way of doing things.
So, what would be a good, SOLID way to implement a method that validates the score of a frame?
Note: Any critique of my code is very welcome. I am very excited learn to create better code, and happy to receive any help given.
When I think SRP, I tend to put the emphasis on the Responsibility aspect. The name of the class, in turn, should ideally describe its Responsibility. For some classes this is about what the class is supposed to 'be' (a Frame could be a good example if it lacks behavior and merely represents state), but when you have a behavioral responsibility, the name is about what the class is supposed to 'do'.
Computing scores by itself is a fairly small responsibility, so let's consider something slightly larger and more naturally decomposable. Here is one possible breakdown of a bowling game with simple responsibilities and with suitably paranoid encapsulation (we're all friends here, but nobody wants anybody to cheat by mistake.)
//My job is to keep score; I don't interpret the scores
public interface IScoreKeeper : IScoreReporter
{
void SetScore(int bowlerIndex, int frameIndex, int throwIndex, int score);
}
//My job is to report scores to those who want to know the score, but shouldn't be allowed to change it
public interface IScoreReporter
{
int? GetScore(int bowlerIndex, int frameIndex, int throwIndex);
}
//My job is to play the game when told that it's my turn
public interface IBowler
{
//I'm given access to the ScoreReporter at some point, so I can use that to strategize
//(more realisically, to either gloat or despair as applicable)
//Throw one ball in the lane, however I choose to do so
void Bowl(IBowlingLane lane);
}
//My job is to keep track of the pins and provide score feedback when they are knocked down
//I can be reset to allow bowling to continue
public interface IBowlingLane
{
int? GetLastScore();
void ResetLane();
}
//My job is to coordinate a game of bowling with multiple players
//I tell the Bowlers to Bowl, retrieve scores from the BowlingLane and keep
//the scores with the ScoreKeeper.
public interface IBowlingGameCoordinator
{
//In reality, I would probably have other service dependencies, like a way to send feedback to a monitor
//Basically anything that gets too complicated and can be encapsulated, I offload to some other service to deal with it
//I'm lazy, so all I want to do is tell everybody else what to do.
void PlayGame(IScoreKeeper gameScore, IEnumerable<IBowler> bowlers, IBowlingLane lane);
}
Note that if you wanted to use this model to simply compute scores (without playing a real game), you can have a stub Bowler (who does nothing) and a MockBowlingLane, who produces a series of score values. The BowlingGameCoordinator takes care of the current bowler, frame and throw, so the scores get accumulated.
What is the purpose of ICheckValid interface? Do you call check_valid elsewhere? In my opinion, since the frame_number seems to be in fact a read-only property of a Frame, why it would be wrong to verify its consistency right in the constructor without any additional interfaces for that? (Constructors are supposed to produce consistent objects and are thus free to validate incoming parameters however they like.)
However, rather than to ask how to properly validate this field, it might be better to ask why indeed you need the frame_number property in the Frame? It seems like this is an index of this item in some array - you may just use the index, why store it in the Frame? You may want to write some if/else logic later, such as:
if (frame_number == 10) {
// some rules
} else {
// other rules
}
However, this is unlikely a SOLID approach as you would probably end up writing this if/else statements in many parts of the Frame. Rather, you may create a base class FrameBase, define much of the logics there plus some abstract methods to be implemented in OrdinaryFrame and TenthFrame, where you would define different rules. This would enable you to avoid frame_number altogether -- you would just create nine OrdinaryFrames and one TenthFrame.
As for critique: your code seems to abstract balls and frames, but ignores 'throws', or 'rolls' for some reason. Consider a need to add trajectory information of each roll, you would need to change the IFrame interface, adding something like void SetThrowTrajectory(int throwNumber, IThrowTrajectory trajectory). However, if you abstract throws away in an e.g. IBallRoll, the trajectory-related functionality would easily fit there (as well as some Boolean computed properties, e.g. IsStrike, IsSpare).
Related
I'm currently working on a OO representation of a simplified chess game. Most of it is straightforward enough but one design decision I'm a little unsure about is the relationship between the chessBoard and pieces. The bottom line is I'm trying to figure out the best way to represent the chessboard / piece relationship so that I can easily and efficiently query "given a spot, is there a piece here" and "given a piece, what spot is it on"?
Currently, the Piece class stores both their own location (using a Spot class) and a reference to the Board class. The board class represents the board as a Dictionary<Spot, Piece> (the simplified game only has a few pieces so it felt unnecessary to store a mostly empty array of N by M spots like other examples I've seen) to track what spots on the board have what pieces on them. This is useful and seems intuitive to me since the piece can use the reference to the board when trying to move and ask "is there anyone at this spot?" and it can return the piece if any that is on a given spot. Similarly, in order to move the piece I need to know where it currently is and storing the location on the piece itself seems like a good OO approach.
The part where I'm running into some questions / trouble is how to keep those values in sync such that if I call (public method) Board.MovePiece() or (private setter) Piece.CurrentPosition = new spot() both Piece.CurrentPosition and the Board's Dictionary<Spot, Piece> are updated properly. Keeping everything as private as possible while making sure that calling a method on either the board or the piece while keeping the other class in sync is very tricky if not impossible. If C# had friend classes like C++ I could just make the Board a friend of the Piece then they could set each other's private vars no problem (I'm aware of internal which improves things but I don't think it prevents other code in the project from theoretically calling stuff it shouldn't). Right now my solution to this is a custom setter on the piece.CurrentPosition property so that every call to change it results in the correct call to public board members (which absolutely works) but I feel like I could do better. The biggest risk is the board methods are public and could be called outside the piece class and thus not update the piece location but I'm not a huge fan of the redundancy / slight complexity smell the code has currently.
Here's a simplified look at my code:
public class Board : IBoard
{
private uint _width;
private uint _height;
private Dictionary<Spot, Piece> _pieceLocations;
public Board(uint width, uint height)
{
_width = width;
_height = height;
_pieceLocations = new Dictionary<Spot, Piece>();
}
// heavily used by piece when determining legal moves, what pieces and free spaces are in range etc.
public Piece CheckSpot(Spot spot)
{
Piece piece;
if (_pieceLocations.TryGetValue(transformSpot(spot), out piece))
{
return piece;
}
return null;
}
/// remove instead of null to potentially optimize space a bit
public bool RemovePiece(Spot spot)
{
if (spot != null)
{
return _pieceLocations.Remove(transformSpot(spot));
}
return false;
}
/// This function will simply attempt to just move the piece to the specified destination.
/// It's up to the caller to make sure the move is a valid chess move, etc
public Spot MovePiece(Spot destination, Piece pieceToBeMoved)
{
// remove piece from current position
// note the need to have current position here
RemovePiece(pieceToBeMoved.CurrentPosition);
// attempt to place at and return new position
return PlacePiece(destination, pieceToBeMoved);
}
/// Simply places piece at specified destination if not occupied by another piece
private Spot PlacePiece(Spot destination, Piece pieceToPlace)
{
var transformedDestination = transformSpot(destination);
//business logic to check for stuff like a piece already at destination
_pieceLocations.Add(transformedDestination, pieceToPlace);
return transformedDestination;
}
Note transformSpot just makes sure coordinates are not out of bounds and "wraps them around" to be within board dimensions if need be.
public abstract class Piece : IPiece
{
protected IBoard _board;
public ColorType Color { get; protected set; }
private Spot _currentPosition;
public Piece(ColorType color, Spot currentPosition, IBoard board)
{
_board = board;
Color = color;
CurrentPosition = currentPosition ?? throw new ArgumentNullException(nameof(currentPosition), "When creating a piece you must specify a location");
}
public Spot CurrentPosition {
get { return _currentPosition; }
// I wanted to make sure that the piece's current position was always in sync with the board.
// Calling <Board> functinos here seemed like a reasonable approach.
protected set {
// if position is being set to null remove from board
if (value == null)
{
_board.RemovePiece(_currentPosition);
_currentPosition = null;
}
else
{
_currentPosition = _board.MovePiece(value, this);
}
}
}
public void Move()
{
// note that I now need the current position to figure out where I can go etc.
// insert logic to determine where we can move using chess rules etc.
var destination = new Spot(x,y);
// if spot is occupied remove piece
var occupyingPiece = _board.CheckSpot(destination);
if (occupyingPiece != null)
{
occupyingPiece.RemovePiece();
}
// call custom setter which in turn updates board to move piece from current spot to destination
CurrentPosition = destination;
}
public void RemovePiece()
{
// call custom setter which in turn updates board to remove piece
CurrentPosition = null;
}
And some super rough pseudo code for the main driver
List<Piece> whitePieces = generateWhitePieces();
List<Piece> blackPieces = generateBlackPieces();
while (gameActive)
{
//somehow determine which piece to move
var pieceToMove = whitePieces.PickPiece();
// could pass and store CurrentPosition at this level but if it's not stored on the piece or easily
// accessible from the board but feels slightly icky
pieceToMove.Move();
pieceToMove = blackPieces.PickPiece();
pieceToMove.Move();
// etc.
}
Again, main flaw on top of some possibly unneeded complexity seems to be that Board.MovePiece() needs to be public for Piece to call it but that means anyone can also call MovePiece() and move something on the board without updating the piece.
Possible solutions I have considered:
I'm totally overthinking this and this is a fairly reasonable approach.
having the piece own its own location feels right, just wish I had better access modifiers to protect sensitive values but allow friends to change them (I'm aware of internal but doesn't seem to solve my issues fully)
I could just remove currentPos and:
have the board class maintain a Dictionary<Piece, Spot>
This feels like simply shifting the issue and having board maintain two dictionaries of essentially the same info in different orders feels silly, but at least it tightly couples the data together and allows the board to be the "authority" on where everything is. Leaning towards this but have a feeling this could be optimized somehow with the right data structure
have the main driver / game class maintain a dictionary / tuple list of pieces and their current position and have the Piece.Move() pass back info on where the board tells them they are now.
Again this just feels like we're shifting the issue but even more so. On the other hand I can kinda see the rationale for the game to want to keep track of pieces but that still feels pretty anti OO and I'd probably prefer keeping this to the Board as described above.
In theory could also
Just make current position setter public so Board could change it directly and add some complex checks in both the Board functions and the Piece.CurrentPosition setter to make sure if one is changed so is the other.
Feels much worse and adds more complexities / risks than it solves in my opinion. If it weren't for this issue CurrentPosition should have a private setter.
Anyway would very much appreciate any feedback / insight!
EDIT: to be clear I'm assuming that the piece class owns its logic when it comes to how it can move, and uses the state of the board to determine what spaces it can move to. Something like Piece.DetermineMove(). Specifically the piece needs to know where it is and what pieces if any are on the spaces it can move to, pieces that threaten it, etc.
If that's a poor design I'm all ears but I have a hard time believing that a Piece class shouldn't own its own movement logic in an OOP design.
Opinions are going to be thick on this one, and there's really no absolutely correct answer. Each will have pros and cons, some of which you might not find out until much later on in development. That being said, here's mine. :)
What you really want to do is ensure that there is only one method to do any operation in your application, and only one place that biblical data is stored in the application (religious connotations aside, biblical meaning "true").
You can start with logical objects (in your domain) and attempt to place this one method into the object that it makes sense for. If it doesn't make sense, then you might need a different [mental] model.
You've started with Board, Piece and Spot and I like this so far. Since we want to keep the data for a location of a piece in one place, I think we want to do that at the board level, because it will make movement easier (a piece won't have to go "up" to the board and back "down" to another piece).
This means a Piece won't have a Spot property, only a type (knight, bishop, etc) and ColorType (white/black). The board will have the dictionary for the pieces with the Spot as the key (it's a good key - there can only be one piece on a square). This makes a lot of the logic easier. Moving a piece means taking it out of the dict and putting it back in at the destination:
// Move attempt method might look like this:
Piece thisPiece = ... ;
Spot old = (1, 1); // origin ..
Spot new = (2, 2); // .. destination
// do some validation
if (pieces.Contains(new) && pieces[new].color == thisPiece.color)
throw new SpotOccupiedByFriendlyPieceAndThisIsntACastleException();
// capture a piece
if (pieces.Contains(new) && pieces[new].color != thisPiece.color)
{
pieces.Remove(new);
}
pieces.Remove(old); // move the old piece from "old"...
pieces.Add(new, thisPiece); //... to "new"
By putting all the pieces in a Dictionary<Spot, Piece> at the board level, there's only one collection that holds the pieces-to-spots relationship (the board owns it), and the board can perform all the logic it needs to.
I want many GameObjects on the scene to have the Y position "animated" programmatically. I have a class, let's call it "TheGameObject", which doesn't inherit from MonoBehaviour and as such can't have the Update() function that I need to achieve the Y movement of the GameObjects.
I decided to try using a delegate but then a problem came up: I can pass only one Transform to the delegate.
Here's the code for the delegate in a static class, let's call it "staticClass", that derives from MonoBehaviour:
public delegate void UpdatingEventHandler(Transform t);
public static event UpdatingEventHandler Updating;
void Update() {
if(Updating != null)
Updating(/*Transform that should be passed*/);
}
And this is the code in the "TheGameObject" class:
public GameObject gameObject { get; set; }
private void spawn() {
GameObject go = new GameObject();
staticClass.Updating += animateYpos(go.transform);
}
void animateYpos(Transform t) {
//modify t.position.y
}
Is there a way to pass each respective Transform to the delegate in order to call Updating() in the static class Update() and have all the GameObjects to move respectively?
The problem isn't the type of the parameter that is passed but which Transform is passed so that each different Transform will have its own Y position modified.
This is sort of totally wrong, Cress!
It's very common for experienced developers to not really understand that Unity
is not object oriented, and has utterly no connection - at all - to concepts like inheritance.
(Sure, the programming language currently used for writing components in Unity, happens to be OO, but that's largely irrelevant.)
Good news though, the solution is incredibly simple.
All you do in Unity is write behaviors that do what you want.
Essay about it ... https://stackoverflow.com/a/37243035/294884
Try to get this concept: say you have a "robot attack device" in your game.
So, the only thing in Unity scenes is GameObjects. (There is nothing else - at all.)
Your "robot attack device" would have these behaviors. ("Behaviours" meaning components attached to it. Componantes are MonoBehavior.)
"robot attack device"
• animate Z position
• shoot every ten seconds
• respond to bashes with sound effect
and so on.
Whereas, your "kawaii flower" might have these behaviors
"kawaii flower fixed NPC"
• shoot every 5 seconds
• respond to bashes with sound effect
• rainbow animation
In this case you're asking how to write a "animate Y" behavior.
It's very easy, first note that everything - everything - you do in Unity you do with an extension, so it will be like
public static void ForceY( this Transform tt, float goY )
{
Vector3 p = tt.position;
p.y = goY;
tt.position = p;
}
Quick tutorial on extensions: https://stackoverflow.com/a/35629303/294884
And then regarding the trivial component (all components are trivial) to animate Y, it's just something like
public class AlwaysMoveOnYTowards:MonoBehaviour
{
[System.NonSerialized] public float targetY;
void Update()
{
float nextY = .. lerp, or whatever, towards targetY;
transform.ForceY(nexyT);
}
}
Note that, of course, you just turn that component on and off as needed. So if the thing is asleep or whatever in your game
thatThing.GetComponent().enabled = false;
and later true when you want that behavior again.
Recall, all you're doing is making a model for each thing in yoru game (LaraCroft, dinosaur, kawaiiFlower, bullet .. whatever).
(Recall there are two ways to use models in Unity, either use Unity's prefab system (which some like, some don't) or just have the model sitting offscreen and then Instantiate or use as needs be.)
{Note that a recent confusion in Unity (to choose one) is: until some years ago you had to write your own pooling for things that you had a few of. Those days are long gone, never do pooling now. Just Instantiate. A huge problem with Unity is totally out-of-date example code sitting around.}
BTW here's the same sort of ForceY in the case of the UI system
public static void ForceYness(this RectTransform rt, float newY)
{
Vector2 ap = rt.anchoredPosition;
ap.y = newY;
rt.anchoredPosition = ap;
}
Finally if you just want to animate something on Y to somewhere one time, you should get in to the amazing
Tweeng
which is the crack cocaine of game engineering:
https://stackoverflow.com/a/37228628/294884
A huge problem with Unity is folks often don't realize how simple it is to make games. (There are many classic examples of this: you get 1000s of questions asking how to make a (totally trivial) timer in Unity, where the OP has tied themselves in knots using coroutines. Of course, you simply use Invoke or InvokeRepeating 99% of the time for timers in Unity. Timers are one of the most basic parts of a game engine: of course, obviously unity through in a trivial way to do it.)
Here's a "folder" (actually just a pointless empty game object, with these models sitting under it) holding some models in a scene for a game.
those are some of the enemies in the game. As an engineer I just popped them in there, the game "designer" would come along and set the qualities (so, the potato is fast, the turnip is actually an unkillable boss, the flying head connects to google maps or whatever).
Same deal, this is from the "folder" (aside, if you use an empty game object as a, well, folder to just hold shit, it's often referred to as a "folder" - it's no less a game object) with some "peeps" ("player projectiles"). Again these are the very models of these things to be used in the game. So obviously these would just be sitting offscreen, as you do with games. Look, here they are, literally just sitting around an "-10" or something outside of the camera frustrum (a good place to remember a Unity "camera" is nothing more than ............. a GameObject with certain components (which Unity already wrote for our convenience) attached.)
(Again: in many cases you may prefer to use prefabs. Unity offers both approaches: prefabs, or "just sitting offscreen". Personally I suggest there is a lot to be said for "just sitting offscreen" at first, as it makes you engineer proper states and so on; you'll inherently have to have a "just waiting" state and so on, which is highly important. I strongly encourage you, at first, to just 'sit your models around offscreen', don't use prefabs at first. Anyway that's another issue.)
Here then are indeed some of those peeps ...
Thank God, I was born an engineer, not a wanker "game designer" so someone else comes along and sets that sort of thing as they see fit. (And of course, indeed adds the profoundly important (from a player point of view) Components such as, you know, "the renderer", sound effects, and the like.
Note, Cress: you may notice above: because "life's like that" in the naming there (it's purely a naming issue, not a deep one) we very un-sensibly went against just what I describe here. So, notice I have a component that should be named, say, "Killableness" or perhaps just "projectileness" or indeed just "power" or "speed". Just because life's like that, I rather unsensibly named it "missile" or "projectile" rather than indeed "flight" or "attackPower". You can see this is very very bad because when I reuse the component "attackPower" (stupidly named here "missile") in the next project, which involves say robotic diggers or something rather than missiles, everyone will scream at me "Dude why is our attack power component, attached to our robotic spiders, called 'missile' instead of 'attack power', WTF?" I'm sure you see what I mean.
Note too, there's a great example there of, while Unity and GameObject have no connection at all to computer science or programming, it's totally normal - if confusing - that in writing components you have to be a master of OO since (as it happens) the current language used by Unity does indeed happen to be an OO language (but do bear in mind they could change to using Lisp or something at any time, and it wouldn't fundamentally affect Unity. As an experienced programmer you will instantly see that (for the components discussed here) I have something like a base class "Flightyness" and then there are subclasses like "ParabolaLikeFlightyness" "StraightlineFlightyness" "BirdFlightyness" "NonColliderBasedFlightyness" "CrowdNetworkDrivenFlightyness" "AIFlightyness" and so on; you can see each have the "general" settings (for Steve the game designer to adjust) and more specific settings (again for Steve to adjust). Some random code fragments that will make perfect sense to you...
public class Enemy:BaseFrite
{
public tk2dSpriteAnimator animMain;
public string usualAnimName;
[System.NonSerialized] public Enemies boss;
[Header("For this particular enemy class...")]
public float typeSpeedFactor;
public int typeStrength;
public int value;
public class Missile:Projectile
{
[Header("For the missile in particular...")]
public float splashMeasuredInEnemyHeight;
public int damageSplashMode;
Note the use of [Header ... one of the most important things in Unity! :)
Note how good the "Header" thing works, especially when you chain down through derives. It's nothing but pleasure working on a big project where everyone works like that, making super-tidy, super-clear Inspector panels for your models sitting offscreen. It's a case of "Unity got it really right". Wait until you get to the things they fucked up! :O
Please conside what Joe said but for passing multiple paramaters to a delegate you can use this iirc :
public delegate void DoStuffToTransform(params Transform[] transform);
I have a large abstract class that handles weapons in my game. Combat cycles through a list of basic functions:
OnBeforeSwing
OnSwing
OnHit || OnMiss
What I have in mind is moving all combat damage-related calculations to another folder that handles just that. Combat damage-related calculations.
I was wondering if it would be correct to do so by making the OnHit method an extension one, or what would be the best approach to accomplish this.
Also. Periodically there are portions of the OnHit code that are modified, the hit damage formula is large because it takes into account a lot of conditions like resistances, transformation spells, item bonuses, special properties and other, similar, game elements.
This ends with a 500 line OnHit function, which kind of horrifies me. Even with region directives it's pretty hard to go through it without getting lost in the maze or even distracting yourself.
If I were to extend weapons with this function instead of just having the OnHit function, I could try to separate the different portions of the attack into other functions.
Then again, maybe I could to that by calling something like CombatSystem.HandleWeaponHit from the OnHit in the weapon class, and not use extension methods. It might be more appropriate.
Basically my question is if leaving it like this is really the best solution, or if I could (should?) move this part of the code into an extension method or a separate helper class that handles the damage model, and whether I should try and split the function into smaller "task" functions to improve readability.
I'm going to go out on a limb and suggest that your engine may not be abstracted enough. Mind you, I'm suggesting this without knowing anything else about your system aside from what you've told me in the OP.
In similar systems that I've designed, there were Actions and Effects. These were base classes. Each specific action (a machine gun attack, a specific spell, and so on) was a class derived from Action. Actions had an list of one or more specific effects that could be applied to Targets. This was achieved using Dependency Injection.
The combat engine didn't do all the math itself. Essentially, it asked the Target to calculate its defense rating, then cycled through all the active Actions and asked them to determine if any of its Effects applied to the Target. If they applied, it asked the Action to apply its relevant Effects to the Target.
Thus, the combat engine is small, and each Effect is very small, and easy to maintain.
If your system is one huge monolithic structure, you might consider a similar architecture.
OnHit should be an event handler, for starters. Any object that is hit should raise a Hit event, and then you can have one or more event handlers associated with that event.
If you cannot split up your current OnHit function into multiple event handlers, you can split it up into a single event handler but refactor it into multiple smaller methods that each perform a specific test or a specific calculation. It will make your code much more readable and maintainable.
IMHO Mike Hofer gives the leads.
The real point is not whether it's a matter of an extension method or not. The real point is that speaking of a single (extension or regular) method is unconceivable for such a complicated bunch of calculations.
Before thinking about the best implementation, you obviously need to rethink the whole thing to identify the best possible dispatch of responsibilities on objects. Each piece of elemental calculation must be done by the object it applies to. Always keep in mind the GRASP design patterns, especially Information Expert, Low Coupling and High Cohesion.
In general, each method in your project should always be a few lines of code long, no more. For each piece of calculation, think of which are all the classes on which this calculation is applicable. Then make this calculation a method of the common base class of them.
If there is no common base class, create a new interface, and make all these classes implement this interface. The interface might have methods or not : it can be used as a simple marker to identify the mentioned classes and make them have something in common.
Then you can build an elemental extension method like in this fake example :
public interface IExploding { int ExplosionRadius { get; } }
public class Grenade : IExploding { public int ExplosionRadius { get { return 30; } } ... }
public class StinkBomb : IExploding { public int ExplosionRadius { get { return 10; } } ... }
public static class Extensions
{
public static int Damages(this IExploding explosingObject)
{
return explosingObject.ExplosionRadius*100;
}
}
This sample is totally cheesy but simply aims to give leads to re-engineer your system in a more abstracted and maintenable way.
Hope this will help you !
I have a question about a XNA game I'm making, but it is also a generic question for future games. I'm making a Pong game and I don't know exactly what to update where, so I'll explain better what I mean. I have a class Game, Paddle and Ball and, for example, I want to verify the collisions between the ball with the screen limits or the paddles, but I come across 2 approaches to do this:
Higher Level Approach - Make paddle and ball properties public and on the Game.Update check for collisions?
Lower Level Approach- I supply every info I need (the screen limits and paddles info) to the ball class (by parameter, or in a Common public static class) and on the Ball.Update I check for collisions?
I guess my question in a more generic way is:
Does an object need to know how to update and draw itself, even having dependencies from higher levels that somehow are supplied to them?
or
Is better to process it at higher levels in Game.Update or Game.Draw or using Managers to simplify code?
I think this is a game logic model question that applies to every game. I don't know if I made my question clear, if not, feel free to ask.
The difficult part of answering your question is that you're asking both: "what should I do now, for Pong" and "what should I do later, on some generic game".
To make Pong you don't even need Ball and Paddle classes, because they're basically just positions. Just stick something like this in your Game class:
Vector2 ballPosition, ballVelocity;
float leftPaddlePosition, rightPaddlePosition;
Then just update and draw them in whatever order suits you in your Game's Update and Draw functions. Easy!
But, say you want to create multiple balls, and balls have many properties (position, velocity, rotation, colour, etc): You might want to make a Ball class or struct that you can instance (same goes for the paddles). You could even move some functions into that class where they are self-contained (a Draw function is a good example).
But keep the design concept the same - all of the object-to-object interaction handling (ie: the gameplay) happens in your Game class.
This is all just fine if you have two or three different gameplay elements (or classes).
However let's postulate a more complicated game. Let's take the basic pong game, add some pinball elements like mutli-ball and player-controlled flippers. Let's add some elements from Snake, say we have an AI-controlled "snake" as well as some pickup objects that either the balls or the snake can hit. And for good measure let's say the paddles can also shoot lasers like in Space Invaders and the laser bolts do different things depending on what they hit.
Golly that is a huge mess of interaction! How are we going to cope with it? We can't put it all in Game!
Simple! We make an interface (or an abstract class or a virtual class) that each "thing" (or "actor") in our game world will derive from. Here is an example:
interface IActor
{
void LoadContent(ContentManager content);
void UnloadContent();
void Think(float seconds);
void UpdatePhysics(float seconds);
void Draw(SpriteBatch spriteBatch);
void Touched(IActor by);
Vector2 Position { get; }
Rectangle BoundingBox { get; }
}
(This is only an example. There is not "one true actor interface" that will work for every game, you will need to design your own. This is why I don't like DrawableGameComponent.)
Having a common interface allows Game to just talk about Actors - instead of needing to know about every single type in your game. It is just left to do the things common to every type - collision detection, drawing, updating, loading, unloading, etc.
Once you're in the actor, you can start worrying about specific types of actor. For example, this might be a method in Paddle:
void Touched(IActor by)
{
if(by is Ball)
((Ball)by).BounceOff(this.BoundingBox);
if(by is Snake)
((Snake)by).Kill();
}
Now, I like to make the Ball bounced by the Paddle, but it is really a matter of taste. You could do it the other way around.
In the end you should be able to stick all your actors in a big list that you can simply iterate through in Game.
In practice you might end up having multiple lists of actors of different types for performance or code simplicity reasons. This is ok - but in general try to stick to the principle of Game only knowing about generic actors.
Actors also may want to query what other actors exist for various reasons. So give each actor a reference to Game, and make the list of actors public on Game (there's no need to be super-strict about public/private when you're writing gameplay code and it's your own internal code.)
Now, you could even go a step further and have multiple interfaces. For example: one for rendering, one for scripting and AI, one for physics, etc. Then have multiple implementations that can be composed into objects.
This is described in detail in this article. And I've got a simple example in this answer. This is an appropriate next step if you start finding that your single actor interface is starting to turn into more of a "tree" of abstract classes.
You could also opt to start thinking about how different components of the game need to talk to each other.
Ball and Paddle, both are objects in the game and in this case, Renderable, Movable objects.
The Paddle has the following criteria
It can only move up and down
The paddle is fixed to one side of the screen, or to the bottom
The Paddle might be controlled by the user (1 vs Computer or 1 vs 1)
The paddle can be rendered
The paddle can only be moved to the bottom or the top of the screen, it cannot pass it's boundaries
The ball has the following criteria
It cannot leave the boundaries of the screen
It can be rendered
Depending on where it gets hit on the paddle, you can control it indirectly (Some simple physics)
If it goes behind the paddle the round is finished
When the game is started, the ball is generally attached to the Paddle of the person who lost.
Identifying the common criteria you can extract an interface
public interface IRenderableGameObject
{
Vector3 Position { get; set; }
Color Color { get; set; }
float Speed { get; set; }
float Angle { get; set; }
}
You also have some GamePhysics
public interface IPhysics
{
bool HasHitBoundaries(Window window, Ball ball);
bool HasHit(Paddle paddle, Ball ball);
float CalculateNewAngle(Paddle paddleThatWasHit, Ball ball);
}
Then there is some game logic
public interface IGameLogic
{
bool HasLostRound(...);
bool HasLostGame(...);
}
This is not all the logic, but it should give you an idea of what to look for, because you are building a set of Libraries and functions that you can use to determine what is going to happen and what can happen and how you need to act when those things happen.
Also, looking at this you can refine and refactor this so that it's a better design.
Know your domain and write your ideas down.
Failing to plan is planning to fail
You could see your ball and paddle as a component of your game, and XNA gives you the base class GameComponent that has an Update(GameTime gameTime) method you may override to do the logic. Additionally, there is also the DrawableGameComponent class, which comes with its own Draw method to override. Every GameComponent class has also a Game property which holds the game object that created them. There you may add some Services that your component can use to obtain information by itself.
Which approach you want to make, either have a "master" object that handles every interaction, or provide the information to the components and have them react themselves, is entirely up to you. The latter method is preferred in larger project. Also, that would be the object-oriented way to handle things, to give every entity its own Update and Draw methods.
I agree with what Andrew said. I am just learning XNA as well and in my classes, for example your ball class. I'd have an Update(gametime) method and a Draw() method in it at the least. Usually an Initialize(), Load() as well. Then from the main game class I will call those methods from their respective cousins. This was before I learned about GameComponent. Here is a good article about if you should use that. http://www.nuclex.org/blog/gamedev/100-to-gamecomponent-or-not-to-gamecomponent
I have two classes, Human and Monster.
both have a Property called MoveBehavior
Human has HumanMoveBehavior, and Monster has MonsterMoveBehavior
I want the HumanMoveBehavior to move AWAY from Monsters, and MonsterMoveBehavior to move TOWARD Humans.
The problem I'm having is where should I put my code to move?
In the Human/Monster class?
Using this approach, I had a Move() Method, which takes a List of all entities in game, decides whether it's a Monster or Human using a method called GetListOfOpponents(List allsprites) and then runs GetNearestOpponent(List opponents);
But this looks really messy.
Should I have a SpriteController that decides where the Sprites move? I'm unsure where I need to put this code :(
Thanks!
You could think of a AIManager that just says:
foreach(GameObject go in m_myObjects) // m_myObjects is a list of all objects that require updating
{
go.Update(); // standard GameObject function
}
After that, each class should take care of its own piece of code. So updating works in the class itself.
So Human says:
// just a class which is a gameObject and also has moving behaviour
// do the same with monster
public class Human : GameObject, IMoveBehaviour
{
public override Update()
{
GoMove();
}
public void GoMove()
{
// human specific logic here
}
}
// This interface describes that some movement
// will happen with the implementing class
public interface IMoveBehaviour
{
void GoMove();
}
With using an interface, you can make the specific language part of the class and you don't have need to ALSO create some class that will handle that for you. Of course it is possible. But in real life, the human/monster is the one that is moving, not some object he is carrying.
UPDATE
Answer to the comment. Because there is an AIManager, or even a complete GameObjectManager would be nice to maintain all GameObjects, you could ask the AIManager for the placed where you could not go.
Because pathfinding is most of the time done by use of some navigation mesh or a specified grid, the GameObjectManager can return the specific Grid with all navigable points on it. You should for certain not define all positions in every monster. Because most of the time, the monster does not exactly know where everyone is (in real life). So knowing where not to go is indeed good, but knowing where everyone is, will give your AI too much advantage as well.
So think of returning a grid with the points where to go and where not to, instead of maintaining such things inside the monster/human. Always check where you should leave what, by thinking about what would be the thing in real life.
The way Valve handled this for entities in Half Life 2, is one of the better ways, I think. Instead of giving each AI its own separate Move methods and calling those, it simply called the Think() method and let the entity decide what it needed to do.
I'd go with what Marnix says and implement an AIManager that loops through each active AI in the game world, calling the Think() method of each. I would not recommended interfacing your Human class with an "IMoveBehavior" simply because it would be better to abstract that into a "WorldEntity" abstract class.
You might have invisible entities that control things like autosaves, triggers, lighting, etc, but some will have a position in the world. These are the ones who will have a vector identifying their position. Have the AI's Think() method call its own move() method, but keep it private. The only one who needs to think about moving is the AI itself.
If you want to encourage the AI to move outside of the Think) method, I would suggest some kind of imperative, such as a Goal-Oriented Action Planning (GOAP) system. Jeff Orkin wrote about this fantastic concept, and it was used in games such as F.E.A.R. and Fallout 3. It might be a bit overkill for your application, but I thought it was interesting.
http://web.media.mit.edu/~jorkin/goap.html