5 days ago

How I implement my FNAF AI. (Educational).


This is a step-by-step breakdown of how I’ve implemented FNAF-like AI in all of my games since creating Stuffed: Stand-alone.

For the purpose of making this more widely accessible, I will be using lua as the language of choice throughout this tutorial, as it is one of the less “noisy” programming languages, allowing for an easier assessment in understanding the code for a potential beginner.

First and foremost, we begin by defining all the locations that we would like our character to be able to utilize throughout a given night as such:

local LOCATIONS = {

SHOWSTAGE = 1,

DININGAREA = 2,

BATHROOM = 3,

KITCHEN = 4,

EASTHALL = 5,

EASTCORNER = 6,

OFFICE = 7,

}

You can think of these locations as a sort of “state.”

Think in terms of a street light. A street light can only be one color at a time, whether that color is either green, yellow, or red.

in terms of our characters, we will be using these locations to represent the “state” that a character can be at, at any given time.

Once we’ve defined our locations, we must now craft the “blueprint” for creating new characters.

We can do this through utilizing metatables, which is Lua’s way of simulating object oriented programming.

Such a metatable would look something like this:

local Character = {}

Character.__index = Character

function Character.new(location, path)

local init = {

location = location,

path = path

}

setmetatable(init, Character)

return init

end

Now that we’ve created our blueprint, we can instance it. Or, “copy” it.

For this example, we will be creating Chica. So for our particular case, we will instance the blueprint into the “Chica” character.

local Chica = Character.new(LOCATIONS.SHOWSTAGE, {

{LOCATIONS.SHOWSTAGE, LOCATIONS.DININGAREA, LOCATIONS.DININGAREA, LOCATIONS.DININGAREA},

{LOCATIONS.DININGAREA, LOCATIONS.BATHROOM, LOCATIONS.EASTHALL, LOCATIONS.BATHROOM},

{LOCATIONS.BATHROOM, LOCATIONS.DININGAREA, LOCATIONS.KITCHEN, LOCATIONS.KITCHEN},

{LOCATIONS.KITCHEN, LOCATIONS.BATHROOM, LOCATIONS.EASTHALL, LOCATIONS.EASTHALL},

{LOCATIONS.EASTHALL, LOCATIONS.KITCHEN, LOCATIONS.EASTCORNER, LOCATIONS.EASTCORNER},

{LOCATIONS.EASTCORNER, LOCATIONS.EASTHALL, LOCATIONS.OFFICE, LOCATIONS.OFFICE},

{LOCATIONS.OFFICE, LOCATIONS.OFFICE, LOCATIONS.OFFICE, LOCATIONS.OFFICE}

})

You may have taken notice to the rather sizable second argument of this instance.

The path is what is known as a 2d array. it has two indexes, a row and a column, and we will be utilizing both of these things in order to determine both where the character is, as well as the moves they will be allowed to take based on that information.

Now that we have our character, we can move onto actually getting the character around.

We will begin by creating a method of the character metatable. You can think of a method as a characteristic that all "Characters" will share.

Character:move_character()

local move_chance = math.random(1,2)

if move_chance == 2 then

local size = #self.path[1] # self represents the variables of the blueprint

local rand_move = math.random(2, size)

self.location = self.path[self.location][rand_move]

end

end

Line by line, the code says this:

1. each time this function is accessed, store the result of a random number roll

between 1 and 2,

2. is the number 2? (50/50) If so, get the size of our array's width, and do a number between 2, (skipping the first number because it represents our character's location,) and the total horizontal elements in the array

3. move the character by determining their current location, and the random roll that we processed

And done. in almost no loc whatsoever,

we now have a very dynanic system in place for creating and moving characters.

If you were using a proper game engine and/or were using some form of a game loop, you would want to wait a custom amount of time prior to actually doing the roll.

Character:move_character()

if self.time >= some kind of time window

local move_chance = math.random(1,2)

if move_chance == 2 then

local size = #self.path[1]

local rand_move = math.random(2, size)

self.location = self.path[self.location][rand_move]

end

self.time_window = 0

end

Additionaly, you'd want to decrement this time_window as the in-game hour would progress, as well as stop the "movement timer" upon the character reaching the office, but that would go beyond this breakdown's scope.

This is the end result of the code, along with a few minor additions for testing clarity.

local LOCATIONS = {

SHOWSTAGE = 1,

DININGAREA = 2,

BATHROOM = 3,

KITCHEN = 4,

EASTHALL = 5,

EASTCORNER = 6,

OFFICE = 7,

}

local curr_location = {

"SHOWSTAGE",

"DININGAREA",

"BATHROOM",

"KITCHEN",

"EASTHALL",

"EASTCORNER",

"OFFICE",

}

local Character = {}

Character.__index = Character

function Character.new(name, location, path)

local init = {

name = name,

location = location,

path = path

}

setmetatable(init, Character)

return init

end

local Chica = Character.new("Chica", LOCATIONS.SHOWSTAGE, {

{LOCATIONS.SHOWSTAGE, LOCATIONS.DININGAREA, LOCATIONS.DININGAREA, LOCATIONS.DININGAREA},

{LOCATIONS.DININGAREA, LOCATIONS.BATHROOM, LOCATIONS.EASTHALL, LOCATIONS.BATHROOM},

{LOCATIONS.BATHROOM, LOCATIONS.DININGAREA, LOCATIONS.KITCHEN, LOCATIONS.KITCHEN},

{LOCATIONS.KITCHEN, LOCATIONS.BATHROOM, LOCATIONS.EASTHALL, LOCATIONS.EASTHALL},

{LOCATIONS.EASTHALL, LOCATIONS.KITCHEN, LOCATIONS.EASTCORNER, LOCATIONS.EASTCORNER},

{LOCATIONS.EASTCORNER, LOCATIONS.EASTHALL, LOCATIONS.OFFICE, LOCATIONS.OFFICE},

{LOCATIONS.OFFICE, LOCATIONS.OFFICE, LOCATIONS.OFFICE, LOCATIONS.OFFICE}

})

function Character:move_character()

while self.location ~= LOCATIONS.OFFICE do

local move_chance = math.random(1,2)

if move_chance == 2 then

local size = #self.path[1]

local rand_move = math.random(2, size)

self.location = self.path[self.location][rand_move]

print (self.name .. " is now located at: " .. curr_location[self.location])

end

end

end

Chica:move_character()



0 comments

Loading...

Next up

VORTEX REWARD #3 - "SHOWSTOPPERS!"

Watch your fingers

You must enter a post.

So

i may or may not make an full art of some person or i may just leave this like that-

Bandana Dee the Dream Friend

Smile! Here, take some happy pills! ✨💊 #Blender #3DModelling #3DArt Buy me a Ko-fi: https://ko-fi.com/barbarafb_

🍒Did you like the game? A demo is available for free on Steam.

✌️ Thanks for playing IndieGameiacs!

⚙️ Free Demo: http://bit.ly/UniDuni

📺 Full Video: https://youtu.be/5qEbVXg7GaQ

#steam #uniduni #clops #screenshotsaturday

Sometimes the suction cup get sticky. Small animation I made in Blender after doing my tutorial on picking up/dropping objects in animations. Crate model by jQueary (https://sketchfab.com/3d-models/game-ready-sci-fi-crate-d98deca6…).

One of the most critical update for Sunblaze demo. Now you are able to pet a cat! Finally!