RPG event handling

Started by
12 comments, last by DrZoidberg 19 years, 4 months ago
Hi all, I have been thinking a lot of how I would handle events in my RPG, but I can't really figure out how. If I create a world[40][30], and I have 2 merchants, one on world[25][35] and one on world[15][10], do I have to define the exact position of the main character on the moment he presses enter (open up the merchant menu) or can I do it some other way? It seems to me that if I would have to use some kind of switch(character.position) it would take ages to do in every single world. I am only asking for a general idea, code backup is always nice, but the idea is what I need :D Thanks, Joshua
-----------------------------Sismondi GamesStarted c++ in October 2004...
Advertisement
// when enter pressed ..
if( distance(player_pos, merchant_pos) <= 1 )
{
// open merchant menu
}

so you check if the player is standing next to a merchant (you'd have to check against every merchant you have in your game.. or any other npc..), you can calculate the distance using pitagora ( c = square_root( a^2 + b^2 )

...
struct pos { int x, int y };
...
int distance(pos a, pos b)
{
return sqrt( abs(pow((a.x - b.x),2)) + abs(pow((a.y-b.y),2)));
}


sorry for the brief post, i can explain it in more detail later if you wish
bye

[Edited by - paramecij on January 9, 2005 7:31:30 AM]
Event system....

What you need, is an event handling system....

Interesting, very interesting.

What you could do, is you store a singly linked list, which containts a pointer to type EVENT, which you then store the deatails of the event.

You then go, and check the list, everytime you want to see if an event happened.

Or you could use a sorted list.

What you basically want are a few functions.

Makeevent(*Event, *key);
Getevent(*key);
Unmakeevent(*key);

So, this would also sit perfectly with a hash table.

In this case the key would probably be a string saying "MERCHENTNEAR"
And the event would have the deatails of the event. (player is at x by y, ect.)

Keep everything modular.
From,
Nice coder
Click here to patch the mozilla IDN exploit, or click Here then type in Network.enableidn and set its value to false. Restart the browser for the patches to work.
ughh.. i think i misunderstood the question, so ignore my previous reply ;)

assuming you're using SDL, you already have an event handling loop, so you can put your custom events in the queue using SDL_PushEvent using SDL_UserEvent structure..


also you could ditch the event idea, and store a pointer to the NPC object in a tile of your world map(make a layer for objects & npc's), at keypress check the tile next to the player(in the direction the player is facing), if it's !=NULL (or whatever) call object->interact(); .. in that way if you had a base class object(perhaps entity would be a better word) with a virtual interact() method, and derive from it an npc,door,button,etc.. classes with their own interact() methods.. in that way the player could be standing next to a door and open it with enter, or could start an conversation, trading screen...

struct world_tile
{
..
base_object *obj; // object on that tile, set to NULL if empty ..
};


... damn,work calls again, later

Nice topic. I'm working on map events for my RPG right now as well. Here are some thoughts on what I'm thinking about doing. There are two types of events we need to check for. Move events (when you move to a new tile) and command events (when the user presses the confirm key).


First let me go into a very simple overview of the different members of my map class:

- a 2D vector containing structs of MapTiles, which hold information about each tile in the map. Things like pointers to the tile images, a bit mask, etc.

- a vector containing MapEvent objects. The MapEvent class holds information for any scripted events on a map.

- a list of MapObjects, which can be anything from an NPC sprite to a house, etc.


Move Events

1) When the user is moving and arrives on a new tile, I check the bit mask of that tile to see if it has an event associated with it.

2) If the event flag is set high, then I call a function that looks through the MapEvent list for an event corresponding to that tile. (Note that a single event may correspond to more than one tile ie, maybe you want an event to occur once the user walks on any tile through a gate that is more than one tile wide).

3) Once I've found that event, I check a flag to see if that event has been processed yet or not.

4) If the event hasn't occured yet, then I call up my Lua script which contains the map script event.

5) The Lua code executes the map event

6) When done, I set the flag for that event to false so I don't process it again.


You also need to keep in mind that when you exit the map and go to another part in the game world, and then come back to that map, you don't want to process those events again. So you need to keep some information about *each* map you've visited (this info would also need to be saved to a file when the user exits the game). So this is probably what we'd do when we'd come to a new map:

- Load the map information from the file
- Check your "game instance" class to see if you've visited the map before. If you have, set MapEvent flags appropriately



Command Events

1) Determine where your player sprite is facing (north, west, etc) and figure out what tile that corresponds to on your map.

2) Run through the MapObjects list to see if any NPC sprites are on that tile.

2a) If you find a sprite on that tile, process the dialogue event (ie, grab the dialogue string from the sprite and render it to the screen).

3) If there are no sprites, then look for other things like hidden treasures, etc.


****************************************************************


These are just some ideas I have, I'm not claiming they are good or anything. In the next week or so I should hopefully get a better idea of this stuff as I work on my map code. Once I get something that looks like it would work well, I'll make some code available (my game is open-source under the GPL). Till then I'll be keeping an eye on this thread. [smile]

Hero of Allacrost - A free, open-source 2D RPG in development.
Latest release June, 2015 - GameDev annoucement

nice ideas all of you! :D
my idea atm is to make a different event header for each world.
and put a check for events in a keyboard input loop.
Normally this should work,
but I guess I will only see once I try :D

If I have any problems I will post them here, and maybe even some screens if my friends do some nice artwork :D
-----------------------------Sismondi GamesStarted c++ in October 2004...
Quote:Original post by Joshnathan
nice ideas all of you! :D
my idea atm is to make a different event header for each world.
and put a check for events in a keyboard input loop.
Normally this should work,
but I guess I will only see once I try :D

If I have any problems I will post them here, and maybe even some screens if my friends do some nice artwork :D



Hmm? Are you talking about checking for input events from the user? The way I have that implemented is that there are several different "modes" for the game, things like boot mode, menu mode, map mode, battle mode, etc. I keep a stack of game modes, where the mode on the top of the stack is the active mode. Each mode processes user input in a different manner.

Why a game mode stack? Well, for example, imagine you are walking around on a map and a random encounter occurs, bringing you to battle mode. After the battle is over, you want to return to the original state of your map mode (ie, all map images are loaded, your player sprite is right where you left it, etc). So all we have to do is pop off the battle mode from the top of the stack and we are back to our original map mode state.

Each game mode has two different public functions: Update() and Draw(). So in my main game loop, I continuously call these two functions on the game mode that is on the top of the stack to process user input, update the state of the game, and draw the next frame to render to the screen.

If you like I could post some code illustrating the concept, though I doubt it's something that's never been done before.
Oops, that above post was me. [grin]

Hero of Allacrost - A free, open-source 2D RPG in development.
Latest release June, 2015 - GameDev annoucement

i agree with roots on this one, i too am working on a 2d rpg but i am using a
STL vector so it takes a little bit of work to get it to act like a stack because you have to read from the back, other then that though it works well because you dont have to worry about running out of room in your stack i just push back typedef'ed statements back and pop them off like so

if((rand()%30 == 1) && (battle == true))
{
V_Game_State.push_back(BATTLE);
V_Battle_State.push_back(_NORMAL);
};

this puts the battle flag into my normal state and pushes back the normal state into a kind of sub-vector that is used spacificly for battle and is .clear()'ed after every battle

hope i helped [smile]
____________________________"This just in, 9 out of 10 americans agree that 1 out of 10 americans will disagree with the other 9"- Colin Mochrie
why not just this.
where player.x and player.y are map positions not screen positions.

if (
(map[player.x-1][player.y] == MERCHANT) ||
(map[player.x+1][player.y] == MERCHANT) ||
(map[player.x][player.y+1] == MERCHANT) ||
(map[player.x][player.y-1] == MERCHANT)
) {
merchantMenu();
}

or even better use a vector of function pointers which relate to differnt objects in the map.

vector < void (*)() > events;

void merchant() {
// ...
}

void enemy() {
// ...
}

then push back the functions into the vector ...
events.push_back(merchant);
events.push_back(enemy);

now when you are testing against the objects all you need is this ...
for (int object = 1; object <= MAXOBJECTS; object++) {
if (
(map[player.x-1][player.y] == object) ||
(map[player.x+1][player.y] == object) ||
(map[player.x][player.y+1] == object) ||
(map[player.x][player.y-1] == object)
) {
events[object - 1]();
}

so if object is 1 then it will call the function merchant since we entered it into the vector first, then the next element is enemy so if object is 2 then the enemy function will be called ... etc

EDIT: i should add why you would use function pointers. basically for maintance and time, its quicker and eiaser to do this than ...

switch (object) {
case 1: merchant(); break;
case 2: enemy(); break;
}

and by using function pointers all you gotta do it push back another function into the events vector and its ready to go with any new event / object.
Woop woop woop woop!

This topic is closed to new replies.

Advertisement