Made an .io game in 10 days✈️
Abhishek
Posted on October 31, 2023
Hello Everyone!
Let's talk gamedev, better yet fast addictive .io games. And how I made
StellarClash.io✈️ in 10 days.
This is a real .io game!! You can open 2 tabs on your browser and see 2 planes!!
Here is the source GitHub🐈
Basic Structure of an .io Game
Frontend - Gamemaker
You have to choose a frontend which is compatible with the HTML5 Canvas. You can directly use the canvas API if you like vanilla JS code but I used Gamemaker and it's really easy!
Because the frontend stuff is mostly just
- Drawing planes and Moving the Camera there
- Drawing bullets
- Showing what is happening on the server
Backend Nodejs Server
This is where all the game logic actually works.
And there is always websocket communication between client and server.
Players
Every player is treated like a point particle and is spawned at a relatively low density area of the game. All players are saved to a players array
Bullets
Shooting is important and based on your level you shoot a specific number of bullets, bullets of specific damage. And on the client side the damage of the bullet appears as its size, so you have an idea how much you'll be hurt.
Food ie Selenium
Some metal... these are like the slither io orbs. The gamemaker particle effects make it look a lot like that.
Levelling system
The levelling system uses a formula.... This formula will need to be updated as the game gets better but here it is
The Game Loop in Nodejs
Here,
- All the players are propelled forward according to their speed and direction
- All the bullets are propelled forward according to their speed and direction. If a bullet is hitting another player, the bullet is destroyed and health and kills of victim and killer are updated.
- If players are close to the food, it is destroyed and added to their score.
- Other behaviors like bots ...
Bot Creation
So bots are created when there are less players and they are made to behave very similar to normal players.
function createBots() {
//go through the players and count how many are bots
var botCount = 0;
realPlayerCount = 0;
for (var i in players) {
var player = players[i];
if (player.bot) {
botCount++;
} else {
if (player.health > 0) {
realPlayerCount++;
}
}
}
if (botCount < MAX_BOTS && realPlayerCount < MAX_BOTS) {
console.log("creating a new bot");
var spawnPoint = bestSpawnPoint(players, spawnPoints, "public");
//for the name of the bot, 30% chance use the name from the list, 70% chance use empty string
var botName = "";
if (Math.random() < 0.3) {
botName = botNames[currentBotName++];
if (currentBotName >= botNames.length) {
currentBotName = 0;
}
}
var player = {
clientId: clientId++,
x: spawnPoint.x,
y: spawnPoint.y,
A: 0,
N: 0,
speed: 10,
health: 100,
maxHealth: 100,
kills: Math.floor(Math.random() * 4),
roomId: "public", ///BOTS WILL ONLY EXIST in public room
username: botName,
ws: null,
bot: {
recoil: 0,
lifetime: 0,
},
skin: Math.floor(Math.random() * 7), //0-6
lastHitTime: 0,
recoil: 0,
};
player.shootingCharacteristics = getShootingCharacteristics(player.kills);
player.speed = player.shootingCharacteristics.thrustSpeed;
player.maxHealth = player.shootingCharacteristics.maxHealth;
players[player.clientId] = player;
//tell other players we created this guy
var sendThis = {
eventName: "create_player",
clientId: player.clientId,
roomId: player.roomId,
x: player.x,
y: player.y,
username: player.username,
skin: player.skin,
};
for (var j in players) {
var otherPlayer = players[j];
//check if same room
if (otherPlayer.roomId != player.roomId) {
continue;
}
if (otherPlayer.clientId != player.clientId) {
//if ws is not null
if (otherPlayer.ws) {
otherPlayer.ws.send(JSON.stringify(sendThis));
}
}
}
}
}
setInterval(createBots, 1000);
Bot Behavior
Inside the game Loop, bots are made to follow the closest player to them and once they are close enough start shooting. Note that there is some randomness allowed here to make it feel real.
if (player.bot) {
player.bot.lifetime++;
//recoil
if (player.bot.recoil > 0) {
player.bot.recoil--;
}
//bot logic
//try to chase the player closest to this bot and once you are close enough, shoot
var closestPlayer = null;
var closestDistance = Infinity;
for (var j in players) {
var otherPlayer = players[j];
//if roomId is different, skip this player
if (otherPlayer.roomId != player.roomId) {
continue;
}
//if health is 0, skip this player
if (otherPlayer.health <= 0) {
continue;
}
if (otherPlayer.clientId != player.clientId) {
var d = distance(player.x, player.y, otherPlayer.x, otherPlayer.y);
if (d < closestDistance) {
closestDistance = d;
closestPlayer = otherPlayer;
}
}
}
if (closestPlayer) {
//chase this player
var dx = closestPlayer.x - player.x;
var dy = closestPlayer.y - player.y;
//if the player is close enough, shoot
if (closestDistance < 100 + 5 * player.kills) {
if (player.bot.recoil <= 0) {
//rotate the bot to face the player
player.A = Math.atan2(-dy, dx) * (180 / Math.PI);
///repeat x times
for (var k = 0; k < player.shootingCharacteristics.spread; k++) {
var bullet = {
x: player.x,
y: player.y,
A: player.A + Math.random() * 10 - 5,
speed: player.shootingCharacteristics.bulletSpeed,
damage: player.shootingCharacteristics.damage,
firedBy: player.clientId,
roomId: player.roomId,
lifetime: 120,
username: player.username,
};
bullets[bulletId++] = bullet;
}
//recoil
player.bot.recoil = player.shootingCharacteristics.recoilTime;
player.recoil = player.shootingCharacteristics.recoilTime;
}
} else {
//just make the bot move in the direction of the player 5 pixels
var fakeN = 0.2 + Math.abs(Math.sin(player.kills)) / 2;
player.x += (dx / closestDistance) * player.speed * fakeN;
player.y += (dy / closestDistance) * player.speed * fakeN;
//rotate the bot to face the player
var newA =
Math.atan2(-dy, dx) * (180 / Math.PI) + 5 * Math.random() - 2.5;
//lerp player.A to newA
player.A = (player.A + newA) / 2;
}
//check if player is out of bounds
var correctedPosition = outOfBounds(player.x, player.y);
player.x = correctedPosition.x;
player.y = correctedPosition.y;
continue;
}
}
Deployment and public facing.
The nodejs websocket server is deployed on heroku for just 7$ a month!!! That is my game server, only 7$🤑🤑🤑💵💵
It is hosted in US so players like me from India can face some lag. But because of extreme lerping, it's smooth lag which kind of does not feel as bad.
The actual game is hosted with Firebase hosting. I bought the domain on Namecheap for like 42$ and then deployed using the firebase CLI.
Future Plans
The next step would be to
- Improve the game - Adding more SFX and VFX to make it look better, and improve the levelling up and evolution
- Develop a following for constant feedback. iogames.forum is the best place imo and then there are other io game sites.
- Iterate 1 and 2 so that players are funnelled to my twitter and iogames.forum where they get updates on the games and can interact with me and that will make the game better
- Ads by Google - I was magically approved as a google H5 Games ad associate but I don't have the basic adsense approval on my site yet😶... so I have to figure some stuff out but hopefully I'll be able to earn a little from this!
Thank you for reading this post! Follow me on
Twitter🐦 for more updates!!
Posted on October 31, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.