19.04.2013, 12:41
(
Last edited by Yashas; 09/07/2015 at 04:05 PM.
)
Efficient Multiple Spawning System
What is this??
If you have more than one spawn point in your spawning system for each city, this is an optimized system that will find the correct spawn point from an array of spawn points to avoid players from flooding at the same spawn.This system follows an algorithm to compute the right spawn point.
The Purpose of the Tutorial:
I've seen many gamemodes that have a lengthy code and inefficient method for spawning players.Even the sample gamemode in the SAMP Server, "Grand Larency" does it in an unoptimized way.Here is my method that will find the spawn point in just 3-4 lines.Instead of using long, lengthy,CPU Consuming switch case or if...else.
What will this system do:
You will've an array of spawn points of different regions.You can have unlimited regions and unlimited spawn points.Region here, means a large area of the map,for example LV,SF,LS.You will have a constant number of spawn points for each region in the array(Will be discussed later).What my system does is, it returns the array index of a spawn point(the index is not random, it gives an appropriate index for avoiding flooding of players) from the spawn point array which belongs to the region that was asked.
Pros and Cons(Advantages & Disadvantages):
Positives:
*Does not repeat the spawn point for the next spawning player until the count is reset
*Easier to read the code, reduces the code drastically.
*Easy to understand, simple knowledge is required to use.
*Can be implemented before you start your game mode and later add contents to it.
*Unlimited Regions and Spawn Points
*Avoids players bumping at one point
Negatives:
*All the spawn points must be in one single array.Might reduce the readability of the code.
*There has to be constant number of spawn points in each region(If you have variable spawn points for different regions, then add the spawn points of the same region again at the end such tat the number of spawn points in every region becomes constant)
How to develop it??
For this tutorial I will use 3 regions(namely LS,SF,LV) and 10 different spawn points for each region(my own spawn points :P ).It's your wish to have as many number of regions and spawn points per region.
Step 1:Setting up the regions
First let's define an ID for each of the region.You have to keep the flow of the define continuous.It has to be in a arithmetic progression with common difference 1(It means the ID should be without gaps, like 0,1,2,3,4 not 1,3,4,6).Also the first region ID should be 0 and +1 for each extra region.
You can define the ID in two ways: using defines,using enums
1.Using #define
Here, where ever we use SPAWN_LS or SPAWN_SF or SPAWN_LV in the code,the value defined in the define directive will be substituted by the compiler.This mainly increases readability of the code and helps avoid silly mistakes.
If you are new to #defines, I suggest you to go through this tutorial by Y_Less(a.k.a ColeMiner).
Ex:a = SPAWN_SF + 1; during compile time it the compiler will substitute the value of SPAWN_SF so it will be a = 1 + 1 since the value of SPAWN_SF is 1.
Using Enumeration
This too does the same.In an enumeration the first variable must be given a value and the remaining variables will have an incremented value of the variable behind it.So here,SPAWN_SF will be 1 (SPAWN_LS + 1) and SPAWN_LV will be 2(SPAWN_SF + 1).
If you are new to enumerations, I suggest you to go through this tutorial by iPLEOMAX.
Use either #define or enumeration, not both.Using both will create errors.
Step 2:Creating spawn points for the regions
The next step is to create different spawn points for each region.
I have collected 10 spawn points for each region.You can make your own spawn points(unlimited spawn points).
You have to write all the spawns in a particular format for my algorithm to work.I will explain it in the next part what it is and how it works.The format is given below.
NOTE:The number of spawn points for each region should be same.If you have unequal number of spawn points for each region then add an existing spawn point of that region twice to get the number of spawns per region equal.
You have to arrange them according to the number you defined each region in this format:
Why '[][4]'??That 4...
Its because every location in San Andreas is written X,Y,Z and the 4th is the Rotation or Facing Angle.It determines the angle at which the player is facing or simply you can say it tells where your tiny player marker in your radar will be pointing to.Therefore, its very important.You'd not like you player spawn facing to a big wall which would be annoying!
Why 'const'?
const is a keyword in PAWN that makes the variable(not literally, it cannot be varied, so its not a variable) unchangeable.Also its faster than variables declared using new.
If you are new to this keyword then refer this page.
Here are my collection of Spawn Points.
10 for each region
Step 3: Declaring Variables to count the spawns
Now you'll need to create one more array of variables that will hold the index of the last used Spawn Point so that the next player who wants to spawn doesn't get the same spawn point(this is to avoid flooding players at the same spawn point and also to avoid a bug where 2 or more players spawn inside each other and get stuck).This variable will be incremented every time a spawn point is used and will be reset when it reaches the last spawn point.
Step 4:Computing the index
This is the part where all the computation will be carried out for determining the correct spawn point.
This function will find the next spawn point of that region and return it.
To keep things neat and readable I will define a few more things.
Parameters:
spawn_region = The REGION where the next spawn point must be.If we give the spawn_region as SPAWN_LV then we'll get a next spawn point that is in LV.
Returns:
The index of the spawn point form the spawns array.The index returned will be a spawn point that belongs to the given region.
The formula for finding the index is = (MAX_SPAWNS_PER_REGION * SPAWN_REGION) + SPAWN_COUNT;
As there are 10 spawn points for each region defined (here in the example script) ,according to the format and the code, every 10 entries in the array belongs to each region.So multiplying 10 with the region ID will give the first entry of the requested region in the array.Later adding the SpawnCount will give an index of the spawn point which is different from a spawn point that was used while spawning the previous player.What if the SpawnCount goes more than the MAX LIMIT??To overcome this problem,the spawn count must not go more than the limit.Hence we reset the counter to 0 every time it reaches the max limit.
The formula is applied and the result is stored in variable i.
The respective SpawnCount variable is incremented so that next player doesn't get the same spawn point once again.
Then the SpawnPoint is checked if it has reached the last spawn point for that region and if so it is reset to 0.
And the index is returned.
This will give us the correct index that we need to use from the spawn points array.
Step 5:Processing the returned index to spawn
We now need to spawn the player using the index that was returned by the function.
SetSpawnInfo is a SA:MP native function that sets the player spawn position.We need to provide it with the X,Y,Z co-ordinates of the spawn point.We will use the index returned by GetSpawnIndex and give the correct set of spawn points.
Final Code
The final code should look somewhat like this
Notes:
What is this??
If you have more than one spawn point in your spawning system for each city, this is an optimized system that will find the correct spawn point from an array of spawn points to avoid players from flooding at the same spawn.This system follows an algorithm to compute the right spawn point.
The Purpose of the Tutorial:
I've seen many gamemodes that have a lengthy code and inefficient method for spawning players.Even the sample gamemode in the SAMP Server, "Grand Larency" does it in an unoptimized way.Here is my method that will find the spawn point in just 3-4 lines.Instead of using long, lengthy,CPU Consuming switch case or if...else.
What will this system do:
You will've an array of spawn points of different regions.You can have unlimited regions and unlimited spawn points.Region here, means a large area of the map,for example LV,SF,LS.You will have a constant number of spawn points for each region in the array(Will be discussed later).What my system does is, it returns the array index of a spawn point(the index is not random, it gives an appropriate index for avoiding flooding of players) from the spawn point array which belongs to the region that was asked.
Pros and Cons(Advantages & Disadvantages):
Positives:
*Does not repeat the spawn point for the next spawning player until the count is reset
*Easier to read the code, reduces the code drastically.
*Easy to understand, simple knowledge is required to use.
*Can be implemented before you start your game mode and later add contents to it.
*Unlimited Regions and Spawn Points
*Avoids players bumping at one point
Negatives:
*All the spawn points must be in one single array.Might reduce the readability of the code.
*There has to be constant number of spawn points in each region(If you have variable spawn points for different regions, then add the spawn points of the same region again at the end such tat the number of spawn points in every region becomes constant)
How to develop it??
For this tutorial I will use 3 regions(namely LS,SF,LV) and 10 different spawn points for each region(my own spawn points :P ).It's your wish to have as many number of regions and spawn points per region.
Step 1:Setting up the regions
First let's define an ID for each of the region.You have to keep the flow of the define continuous.It has to be in a arithmetic progression with common difference 1(It means the ID should be without gaps, like 0,1,2,3,4 not 1,3,4,6).Also the first region ID should be 0 and +1 for each extra region.
You can define the ID in two ways: using defines,using enums
1.Using #define
Code:
#define SPAWN_LS 0 #define SPAWN_SF 1 #define SPAWN_LV 2
If you are new to #defines, I suggest you to go through this tutorial by Y_Less(a.k.a ColeMiner).
Ex:a = SPAWN_SF + 1; during compile time it the compiler will substitute the value of SPAWN_SF so it will be a = 1 + 1 since the value of SPAWN_SF is 1.
Using Enumeration
Code:
enum Spawns_t { SPAWN_LS = 0, SPAWN_SF, //This will be 1 (assigned by the compiler.It is the rule of enumeration) SPAWN_LV //This will be 2 }
If you are new to enumerations, I suggest you to go through this tutorial by iPLEOMAX.
Use either #define or enumeration, not both.Using both will create errors.
Step 2:Creating spawn points for the regions
The next step is to create different spawn points for each region.
I have collected 10 spawn points for each region.You can make your own spawn points(unlimited spawn points).
You have to write all the spawns in a particular format for my algorithm to work.I will explain it in the next part what it is and how it works.The format is given below.
NOTE:The number of spawn points for each region should be same.If you have unequal number of spawn points for each region then add an existing spawn point of that region twice to get the number of spawns per region equal.
You have to arrange them according to the number you defined each region in this format:
Code:
const Float:Spawns[][4] { REGION_0_SPAWN_1 REGION_0_SPAWN_2 REGION_0_SPAWN_3 ..... REGION_1_SPAWN_1 REGION_1_SPAWN_2 REGION_1_SPAWN_3 ..... REGION_2_SPAWN_1 REGION_2_SPAWN_2 REGION_2_SPAWN_3 ...... }
Its because every location in San Andreas is written X,Y,Z and the 4th is the Rotation or Facing Angle.It determines the angle at which the player is facing or simply you can say it tells where your tiny player marker in your radar will be pointing to.Therefore, its very important.You'd not like you player spawn facing to a big wall which would be annoying!
Why 'const'?
const is a keyword in PAWN that makes the variable(not literally, it cannot be varied, so its not a variable) unchangeable.Also its faster than variables declared using new.
If you are new to this keyword then refer this page.
Here are my collection of Spawn Points.
10 for each region
Code:
const Float:Spawns[][4] { {395.3744,-1799.8812,7.8281,2.9473}, //LS Spawns {595.5536,-1243.5162,18.1057,22.3843}, {656.2115,-1225.1598,16.7225,70.0481}, {1004.4772,-1361.2067,13.3209,357.1465}, {1169.7753,-1489.6567,22.7650,89.2481}, {2807.9282,-1176.8883,25.3805,173.6018}, {2621.5681,-2227.2996,13.3710,86.5449}, {1938.9319,-2147.9319,13.5547,179.5551}, {1446.3792,-2286.4343,13.5469,92.1186}, {1235.4366,-2037.1150,61.0313,272.8595} {-1935.0742,678.1586,46.5625,356.4240}, //SF Spawns {-1922.5177,680.0504,46.5625,2.6907}, {-1934.6843,264.8631,41.0469,276.9846}, {-2022.3842,155.8002,28.8359,266.6432}, {-2314.1555,-169.0953,35.3203,178.2457}, {-2126.3633,-383.9755,35.3359,2.5950}, {-2720.4807,-317.9581,7.8438,41.5845}, {-2521.2214,-621.2564,132.7300,1.2376}, {-1928.7382,-790.2328,32.1506,273.2949}, {-1953.3707,1339.3734,7.1875,174.4267} {1098.1039,1609.9438,12.5469,180.6180}, //LV Spawns {2007.6625,1544.3978,12.9850,272.5070}, {2024.0055,1343.0667,10.8203,268.3386}, {2476.1292,1340.7408,10.8289,87.9012}, {2496.2332,1434.5453,10.8203,189.2649}, {2483.7869,1527.8451,11.0802,319.4963}, {2092.6619,2075.7512,10.8203,270.5955}, {2095.9263,1285.3276,10.8203,1.1614}, {1995.7908,1073.3232,10.8203,8.5701}, {1705.8315,1255.5388,10.6813,353.0535} }
Now you'll need to create one more array of variables that will hold the index of the last used Spawn Point so that the next player who wants to spawn doesn't get the same spawn point(this is to avoid flooding players at the same spawn point and also to avoid a bug where 2 or more players spawn inside each other and get stuck).This variable will be incremented every time a spawn point is used and will be reset when it reaches the last spawn point.
Code:
new SpawnCount[3] = 0; //3 because I am using 3 different REGIONS
This is the part where all the computation will be carried out for determining the correct spawn point.
This function will find the next spawn point of that region and return it.
To keep things neat and readable I will define a few more things.
Code:
#define MAX_SPAWNS_PER_REGION 10
Code:
stock GetSpawnIndex(spawn_region) { new i = (MAX_SPAWNS_PER_REGION * spawn_region) + SpawnCount[spawn_region]; //This will get the index of the next spawn of the spawn points array pawnCount[spawn_region]++; //Increment the count if(SpawnCount[spawn_region] >= MAX_SPAWNS_PER_REGION) //If it goes more than the limit then we might get an error "Array index out of bounds" which in turn would crash the server. { SpawnCount[spawn_region] = 0; //Reset the count } return i; //Return the index of the spawn point from the array }
spawn_region = The REGION where the next spawn point must be.If we give the spawn_region as SPAWN_LV then we'll get a next spawn point that is in LV.
Returns:
The index of the spawn point form the spawns array.The index returned will be a spawn point that belongs to the given region.
The formula for finding the index is = (MAX_SPAWNS_PER_REGION * SPAWN_REGION) + SPAWN_COUNT;
As there are 10 spawn points for each region defined (here in the example script) ,according to the format and the code, every 10 entries in the array belongs to each region.So multiplying 10 with the region ID will give the first entry of the requested region in the array.Later adding the SpawnCount will give an index of the spawn point which is different from a spawn point that was used while spawning the previous player.What if the SpawnCount goes more than the MAX LIMIT??To overcome this problem,the spawn count must not go more than the limit.Hence we reset the counter to 0 every time it reaches the max limit.
The formula is applied and the result is stored in variable i.
The respective SpawnCount variable is incremented so that next player doesn't get the same spawn point once again.
Then the SpawnPoint is checked if it has reached the last spawn point for that region and if so it is reset to 0.
And the index is returned.
This will give us the correct index that we need to use from the spawn points array.
Step 5:Processing the returned index to spawn
We now need to spawn the player using the index that was returned by the function.
Code:
new index = GetSpawnIndex(SPAWN_SF); //You can provide any region to GetSpawnIndex depending on your needs. SetSpawnInfo(playerid,teamid,skinid,Spawns[index][0],Spawns[index][1],Spawns[index][2],Spawns[index][3],-1,-1,-1,-1,-1,-1);
Final Code
The final code should look somewhat like this
Code:
#define SPAWN_LS 0 #define SPAWN_SF 1 #define SPAWN_LV 2 #define MAX_SPAWNS_PER_REGION 10 ///////////////////////////////////////////////////////////////////////////////////// const Float:Spawns[][4] { {395.3744,-1799.8812,7.8281,2.9473}, //LS Spawns {595.5536,-1243.5162,18.1057,22.3843}, {656.2115,-1225.1598,16.7225,70.0481}, {1004.4772,-1361.2067,13.3209,357.1465}, {1169.7753,-1489.6567,22.7650,89.2481}, {2807.9282,-1176.8883,25.3805,173.6018}, {2621.5681,-2227.2996,13.3710,86.5449}, {1938.9319,-2147.9319,13.5547,179.5551}, {1446.3792,-2286.4343,13.5469,92.1186}, {1235.4366,-2037.1150,61.0313,272.8595} {-1935.0742,678.1586,46.5625,356.4240}, //SF Spawns {-1922.5177,680.0504,46.5625,2.6907}, {-1934.6843,264.8631,41.0469,276.9846}, {-2022.3842,155.8002,28.8359,266.6432}, {-2314.1555,-169.0953,35.3203,178.2457}, {-2126.3633,-383.9755,35.3359,2.5950}, {-2720.4807,-317.9581,7.8438,41.5845}, {-2521.2214,-621.2564,132.7300,1.2376}, {-1928.7382,-790.2328,32.1506,273.2949}, {-1953.3707,1339.3734,7.1875,174.4267} {1098.1039,1609.9438,12.5469,180.6180}, //LV Spawns {2007.6625,1544.3978,12.9850,272.5070}, {2024.0055,1343.0667,10.8203,268.3386}, {2476.1292,1340.7408,10.8289,87.9012}, {2496.2332,1434.5453,10.8203,189.2649}, {2483.7869,1527.8451,11.0802,319.4963}, {2092.6619,2075.7512,10.8203,270.5955}, {2095.9263,1285.3276,10.8203,1.1614}, {1995.7908,1073.3232,10.8203,8.5701}, {1705.8315,1255.5388,10.6813,353.0535} } //////////////////////////////////////////////////////////////////////////// new SpawnCount[3] = 0; //////////////////////////////////////////////////////////////////////////// stock GetSpawnIndex(spawn_region) { new i; i = (MAX_SPAWNS_PER_REGION * spawn_region) + SpawnCount[spawn_region]; //This will pick the next spawn SpawnCount[spawn_region]++; //Increment the count if(SpawnCount[spawn_region] >= MAX_SPAWNS_PER_REGION) //Impossible to go above 10 { SpawnCount[spawn_region] = 0; //Reset the count } return i; //Return the index of the spawn point from the array } ///////////////////////////////////////////////////////////////////////////// public OnPlayerConnect (playerid) { new skinid = random(299); new index = GetSpawnIndex(SPAWN_SF); //The second parameter(i.e:SPAWN_SF here) can be any region SetSpawnInfo(playerid,1,skinid,Spawns[index][0],Spawns[index][1],Spawns[index][2],Spawns[index][3],-1,-1,-1,-1,-1,-1); return 1; }
- Using #defines make the code neater.It helps in making a change and also increases the readability of the code.
- Don't use negative values while defining Regions.
- Begin the first region with 0 and the following regions must be in a +1 progression(i.e:0,1,2,3,4,5,etc)
- To reduce complications I had avoided few optimizations and some good programming habits.But you can do it if you know.
- Use static variable inside GetSpawnIndex instead of a global variable for SpawnCount.
- You can optimize the code by using this code:
Code:if(++SpawnCount[spawn_region] >= MAX_SPAWNS_PER_REGION)
- [8th March 2014]Revised the whole tutorial.Fixed many spelling mistakes,grammatical mistakes and improved the language.