-
Notifications
You must be signed in to change notification settings - Fork 4
/
ai_state_threatened.go
145 lines (121 loc) · 3.27 KB
/
ai_state_threatened.go
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
package gamecs
import (
"fmt"
"log"
"github.com/Flokey82/aistate"
"github.com/Flokey82/aitree"
"github.com/Flokey82/go_gens/vectors"
)
const StateTypeFlee aistate.StateType = 1
// StateFlee
type StateFlee struct {
ai *CompAi
}
func NewStateFlee(ai *CompAi) *StateFlee {
return &StateFlee{ai: ai}
}
func (s *StateFlee) Type() aistate.StateType {
return StateTypeFlee
}
func (s *StateFlee) Tick(delta uint64) {
// Check if we are being chased!
// Are we safe?
// TODO: Return false if the state isn't complete yet.
// Return true if we're done and safe.
}
func (s *StateFlee) OnEnter() {
log.Printf("entering state %d", s.Type())
s.ai.CAiPath.running = true // Run away!
// Select a random point to run towards.
// Ideally we'd choose target location that would lead us away from the threat.
s.ai.SetTarget(vectors.RandomVec2(128.0))
log.Println(fmt.Sprintf("fleeing to Target %.2f, %.2f", s.ai.CAiPath.Target.X, s.ai.CAiPath.Target.Y))
}
func (s *StateFlee) OnExit() {
log.Printf("leaving state %d", s.Type())
s.ai.CAiPath.running = false // We're safe, no need to run anymore.
}
const StateTypeAttack aistate.StateType = 2
// StateAttack
type StateAttack struct {
ai *CompAi
ait *aitree.Tree
target *Agent
}
func NewStateAttack(ai *CompAi) *StateAttack {
s := &StateAttack{
ai: ai,
ait: aitree.New(),
}
// New action sequence.
fci := aitree.NewSequence("chase and eliminate threat")
s.ait.Root = fci
// Move towards the target.
am := newActionMoveTo(ai, s.needTarget, func() vectors.Vec2 {
return s.target.Pos
})
fci.Append(am)
// Attack the target.
at := newActionAttack(ai, func() *Agent {
return s.target
})
fci.Append(at)
return s
}
func (s *StateAttack) Type() aistate.StateType {
return StateTypeAttack
}
func (s *StateAttack) needTarget() bool {
return !s.foundTarget()
}
func (s *StateAttack) foundTarget() bool {
return s.target != nil && s.ai.CanSeeEntity(s.target)
}
// findTarget attempts to find a target to attack.
func (s *StateAttack) findTarget() {
// Check if we have already found a target.
if s.foundTarget() {
// Check if the target is dead.
// If so, we give up pursuing the target.
if s.target.Dead() {
s.giveUpTarget()
}
return
}
// Set our target to the current position of the first entity that we have perceived.
// (the first is the closest).
// Ideally we would choose our target based on distance, threat level, etc.
if len(s.ai.Entities) > 0 {
for _, e := range s.ai.Entities {
if e.Dead() {
continue
}
s.target = e
s.ai.running = true // Run to intercept.
break
}
} else {
s.giveUpTarget() // No target in sight, give up.
}
}
// giveUpTarget gives up on the current target.
func (s *StateAttack) giveUpTarget() {
s.target = nil
// TODO: Unset aipath target.
s.ai.running = false // No need to run anymore.
}
func (s *StateAttack) Tick(delta uint64) {
if s.ait.Tick() == aitree.StateFailure {
log.Println(fmt.Sprintf("%d: StateAttack failed!!", s.ai.id))
} else if s.target != nil {
log.Println(fmt.Sprintf("chasing Target %.2f, %.2f", s.ai.CAiPath.Target.X, s.ai.CAiPath.Target.Y))
}
}
func (s *StateAttack) OnEnter() {
log.Printf("entering state %d", s.Type())
s.findTarget()
}
func (s *StateAttack) OnExit() {
log.Printf("leaving state %d", s.Type())
s.giveUpTarget()
}