Today I’m going to talk about MiniRoyale.io and how I made it. MiniRoyale is a multiplayer FPS shooter with battle royale mode.
The game has been released at March 4, 2019 and since that day, 630.000 unique visitors have played game. It still goes well and we still update game with new features.
The game has a community in Discord and they request new features, they report bugs, they help a lot! Without them, the game wouldn’t be like that. I also want to thank them for their support.
The game has 10.000 daily users and 100-200 avg. concurrent online users.
Game has 2 different maps, and 3 different scenes including maps. We have a login screen, map1 scene (North city map) and map2 scene (South city map).
Here is a screenshot from login screen :
As you can see, it has a 2D screen, which is the coolest feature of Playcanvas. You can create cool UIs with this feature of editor that is not possible with HTML. The UI will be rendered in canvas and all mouse interactions will continue to work! It’s like new and better way of DOM
The background scene is 3D and you can see some animations while you get ready for matchmaking.
In this scene I have a script that allows me to create DOM input element. I needed that because Playcanvas doesn’t support input and select field yet. Users need to enter their usernames, so I created this script.
Here is a screenshot from my input script. So basically, it allows me to create DOM element with this element’s position and size. I can define an ID to use it on scripts later and for selection, I can add options in that element…
As you can see, input script has some attributes that works in Playcanvas editor. This is another cool feature of this editor. You can simply create an attribute field with using “attributes.add” function. Here is a screenshot from input script of mine and how it creates these fields in Playcanvas editor :
I uploaded input script here : Playcanvas input · GitHub
When you press “Join Match” button, it calls a function that will load other scene. But before that, it saves your variables in localStorage, so it could connect correct server IP when scene is loaded.
I also use these variables on your next visit. It remembers your preferences.
When It loads map, on each map, there is an object that makes all network connections. It has lots of attributes to run game, overlay and players. Here is a screenshot from it :
At the beginning, it shows map selection entity, so users can select their deploy position. It’s also 2D scene. The locations are static and they are connected to spawn positions in 3D world. When you click on that button, your deploy position is being sent to network script and is being broadcasted to all users. If there is a signal from server about another user’s position, then network script disables that button. That’s why network script has all authority. Here is a screenshot from position selection buttons :
It stores flags in array type attribute.
It also enables helicopter entity, so we could see cool animation before we jump to city
You know, even for helicopter, I used scripts to rotate it’s rotor. You don’t need animation for this kind of animations, it can be done by scripts and their update functions.
There is also another cool thing that I would like to talk about. It’s border. As you may guess, it’s connected to network script. But it’s a light! I used spot light and define a range and angle to make it like circle. Its y position is 500 and each tick it comes closer to map. That position change provides a visual, that is similar to CS:GO’s death zone mode.
Here are two images for different positions :
I use circle distance function to check if you are in circle or not. I can also start zone thing in random position with changing x and z.
Then game interface becomes enabled and player entity with that change, we start to play game. When I start this game project, I started with Playcanvas’s FPS template. Here is a link for template :
https://developer.playcanvas.com/en/tutorials/first-person-movement/
You can build everything top on that. It provides all essential stuff like locking mouse, keydown and keyups, collisions and physics.
As I mentioned before network script runs everything. For other players, it clones an enemy entity and enable its script, so he could emulate opponent’s actions.
Enemy entity is an object that contains a soldier model, script and weapons in it. Weapons will be disabled at the beginning and when user takes a weapon from loot locations, network script will enable a weapon in this entity element. With this way, we only show one weapon that is attached to them.
I used findByName to find soldier model’s hand in node tree and attach my weapon model to it.
We also have a player control that provides FPS interface. It only has hands, we don’t need rest of its body. This hand model is more detailed than enemy models, since it’s FPS, it’s important to keep detailed near models.
The player model has also same structure to hide and show weapons in hand. It’s also attached body’s arm, weapon and hand move in same structure.
It also has lots of sounds on them for different cases.
All actions, like keydown, key up, mouse position changes, will be transfered to server. And after some calculations, your actions will be rendered as an enemy on other player’s clients.
I won’t go too much detail for networking, since it’s more complicated thing. But maybe, we could talk about it in another post.
There are some other interesting thing I would like to mention. It’s map. It is a huge image and its position is connected to player’s x and z coordinates.
But I used mask feature to show in container. Here are two images, that shows how map exactly looks like :
When I disable mask functionality, we see whole map and border
House models don’t have doors and glasses, they are actually in Playcanvas’s entity structure. We created one prototype for house and cloned it. They all have same scripts and structures. Doors have their own scripts, glasses have own their scripts etc…
For network side, we simply use their guid values. All of these glasses and doors have unique guid values. And guid value is generated while we create map in editor. We send guid value and state id like, open or break over network. Then all players see if glass breaks or door opens. When information arrived to other clients, their network entity finds object by guid and trigger same functionality on script.
Without Playcanvas editor, this game wouldn’t be possible. We worked on this project with two other friends of mine at the same time. While they design map, I worked on coding stuff, and we were able to test it without uploading and deploying to anywhere.
I want to thank to PlayCanvas for all their effort.
I’ll try to share more information about networking, optimisation, account system, leaderboard soon.