-
Notifications
You must be signed in to change notification settings - Fork 2
/
Enemy.py
278 lines (215 loc) · 8.42 KB
/
Enemy.py
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
from abc import ABCMeta, abstractmethod
import pygame
from pygame.locals import *
from Sound import Sound
from Stage import Stage
from Text import Text
class Enemy:
def __init__(self, screen):
self.screen = screen
self.player = Stage.player_object
# 敵固有の設定
for enemy in Stage.enemy_object_list:
enemy.specific = self.specific_settings(self.screen, enemy)
def update(self):
for enemy in Stage.enemy_object_list:
enemy.update(enemy.specific.list_number)
# 画面内の領域のみ処理
if enemy.isDraw:
# ブロックとの当たり判定
if enemy.isPhysics:
enemy.collision(Stage.block_object_list)
# プレイヤーとの当たり判定
player_collision_x, player_collision_y = enemy.sprite_collision(self.player)
# 死亡アニメーション時は戻る
if not self.player.isDeath:
if not player_collision_x(enemy.specific.side_collision):
player_collision_y(enemy.specific.top_collision, enemy.specific.bottom_collision)
# 敵固有の動作
enemy.specific.update()
# 画面外になったらオブジェクト削除
if enemy.isRemove:
enemy.remove()
Stage.enemy_object_list.remove(enemy)
@classmethod
def specific_settings(cls, screen, enemy):
player = Stage.player_object
if enemy.name == "enemy":
return Round(screen, player, enemy)
elif enemy.name == 'koura1':
return Koura(screen, player, enemy)
elif enemy.name == 'fish1' or enemy.name == 'fish2':
return Fish(screen, player, enemy)
else:
return Round(screen, player, enemy)
# 敵を実装する際に継承するクラス
class AbstractEnemy(metaclass=ABCMeta):
def __init__(self, screen, player, enemy, kill_text):
self.screen = screen
self.player = player
self.enemy = enemy
self.kill_text = kill_text # プレイヤーを倒した時に放つ言葉
self.list_number = 0 # 画像が複数枚ある場合の切り替え
@abstractmethod # 敵独自の動き
def update(self):
pass
@abstractmethod # プレイヤーの上に当たった場合
def top_collision(self):
pass
@abstractmethod # プレイヤーの下に当たった(踏まれた)場合
def bottom_collision(self):
pass
@abstractmethod # プレイヤーの横に当たった場合
def side_collision(self):
pass
def kill(self):
self.player.isDeath = True
Text.set(self.screen, self.kill_text, sprite=self.enemy)
# まるい敵
class Round(AbstractEnemy):
def __init__(self, screen, player, enemy):
kill_text = [
"遅すぎるんだよ!!",
"無駄無駄無駄無駄ァ!!",
"テラヨワス",
"ぷー クスクス",
"強靭!!無敵!!最強!!!!",
"性能の差だな…",
"カエレ!!",
"ニマニマ"
]
super().__init__(screen, player, enemy, kill_text)
enemy.isEvent = True if enemy.data == 27.2 else False
def update(self):
pass
def top_collision(self):
super().kill()
def bottom_collision(self):
# 踏めない敵
if self.enemy.data == 27.1:
Sound.play_SE('humi')
# 踏んだ勢いでジャンプ
self.player.y_speed = self.player.JUMP_SPEED - 4.7
self.player.y -= 10
self.player.limit_air_speed()
# 踏める敵
else:
Sound.play_SE('humi')
# 踏まれたら消える
self.enemy.remove()
Stage.enemy_object_list.remove(self.enemy)
# 踏んだ勢いでジャンプ
self.player.isJump = True
self.player.y_speed = self.player.JUMP_SPEED + 1
self.player.y -= 10
self.player.limit_air_speed()
def side_collision(self):
super().kill()
# 甲羅亀
class Koura(AbstractEnemy):
def __init__(self, screen, player, enemy):
kill_text = "鉄壁!!よって、無敵!!"
super().__init__(screen, player, enemy, kill_text)
enemy.direction = -1
def update(self):
for other_enemy in Stage.enemy_object_list:
if other_enemy.isDraw and other_enemy != self.enemy:
# 甲羅が他の敵に当たった時はそのまま倒す
if self.list_number == 1 and self.enemy.direction != 0:
def _remove():
Sound.play_SE('koura')
other_enemy.remove()
Stage.enemy_object_list.remove(other_enemy)
enemy_collision_x, enemy_collision_y = self.enemy.sprite_collision(other_enemy)
enemy_collision_x(_remove)
def top_collision(self):
super().kill()
def bottom_collision(self):
Sound.play_SE('humi')
# 甲羅になる場合
if self.list_number == 0:
self.list_number = 1
self.kill_text = "ざまぁw"
self.enemy.direction = 0
self.enemy.x += 4
self.enemy.x_speed = 4.0
self.enemy.width = self.enemy.img_left[self.list_number].get_width()
self.enemy.height = self.enemy.img_left[self.list_number].get_height()
# 甲羅を蹴る場合
elif self.list_number == 1:
if self.enemy.direction == 0:
self.kick_koura()
elif not self.player.isDeath:
self.enemy.direction = 0
# 踏んだ勢いでジャンプ
self.player.isJump = True
self.player.y_speed = self.player.JUMP_SPEED + 1
self.player.y -= 10
self.player.limit_air_speed()
def side_collision(self):
# 甲羅が止まっている場合はそのまま蹴る
if self.list_number == 1 and self.enemy.direction == 0:
self.kick_koura()
else:
self.player.isDeath = True
Text.set(self.screen, self.kill_text, sprite=self.enemy)
# 甲羅を蹴った時の動作
def kick_koura(self):
if self.player.x > self.enemy.rect.left:
self.enemy.direction = 1
self.enemy.x -= 10
else:
self.enemy.direction = -1
self.enemy.x += 10
# 飛ぶ魚
class Fish(AbstractEnemy):
def __init__(self, screen, player, enemy):
kill_text = "Zzz"
super().__init__(screen, player, enemy, kill_text)
enemy.isPhysics = False
enemy.direction = 0
self.isAnimation = False
self.y_speed = 6
# 上向き
if enemy.name == 'fish1':
self.direction = -1
enemy.rect.top = 480
self.isDive_dokan = self._isDokan()
# 下向き
else:
self.direction = 1
enemy.rect.top = -45
self.isDive_dokan = False
# 下に土管がある場合は土管から出る
def _isDokan(self):
start_x = self.enemy.rect.left
start_y = self.enemy.y + self.enemy.height / 3 + 15
end_x = self.enemy.width
end_y = self.enemy.height / 3
new_rect = Rect(start_x, start_y, end_x, end_y)
# pygame.draw.rect(self.screen, (0, 0, 255), new_rect) # 当たり判定可視化 (デバック用)
for block in Stage.block_object_list:
collide = new_rect.colliderect(block.rect)
if collide and block.name == 'dokan1':
self.y_speed = 4
self.enemy.x += 5
self.enemy.rect.top = block.rect.bottom + 15
return True
return False
def update(self):
if not self.isAnimation:
self.animation_start()
if self.isAnimation:
self.enemy.rect.top += self.y_speed * self.direction
# アニメーションのスタート
def animation_start(self):
distance = 37 if self.isDive_dokan else 92
if self.enemy.rect.left > 0 and self.enemy.rect.left - self.player.x < distance:
Sound.play_SE('kirra')
self.isAnimation = True
def top_collision(self):
super().kill()
def bottom_collision(self):
super().kill()
def side_collision(self):
super().kill()