-
Notifications
You must be signed in to change notification settings - Fork 0
/
fsm.gd
157 lines (135 loc) · 3.75 KB
/
fsm.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
extends Node
class Group:
var parent=null
var links=null
var attributes=null
class State:
var attributes=null
var parent=null
var links=null
class Link:
var next_state=null
var type=null
var timeout=0
var timer=null
var condition_owner=null
var condition_method=null
var condition_expected=true
var timers={}
var groups={}
var states={}
var state_time=0
var current_state=null
var current_state_object=null
var links=[]
signal state_changed(state_from,state_to,params)
func process(delta=0):
if current_state==null or current_state_object==null or links.size()==0:
return
state_time+=delta
for t in timers.keys():
timers[t]+=delta
for link in links:
var condition=true
var found=false
if link.type=="timeout" or link.type=="timed condition":
if link.timer!=null:
condition=timers[link.timer]>link.timeout
else:
condition=state_time>link.timeout
found=true
if condition and (link.type=="condition" or link.type=="timed condition") and link.condition_owner.has_method(link.condition_method):
condition=condition and (link.condition_owner.callv(link.condition_method,[])==link.condition_expected)
found=true
if condition and found:
set_state(link.next_state)
return
func set_state(new_state):
state_time=0
var old_state=current_state
current_state=new_state
current_state_object=states[current_state]
_rebuild_links()
emit_signal("state_changed",old_state,new_state,get_groups_attributes())
func get_groups_attributes():
var attributes
if current_state_object.parent!=null:
attributes=get_group_attributes(current_state_object.parent)
else:
attributes={}
if current_state_object.attributes!=null:
for a in current_state_object.attributes.keys():
attributes[a]=current_state_object.attributes[a]
return attributes
func get_group_attributes(group_name):
var attributes
var g=groups[group_name]
if g.parent!=null:
attributes=get_group_attributes(g.parent)
else:
attributes={}
if g.attributes!=null:
for a in g.attributes.keys():
attributes[a]=g.attributes[a]
return attributes
func _rebuild_links():
links=[]
if current_state_object.parent!=null:
_fill_links(current_state_object.parent)
if current_state_object.links!=null:
for l in current_state_object.links:
links.append(l)
func _fill_links(group):
if not groups.has(group):
return
var group_instance=groups[group]
if group_instance.parent!=null:
_fill_links(group_instance.parent)
if group_instance.links!=null:
for l in group_instance.links:
links.append(l)
func add_group(name,attributes=null,parent=null):
var instance=Group.new()
if attributes!=null:
instance.attributes=attributes
if parent!=null:
instance.parent=parent
groups[name]=instance
func add_state(name,attributes=null,group=null):
var instance=State.new()
if attributes!=null:
instance.attributes=attributes
if group!=null:
instance.parent=group
states[name]=instance
func add_link(state,next_state,type,params):
if states.has(state):
_add_link(states[state],next_state,type,params)
elif groups.has(state):
_add_link(groups[state],next_state,type,params)
func _add_link(instance,next_state,type,params):
var link=Link.new()
link.next_state=next_state
link.type=type
if type=="condition":
link.condition_owner=params[0]
link.condition_method=params[1]
if params.size()>2:
link.condition_expected=params[2]
elif type=="timeout":
link.timeout=params[0]
if params.size()>1:
link.timer=params[1]
elif type=="timed condition":
link.timeout=params[0]
link.condition_owner=params[1]
link.condition_method=params[2]
if params.size()>3:
link.condition_expected=params[3]
if params.size()>4:
link.timer=params[4]
if instance.links==null:
instance.links=[]
instance.links.append(link)
func add_timer(name):
timers[name]=0