<title>BITS at Night✈</title>

<header>

BITS at Night✈

Prelude</header>
<nav id="e1d470cc-3f77-494c-9470-a909fbdd151a" class="block-color-gray table_of_contents"></nav>

20 August

Prelude

Horror - Top Down Game?

Okay so I was thinking of bits at night, a horror multiplayer game based on illumination.

  • So firstly its topdown shooter multiplayer kind. Easy to make that part with node.
  • For the map I really dont know design so its way out of my league to design that so google earth + some editing can make you a nice map.
  • Then we need a lot of darkness but the user can toggle a torch light and move around a little.
  • So there are other players and monsters. The most interesting game mode would be battle royale. For now keep it simple 1 room. Players can kill each other and monsters are bots that attack people.

Dev flow

  1. Basic top down movement system
  1. Menu to Enter game
  1. Updating coordinates on node (try server authority)
  1. Make other players appear and disappear.
  1. map with walls - can be done later anytime
  1. Illumination and torch and whatnot
  1. Monsters AI - Randomly spawning and attacking you
  1. Jumpscares
  1. Battle royale system (restrictions on joining and alive count)

Okay this looks fine. I think I can start. Ill make a desktop folder and repo

1. Basic topdown movement system

Random cheap map with walls and a player

  • Draw some walls and make a circular player object with like a gun or a torch

Okay important point in coding….. don’t get suck on anything but the current goal. Thats all that matters.

  • I think this is fine.
  • So I integrated the Walls collision system but its not exactly fine. The guy is getting stuck in walls. So Im trying to have like a system that brings the player back to where he came from.

Collision Control Sytem

  • I have an array of old coordinates values. So whenever a player is wall stuck itll take the player back I guess?
  • Or wait, if a wall is close , push the guy away from the wall
var move = keyboard_check(ord("W")) - keyboard_check(ord("S"))
speed = 5*move
if(point_distance(x,y, mouse_x , mouse_y) > 30){
    direction = point_direction(x,y, mouse_x , mouse_y);
    
}
if(position_meeting(x + lengthdir_x(speed , direction),y +  lengthdir_y(speed , direction),oWall)){
    //colliding with a wall - no freedom in image angle , only in direction
    speed =0
    
    
}else{
    //not colliding with a wall
    image_angle = direction;
}
  • Finally something that works!. It was getting annoying. And I think the most important thing would be camera now

Camera

  • This is just boilerplate so I dont think its so important to log about it much
  • Just a slow interpolated camera

I changed up the values and the movement is looking really nice now 🙂

Result

2.Menu to enter game

  • I will make a new room. Basic room. Just takes in your name and then sends you to the multiplayer stuff.
  • So I added some font and made some buttons and text and a field for your name and all
//oMenu Create
global.username = "";
keyboard_string=""
//oMenu Draw GUI
var bh = camera_get_view_height(view_current)
var bw = camera_get_view_width(view_current)
var scale = .4*bw/1300;  //if we want to scale up the font
var mx = device_mouse_x_to_gui(0)
var my = device_mouse_y_to_gui(0)
draw_set_color(c_white)
draw_set_font(fPressStart2P)
draw_set_halign(fa_center);
draw_set_valign(fa_center);
draw_text_transformed(bw*0.5 , bh*0.25 , "BITS at Night" , scale, scale ,0 )
draw_text_transformed(bw*0.5 , bh*0.5 , "Enter a username" , 0.5*scale, 0.5*scale ,0 );
//Enter button
draw_set_color(c_green)
draw_roundrect(bw*0.4 , bh*(0.65-0.04) , bw*0.6 ,bh*(0.65+0.04) ,false )
draw_set_color(c_white)
draw_text_transformed(bw*0.5 , bh*0.66 , "PLAY" , scale, scale ,0 )
if(mouse_check_button_pressed(mb_left)){
    
    var c1 = mx < bw*0.6
    var c2 = mx > bw*0.4
    var c3 = my > bh*(0.65-0.04)
    var c4 = my < bh*(0.65+0.04)
    if(c1 and c2 and c3 and c4){
        room_goto(rGame)
    }
}
//Textbox for name
draw_set_color(c_white)
draw_roundrect(bw*0.4 , bh*(0.4-0.04) , bw*0.6 ,bh*(0.4+0.04) ,false )
draw_set_color(c_black)
if( string_length(keyboard_string) > 10){
    keyboard_string =  string_delete(keyboard_string ,10 , 1 )
}
draw_text_transformed(bw*0.5 , bh*0.4 , keyboard_string , 0.5*scale, 0.5*scale ,0 )

Result

  • Ok this is cute

3. Updating Coordinates on Node

Setting Up node js server

  • So in the main repo Im making a folder called server for the node project
  • Then the boilerplate websocket server stuff

Setting up GMS2

  • Async networking boilerplate

Next lets set up the event based communication stuff.

Ask server to create a player

  • So in the oMenu after the guy clicks on PLAY I am going to tell the server to “create_me”

//DEAD PLAYERS CAN BE GHOSTS — ok so my mom cracked a joke on the walls movement bugs and it let me to a very cool mechanic

Battle royale + horror : dead players become ghosts and can haunt and kill existing players. Dead ghosts are just spectators.

  • So the main part is the players array that holds all the players. So we will have all our player properties here. x , y , name , id and everything.
  • Some more properties that we will add later is torchLight switched on?
  • We are also telling the new guy and everyone already existing on the server that here is someone new

Updating player info

  • I want to do this using the server so we have good authority but because we have walls I cant trust …
  • So basically the client would send the latest coordinates
  • I created a global to hold if the torchlight is on or not
  • I added an angle and torch attribute here in node player info too

Sending updates to the server

Result - Server Updating this

So I was running this on chrome it was lame fps. Edge was fine. I guess its something to do with the …Okay I disabled webGL it works fine.

4. Make other players appear and disappear

Sending position updates from node

  • I need to tell every player about every player. So I will make a new function for that that repeats every 16 ms or so.
  • This function grabs a players info, puts it in a dictionary , and sends that dictionary over to everyone
function stateUpdate() {
    for (let i in players) {
        var sendThis = {
            eventName: "state_update", //grabbing this player's info
            id: players[i].id,
            x: players[i].x,
            y: players[i].y,
            A: players[i].A,
            T: players[i].T,
        }
        for (let j in players) {
            players[j].socket.send(JSON.stringify(sendThis));  //sending it to every other player
        }
    }
    setTimeout(stateUpdate, 1000 / 30);
}

Receiving the updates on GMS

  • Now we need to update these player coordinates and angle to their respective oEnemy instances

Bug report :

  • When webgl is set to disabled then the fps is good but after 3 oEnemies the game doesnt update their positions
  • When webgl is set to required then the fps is low asf but oENemies are getting updated. Here is auto detect
  • When webgl is set to auto detect then the fps is bad in chrome but players are updating. In edge however everything is working perfectly.
  • Maybe its that hardware acceleration that I switched off in chrome? Lets try switching it on and playing.

Yes I was right…… I guess the movement could be more smooth though. Lets amp up the interpolation.

  • Nope its worse. I set it to half half and lets increase nodejs state update frequency

Wow, its just so damn smooth. I fixed it. I changed it up from 50ms to 16ms

Result

The lighting system seems cool… Ill do that tomorrow. Dont fucking think about it now. Your progress for today was pretty good.

23 August

5. Lighting System

  • So what I’m going for is dynamic lighting. Now I guess I have to understand surfaces and whatnot for that.
  • Okay I followed the tutorial and pretty much understood. We are drawing the lights(non shadow) as a polygon
  • Actually lights first then polygon. for shadow

First the light sprite is drawn in oLigthing. Then the walls

///see shaun spalding jobo thing

24 August

Okay I need to see the shaun spalding jobo video. If my systems dont work I will use that extension.

Ok so my systems dont work and I’m going to use that extension👏👏👏

Even this could have worked

Jobo Lighting System

  • Okay I pretty much understood shaun spaldings tutorial.

Okay this system is trash on html5 and websockets primarily use h5 so I cant, fuck it

GMS Official Simple Tutorial Lighting System

  • So I followed that tutorial and it wasnt so bad really. This is the end result and this is just the beginning.
  • So in the oLighting object you can make different lights work for different objects and its really cool.

I can also add streetlights and all

Result of Lighting and multiplayer

6. Guns Concept

So for the shooting dynamic, itll be part server authority so thats good right? Ill draw some simple bullet sprite and add some speed

Generating a Bullet

The result looks a bit like this

Event to send this to server.

  • We need to tell the server we shot a bullet.

Server Handling this (Part 1 - telling other players someone got shot)

How GMS makes it look like a player shot a bullet

case "bullet_shot":
                
                with(oEnemy){
                    if(clientId == real(realData[?"shooter"]) ){
                        //creating a bullet
                        var bullet = instance_create_layer(x +lengthdir_x(13 ,direction -85) ,y+lengthdir_y(13 ,direction-85)  ,"Instances",oBullet);
                        bullet.speed = 10;
                        bullet.direction = image_angle;
                        bullet.image_angle = bullet.direction;
                        reloading = 20;
    
                        //recoil animation
                        x -= lengthdir_x(10 , direction)
                        y -= lengthdir_y(10 , direction)                        
                    
                    }
                }
            break;

7. Authoritative Bullets

Right now the bullets dont really do anything. We need code that traces the path of the bullets and checks if it is hitting someone. This also needs to be done by a centralised authority , so the node server.

shootBullet Function

function shootBullet(shootersId) {
    var frame = 0
    var init_x = 0;
    var init_y = 0;
    var angle = 0;
    for (let i in players) {
        if (players[i].id == shootersId) {
            init_x = players[i].x;
            init_y = players[i].y;
            angle = players[i].A;
        }
    }
    //trace the trajectory of the bullet
    while (frame < 400) {
        var current_x = init_x + Math.sin(3.1415 / 180 * angle);
        var current_y = init_y - Math.sin(3.1415 / 180 * angle);
        //we have the current coordinates of the bullet. Now check if it is colliding with someone
        for (let i in players) {
            var distance = Math.sqrt((current_x - players[i].x) ** 2 + (current_y - players[i].y) ** 2);
            if (distance < 16) {
                if (players[i].id != shootersId) { //make sure friendly fire doesnt exist
                    return players[i].id; //id of the guy who got shot
                }
            }
        }
    }
    return -1; ///-1 means the bullet hasnt hit anyone yet
}
  • Here we are tracing each step of the bullet in the direction in which it was fired and checking if it is hitting any player
  • It returns the id of the player we hit, or -1 if we hit no one
  • We do this by using perpendicular distance from the line in which the bullet was shot.

Using this to kill the player who got shot

  • By kill I mean destroy websocket.
  • So we are basically destroying that player for everyone else.

oh fuck i forgot to close the while loop in the shootBullet func

……also for x its cos not sin…lot of silly errors there.

Results

Yess the player we shoot is dying! This is extremely cool but I do think we could add a health variable. 1 shot to kill a player seems too lame

8. Health

  • Just like any other property like x , y , angle , now we will also use Health, denoted by H in nodejs
  • And when a player is hit by a bullet, I am reducing the health by 30.
  • I also drew healthbars for everyone so this is easier to see.

25 August

Adding Health Effects

  • So when like you are getting shot adrenaline pumps up and you can see a little more than normal.
  • So the lighting is controlled in oLighting, thats where I will make changes
  • So darkness always resets itself. Once health changes, let me change darkness to 0.7 or something.
  • In the oPlayer Step
  • Also the shader blink thing.

Cool progressive Result After Adding Healthbars, Blinkness

9. Ghosts

Differences in Ghosts and Normal Players

  1. Ghosts can see in the dark
  1. Ghosts have no healthbar or health concept. They are gone if light falls on them for like 300ms. Maybe they do need health of some sort, but no healthbar shown
  1. Ghosts can go through walls
  1. Ghosts can jumpscare players and kill them.

Adding a body attribute

  • Like body of the player. “P” , “G” , “D”
  • So player or ghost or dead(like out of the game)

Adding Logic

Turning P into G after death

Changes to oPlayer, oEnemy

  • As a ghost, dont show healthbar or walls….

Ghosts are like air, they cant be shot

  • Changes to the bullet tracing code. Shoot only if person is a P

Ghosts Sprite

This is what I created in aseprite. Yeah I know top views suck for this….

Final Result After Ghosts Integration💜💜

9. Killing Ghosts

So for killing ghosts….

  • Basically if light falls on a ghost for like 1 second the ghost should die.
  • For this we can check if the ghost (considered a point) is inside a triangle consisting of the player and some lights

26 August

Dont have a lot of time today so by 11 see how much you can do.

The Math of it…

  • So firstly lets bring the origin to the player who is catching the ghost
  • So theta is the direction of the player.
  • P1 and P2 are like the endpoints of the iso triangle I am trying to make.
  • So we need to check if a ghost is inside <0,0> , P1 and P2
  • Lets make a function that does this for us
  • How to find P1 and P2? Lets assume the yellow radius (torch range ) is 80.
  • So P1 and P2 are R e^(i theta +/- 40)

Making the Function in js

  • To check if a point is actually in triangle you can do the coordinate geometry thing. L1, L2 , L3 must be the opposite signs for the ghost point as the point of the triangle opposite to the side
  • so I found this algorithm on stackoverflow
bool intpoint_inside_trigon(intPoint s, intPoint a, intPoint b, intPoint c)
{
    int as_x = s.x-a.x;
    int as_y = s.y-a.y;
    bool s_ab = (b.x-a.x)*as_y-(b.y-a.y)*as_x > 0;
    if((c.x-a.x)*as_y-(c.y-a.y)*as_x > 0 == s_ab) return false;
    if((c.x-b.x)*(s.y-b.y)-(c.y-b.y)*(s.x-b.x) > 0 != s_ab) return false;
    return true;
}
  • I made some changes to the function to work in js and uk use arrays for points
  • Then I made this function which checks the whole thing for us

ghostHealthReducer Function

  • This function will check all torchlights from P and see if a G is inside. If yes, reduce health by like 30 I guess?
  • No reduce by 1 every 16ms. So…..per sec 60 health gone ig?

Result…

I temporarily still showed the ghost healthbar.

10. Ghosts Attacking Players

  • This part is going to be real fun.
  • So basically if (a ghost comes up real close to a player) and (the ghost is not under any torchlight), jumpscare and kill the player
  • Okay this is much easier to code than I expected, because we only have to follow the 2 conditions stated above…Ill do it tomorrow

5 September

Yeah right “Ill do it tomorrow”

Ghost Scare Check Function

  • So here I am just doing the above things in code

The Jumpscare from Node

  • We need to scare this player. So message the GMS client some event like jumpscare

Handling the Jumpscare in GMS2

  • For now I will just make some alert like you got jumpscared

Result

11. Jumpscares and Freaky Music

  • Now lets make some realism in the game.
  • The player who gets jumpscared needs to really get scared. I mean jumpscare music and everything
  • Firstly lets apply some theme music
  • I will use oCamera for all audio related things

Freaky Theme Music

  • Plays when you are a P , not a G
  • The music I got from this website

Transition to Jumpscares Music

  • So the idea is to have the music play whenever a ghost is nearby
  • Kind of a warning to the player because ghosts have a lot of advantages
//if you are a P and theres a G very close by transition to jumpscare
if(oPlayer.body == "P"){
    var closestGhost = noone;
    var closestGhostDistance = 100000;
    with(oEnemy){
        if(body == "G"){
            if( distance_to_object(oPlayer) < closestGhostDistance  )
            {
                closestGhostDistance = distance_to_object(oPlayer) ;
                closestGhost = id;
            }
        }
    }
    var ghostNearby = false;
    if(closestGhost != noone){
        if(point_distance(oPlayer.x , oPlayer.y , closestGhost.x,closestGhost.y) < 100){
            ghostNearby = true;
        }
    
        if(ghostNearby and ! audio_is_playing(TransitionToJumpscare)){
            audio_play_sound(TransitionToJumpscare , 2 , true);
        
        }
          
    }
    if(!ghostNearby) {
        audio_stop_sound(TransitionToJumpscare);
    }
}else{
    audio_stop_sound(TransitionToJumpscare);
}

Real Jumpscare Music and Jumpscare

20 September

  • Okay first lets do the jumpscare music
  • I also drew a jumpscare ghost, there is only 1 problem. Its not scary
  • Omg this is so much better.
  • I like the guys in the comments saying, as a ghost I can relate to this.
  • Okay the music is fad but the ghost is just fine… lets see

Adding Gunshot sounds

  • I took the sounds from gatdamn.io and also the code from there. Im just going to say it. That game’s sound system is a masterpiece.
  • Its basically sound falloff exponentially

I should really do the map

12. BITS Map and Walls Config

  • We Want Invisible walls and a simple simple map.

21 September

I dont want to waste too much time on this. Its graphics bro

Wall Placement

This part can get really really difficult Let me actually resize the canvas to cut out NAB?… No its okay. Just see how the wall placement is looking

After tedius work. Fucking this is the result

  • I removed the walls covering the central lawn, it felt too restrictive

22 September

Okay we need to head towards production now. You need

  1. spawnpoints randomply generated by server
  1. /if you are a ghost and you are killed , you just die! , death screen , youw ere killed by …
  1. some streetlights
  1. better jumpscare
  1. arrow to show closest player
  1. map edits for clear roads and A mess fixes

13. Random Spawn System , Streetlights

Spawn System in Node.js

  • As of now in node all players spawn at the same point which is
  • So I will create an array of spawnable points where the guy can be spawned
  • A spawn system that takes the least populated point to put the user to.
  • Ngl this was fun. Now put this for the player’s spawn
  • To check if this is working, firstly a player will be spawned somewhere and then at the point farthest from the first player.
  • Did some bug corrections and yesss it does work! One guy got got spoawned in INS and other in malakars , then the next one in DH2 front , so happy

Respawn ghosts !!! Very imp

  • After a P kills a P , one P becomes a G and can easily be killed. So we need to send the G to a place where there are less P’s
  • This means I will do a slight modification to the function such that ghosts are not included in search
  • Also the <x,y> interpolation must be skipped .

Cute streetlights

  • So I want like some streetlights scattered across the bits map. This makes it feel a little less dark

Streetlight Placement

  • Went into a bug spriral but now its fine

I Added a flickering effect too

14. Major UI fixes

So this would be the next step

  1. Kill count
  1. Alive and ghosts counts
  1. Death UI saying you died I guess…

23 September - 2 pomodoro sessions try to finish this stuff

Kill Count

  • I actually havent made a kill count. I need to make one
  • Everytime a P takes down a G or a P , ++
  • Everytime a G scares the fuck out of a P ++
  • Making a new attribute K for kills
  • Even on GMS side I am using the built in variable score for your kills. For enemies its just a variable called kills

Adding to Kills

We have to do this casewise

  1. P killing a P
  1. P killing a G
  • In the ghost health reducer function as of now what was happening was once a G is dead its ws was being closed.
  • I added code to just ++ killers kill count
  1. G killing a P
  • When a ghost scares a P the G must get ++ kill

Done with testing, it works 🙂

  • By this point we have a kinda fun to play game

Ghosts and Players count

This results in

Death UI saying you died and all

  1. When you are a P and you are knocked out you need to recieve a message “You were killed by _____”
  1. When you are a G and you are torched you need the full UI screen showing Game stats and whatnot

Messages UI

Stuff that shows in read whenever there is an alert

  • Let there be a global.messages array in oController
  • Whenever there is a message, it lasts 2 seconds and fades away
  • 1 to 0.5 alpha in 120 frames
  • Now all we need to do is push to this array whenever we have a message to show
  • we push another arrray [ “MESSAGE” , 6 ]
  • This will show “MESSAGE” in red for 6 seconds
  • Its a very neat simple system

24 September

Server sent messages

  • When a P is knocked out, the server needs to tell some message to GMS. Do that
  • So a G can scare a P or a P can shoot a P
  • In the ghosts scare players function I am adding code for this alert
  • So basically line alerts will show the message
  • If the P is shot down by another P

How GMS handles this

Result

Fullscreen Death Alert

  • When a user is actually dead and gone, as of now the ws is being closed.
  • We need a different system where “destroy_player” is broadcasted to everyone
  • But the player should not be removed from players array yet
  • Umm tbh this is hard because it would require making major changes

Should we have spectator mode or not? I think we should

So everywhere we need to add something like , if player body == “D” then do this do that

In the ghost health reducer function

How GMS Handles this

  • Thats a simple death cam system

Designing the Player Stats screen after you have fully died

  • I am setting an alarm when the player dies so you can see the stats screen pop up later.

26 September

15. Leaderboard and Minimap

  • You can have a leaderboard if you know who has how many kills
  • We have all oEnemy kills in the kills variable
  • So we need to graphically display this in the lower left corner. I can take it from gatdamn.io but lets do from scratch, like a coding challenge

30 September

How did the last 4d go? I guess I need a bit of an extension.

What all is left?

  1. Leaderboard
  1. Minimap
  1. Death screen , you were killed by…
  1. Playtesting

Now the extras

  1. Rooms

Leaderboard

Please copy this from gatdamn.io

I did. It was a little buggy and I tried to fix it. Keyword is tried.

Minimap

Same code copied from gatdamn.io

16. Hosting and Playability

Fuck man , always leave this to the end. I dont mind tho.

Please please firebase host me

Yayy tutorial is there .

3 September

So much fucking time went in solving effects bugs and leaderboard bugs. I dont even fucking know if its fucking working. I have to make the itchy page fast

Bullets

  • We need to tag bullets by who shot them so that we can destroy the bullets at the right collisions

//if you are a ghost and you are killed , you just die! , death screen , you were killed by …

//better jumpscare

Leave a comment

Log in with itch.io to leave a comment.