Temple of The Roguelike Forums
Development => Programming => Topic started by: chasm on September 24, 2013, 10:12:01 AM
-
I know how to implement some basic RL components such as displaying characters in a terminal and make them moving or different kinds of dungeon algorithms. I have also written a lot of numerical programs, so it's not like I'm a complete beginner.
But when it comes to actual gameplay, I'm stuck how to do this.
Things like how (vectors, arrays, etc.) to store information about tiles (like open/closed for a door or traversable/non-traversable, etc.) or loading a new dungeon when leaving the screen, etc. So actually things that are not unique to roguelikes, but are necessary for games in general.
I haven't found any tutorial that stresses such concepts in a more general fashion, i.e. simply the ideas how to do this rather than giving instructions how to write this in a certain programming language with a certain library.
Do you know any good tutorials or even a book about this?
What would you consider the best to begin with?
I have thought about writing something similar to interactive fiction, just to get an idea how to implement acting within the game, would this be a reasonable start?
Thank you in advance.
-
Interesting question. It's true you won't see too many tutorials approach things in a totally language-agnostic way.
However your post is a bit paradoxical. You want tutorials that talk about things in a general way, but your example (vectors, arrays, etc.) is implementation details of specific languages.
Have you gone through a complete roguelike tutorial like the Python one at Roguebasin? Many times what seems obvious in observation (i.e. skimming through a tutorial) is only learned through practice (i.e. actually doing the tutorial).
-
You could try using an existing engine such as T-Engine. I believe you could make an interactive fiction game using the engine easily, just making dialogs and buttons.
-
The implementation details don't really matter. Pick one approach (like storing the dungeon as an array of chars, or a dictionary of Points and Tiles, or a 2d array of Terrain instances) and play with it for a while. As long as it's encapsulated and other code isn't looking into the details of it, you'll be able to change it when you need to. Clean code hides those details anyway. So I often have a World class with methods like isOpenDoor(x,y), isClosedDoor(x,y), blocksVision(x,y), getCreature(x,y), etc. How that's handled within the Wold class (vector, arrays, etc) doesn't really matter and if it does (performance reasons, torus shaped worlds, blood splatters, etc) then I swap the implementation out for something more complex.
-
However your post is a bit paradoxical. You want tutorials that talk about things in a general way, but your example (vectors, arrays, etc.) is implementation details of specific languages.
I think such a tutorial should specify ideas at some point. You need to store information about tiles, like position, properties, etc., so I think there also should be examples how to do that, array was my first idea (a vector is just similar idea-wise), maybe there are other (and better or more general) methods. But with the information “You need to store information” only, it's too general and diffictult to actually implement.
Have you gone through a complete roguelike tutorial like the Python one at Roguebasin? Many times what seems obvious in observation (i.e. skimming through a tutorial) is only learned through practice (i.e. actually doing the tutorial).
I have read through the one that uses the libtcod library. However, I didn't find it useful to understand game programming profoundly. There were a couple of things that were already implemented within the library, so it wasn't explained how exactly this was coded and why it was done like that.
You could try using an existing engine such as T-Engine. I believe you could make an interactive fiction game using the engine easily, just making dialogs and buttons.
I don't want to use existing engines as they already have implemented those thing I want to understand.
I'm actually not really interested in interactive fiction either, but I thought that writing something simple like that could help me understand the processes behind.
The implementation details don't really matter. Pick one approach (like storing the dungeon as an array of chars, or a dictionary of Points and Tiles, or a 2d array of Terrain instances) and play with it for a while. As long as it's encapsulated and other code isn't looking into the details of it, you'll be able to change it when you need to. Clean code hides those details anyway. So I often have a World class with methods like isOpenDoor(x,y), isClosedDoor(x,y), blocksVision(x,y), getCreature(x,y), etc. How that's handled within the Wold class (vector, arrays, etc) doesn't really matter and if it does (performance reasons, torus shaped worlds, blood splatters, etc) then I swap the implementation out for something more complex
Your short explanation quite describes what I'm looking for, like those examples you mentioned.
I just need something to begin with.
-
I think such a tutorial should specify ideas at some point. You need to store information about tiles, like position, properties, etc., so I think there also should be examples how to do that
You are talking about save and load game, right? It really is implementation specific. In C++ and with classes it's actually quite easy, when you build the structure of game as tree-like, with possibly Game World class as the owner of everything else. Each class is going through the stuff that needs to be saved and that process is reversed in loading. Although there can be some issues in loading, when you need to construct empty objects and then fill them with saved data (but they can be solved of course).
You can look at the source code of Teemu to see how I did save/load game. It can be downloaded from the home page of the game:
http://koti.mbnet.fi/paulkp/teemu/teemu.htm
Look at Save and Load functions in classes. They are all using Tar_Ball class to store information in hybrid binary/text format.
-
I think george was right to call your question paradoxical. You ask about general concepts like storing game objects information and not implementation details. Yet those are exactly what implementation details of some specific game are. For example, game may have or may not have any tiles -- this will influence inner logic tremendously, both data- and algorithm-wise. There may be or may not be any doors to open and close. Whether there will be a new dungeon to load when leaving the screen is also up to you. There are multitude of options. So you cannot just wave this point aside as something 'oh i just meant similar idea-wise'. All these design choices together are the game itself.
That's why your question looks like "any tutorial on concepts about everything?".
Try to write several mock-ups. For example, trivial ping-pong game and simplest one-screen one-level rogue-like. You'll see there are almost no similarities. You can't expect any tutorial on the subject this broad.
-
I think such a tutorial should specify ideas at some point. You need to store information about tiles, like position, properties, etc., so I think there also should be examples how to do that, array was my first idea (a vector is just similar idea-wise), maybe there are other (and better or more general) methods. But with the information “You need to store information” only, it's too general and diffictult to actually implement.
But it's true - what matters is that the information gets stored, not how it gets stored (notwithstanding good programming practices).
You could store every tile as a single integer or a char in a multidimensional array and that will work fine. Open a door and that tile's variable changes from the closed door value to the open door value. You could make your tiles objects with isPassable, isDoor, isOpen, etc. variables for each one and that would work too. You could program doors so that they're special objects on tiles instead of being the tiles themselves. There are any number of possible implementations.
Is any specific thing giving you trouble?
-
Ok, I think I got it now, I have just hoped that there acutally would be something 'general' to begin with.
So it's difficult to specify the question I originally asked.
Although your short explanations already helped me.
You are talking about save and load game, right? It really is implementation specific. In C++ and with classes it's actually quite easy, when you build the structure of game as tree-like, with possibly Game World class as the owner of everything else.
This approach sounds comprehensible. I surely will give it a try to follow your code you mentioned.
That's why your question looks like "any tutorial on concepts about everything?".
Yes, I now admit that it actually reads like this.
I was mostly referring to concepts that are used by traditional roguelikes. But now I see that even then there are plenty of possibilities do implement this.
You could store every tile as a single integer or a char in a multidimensional array and that will work fine. Open a door and that tile's variable changes from the closed door value to the open door value. You could make your tiles objects with isPassable, isDoor, isOpen, etc. variables for each one and that would work too. You could program doors so that they're special objects on tiles instead of being the tiles themselves. There are any number of possible implementations.
This also sounds very comprehensible and a good approach to begin with.
Do you know by chance a text-based roguelike that uses this approach?
Is any specific thing giving you trouble?
Currently, it's basically those examples I mentioned, because I know how to make the hero move and how to generate a dungeon (classical terminal output). It's how to make him interact within the dungeon and its objects.
Moreover I don't want to simply implement something, but also understand why and how it is working.
-
Currently, it's basically those examples I mentioned, because I know how to make the hero move and how to generate a dungeon (classical terminal output). It's how to make him interact within the dungeon and its objects.
Moreover I don't want to simply implement something, but also understand why and how it is working.
Alright, well the best way to handle that depends on what you want to do. If your game is pretty simple and tiles don't do anything too wacky, you could make a two dimensional array for each floor, with the array's dimensions being the maximum width and the maximum height of a floor in your game. Something like this:
int tile[MAX_SIZE_X][MAX_SIZE_Y];
or if you wanted persistent floors, maybe this instead:
int tile[MAX_FLOORS][MAX_SIZE_X][MAX_SIZE_Y];
Then elsewhere you'd have constant values for each type of tile in your dungeon. Maybe EMPTY_FLOOR is 0, WALL is 1, OPEN_DOOR is 2, CLOSED_DOOR is 3, etc.
So let's say that the player/a monster/whatever uses the open command on coordinate 12,16, which is a closed door. Your function might look something like this:
bool openDoor(int targetX,int targetY) {
// If the action is unsuccessful, this should not consume the actor's turn. If it's a monster, their AI needs to select a different action.
// If it's the player, we can display a message about how they tried to open a wall or whatever.
bool actionSuccessful;
// If the tile is a closed door, we allow the actor to open it
if(tile[targetX][targetY] == CLOSED_DOOR) {
tile[targetX][targetY] = OPEN_DOOR;
actionSuccessful = true;
} else {
actionSuccessful = false;
}
return actionSuccessful;
}
So the game will see that the value stored in tile[12][16] is 3, because that is the value we have associated with closed doors. It will check whether that value matches the value for closed doors, and since it does, the game will change the value of tile[12][16] to 2, because that is the value we have associated with open doors. Then it will set actionSuccessful to true and return the value of true so that the function that called this one will know that the door-opening attempt succeeded.
Maybe you'd want to add additional bits to check whether the actor in question is capable of opening doors at all, but you get the idea.
If you want your tiles to be more complex or more varied, making each tile an object would be a better idea. That way each tile can have an "openable" variable, and your open door function will check for that instead. Then you can have the function work for multiple door types without having to resort to this:
if(tileType == CLOSED_STONE_DOOR || tileType == CLOSED_WOODEN_DOOR || tileType == CLOSED_METAL_DOOR) {
// Do whatever
}
instead you'd do
if(tile[targetX][targetY].openable == true) {
// Do whatever
}
And then it'd be easy to give every tile the properties you want. The burnable variable for wooden doors is set to true, but for metal doors it's false. You could make the wooden door a member of the wooden tiles class, which is a subclass of tiles where burnable is always set to true. Or you could have a variable for a tile's material and set it to equal a WOOD constant, which would mean the tile is burnable, and breakable if your character has enough attack power, and so forth.
If every wooden door is identical to every other wooden door (like, you can't carve anything into them and you can't partially damage them without breaking them or whatever), then another possibility is to combine the two implementations I've suggested above. Make one object in the tiles class for each type of tile in the game. So one object for empty floors, one object for stone walls, etc. Then assign a constant number to each tile type.
That will allow you to make an array of integers for each tile in the game, and the value stored in the array is the number associated with the appropriate tile type. So if the constant value for EMPTY_FLOOR is 0 and the tile at 25,19 is an empty floor, you'd set tile[25][19] to 0 and then whenever anything in the game needs to interact with 25,19, it'd look up its value in the array, see that its value is 0, and thus it is an empty floor, and from that point on the game would read whatever information it needs from the empty floor object's variables.
Does that make sense? Is it the sort of thing you're looking for help with?
I'm sure there are people here who are much better at programming than I am. If someone posts that I'm the worst coder of all time and my example code makes them want to gouge their eyes out, they're probably right and you should use their suggestions instead.
-
Wow, this is great, thanks a lot.
I guess, I got the idea (or just an idea) how to set tile properties via integers and functions.
I haven't responded yet as I've been trying to implement it to show the result here, but I'm having some minor problems with ncurses and key capture.
I have begun with just one (simple) dungeon, the hero moving around and opening doors. I will put the code here, when I have succeeded.
I also made a boolean fuction similar to the door opening one above to determine wether a tile is passable or not.
-
Ok, I still cannot get the code working. Maybe there's someone here more capable of ncurses and C who likes to give me some input.
Nevertheless, I put my code here, maybe I used some wrong approaches in the first place.
#include<stdio.h>
#include<stdbool.h>
#include<time.h>
#include<ncurses.h>
#define MAX_X 40
#define MAX_Y 70
int tile[MAX_X][MAX_Y];
// Tile Properties:
const int empty = 0;
const int wall = 1;
const int open_door = 2;
const int closed_door = 3;
const int locked_door = 4;
const int hero = 5;
// Passable objects
bool Passable(int tx, int ty)
{
bool successful;
if(tile[tx][ty]==empty || tile[tx][ty]==open_door)
{successful = true;}
else
{successful = false;}
return successful;
}
// Move
void Move(int x, int y)
{
if (tile[x][y]==hero)
{
if(Passable(x,y+1)==true)
{tile[x][y] = tile[x][y+1];}
if(Passable(x-1,y)==true)
{tile[x][y] = tile[x-1][y];}
if(Passable(x+1,y)==true)
{tile[x][y] = tile[x+1][y];}
if(Passable(x,y-1)==true)
{tile[x][y] = tile[x][y-1];}
else
{mvaddstr(0,0,"You cannot pass");}
}
}
// Open Doors
bool OpenDoor(int tx, int ty)
{
bool successful;
if(tile[tx][ty]==closed_door)
{
tile[tx][ty] = open_door;
successful = true;
mvaddstr(0,0,"The door is opened");
}
else
{
successful = false;
if(tile[tx][ty]==empty || tile[tx][ty]==wall)
{mvaddstr(0,0,"There is no door to open");}
if(tile[tx][ty]==open_door)
{mvaddstr(0,0,"The door is already open");}
if(tile[tx][ty]==locked_door)
{mvaddstr(0,0,"The door is locked");}
}
return successful;
}
// Generate the dungeon
void MakeMap()
{
for (int x=1;x<=MAX_X;x++)
{
for (int y=1;y<=MAX_Y;y++)
{
tile[x][y]=empty;
int x0 = MAX_X/2;
int y0 = MAX_Y/2;
tile[x0][y0]=wall; //begin at (x0,y0)
for (int i=0;i<=N;i++)
{
// here should be a dungeon algorithm
// just make some random distribution of
// tile[x][y]=empty;tile[x][y]=closed_door;tile[x][y]=wall;
}
}
}
}
// Put the hero
void Hero()
{
tile[MAX_X/2][MAX_X/2]=hero;
}
void ShowMap()
{ //ncurses stuff here
initscr();
start_color();
clear();
cbreak();
noecho();
for (int ix=1; ix<MAX_X;ix++)
{
for (int iy=1; iy<=MAX_Y;iy++)
{
switch(tile[ix][iy])
{
case 0:
mvaddstr(ix,iy,"#");
break;
case 1:
mvaddstr(ix,iy,".");
break;
case 2:
mvaddstr(ix,iy,"/");
break;
case 3:
mvaddstr(ix,iy,"+");
break;
case 4:
mvaddstr(ix,iy,"+");
break;
case 5:
mvaddstr(ix,iy,"@");
break;
}
}
}
refresh();
getch();
}
void Action()
{
//starting point
int x = MAX_X/2;
int y = MAX_Y/2;
wmove(stdscr,x,y);
keypad(stdscr, true);
int key=getch();
while (key != 'q')
{
switch(key)
{
case 'KEY_DOWN':
Move(x,y+1);
break;
case KEY_LEFT:
Move(x-1,y);
break;
case KEY_RIGHT:
Move(x+1,y);
break;
case KEY_UP:
Move(x,y-1);
break;
case 'h':
OpenDoor(x-1,y);
break;
case 'j':
OpenDoor(x+1,y);
break;
case 'u':
OpenDoor(x,y-1);
break;
case 'n':
OpenDoor(x,y+1);
break;
case 'q':
endwin();
default:
mvaddstr(0,0,"Press 'q' to quit");
break;
}
}
}
int main()
{
srand(time(0));
MakeMap();
Hero();
ShowMap();
Action();
return 0;
}
-
Ok, I still cannot get the code working. Maybe there's someone here more capable of ncurses and C who likes to give me some input.
Nevertheless, I put my code here, maybe I used some wrong approaches in the first place.
To get help with problems in code and software, it's best to provide specific information about what went wrong - no-one can say much about something that "doesn't work", but if you say what doesn't work, when, whether there was an error message at runtime or compile time, what the error messages were, etc., then often there will be someone who's had a similar problem in the past.
Sticking to that advice will make learning to program much smoother, and will get problems solved much quicker online. Stackoverflow (http://stackoverflow.com) is a great model of this kind of interaction.
-
Making "hero" a tile type is a Real Bad Idea. It's confusing and it'll lead to more than a few problems. Instead you should have heroX and heroY integers to track their location. Better yet, make arrays of integers to store the x and y locations of every man, animal, and monster in the dungeon.
Even though programming a game is about manipulating abstract data, imo the best way to do it is to think about everything in terms of concrete nouns and verbs (with objects and variables being nouns and functions/methods being verbs). The tile array describes different segments of the building the game is taking place in. That description doesn't fit the hero, so he or she shouldn't be tracked by that variable.
-
I'm up to a few thousand lines of code already into my project and so far using tables to keep track of everything seems to be working out:
;pWorldTable coords from (0,0) to (4 Billion,4 Billion)
; DWORD,DWORD == # entries,ID# of active area (used to calculate which WX,WY to -> to)
; DWORD,DWORD == WorldX,WorldY our first area starts at (2 Billion, 2 Billion)
; DWORD,DWORD == pLocalTable,RESERVED
; DWORD,DWORD == WorldX,WorldY
; DWORD,DWORD == pLocalTable,RESERVED
; etc.
;
; pLocalTable coords start from (0,0) to (width of window,height of window)
; DWORD == <RESERVED>
; DWORD == MobsTable
; DWORD == StructsTable
; etc.
;
; pMobsTable
; DWORD,DWORD == # mobs,<RESERVED>
; DWORD,DWORD == X|Y,pChar pointer to char/mob/item detail sheet
; DWORD,DWORD == X|Y,pChar pointer to char/mob/item detail sheet
; etc.
;
; pStructsTable
; DWORD == RESERVED
; DWORD == pStructure
; DWORD == pStructure
; ...
; ...
; 0
;
; pStructure
; DWORD,DWORD == RESERVED, RESERVED
; DWORD,DWORD == RoomX|RoomY,RoomW|RoomH
; DWORD,DWORD == WallX|WallY,pChar pointer to char/mob/item detail sheet
; DWORD,DWORD == WallX|WallY,pChar pointer to char/mob/item detail sheet
; etc.
I use nested tables, so for instance my WorldTable contains a bunch of LocalTables and each LocalTable contains a MobTable, StructsTable and soon an ItemsTable. And each MobsTable would list an X,Y and it's corresponding pointer to a Character Sheet of the mob/item at that location.
And everything, you, the mobs and even a piece of the wall in a structure has their own Character Sheet:
;Char sheet offsets
OFFSET_MOB_OBJ_ID equ 0
OFFSET_MOBSPEED equ 4
OFFSET_NAME equ 8
OFFSET_SYMB equ 12
OFFSET_COLOR equ 16
OFFSET_ALTCOLOR equ 20
OFFSET_VISIBLE equ 24
OFFSET_MOBMEM equ 28
OFFSET_MOBMEM_COMBATANT equ 0
OFFSET_MOBMEM_NUMSTEPS equ 4
OFFSET_MOBMEM_ENCCS equ 8
OFFSET_MOBMEM_ORIGPATH equ 12
OFFSET_MOBMEM_ALTPATH1 equ 16
OFFSET_MOBMEM_ALTPATH2 equ 20
OFFSET_MOBMEM_DMGMSG equ 24
OFFSET_FONTWH equ 32
OFFSET_STATS equ 36
OFFSET_HPCURRHP equ 40
OFFSET_ALLEGIANCE equ 44
OFFSET_WEAPON equ 48
OFFSET_DOORWAY equ 52
OFFSET_BgXY equ 56
OFFSET_STATUS equ 60
OFFSET_STATUSMSG equ 64
To keep it simple I'm just using a single character sheet for everything so not all the fields would be used by some things so I'm wasting quite a few bytes for sure but OTOH if I decide later on to implement destructible environments, the HP field is already in place for me to use for the walls for instance.
I'm using Assembly btw so I don't know if any of this would apply at all in an OOP language.
-
show-off ;D
-
Assembly? That's sort of like Gamemaker, right? :P
-
I thought Assembly was for Noobs ? LOL
-
To get help with problems in code and software, it's best to provide specific information about what went wrong - no-one can say much about something that "doesn't work", but if you say what doesn't work, when, whether there was an error message at runtime or compile time, what the error messages were, etc., then often there will be someone who's had a similar problem in the past.
You're totally right. I was just thinking it might not be an ncurses thing, but rather a problem of the implementation itself. So maybe someone who never used ncurses might be able to help as well.
This is the actual error that I don't understand:
I used getch() to capture the keyboard input, however it will only return "Press 'q' to quit", even when a key is pressed that I defined to do something else (like the arrow keys or u, h, n, j).
Even though I implemented while (key != 'q') in the function Action(), the program terminates after the second key is pressed.
Making "hero" a tile type is a Real Bad Idea. It's confusing and it'll lead to more than a few problems. Instead you should have heroX and heroY integers to track their location. Better yet, make arrays of integers to store the x and y locations of every man, animal, and monster in the dungeon.
I worried about that, too. Would it make sense to write a function like GetLocation() that returns both coordinates? I actually wanted to do this at first, but I didn't really know how to do that (if it makes sense, I will again try to implement it by myself), so I chose the simplest thing I could think of.
What do you mean by arrays of integers? I would have rather thought about a list or a 2-dim. vector. Could you give an example?
Even though programming a game is about manipulating abstract data, imo the best way to do it is to think about everything in terms of concrete nouns and verbs (with objects and variables being nouns and functions/methods being verbs). The tile array describes different segments of the building the game is taking place in. That description doesn't fit the hero, so he or she shouldn't be tracked by that variable.
This is very interesting.
I've never thought like that. I admit that I rather have a hard time to actually imagine variables and functions like this as I still think of (tile) arrays as tensors rather than actual maps.
But as I'm still a beginner with game programming, I'm not beyond hope, I think.
-
To get help with problems in code and software, it's best to provide specific information about what went wrong - no-one can say much about something that "doesn't work", but if you say what doesn't work, when, whether there was an error message at runtime or compile time, what the error messages were, etc., then often there will be someone who's had a similar problem in the past.
You're totally right. I was just thinking it might not be an ncurses thing, but rather a problem of the implementation itself. So maybe someone who never used ncurses might be able to help as well.
This is the actual error that I don't understand:
I used getch() to capture the keyboard input, however it will only return "Press 'q' to quit", even when a key is pressed that I defined to do something else (like the arrow keys or u, h, n, j).
Even though I implemented while (key != 'q') in the function Action(), the program terminates after the second key is pressed.
That error sounds a lot like the errors I get when I forget to put breaks in a switch statement and indeed, searching for "press" in your code I found just that:
...
case 'n':
OpenDoor(x,y+1);
break;
case 'q':
endwin();
/* add "break;" here */
default:
mvaddstr(0,0,"Press 'q' to quit");
break;
...
-
Good catch, Quendus.
I worried about that, too. Would it make sense to write a function like GetLocation() that returns both coordinates?
It would be easier to make one function for each coordinate instead. Make a getLocationX() and a getLocationY() and just call them one after the other to get a pair of coordinates.
What do you mean by arrays of integers? I would have rather thought about a list or a 2-dim. vector. Could you give an example?
The arrays I'm thinking of would look something like this:
int actorLocationX[MAX_ACTORS];
int actorLocationY[MAX_ACTORS];
And then just assign everything a number when they spawn. The hero will probably spawn first, so they're number zero. Personally, I'd reserve the number zero slot for them just so you can always easily interact with the hero's data if you need to.
Anyway, in that system you could have something like this:
// We want to know where a given character is.
void printActorLocation(int actorNumber) {
int targetX = getLocationX(actorNumber);
int targetY = getLocationY(actorNumber);
std::cout<<"Actor number " <<actorNumber<<" is located at "<<targetX<<", "<<targetY";
}
// Returns the x coordinate of a given character
int getLocationX(int targetNumber) {
return xLocation[targetNumber];
}
// Returns the y coordinate of a given character
int getLocationY(int targetNumber) {
return yLocation[targetNumber];
}
Something like that.
A vector should be able to accomplish the same thing, my understanding is that they're more or less the same thing, but the size of an array is constant and the size of a vector can change. I could be wrong.
Another method, and probably a better one, would be to make a class containing the hero and all the monsters and NPCs and such and then referring to them through that.
Something like this:
class Actor {
// Whether the actor is alive and active
bool alive;
// The actor's name
string actorName;
// The actor's health
int maxHealth;
int health;
// The actor's location
int xLocation;
int yLocation;
void displayHeroData();
void displayActorData(Actor);
};
// I'm not going to assign the hero a location or any stats in this example, but pretend we did that at some point
Actor hero;
// Prints data for the hero specifically
Actor::displayHeroData(){
std::cout<<"The hero has "<<hero.health<<"/"<<hero.maxHealth<<" hit points.\n";
std::cout<<"They are located at "<<hero.xLocation<<", "<<hero.yLocation<<".";
}
// Prints data for any actor. This could also be used to display the hero's data
// In a real program, you would never want to include both this function and the one above it. It's redundant.
Actor::displayActorData(Actor currentActor){
std::cout<<currentActor.actorName<<" has "<<currentActor.health<<"/"<<currentActor.maxHealth<<" hit points.\n";
std::cout<<"They are located at "<<currentActor.xLocation<<", "<<currentActor.yLocation<<".";
}
Hopefully those examples are useful. I didn't bother to specify which parts of the class are private, protected, or public to keep the example simple, but you'll want to practice encapsulation in your own programs.