Clean code question / refactoring

Hi here! :slight_smile:
I would need suggestions about clean code and refactoring, can’t find a proper way.

I have an enemy.go along with its enemy.script which holds the basic common stuff (update, movement, etc.) along with 3 different types of AI. I find it a bit messy that the script is already 250+ lines long so I decided to extract the different AI logics into seperate scripts to make it more clear. However if I call out to another script by msg.post I will only get it done by the next frame.
I was looking for something similar like in Java to call out and continue the flow after the job is done.
Could you please suggest?
Below is the code snippet:

function update(self, dt)
	-- choose destination depending on AI type
	if not self.isMoving and not self.isTurnFinished then
		if self.aiType == hash("random_walker") then
			randomWalkerAi(self)
		elseif self.aiType == hash("tracker") then
			usingTrackerAi(self)
		elseif self.aiType == hash("artifact_guarder") then
			usingArtifactGuarderAi(self)
		end
	end
	-- actual movement update
	if self.isMoving then
		...
	end
end

Use simple Lua modules. Each module can have one of the AI functions.
lib/ai/random_walker.lua

return function(self)
  -- Random walk code here
end

enemy.script

local randomWalkerAi = require('lib.ai.random_walker')

-- Your regular script code here.

Thank you for the prompt reply.
I’m trying to grasp the idea but still not clear :confused:
As I understand it returns a function but how can I get back for example a table?
I would have the following in the module:

 return function()
	local pool = {}
	local x = go.get_position().x
	local y = go.get_position().y

	if wallPositions[x + (y + TILE_SIZE) * TILE_SIZE] == nil and y < (LAST_INNER_ROW - 1) * TILE_SIZE then
		table.insert(pool, "UP")
	end
	if wallPositions[x + (y - TILE_SIZE) * TILE_SIZE] == nil and y > FIRST_INNER_ROW * TILE_SIZE then
		table.insert(pool, "DOWN")
	end
	if wallPositions[(x - TILE_SIZE) + y * TILE_SIZE] == nil and x > FIRST_INNER_COL * TILE_SIZE then
		table.insert(pool, "LEFT")
	end
	if wallPositions[(x + TILE_SIZE) + y * TILE_SIZE] == nil and x < (LAST_INNER_COL - 1) * TILE_SIZE then
		table.insert(pool, "RIGHT")
	end
	if #pool == 0 then
		table.insert(pool, "PASS")
	end
    return pool
end

What I would like to get back is the pool.

if self.aiType == hash("random_walker") then
	self.selectionPool = require("main.enemies.ai.random_walker")

But it assignes a function instead of the table.

Thank you in advance! :slight_smile:

Put

local randomWalkerAi = require('main.enemies.ai.random_walker')

At the first line of your script file.
Then you can use randomWalkerAi as a simple function.

if self.aiType == hash("random_walker") then
	self.selectionPool = randomWalkerAi(self)
2 Likes

Read more about modules here:

3 Likes

My two cents. First off, 250 lines is not a lot. Dividing your code into a lot of little chunks can just as easily be “messy” and hard to sort through. For larger files, use the search function to navigate rather than trying to scroll with the mouse or page-up/down.

If you’re going to use these AI functions in multiple enemy scripts, then a module is the way to go. If you’re only going to have one enemy script for all your enemies, then there’s no real point to separate them…but if things feel tidier for you that way, go for it.

Don’t forget that Lua treats functions like any other value, so you can put them in tables. This is how I would do it:

-- Pre-hashing names is good for performance,
-- especially if you use them in update or on_message.
local RANDOM_WALKER = hash("random_walker")
local TRACKER = hash("tracker")
local ARTIFACT_GUARDER = hash("artifact_guarder")

local AI_UPDATE = {
	[RANDOM_WALKER] = randomWalkerAi,
	[TRACKER] = usingTrackerAi,
	[ARTIFACT_GUARDER] = usingArtifactGuarderAi,
}

local function test_update(self, dt)
	-- choose destination depending on AI type
	if not self.isMoving and not self.isTurnFinished then
		AI_UPDATE[self.aiType](self)
	end
	-- actual movement update
	if self.isMoving then
		-- ...
	end
end
3 Likes

Thank you for all the ideas and practices, will try them out. :slight_smile: