generated from sionleroux/ebitengine-game-template
/
boss.go
171 lines (157 loc) 路 3.83 KB
/
boss.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package main
import (
"errors"
"log"
)
//go:generate ./tools/gen_sprite_tags.sh assets/sprites/Zombie_big.json boss_anim.go boss
// Boss zombie, it is bigger than the rest and you need to kill it twice
type Boss struct {
*Zombie // Inner zombie behaviour
Daemon bool // Whether it has respawned into daemon mode aka Phase 2
State bossAnimationTags // Boss animation state
Frame int // Current animation frame
Dying bool // Whether the death and respawn animation is still playing
Dead bool // Whether the boss has reached its final death
}
// Update boss-specific zombie behaviour
func (z *Boss) Update(g *GameScreen) error {
if z.Dead {
return errors.New("Zombie Boss died")
}
if !z.Dying {
z.hitpointBasedStateChanges(g)
}
z.Frame = Animate(z.Frame, g.Tick, z.Sprite.Meta.FrameTags[z.State])
if z.Frame == z.Sprite.Meta.FrameTags[z.State].To {
z.animationEndTriggers(g)
}
if z.Frame == z.Sprite.Meta.FrameTags[z.State].From {
z.animationStartTriggers(g)
}
if z.State == bossDeath1 || z.State == bossDeath2 || z.State == bossPhase2 {
return nil
}
err := z.Zombie.Update(g)
return err // probably dead inside, return early without handling
}
// Draw draws the Zombie to the screen
func (z *Boss) Draw(g *GameScreen) {
z.Zombie.Frame = z.Frame
z.Zombie.Draw(g)
}
// State changes triggered by LAST frame of animation
func (z *Boss) animationEndTriggers(g *GameScreen) {
switch z.State {
case bossHit1:
z.State = bossWalking1
z.Zombie.State = zombieWalking
case bossHit2:
z.State = bossWalking2
z.Zombie.State = zombieWalking
case bossDeath1:
z.Daemon = true
z.Speed = zombieSprinterSpeed * 2
z.State = bossPhase2
z.Zombie.State = zombieWalking
case bossPhase2:
z.Dying = false
z.State = bossRunning
z.Zombie.State = zombieWalking
g.Sounds[soundBigZombieScream].Play()
case bossDeath2:
z.Die(g)
z.Zombie.State = zombieDead
}
}
// State changes triggered by FIRST frame of animation
func (z *Boss) animationStartTriggers(g *GameScreen) {
switch z.State {
case bossDeath1:
g.Sounds[soundBigZombieDeath1].Play()
case bossDeath2:
g.Sounds[soundBigZombieDeath2].Play()
}
}
func (z *Boss) hitpointBasedStateChanges(g *GameScreen) {
if z.Daemon {
switch z.HitToDie {
case 2:
switch z.Zombie.State {
case zombieHit:
z.State = bossDeath1
case zombieIdle:
z.State = bossIdle4
case zombieWalking:
z.State = bossRunning
}
case 1:
switch z.Zombie.State {
case zombieHit:
z.State = bossDeath2
}
}
} else {
switch z.HitToDie {
case 10, 9, 8:
switch z.Zombie.State {
case zombieIdle:
z.State = bossIdle1
case zombieWalking:
z.State = bossWalking1
case zombieHit:
z.State = bossHit1
}
case 7: // transition to bleeding arm
switch z.Zombie.State {
case zombieHit:
z.State = bossHit1
case zombieIdle:
z.State = bossIdle2
case zombieWalking:
z.State = bossWalking2
}
case 6, 5:
switch z.Zombie.State {
case zombieHit:
z.State = bossHit2
case zombieIdle:
z.State = bossIdle2
case zombieWalking:
z.State = bossWalking2
}
case 4, 3: // transition to 2 bleeding arms
switch z.Zombie.State {
case zombieHit:
z.State = bossHit2
case zombieIdle:
z.State = bossIdle3
case zombieWalking:
z.State = bossWalking3
}
case 2: // transition to red daemon
switch z.Zombie.State {
case zombieHit:
z.Dying = true
z.State = bossDeath1
case zombieIdle:
z.State = bossIdle4
case zombieWalking:
z.State = bossRunning
}
case 1:
switch z.Zombie.State {
case zombieHit:
z.State = bossDeath2
}
}
}
}
func (z *Boss) Remove() {
z.SpawnPoint.RemoveZombie(z)
}
func (z *Boss) Die(g *GameScreen) {
log.Println("Boss defeated!")
z.Dead = true
g.BossDefeated = true
z.Zombie.Die(g)
}