First post so hi! (please correct me if I use some term wrong)
I've got a class Screen in which I create an instance of another class named Player (let's call this instance Player). Now, in Screen I have a method called ResetHUD which I would like to call from Player.
How would I do that? The only code inside ResetHUD is 1 line which sets a variable to another variable. As far as I know I can use EventHandler (but since ResetHUD doesn't need any arguments I'm thinking that I'm using that wrong) or delegates (which I have no idea how to use).
Help is appreciated!
It sounds like you have a containment relationship... the Screen object contains one (or more?) Player objects.
When Screen creates Player, it can set a property on Player indicating the parent (creating) Screen object.
class Player
{
private Screen parentScreen;
public Player(Screen parentScreen) { this.parentScreen = parentScreen; }
public MyMethodThatHasToCallScreensMethod()
{
parentScreen.ResetHUD();
}
}
class Screen
{
public Player CreatePlayer()
{
return new Player(this);
}
}
You can also use events (events by the way can have parameters, or not, depending on what you need).
This is my favorite tutorial on events and delegates in C#. Starts simple and builds on each step.
http://www.akadia.com/services/dotnet_delegates_and_events.html
Put a MyScreen property on the Player class. When you create the Player class, set that property to your screen class. You now have a reference to screen that you can call from inside player.
Well, something in Player needs to have a reference to the Screen instance. Options:
When you create the Player, pass this to the constructor so that it can remember the Screen it belongs to
Create an event on Player and subscribe to it from Screen
Pass the Screen along as parameters along the method call chain involved (this may not be practical in your situation)
Related
I have this simple code to change the sprite of an image everytime I click a button.
using UnityEngine;
using UnityEngine.UI;
public class SampleChange : MonoBehaviour {
public Sprite sampleSprite;
public Image sampleImage;
public void Start()
{
sampleImage = GetComponent<Image>();
}
public void changeColor()
{
sampleImage.gameObject.GetComponent<Image>();
sampleImage.sprite = sampleSprite;
}
}
I attached this script to an EmptyGameObject and Loaded the function on the Button that is parented on a Canvas alongside the Image. I already also placed the Image and Sprite objects in the inspector:
Inspector Settings
When I run the game and click the Button, it gives me this error:
NullReferenceException: Object reference not set to an instance of an object
SampleChange.changeColor () (at Assets/Scripts/SampleChange.cs:18)
The cs:18 is the sampleImage.sprite = sampleSprite;. I really don't know why it's not working.
OK simple,
public Image sampleImage;
that means
you will set "sampleImage" variable in the inspector, in the editor, before you hit Play
But this one ..
sampleImage = GetComponent<Image>();
means
you will set "sampleImage" variable in code when the scene is running.
You have to sort it out and do it "one way or the other".
Suggest you use the first method while U learning.
(If you do use the second method, the "Image" must actually be on the game object which is holding the script in question. If you struggle with that, I would urge you to ask a separate question, or just study up on the basics using Unity tutorials.)
Cheers
It appears that you have no constuctor defined for your class and that you are just trying to call the changeColor() method as if it were a static function of the class. You need to construct objects of your class and then call the methods you defined on those objects, not on the class itself.
i need to declare a variable class in my code so i can access a function (having the same name in all classes) but doing each time a different behavior).
and this is my code:
using UnityEngine;
using System;
using System.Collections;
public class Bubble : ItemBehaviour
{
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
void OnMouseDown ()
{
theclass.Behaviour ();
}
}
knowing that (theclass gonna be variable ).
Thank you guys for your answer but it is a bit special.
My game is about interaction between player and game objects when the player approach any item that is "interactible" lets say, a bubble shows up, this bubble is a GameObject and it is the same for any object that allow interactions,
So since i am doing a 2D game i thought, it would be great if i make a "universal"
EmptyGameObject that contains all common aspects that anyObject would contain, and i grouped main functions and common ones in a general script and i added it to this emptyGameObject, then i added the Bubble prefab to this Game object and i a dded a code to it this code contains what i wrote in my firs post.
i was thinking that now each time i want an object i just drop this emptygameobject prefab and changes sprites and characteristics.
And each object have a different behavior (ex: i can delete an apple as if the character consumed it but i can not consume a door, the door would rather trigger an animation than being destructed ) i am specifying all this in a class for each item.
now whatever the class is (the object is) the trigger is in the bubble class (which i posted first) but the class will be different each time and i can not make a class that contains polymorphism because its not the same context each time.
I think you should create an interface that declares all the functions you would like to use in different classes.
interface IBehaviour
{
void Behaviour();
void AnotherBehaviour();
}
with this you define a behaviour what a class, which implements the interface, is capable of.
And then your classes would be:
class MyClass1 : Ibehaviour
{
}
class MyClass2 : IBehaviour
{
}
Apart from this you can use abstract classes. There are a lot of well-written articles about these topics on the Internet.
Firstly, I recommend to get familiar with OOP principles.
This link is a good way to start.
Good luck.
Thank you all,
The matter was solved by creating a global (abstract) gameOject that contains the class that we want to inherit from, and then each time the gameObject atached to this class calls (Behavior function) it trigger whatever the override is for this function for this object.
I have a bunch of screens that all inherit from a base abstract class called GameScreen. They include various buttons that, if pressed, I want to use to change the Current Screen. For now, I am trying to change the screen from startScreen to overviewScreen.
I have a variable in my Game1 class:
public GameScreen CurrentScreen;
Which is initially set as:
CurrentScreen = startScreen;
I then use the following lines to Update and Draw the game, based on which screen is the Current screen:
CurrentScreen.Update();
...
CurrentScreen.Draw(spriteBatch);
In my startScreen classs, I want to write something like this within the update method:
if (//Button is pressed)
{
game.CurrentScreen = overviewScreen;
}
Now clearly that won't work. But I can't see how to do it. Basically I want to access the CurrentScreen variable from within a class, and change it to whichever screen I want, and I feel like there must be a clean way to do this.
Let me know if any additional info is required, I feel like I haven't explained this at all well.
EDIT
startScreen and overviewScreen are classes that, primarily contain the Update and Draw methods for screens I want to display. GameScreen is a base class they all derive from. CurrentScreen is just meant to be a variable that determines which screen is active.
Ok, notw it's cleaner for me. You could add few methods to your Game1 class
public void SwitchToStartScreen(){...}
public void SwitchToOverviewScreen(){...}
//etc
Then you could add a property to your startScreen class (and other ones too)
public Game1 Parent {get;set;}
And force the constructor to pass Game1 object, in which you would assign that parameter to Parent property. Then on particular condition you could just use
Parent.SwitchToOverviewScreen();
Accessing and changing properties manually from outer classes is violating object-oriented principles.
Also, use brief naming convention, because it's hard to understand what you wrote if one of class definitions uses Pascal case while other use Camel case. Your startScreen has more like an object name, while it's used like a class name. Eithar that or you're not seeing the difference between class and an object.
By default in C# Pascal case is used for declaring classes.
use the static objects
public static GameScreen CurrentScreen;
and same for the overviewScreen
I'm trying to make a 2D game using C# (with XNA which is irrelevant to the problem). I've made a basic tile class from which all tiles in the game will inherit basic functions from, like how to draw itself onto the screen and such.
What I have is then a list of that base tile class which holds every single other class which inherits from the base class, I.E: Doors, Walls, Floor-tiles etc.
List<TileBase> tileList = new List<TileBase>();
...
tileList.Add(new Door(arguments));
tileList.Add(new Wall(arguments));
The problem comes later when I want to only affect a certain type of class inside that list. For example, the doors have certain functions for Open(), Close() and Toggle().
If I try to simply make a loop which loops through every Door class in my list:
foreach(Door door in tileList)
{
door.Toggle();
}
I get an error:
"Unable to cast object of type '...Tiles.Wall' to type '...Tiles.Door'."
So basically, I have a list full of different classes. How do I reach the specific functions in a class in a loop without making the program crash as it attempts it on another type of class which doesn't have said functions.
You could investigate the OfType method, it filters based on type:
using System.Linq;
...
foreach(var door in tileList.OfType<Door>())
{
door.Toggle();
}
You can iterate using base class and then check if the spesific object is instance of the Door class. If yes, cast to the Door object.
foreach(TileBase td in tileList)
{
if(td is Door)
{
((Door) td).Toggle();
}
}
foreach(Door door in tileList.where(a=>a is Door))
{
door.Toggle();
}
I've been learning C# over the summer and now feel like making a small project out of what I've done so far. I've decided on a sort of text based adventure game.
The basic structure of the game will involve having a number of sectors(or rooms). Upon entry into a room, a description will be outputted and a number of actions and such you may take; the ability to examine, pick up, use stuff in that room; possibly a battle system, etc etc. A sector may be connected up to 4 other sectors.
Anyway, scribbling ideas on paper on how to design the code for this, I'm scratching my head over the structure of part of my code.
I've decided on a player class, and a 'level' class that represents a level/dungeon/area. This level class would consist of a number of interconnected 'sectors'. At any given time, the player would be present in one certain sector in the level.
So here's the confusion:
Logically, one would expect a method such as player.Move(Dir d)
Such a method should change the 'current sector' field in the level object. This means class Player would need to know about class Level. Hmmm.
And Level may have to manipulate the Player object (eg. player enters room, ambushed by something, loses something from inventory.) So now Level also needs to hold a reference to the Player object?
This doesn't feel nice; everything having to hold a reference to everything else.
At this point I remembered reading about delegates from the book I'm using. Though I know about function pointers from C++, the chapter on delegates was presented with examples with a sort of 'event based' programming viewpoint, with which I did not have much enlightenment about.
That gave me the idea to design the classes as follows:
Player:
class Player
{
//...
public delegate void Movement(Dir d); //enum Dir{NORTH, SOUTH, ...}
public event Movement PlayerMoved;
public void Move(Dir d)
{
PlayerMoved(d);
//Other code...
}
}
Level:
class Level
{
private Sector currSector;
private Player p;
//etc etc...
private void OnMove(Dir d)
{
switch (d)
{
case Dir.NORTH:
//change currSector
//other code
break;
//other cases
}
}
public Level(Player p)
{
p.PlayerMoved += OnMove;
currSector = START_SECTOR;
//other code
}
//etc...
}
Is this an alright way to do this?
If the delegate chapter was not presented the way it was, I would not have thought of using such 'events'. So what would be a good way to implement this without using callbacks?
I have a habit of making highly detailed posts... sorry v__v
What about a 'Game' class which would hold the majority of the information like a Player and a current room. For an operation such as moving the player, the Game class could move the player to a different room based on the room's level map.
The game class would manage all the interactions between the various components of the games.
Using events for something like this brings the danger that your events will get tangled. If you're not careful you'll end up with events firing each other off and overflowing your stack, which will lead to flags to turn events off under special circumstances, and a less understandable program.
UDPATE:
To make the code more manageable, you could model some of the interactions between the main classes as classes themselves, such as a Fight class. Use interfaces to enable your main classes to perform certain interactions. (Note that I have taken the liberty of inventing a few things you may not want in your game).
For example:
// Supports existance in a room.
interface IExistInRoom { Room GetCurrentRoom(); }
// Supports moving from one room to another.
interface IMoveable : IExistInRoom { void SetCurrentRoom(Room room); }
// Supports being involved in a fight.
interface IFightable
{
Int32 HitPoints { get; set; }
Int32 Skill { get; }
Int32 Luck { get; }
}
// Example class declarations.
class RoomFeature : IExistInRoom
class Player : IMoveable, IFightable
class Monster : IMoveable, IFightable
// I'd proably choose to have this method in Game, as it alters the
// games state over one turn only.
void Move(IMoveable m, Direction d)
{
// TODO: Check whether move is valid, if so perform move by
// setting the player's location.
}
// I'd choose to put a fight in its own class because it might
// last more than one turn, and may contain some complex logic
// and involve player input.
class Fight
{
public Fight(IFightable[] participants)
public void Fight()
{
// TODO: Logic to perform the fight between the participants.
}
}
In your question, you identified the fact that you'd have many classes which have to know about each other if you stuck something like a Move method on your Player class. This is because something like a move neither belongs to a player or to a room - the move affects both objects mutually. By modelling the 'interactions' between the main objects you can avoid many of those dependencies.
Sounds like a scenario I often use a Command class or Service class for. For example, I might create a MoveCommand class that performs the operations and coordinations on and between Levels and Persons.
This pattern has the advantage of further enforcing the Single Responsibility Principal (SRP). SRP says that a class should only have one reason to change. If the Person class is responsible for moving it will undoubtedly have more than one reason to change. By breaking the logic of a Move off into its own class, it is better encapsulated.
There are several ways to implement a Command class, each fitting different scenarios better. Command classes could have an Execute method that takes all necessary parameters:
public class MoveCommand {
public void Execute(Player currentPlayer, Level currentLevel) { ... }
}
public static void Main() {
var cmd = new MoveCommand();
cmd.Execute(player, currentLevel);
}
Or, sometimes I find it more straightforward, and flexible, to use properties on the command object, but it makes it easier for client code to misuse the class by forgetting to set properties - but the advantage is that you have the same function signature for Execute on all command classes, so you can make an interface for that method and work with abstract Commands:
public class MoveCommand {
public Player CurrentPlayer { get; set; }
public Level CurrentLevel { get; set; }
public void Execute() { ... }
}
public static void Main() {
var cmd = new MoveCommand();
cmd.CurrentPlayer = currentPlayer;
cmd.CurrentLevel = currentLevel;
cmd.Execute();
}
Lastly, you could provide the parameters as constructor arguments to the Command class, but I'll forgo that code.
In any event, I find using Commands or Services a very powerful way to handle operations, like Move.
For a text-based game, you're almost certainly going to have a CommandInterpretor (or similar) object, which evaluates the user's typed commands. With that level of abstraction, you don't have to implement every possible action on your Player object. Your interpreter might push some typed commands to your Player object ("show inventory"), some commands to the currently-occupied Sector object ("list exits"), some commands to the Level object ("move player North"), and some commands to specialty objects ("attack" might be pushed to a CombatManager object).
In that way, the Player object becomes more like the Character, and the CommandInterpretor is more respresentational of the actual human player sitting at the keyboard.
Avoid getting emotionally or intellectually mired in what the "right" way to do something is. Focus instead on doing. Don't put too much value on the code you've already written, because any or all of it may need to change to support things that you want to do.
IMO there's way too much energy being spent on patterns and cool techniques and all of that jazz. Just write simple code to do the thing you want to do.
The level "contains" everything within it. You can start there. The level shouldn't necessarily drive everything, but everything is in the level.
The player can move, but only within the confines of the level. Therefore, the player needs to query the level to see if a move direction is valid.
The level isn't taking items from the player, nor is the level dealing damage. Other objects in the level are doing these things. Those other objects should be searching for the player, or maybe told of the player's proximity, and then they can do what they want directly to the player.
It's ok for the level to "own" the player and for the player to have a reference to its level. This "makes sense" from an OO perspective; you stand on Planet Earth and can affect it, but it is dragging you around the universe while you're digging holes.
Do Simple Things. Any time something gets complicated, figure out how to make it simple. Simple code is easier to work with and is more resistant to bugs.
So firstly, is this an alright way to
do this?
Absolutely!
Secondly, if the delegate chapter was
not presented the way it was, I would
not have thought of using such
'events'. So what would be a good way
to implement this without using
callbacks?
I know a lot of other ways to implement this, but no any other good way without some kind of callback mechanism. IMHO it is the most natural way to create a decoupled implementation.