Architecture philosophy - should objects store information about the world? - c#

I'm making a tetris-like game.
There are two classes in the game: simulator and block (i.e. a tetris block)
Right now, block only holds information about itself that is independent of any other parts of the game. So it's information like "shape", "color", "rotation" etc. (Notably excluding position)
simulator on the other hand, contains an data structure of block's and is responsible for their behaviours (falling, etc.)
Currently, to track the position of each block, simulator actually has an array called array_block_position, which is an array containing sub-arrays in the form of [block-instance, position], e.g. [block#3, (10,12)]
Now, I have this dilemma:
I am tempted to add a "position" variable inside the block class itself instead of tracking their positions in simulator, so simulator can have an array of visible_blocks that is simply an array of block instances rather than an array of arrays. (Visible is emphasized because there may be blocks that are not a part of the playing field, such as the block that is about to be deployed but not yet)
I am uncertain whether I should add "position" as a variable to the block class itself because of some vague memory of learning that this being a bad idea in college, but I no longer remember why it's supposed to be bad, if at all.
I want to know, in general, whether (and when) it's acceptable to store information about an object's relationship with the external world inside the object itself.
(My instincts tells me "no", because a variable like "position" is not meaningful to an object like block without some reference to the external world, but my reasoning sees no immediate problem with something like this in practice)

Related

Is it possible to get the value of a class attribute from a running application?

There is a simulator. In this simulator we have to pass a corridor. In the corridor there is a door and a puzzle, the solution of which opens this door. As soon as we solve the puzzle, the value of the boolean attribute of the class (something like isOpen) changes to true
This corridor needs to be traversed several times. The corridor itself doesn't change, but the puzzle is random each time.
So, I decided to create a macro application that reaches the puzzle and waits until I solve it
And since the simulation has the boolean variable I need, I was wondering: can I get it, in order to then create a delay in the macro until it is true?
The main problem here is that the two programs are not connected in any way.
I also want to note that I have an understanding that all variables lose their names after compilation, and that variable values subsequently occupy a random place in memory
Also, I have experience with programs like CheatEngine, which is to find the address of a value by its value
But I may just not know all the details, thinking that it's impossible, even if in reality there are ways to do it.
For this reason, I would appreciate it if you could explain to me how this can be done, or, if it is not possible, explain why.
Also, I wouldn't mind a response like "Read this "
I understand that you want to inspect one or more properties of an instance of an object at runtime and this can be achieved by using the so-called Reflection.
The latter provides functionalities that allow you to examine objects at runtime, get their Type, read their properties and invoke their methods. It should be used carefully.
Using reflection you can do
// retrieves the value of the property "NameOfProperty" for the instance of object myobj
bool myFlag = myobj.GetType().GetProperty("NameOfProperty").GetValue(myobj, null);

C# / Unity - Need help debugging my Chess program - trouble creating instance of class within another instance of the same class

I'm creating a Chess program. I've decided to make it so that, when a piece is selected, all of its possible legal moves are displayed. In order for that to work, I have to have a mechanism to predict the outcomes of moves (because you can't make a legal move which puts your own king in check, for example). This will also be useful when I start working on computer opponents, since the AI will need to be able to see several turns in advance in order to make intelligent decisions.
To this end, I've made it so that, at the start of each turn, all possible moves are calculated for the player's pieces, and then each of those possible moves is simulated to see whether or not it leaves the King in check. If so, that option is removed. I have a main class called BoardManager which controls the visuals and contains the actual chess board layout (in a ChessBoardSim), and I have a class ChessBoardSim, whose objects each contain one possible board state. ChessBoardSim can create other instances of ChessBoardSim, allowing the state of the board any number of turns in advance to be simulated.
I have a bug which I've been struggling with for over 5 hours, which appeared after I tried to restructure a lot of the code. I'm at my wit's end, and I just need a fresh pair of eyes. The issue is making it so that pieces aren't being removed from their old positions when moved, and the locations of some of the pieces on the board seem to be shifted two tiles up. I believe, based on the debugging, that the problem is appearing in CalculateAllMovementOptions() in the ChessBoardSim class - for some reason, when a ChessBoardSim has a ChessBoardSim child and the CalculateAllMovementOptions() function is called in the child, it changes the data in the parent.
I've included the full code below, and I'll describe the specific issue as best I can.
The flow of the problem is:
1: private void Start() in BoardManager is called.
2: The program draws and populates the board properly. A ChessBoardSim (called ChessPieces) is created to contain the data of the current board state.
3: StartTurn() is called in BoardManager, in order to begin the game.
4: StartTurn() calls ChessPieces.CalculateAllMovementOptions(). The intended function of CalculateAllMovementOptions() is to get back an array of Lists. Each List in the array contains the legal moves of one of the player's pieces. However, this actually seems to be changing the actual board data, and I can't work out why.
When a player tries to move a piece, the game breaks because the pieces aren't where they're supposed to be and the software can't cope with it. The piece which is moved doesn't remove itself from its old location (despite my best efforts), and this causes there to be two instances of that object, leading to an indexoutofrange exception when a piece of the code tries to access the 17th element of an array with 16 elements.
I would really appreciate it if anyone could help me, I feel like I've wasted an entire day on this already and I'm sure I'm missing something simple.
The link to my code is https://github.com/FC123321/Chess
Array.Clone doesn't create a deep copy of an array, so when you call boardLayout.Clone() in SimulateBoard (and again in the ChessBoardSim constructor), you are copying the references in boardLayout to the new array. This means that the pieces in the new array are the same object in the old one.
This means that when you're in MovePiece in SimulateBoard and you call piece.SetPosition and such on members of that copied array, you're setting the position of the pieces in the source of the copy as well.
Instead of using boardLayout.Clone(), you need to loop through the whole source array, and do newBoardLayout[x,y] = new ChessPiece(); and then copy over the values to the new ChessPiece. Alternatively, you could create a new ChessPiece constructor that takes another chess piece and copies the values there:
// ChessPiece copy constructor
public ChessPiece(ChessPiece other) {
this.Position = new int[2] { other.Position[0], other.Position[1]};
this.isWhite = other.isWhite;
this.movementType = other.movementType;
this.hasMoved = other.hasMoved;
this.turnDoubleMoved = other.turnDobleMoved;
}
// instead of boardLayout.Clone() in the ChessBoardSim constructor:
for (int x=0 ; x<8;x++){
for(int y=0; y<8;y++){
if (boardLayout[x,y] != null)
this.boardLayout[x,y] = new ChessPiece(boardLayout[x,y]);
}
}
// In SimulateBoard, take out the redundant Clone call
ChessBoardSim simBoard = new ChessBoardSim(boardLayout, turnNumber);

Shattering objects without creating new ones in Unity

I'm crating mobile unity game where a player will be hooking flying islands with a rope. I want the islands to sometimes destroy when pulled to strong by the rope.
I know that normal way of shattering objects is to destroy previous object and spawn its parts at the same place, but it won't work in my case, because I want the rope to remain hooked to one piece after shattering the object (same part of the object that it was hooked to before).
The only solution that came to my mind is to have these objects always created from separate parts, but connected with joints or script. Then they could be broken into separate pieces on some condition. I'm not sure if this solution is good or if there is better one, it would be great if someone could help me with this.
"I know that normal way of shattering objects is to destroy previous object and spawn its parts at the same place,"
There is no other possibility, whatsoever. That is how you do it.
Even if you dynamically create the new objects, you still do exactly what you say in that sentence.
"but it won't work in my case, because I want the rope to remain hooked to one piece after shattering the object (same part of the object that it was hooked to before)."
There is no problem whatsoever.
You simply hook that new piece to the rope. It's that simple.
Before .. one large piece "A" and connected to the rope at some point
After .. seven pieces "B" through "H". One of them (say "F") is connected to the rope.
You're done.
The only solution that came to my mind is to have these objects always created from separate parts, but connected with joints or script.
Yes, you can absolutely, totally do that.
Note that when you say "connected with joints or scripts". It is far easier that that!
Say you have seven pieces, named "1" through "7"
Have an empty game object called "Holder"
Just put the 7 objects "under" holder - i.e. holder is the parent.
It's that simple - nothing to it. Go for it!
Treat "holder" as one object. So if you want to move it or whatever, just move "holder".
If you prefer ...... let's say that small-piece "3" is the "one" which is attached to the rope.
Simply, make all the rest (1,2,4,5,6,7) the children of "3". It will all simply move as one thing. That's perhaps even easier for you.
Again, you're done!
Regarding your good question of how to "make one children of parent object stop being children and be separate object"
Simple,
smallObject.transform.parent = null;
but more likely, you will have some "overall" object, right? Or, the large object is attached the rope perhaps.
Quite simply, change the parent of the small object to that parent of the large object
Transform currentParentOfBigObject;
currentParentOfBigObject = bigObject.transform.parent;
.. create or separate the small objects ..
smallObject.transform.parent = currentParentOfBigObject;
.. perhaps get rid of the big object if relevant ..

Data structure for simple animations in games

I'm trying to create a system in which numbers are changed according to the time elapsed since last update, their target/destination value, etc.
In an earlier project, I created an abstract class for animation data which contained Tick(), IsDone(), etc, which were then implemented for each facet of the game object I wanted to animate, such as position and opacity. The animation data were held by the game object, with the Tick() function being called by the game object's Tick() function, which is called by the engine's logic update loop using a list of all game objects.
However, I now have more things I want to animate, and was looking in to doing so with as few classes as possible, and definitely not with N+1 classes.
I looked in to saving references to the variable being animated, using the fact that all variables I wanted to animate were floats. However, it appears C# pointers are analogs to the C pointers, and so I cannot save pointers to the values being animated, which appears to be impossible for the CLR in the first place.
The only alternative I could think of is to use reflection to record the argument being passed, then use reflection again to find the value to alter each tick. But then using dozens of reflection calls 60 times a second did not appeal to me.
Since animating objects is a near universal feature in games, I was wondering if there were established practices.

Property of one class is another class, and vice-versa

I'm programming a board game in C# where the two most important classes are Piece and Square. Typically every instance of Piece has a Square (as a property) and every instance of Square may have a Piece (also as a property) or may be empty.
I placed code in the set methods of Square.Piece and Piece.Square to ensure that this relationship was maintained (e.g. when a piece is moved from one square to another) and to avoid the obvious danger of the linked properties calling each other's set methods in an endless loop.
But when a piece is removed from the board and its square set to 'null' I seem to have too many if statements to avoid null exceptions and what seemed a very simple pattern conceptually becomes far too complex and error-prone in practice.
I'm wondering whether my whole approach is wrong. Should a piece have a square as a property when Square also has Piece as a property? Have I in fact started coding an anti-pattern? A Piece's Square may be null on creation, and a Square's Piece is frequently null (representing empty). Should I use another way to represent empty Squares and Pieces which are not on the board?
I'm assuming there are preferred, robust solutions to the more general case of when one class is linked to another in a two-way relationship such as this.
Many thanks for any ideas.
Use an higher level abstraction, with methods like
move(piece, originalSquare, destinationSqueare)
place(piece, square)
remove(piece)
promote(originalPiece, finalPiece)
...
these methods will use your basic methods from Piece and Square, and will be the ones used by your main logic
It seems to me that you're overthinking the process of removing a Piece from the Board.
The game is going to be centered on the Board class. Once you remove a Piece from the Board, that piece is gone; you're not going to do anything with it anymore. You won't be calling any of its methods or anything. That object is now dead -- unreachable. So there's not actually any reason to change the Piece's state to null out its Board reference.
This is indeed a very common pattern, and the usual practice is to just let it go. Once nobody references the Piece anymore, you're done; it no longer matters that the Piece still happens to reference the Board. Let it keep its reference; it won't cause any harm (since nobody will be doing anything with that Piece anymore), and it'll be garbage collected soon anyway.

Categories

Resources