This tutorial will tell you the very basic of how to do an MMORPG using mplay, however, a pretty good pre-knowledge is required.
Let us first think of what an MMORPG is. It is an online game with capability for lots of people. So basically, it’s any online game but with such coding that it can allow more people than usual. This is how we will think about it when we create our simple MMORPG engine. And if you know how to do online-games already, which is assumed since you are trying to do an MMORPG, the problem you will have to conquer is “how can we identify and share values for a large unknown number of players?” and the answer comes below. And some basics as well.
First of all, since this is a normal online game although it can accept more players we will not use a server. The one that hosts is the server for everyone else. And therefore just add basic connection / session create code when the host hosts.
mplay_init_tcpip(ip);
mplay_session_create(“MyMMORPG”,0,”Server”);
mplay_data_write(0,1);
global.myid = 1;
0 will make the session accept an arbitrary number of players, which is just what we want. Of course you also need to test whether your calls were successful, and if not, display an error message and so on, but I will leave such things up to you and focus on the mplay part. Next thing is to put in mplay_data_mode(true); such that when the original creator leaves the game, another player will host the game in his place. So the same session will continue to run into infinity as long as there is at least one player left in it.
Now when that code is executed, hopefully the player will have moved on into the gaming-area. So let’s see how we can join his session.
mplay_init_tcpip(ip);
mplay_session_join(0,”Client”);
global.myid = mplay_data_read(0)+1;
mplay_data_write(global.myid,1);
mplay_data_write(0,global.myid);
And then move on to next room… if everything was executed correctly, but again, you’ll have to add this yourself… if !(mplay…) /*End*/… We will need the global variable myid later, all our players will need specific ID’s or we will not know who does what. Using the mplay_data_write/mplay_data_read functions will ensure that into infinitive all players will always have an unique number. First player gets number 1, second player gets 1+1, third 2+1 etc. We also write to the index of global.myid, we set it to one. We will use this to control whether or not the player is still in the room.
Now both clients and the first one to start the game, called server will be redirected to the gaming area. This is where they will be able to play. We only use one room, where everyone can meet and chat. The room can be designed in any way, but do not put out players. We will need two objects only for all players in the world, one for you and one for everybody else. You can input yourself into the world if you wish to, or you can create him. But let’s put him in from the beginning and we can use him as an executing instance to initialize the other players. This will be his create event:
global.data = ds_map_create();
for (i=0; i<mplay_data_read(0); i+=1) {
if (mplay_data_read(i)) {
instid = instance_create(0,0,obj_player);
ds_map_add(global.data,i,instid);
}
}
Our datastructure now holds all instance id:s of all players in the game, and they are all created. However, other players that joined before you still can’t see you, so we’ll add you to their screen as well.
mplay_message_send(0,1,global.myid);
We will send a message and tell them that we need to create a new instance for a new player and that the unique number of that player is global.myid. Before we make the receivers create you we must however first devise a system for how the message’s ids are interpreted. Because each player will need to send some values later on, like x and y, and we have an unknown number of players and therefore an unknown number of messages and no message may have the same id. Therefore we need to figure out how we can make safe numbers.
Every player has an id of their own, say that we have 8 players and none has left then we the ids are 1, 2, 3, 4, 5, 6, 7 and 8. And they will send say 3 different values; x, y and sprite_index. Then we have 24 messages. And then we have some system-messages like the one above that tells everyone else to create an instance. I will use ids 0-99 for system-messages and I will have a pattern for the rest player-defined message ids. First message of player 1 will be 101, second 201, third 301 and so on. So for an example the fifth player will send his x-variable as id 105, his y as 205, and sprite_index as 305. I will use the same system for mplay data stacks. Now we know that id 1 is free for sure, and we reserve it for “create instance”-messages.
In step event of your player object, the player you are yourself, you can read the messages and take action like this:
mreceive = mplay_message_recieve(0);
mid = mplay_message_id();
mvalue = mplay_message_value();
if (mreceive && (mid==1)) {
instid = instance_create(0,0,obj_player);
ds_map_add(global.data,mvalue,instid);
}
And you can now see how you can easily add more messages to interpret. That is what we will do now, as we create the system which will synchronize all movements. I will not create a movement system or anything like that in this tutorial. I will just show you how to do mplay. But anyway, put this when you walk somewhere:
mplay_message_send(0,100+global.myid,x);
mplay_message_send(0,200+global.myid,y);
And when you change sprite, for an example if you start fighting or if you walk or anything like that which you can not figure out from client side (you must always try to figure things out from your side without any mplay, which we will discuss soon), you do this:
mplay_message_send(0,300+global.myid,sprite_index);
And then to your code you’ll add an action for each received message. You can make it look like this:
mreceive = mplay_message_recieve(0);
mid = mplay_message_id();
mvalue = mplay_message_value();
if (mreceive && (mid==1)) {
instid = instance_create(0,0,obj_player);
ds_map_add(global.data,mvalue,instid);
}
if (mreceive && (mid>100)) {
nid = string_char_at(string(mid),1);
player = string_char_at(string(mid),string_length);
if (nid==1) {
(ds_map_find_value(global.data,player)).x = mvalue;
}
if (nid==2) {
(ds_map_find_value(global.data,player)).y = mvalue;
}
if (nid==3) {
(ds_map_find_value(global.data,player)).sprite_index = mvalue;
}
}
I checked first whether the id was larger than 100, because this means it was not a system message. Then I intialize the variables nid and player, by reading the first number of the id (we know that 101 will send x, 204 will send y etc) and player by reading the last number of mid (since we know that mid originally was created by 100+global.myid, or 200+global.myid etc). Using values from the data structure that we earlier created we can find the instance corresponding to the player that sent the message. We can therefore now walk around and see each other.
Now is the time to do some discussion about what really needs to be transferred using mplay and what needs not. We don’t want to send more messages than we actually have to. All messages slow down a little, so the more we can do on our own the better. For an example, if you walk on a gold coin on the ground your player automatically picks it up (and destroys the coin object itself), then you would not need to send that info, instead you could put instance_destroy() in collision with obj_player, which would be the object to represent all the other players. Try to apply things like this as often as you can.
Another thing you need to think of is when to use data and when to use messages. Often changing values such as x and y might be better synchronize with messages, but stats such as the individuals attack and defence would better be synchronized with data. Here comes an example of how you could do to retrieve those stats of the player with id 5. We’re using the same system as with messages.
First this is how to write info, attack and defence for player five:
mplay_data_write(105,my_attack);
mplay_data_write(205,my_defence);
And to collect the data:
Player5attack = mplay_data_read(105);
Player5defence = mplay_data_read(205);
If you walk into a player and you don’t know what player it is, you can use the instance ID (called coll_id) to find out:
pos = ds_map_find_first(global.data);
for (i=0; i<ds_map_size(global.data); i+=1) {
if (ds_map_find_value(global.data,ds_map_find_next(global.data,pos))==coll_id) {
player = ds_map_find_next(global.data,pos);
} else {
pos = ds_map_find_next(global.data,pos);
}
}
PlayerAttack = mplay_data_read(real(“10”+string(player)));
PlayerDefence = mplay_data_read(real(“20”+string(player)));
}
So, now you can use both data and messages. And players are synchronized. You should have a basic understanding of how to create an MMORPG. Two things I guess remains for me to tell you, how to synchronize other moving things such as enemies or bears, and how to log off.
You can synchronize anything just as we have synchronized the players. But you’ll have to make a system for their messages as well. For an example, you are unlikely to have more than 50 players online at the same time, so 150-200, 250-300 etc. can be used for other message. So if you want to send a bear x, instead of 100+global.myid it would be 150+global.bearid. Also you would only want one to send out that information, and that would be the one who hosts. He has the “real bear” and the other just have one object that represents all bears. The real bear computes movements and sends it out. You create a bear the same way you create a player. When you create a session you can create a variable like global.master = true;, such that you later can check “if (global.master==true)… do server stuff”.
To log out you just need to send a message to everybody else that tells them to delete you from their data structure and deletes your instance. Then you need to do mplay_data_write(global.myid,0); and that’s it.
If you will try to construct an MMORPG step by step following this tutorial remember to think about what events and objects that I use, for I do not always say that. I require quite a lot knowledge from those who want to do this.
Good luck everyone!
If you want support on how to use this tutorial and bug-searching you must be specific in your comments! I would say there will be quite a little chance of helping you if you don't post your file or error message with very good explanation...
.
Users logged in:
Comments
Loading comments...