Architectural Problems

Godot Version

4.6

Question

How bad is the architecture of this project ?

godot_pizza_delivery/nav-test/nav-test at main · DarkGrey456/godot_pizza_delivery

any tips are welcome for how to fix the logic involved, cheers,

edit: link to the root of the project:

DarkGrey456/godot_pizza_delivery: pizza_delivery_game

You’d likely get better feedback if you provided the full project. It’s a lot more work to browse files on GitHub than to browse through a project in Godot.

Cheers, the project is uploaded with the github repo

1 Like

Oh ok, it’s a few folders down. I didn’t expect it there.

Warnings & Errors

You have warnings popping up in the console. Start by fixing them.

  1. W 0:00:01:450 GDScript::reload: The parameter “min” is never used in the function “rand_pos_in_zone()”. If this is intended, prefix it with an underscore: “_min”.
    UNUSED_PARAMETER
    delivery_agent.gd:28 @ GDScript::reload()

  2. W 0:00:01:450 GDScript::reload: The function parameter “min” has the same name as a built-in function.
    SHADOWED_GLOBAL_IDENTIFIER
    delivery_agent.gd:28 @ GDScript::reload()

  3. W 0:00:01:450 GDScript::reload: The parameter “max” is never used in the function “rand_pos_in_zone()”. If this is intended, prefix it with an underscore: “_max”.
    UNUSED_PARAMETER
    delivery_agent.gd:28 @ GDScript::reload()

  4. W 0:00:01:450 GDScript::reload: The function parameter “max” has the same name as a built-in function.
    SHADOWED_GLOBAL_IDENTIFIER
    delivery_agent.gd:28 @ GDScript::reload()

  5. W 0:00:01:450 GDScript::reload: The variable “len” has the same name as a built-in function.
    SHADOWED_GLOBAL_IDENTIFIER
    delivery_agent.gd:40 @ GDScript::reload()

  6. W 0:00:01:450 GDScript::reload: The parameter “event” is never used in the function “_unhandled_input()”. If this is intended, prefix it with an underscore: “_event”.
    UNUSED_PARAMETER
    delivery_agent.gd:47 @ GDScript::reload()

  7. W 0:00:01:450 GDScript::reload: The local variable “vecTo” is declared but never used in the block. If this is intended, prefix it with an underscore: “_vecTo”.
    UNUSED_VARIABLE
    delivery_agent.gd:61 @ GDScript::reload()

  8. W 0:00:01:463 GDScript::reload: The parameter “delta” is never used in the function “_process()”. If this is intended, prefix it with an underscore: “_delta”.
    UNUSED_PARAMETER
    scene.gd:26 @ GDScript::reload()

  9. W 0:00:13:187 delivery_agent.gd:45 @ compute_lookat_basis(): Target and up vectors are colinear. This is not advised as it may cause unwanted rotation around local Z axis.
    <C++ Source> core/math/basis.cpp:1044 @ looking_at()
    delivery_agent.gd:45 @ compute_lookat_basis()
    delivery_agent.gd:62 @ _physics_process()

  10. W 0:00:13:137 character_body_3d.gd:20 @ compute_lookat_basis(): Target and up vectors are colinear. This is not advised as it may cause unwanted rotation around local Z axis.
    <C++ Source> core/math/basis.cpp:1044 @ looking_at()
    character_body_3d.gd:20 @ compute_lookat_basis()
    character_body_3d.gd:36 @ _physics_process()

You have three broad categories: Unused variables, poorly named variables, and colinear vectors. If you’re not using a function argument, prepend it with an underscore. If you’re not using a variable, comment the line out if you plan to use it later, or delete it. Then rename short variable names that copy the names of functions into something longer and more descriptive.

Finally, take a look at those colinear vectors. Your agents are either looking straight up or straight down, and cannot rotate.

Running your project is like being asked to help find something, and walking into their room and finding papers all over the floor. Clean up the mess. It’s obscuring the errors.

  1. E 0:00:13:139 navigation_region_3d.gd:76 @ get_order(): Index p_index = 0 is out of bounds (p_instance->size() = 0).
    <C++ Source> core/variant/variant_call.cpp:681 @ func_Array_get()
    navigation_region_3d.gd:76 @ get_order()
    delivery_agent.gd:69 @ _physics_process()

Conclusion

Before we can even start to evaluate your code, you need to fix your code. You should always fix all errors immediately. You cannot do that if you have warnings spilling out all over the place, so all warnings should be fixed immediately.

Start by making the Debugger report no warnings or errors, and likely you’ll have code that works better. Either way, it is not worth my time to look at it until you’ve fixed these things.

solved most of them but the problem in ‘compute_lookat_basis’ seems to be a bug in godot …

I check that the distance from the target to the global_position is greater than 0.05, then I take the direction vector from global_position to target and normalize then project the line by 2000 units, and add global position …. godot seems to warn that the UP vectors are the same even after i change the code … so its a bug.

I have seen ‘solutions’ to the look_at problem elsewhere, thats beyond the scope of the problem.

model.global_basis = model.global_basis.looking_at( look_targ, Vector3(0.0,1.0,0.0))

When doing look at always check if the wanted look direction coincides with the up vector. If that’s the case the cross product used by the function will be mathematically undefined and the function will report the error. If those vectors have the same direction - choose an alternative up vector.

2 Likes

yeah that’s working now, the looking_at function worked best, while the other one says in the description its rotating the local basis … . My other project has a custom basis calculation but pasting that in didn’t work either …so looking_at will do …

the project was made in about an hour … and I must say it is a bit messy but I was trying to get the code into shape before testing the collect/ deliver system. I would say its significantly less code than a similar project in java . The issue is actually the software design and the node tree, how should everything fit together - there are questions like " should i use area box signals or the navigation agent target_reached signal?” and “should i avoid the manager pattern (or anti-pattern) or is this appropriate here?” and “does passing the manager into the child objects really break the system? how would the code be clearer otherwise?”.

Looks cleaner now. Still 3 warnings.

  1. W 0:00:01:336 GDScript::reload: The function “looking_at()” is a static function but was called from an instance. Instead, it should be directly called from the type: “Basis.looking_at()”.
    STATIC_CALLED_ON_INSTANCE
    delivery_agent.gd:46 @ GDScript::reload()

  2. W 0:00:01:343 GDScript::reload: The function “looking_at()” is a static function but was called from an instance. Instead, it should be directly called from the type: “Basis.looking_at()”.
    STATIC_CALLED_ON_INSTANCE
    character_body_3d.gd:20 @ GDScript::reload()

  3. W 0:00:01:343 GDScript::reload: The parameter “event” is never used in the function “_unhandled_input()”. If this is intended, prefix it with an underscore: “_event”.
    UNUSED_PARAMETER
    character_body_3d.gd:22 @ GDScript::reload()

In my professional experience, it is hard to test functionality when there’s that much information in the debugger. It also tends to be a waste of time, because things change or are resolved when the errors are resolved.

I get that you’re in a hurry, but keep in mind you’re in essence asking us to do free work for you. It’s polite to make that work as easy as possible for us.

Good question. Depends on what you’re doing next. Who needs to know it is there? If you are using an Area3D body_entered signal, then you have access to whatever object the Area3D is attached to, as well as the delivery agent through the body variable. If you need to pass something between them, this is the signal to use.

If you’re using the NavigationAgent3D target_reached signal, it just means the delivery agent is close to wherever you sent it. It make not visually be inside the Area3D yet, depending on what tolerances you set on the NavigationAgent3D. If this is going to cause a visual problem, it’s probably not a good choice. Also, depending on what you’re doing next, and whose driving that - you may have to have something listening to this signal externally - which is going to create more closely coupled code you may not want.

You should always avoid that Manager Anti-Pattern. It’s a good idea to step back and ask yourself, “What am I trying to accomplish here?” TBH, I have no idea what you’re trying to accomplish. But if each delivery agent can manage it’s own life, the manager pattern becomes unnecessary. It might make sense to have a Dispatcher to tell delivery agents what they’re picking up, delivering, and from/to where. But doesn’t micro-manage the entire process.

I think it’s important to ask yourself, “What am I trying to accomplish here?” I started understanding your code by cleaning it up, and by renaming variables so they told me what they do. For example the variable name rn indicates that something is random. I changed it to random_house so that throughout the code, I know than I’m looking at data from the random house we picked. I don’t have to refer to the variable declaration to understand what we are doing 5 lines below. We reduce the cognitive load of reading the code.

Well, let’s take a look at your DeliveryManager code. (I’ve cleaned it up a bit according to the GDScript Style Guide to make it easier to read.)

class_name DeliveryManager extends NavigationRegion3D

var houses_to_order: Array[Node3D] = []
var orders_address: Array[Node3D] = []
var order_count: int = 0
var orders_queue: Array[CustomerOrder]= []
var orders_in_progress: Array[CustomerOrder] = []
var orders_complete: Array[CustomerOrder] = [] 
var time_per_day: float = 60.0
var curr_time: float = 0.0
var first_time: bool = true
var order_timer: float = 0.0

@onready var restaurants_list: Node = $RestaurantsList
@onready var houses_list: Node = $HousesList


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	for house in houses_list.houses:
		houses_to_order.append(house)


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	if first_time:
		first_time = false

	curr_time += delta
	order_timer += delta
	if curr_time > time_per_day:
		clear_lists()
	if order_timer > 0.5:
		order_timer = 0.0
		random_order()


func random_order():
	var random_house = randi_range(0,houses_to_order.size()-1)
	var new_order: CustomerOrder = CustomerOrder.new()
	new_order.order_id = order_count
	new_order.house_id = houses_to_order.get(random_house).id
	new_order.delivery_address = houses_to_order.get(random_house).get_address()
	new_order.rest_id = randi_range(0, restaurants_list.restaurants.size()-1)
	new_order.collection_address = restaurants_list.get_restaurant(new_order.rest_id).get_address()
	# add the order id to the restaurant
	restaurants_list.get_restaurant(new_order.rest_id).orders.append(new_order.order_id)
	
	orders_queue.append(new_order)
	var obj = houses_to_order.get(random_house)
	orders_address.append(obj)
	houses_to_order.erase(obj)
	order_count += 1


func complete_order(order_id:int):
	var ocount = 0
	var order_found = false
	for e in orders_in_progress:
		if e.order_id == order_id:
			order_found = true
			break
		ocount += 1
	if order_found:
		var order = orders_in_progress.get(ocount)
		orders_in_progress.erase(order)
		orders_complete.append(order)


func get_order():
	if orders_queue.size() > 0:
		var order = orders_queue.get(0)		
	
		orders_queue.erase(order)
		orders_in_progress.append(order)
		return order
	return null


func clear_lists():
	for e in orders_address:
		houses_to_order.append(e)
		
	orders_address.clear()

random_order()

Let’s look at the first line at is was originally:

var rn = randi_range(0,houses_to_order.size()-1)

What are we trying to accomplish here? We are randomly picking an item from an Array using the length of the array minus one. We are assigning it to a variable that indicates out value is random.

Let’s look at the Array declaration:

var orders_address: Array[Node3D] = []

Then the assignment of that Array:

@onready var houses_list: Node = $HousesList


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	for house in houses_list.houses:
		houses_to_order.append(house)

Now let’s look at the Scene Tree:

Then the House Scene:

And the house.gd code:

extends MeshInstance3D

var id 
var order_id = -1
var delivery_manager : DeliveryManager

@onready var delivery_area: Area3D = $Address/Area3D
@onready var address: Marker3D = $Address


func get_address()->Vector3:
	return address.global_position


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	delivery_area.connect("body_entered",on_delivery)


func on_delivery(body:Node3D):
	if body is DeliveryAgent:
		if (body as DeliveryAgent).has_order(order_id):
			(body as DeliveryAgent).complete_order()
			delivery_manager.complete_order(order_id)
			order_id = -1

So we have an Array of Node3D objects that are in fact MeshInstance3D objects. However, from an OOP perspective, they are House objects. By calling them that, it not only makes our code cleaner and easier to read, it reduces the chance for bugs - and most importantly in this context - it helps us think about our architecture. Because now instead of being a Node3D/MeshInstance3D object that is managed, it’s a House.

So let’s fix the code to say that. We will start with our House object.

House

Before writing code, let’s talk about a house. When I order delivery of food these days, I use an app and they show up at my door. My responsibility is to say what I want, what my address is, and where I want it left (ring the doorbell, leave it on porch, etc.) I do not tell the app it’s delivered. I do not call and tell the pizza place I got my pizza. Once it’s delivered, I’m eating it and I don’t care is you know it’s delivered.

So for our code for House, the first thing we want to do is declare it as one.

class_name House extends MeshInstance3D

Next, let’s look at the variables we have declared:

var id: int

From a programming perspective, this is our address. We don’t even refer to it ourselves. If someone else is using it, they could potentially already get that information another way? Is this a useful piece of information to provide? Maybe, but architecturally, we are passing around a reference to this House object, which is a Reference, which is in fact a memory address pointing to us. Maybe we don’t need this.

var order_id: int = -1

Have you ever had someone ask you what your order id is, and your immediate response is “I don’t know!” This is not typically information that homeowners track. Later on we use it to tell the DeliveryManager we got our stuff. But let’s be honest, the DeliveryAgent is responsible for telling them that (and taking a verification picture). Probably don’t need this.

var delivery_manager: DeliveryManager

You probably see where I’m going with this. How often have you called up the pizza delivery guy’s boss to tell them that you got your pizza. Never. And now we get to the question, “Does passing the manager into the child objects really break the system?” And the answer is no, but it seems kinda silly when you look at it from a real world example.

Next up, we have our @onready variables.

@onready var delivery_area: Area3D = $Address/DeliveryArea
@onready var address: Marker3D = $Address

You may notice I tweaked the node path. Why?

Well now it’s a lot clearer where the DeliveryArea is without reading the variable declaration. I can see it.

These variables make sense. One is the “address” that the NavigationAgent3D is going to actually use to find us. The other is the Area3D telling us when the thing was delivered. Except - we don’t do anything with that information, except tell the DeliveryManager, which as we’ve determined, is now a ridiculous use case.

So now we simplify everything.

image

A House object does not need a DeliveryArea, because our House and its imaginary occupants do not actually do anything with the delivered pizza/whatever.

Likewise, that simplifies our code immensely:

class_name House extends MeshInstance3D

@onready var address: Marker3D = $Address


func get_address()->Vector3:
	return address.global_position

Let’s go back up to our DeliveryManager code and the random_order() function.

random_order() Redux

This function is to create a random order. But let’s take a look at our definition of a House from a practical point of view. A House contains people that place an order, and sits at an address where the order is delivered. A House doesn’t care if anyone knows the order is delivered once they get it. they’re done. But also… they’re the ones placing the order.

So if we have a Manager, it does make sense that they’re telling the houses what to order. But really, how is that realistic? If we break it down from an OOP perspective, let’s say we want different houses ordering different things? A Manager must not only know that all houses and restaurants exist, but every possible item that can be ordered, so that it can generate orders. If the houses handle ordering (and perhaps ultimately determining that they got what they ordered - which is different from the delivery arriving), the Manager never needs to know what was ordered. It only cares that its worker bees pick up and deliver orders. what’s inside them doesn’t matter to them. They in effect become more like a Dispatcher.

So let’s do a little refactoring.

class_name DeliveryManager extends NavigationRegion3D

var houses: Array[House]

I’ve renamed houses_to_order to houses. Why? Well, I like verbose, descriptive variable names, but there’s only one collection of houses and that’s ones ordering. also, now that we’ve typed our House object, we can make an Array of type House. In fact, if we just make those minor changes (without the deletions from before), the code continues to work as before.

So now every frame we are calling random_order(). For now, we can continue to do this here, but looking at our definition of a DeliveryManager, it might make sense for the Game itself to determine how often Houses get hungry and order.

With the name refactor, our code now looks like this:

func random_order():
	var random_house = randi_range(0, houses.size()-1)
	var new_order: CustomerOrder = CustomerOrder.new()
	new_order.order_id = order_count
	new_order.house_id = houses.get(random_house).id
	new_order.delivery_address = houses.get(random_house).get_address()
	new_order.rest_id = randi_range(0, restaurants_list.restaurants.size()-1)
	new_order.collection_address = restaurants_list.get_restaurant(new_order.rest_id).get_address()
	# add the order id to the restaurant
	restaurants_list.get_restaurant(new_order.rest_id).orders.append(new_order.order_id)
	
	orders_queue.append(new_order)
	var obj = houses.get(random_house)
	orders_address.append(obj)
	houses.erase(obj)
	order_count += 1

Let’s do a few optimizations and renaming of variables for clarity.

Our first line can be changed to something a lot clearer to read:

var random_house = houses.pick_random()

Now that I understand the code more now, random_house is just house, and calling it that will help us see what things the House should be doing. Something much harder to see when it was called rn.

var house = houses.pick_random()

That’s going to make some of our code fail, but it will also simplify it. Instead of using:

new_order.house_id = houses.get(house).id

We just do:

new_order.house_id = house.id

And so on, until we get to this line:

var obj = houses.get(house)

Now what is clear, is we are creating obj to hold a reference to house, but we already have that. This means the whole definition of obj can be deleted and house can be used instead. The next two lines become:

	orders_address.append(house)
	houses.erase(house)

And our code still runs, but instead of doing 4 Array lookups with an index, we just refer to the House object every time.

OrderTaker

Breaking it down a bit more, you can hopefully see that it makes sense to have an OrderTaker separate from the manager. They can prod the houses randomly to order to keep track of the number of orders, but each House when told it can order, can call up the OrderTaker with a signal.

class_name OrderTaker

signal place_order(house, restaurant_id)

var order_count: int = 0
var orders_queue: Array[CustomerOrder]

func _ready() -> void:
	place_order.connect(_on_place_order)

func _on_place_order(house: House, restaurant_id: int) -> void:
	var new_order: CustomerOrder = CustomerOrder.new()
	new_order.order_id = order_count
	new_order.house_id = house.id
	new_order.delivery_address = house.get_address()
	new_order.rest_id = restaurant_id
	new_order.collection_address = restaurants_list.get_restaurant(restaurant_id).get_address()
	restaurants_list.get_restaurant(restaurant_id).orders.append(new_order.order_id)
	
	orders_queue.append(new_order)
	orders_address.append(house)
	houses.erase(house)
	order_count += 1

Conclusion

As we continue on, and create objects to handle each thing, the need for a Manager should become less and less until their job is redundant, or their name changes to the job they have left.

Naming variables and classes is really important to that though. If nothing is named, then it’s all a part of the machine. As you think about intentional names for objects, it helps determine their responsibilities. It will allow you to abstract and encapsulate the objects.

Hope that helps.

1 Like

Thats what I had planned to use, however getting the thing to work suddenly got in the way for about 10 minutes so I had to take the shortcut and change delivery jobs with the state machine in the DeliveryAgent. Actually they would probably reach the area, transfer the orders items from their inventory, then signal to the web server that they completed the delivery - then the web server (this could be the other name for the manager object) signals to the customer that the agent has delivered.

Yeah ‘distpatcher’ is probably a better name for the “manager” object.

short and fast typing for “random_number”

The list named houses_to_order is just the name for the current customer list. The idea was that the possible customer list could be every house in the city, then when an order is made its highly unlikely that the same house will make another order on the same day. so I removed the house from the houses_to_order list and put it in orders_addresses which contained orders ready to go … these in fact are not needed and could be contained within an 'Order token passed to the Restaurant, that holds the Order details and inventory items ready for the DeliveryAgent.

So I think I should divide the DeliveryAgents job into two, Collection and Delivery … the collection job involves getting an inventory from a restaurant, maybe waiting for them to finish cooking, and possibly dealing with missing items. Then the Delivery object has the inventory of FoodItems, and a delivery address and probably a receipt style data set with restaurant name, customer name etc.

yeah I agree … perhaps there is a token like a pin number that the customer uses to unlock the order from the DeliveryAgent.

yeah the order id might be the sort of data that the client app might save, for example when you order food.

I see what your getting at …

In fact the signal may not be connected or I have a reference to the Area3D in code and might not have called it ‘DeliveryArea’ …

This was the area that triggered the signal for delivery complete (or was supposed to)

I have to agree with all this, thankyou for making the effort to answer properly. The OrderTaker is a good idea too.

The manager object is the communication bottleneck in the system - it links the houses and restaurants to the delivery agents, but as everything communicates through that same object the system is not easily scalable, and probably would be better in a multi threaded form.

1 Like

Which makes sense now that I went through your code trying to figure out what it did, assigned kinda the wrong name to it, then used a function to assign a new value to it. Again, naming is important. In this case, your abbreviation was great for your brain in the moment. It was not for mine. It would have saved time in me fixing your code.

Short and fast typing doesn’t beat short and fast copying and pasting. And perhaps you didn’t know about the pick_random() function for Arrays in GDScript, so it wouldn’t have mattered. But you’re clearly coming from another language that does not support duck typing based on the code you are writing.

I know it’s a hard habit to break, but names like that are going to continue to cause you problems with warnings, communication with others, and possibly even communication with your future self. Breaking the habit will help you think about your code more clearly, which is one of the reasons I took the time to go step-by-step.

I’m not trying to attack you for doing it, just encourage you to be more communicative with yourself and everyone else.

Which is fine, but you don’t use it as such currently. This is is how I would do it.

The Area3D triggers the House to accept the items from the DeliveryAgent. When the items are out of the Delivery Agent’s inventory, it signals to the Dispatcher the delivery is complete.

Then if you’re checking for wrong items, the House knows what it ordered, and reports problems to whomever it wants to.

1 Like

Yeah that is one i didnt know about, very useful

Most of my other code is actually verbose, i just had to dive into that function and get something working, ready to refactor later.

Yeah thats the way, the idea is to extend the area to eventually be a parking space or region near the front door for more depth in the simulation … its a component for a city simulator, the logistics of modern hot food deliveries, but the ideas could also be adapted to old fasioned cities. The carried objects and Delivery orders could be contracts or information exchanges. There should be a house address for each NPC

Each order could associated with an NPC instead, so the Delivery Agent could have to wait and meet the NPC instead of just conpleting the order at the door. Then it might also make sense to use the navigation agent signal target_reached.

So my next plan tomorrow is to refactor the code, simplify where possible, then im going to look at reducing the manager object.

The manager or Dispatcher isnt a parent node of the NPC’s and the script is on the navigation region because i planned to fill the lists with for node in get_children(): etc … but a node like that could act like a behaviour tree system.

Again, I’m just trying to encourage you not to take that shortcut, because it hurts you in the long term. If you had the practice of naming variables more verbosely, you wouldn’t look for shorter, more confusing names. I’m also making this point for others who read this thread.

You don’t need to justify your choices to me. Next time, I can just pass on reviewing someone’s code who takes that shortcut. Because I’ve spent way too much energy on this particular point.

Sounds good.

I think extending nodes is a great thing when it makes sense. I think it makes sense for the Dispatcher. As it evolves, that might change. Also, keep in mind the idea of Composition over Inheritance. While I think both are useful and have their place in Godot, Nodes make great component systems.

I’ve improved the project a bit now, some refactoring then I had to backtrack slightly. The code for the Dispatcher now looks like this:

class_name Dispatcher
extends NavigationRegion3D



var ready_customers:Array[Node3D] = []
var busy_customers:Array[Node3D] = []

@onready var restaurants_list: Node = $RestaurantsList
@onready var houses_list: Node = $HousesList

@onready var label: Label = %Label
@onready var label_2: Label = %Label2
@onready var label_3: Label = %Label3

	
var order_count:int = 0

var orders_queue :Array[CustomerOrder]= []
var orders_in_progress :Array[CustomerOrder] = []
var orders_complete :Array[CustomerOrder] = [] 

var time_per_day = 60.0
var curr_time = 0.0

var first_time = true
var order_timer = 0.0


#========================================================================	
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	for e in houses_list.houses:
		ready_customers.append(e)

#========================================================================			
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	curr_time += delta
	order_timer += delta
	
	label.text = "Orders Complete: " + var_to_str(orders_complete.size())
	label_2.text = "Order Queue: " + var_to_str(orders_queue.size())
	label_3.text = "Orders in progress: " + var_to_str(orders_in_progress.size())
	
	if order_timer > 1.5:
		order_timer = 0.0
		if ready_customers.size() > 0:
			random_order()

#========================================================================	
func random_order():
	var random_num = randi_range(0, ready_customers.size()-1) 
	var house :House=  ready_customers.get(random_num)
	
	house.order_id = order_count
	
	var new_order:CustomerOrder = CustomerOrder.new()
	new_order.order_id = order_count
	new_order.house_id = house.id
	new_order.delivery_address = house.get_address()
	
	# needs refactoring below
	new_order.rest_id = randi_range(0, restaurants_list.count-1)
	var restaurant = restaurants_list.get_restaurant(new_order.rest_id)
	new_order.collection_address = restaurant.get_address()

	restaurant.orders.append(new_order.order_id)
	
	orders_queue.append(new_order)

	busy_customers.append(house)
	ready_customers.erase(house)
	order_count += 1
	
#========================================================================		
func get_house_from_busy_list(house_id:int):
	var the_house = null
	for house in busy_customers:
		if (house as House).id == house_id:
			the_house = house
			
	return the_house
	
#========================================================================		
func complete_order(order_id:int):

	var order_found = false
	var order:CustomerOrder = null
	for e in orders_in_progress:
		if e.order_id == order_id:
			order_found = true
			order = e
			break
		
	if order_found:
		orders_in_progress.erase(order)
		orders_complete.append(order)
		var house = get_house_from_busy_list(order.house_id)
		busy_customers.erase(house)
		ready_customers.append(house)
		
#========================================================================		
func get_order():
	if orders_queue.size() > 0:
		var order = orders_queue.get(0)		

		orders_queue.erase(order)
		orders_in_progress.append(order)
		return order
	return null