Skip to content

Commit 503391d

Browse files
authored
Add files via upload
1 parent 290361a commit 503391d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+5238
-0
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
from tkinter import Tk, Canvas
2+
3+
from PIL.Image import open as openImage
4+
from PIL.ImageTk import PhotoImage
5+
6+
7+
class Background(Canvas):
8+
"""
9+
Classe para gerar um plano de fundo animado
10+
"""
11+
12+
__background = []
13+
__stop = False
14+
15+
def __init__(self, tk_instance, *geometry, fp="background.png", animation_speed=50):
16+
17+
# Verifica se o parâmetro tk_instance é uma instância de Tk
18+
if not isinstance(tk_instance, Tk): raise TypeError("The tk_instance argument must be an instance of Tk.")
19+
20+
# Recebe o caminho de imagem e a velocidade da animação
21+
self.image_path = fp
22+
self.animation_speed = animation_speed
23+
24+
# Recebe a largura e altura do widget
25+
self.__width = geometry[0]
26+
self.__height = geometry[1]
27+
28+
# Inicializa o construtor da classe Canvas
29+
Canvas.__init__(self, master=tk_instance, width=self.__width, height=self.__height)
30+
31+
# Carrega a imagem que será usada no plano de fundo
32+
self.__bg_image = \
33+
self.getPhotoImage(image_path=self.image_path, width=self.__width, height=self.__height, closeAfter=True)[0]
34+
35+
# Cria uma imagem que será fixa, ou seja, que não fará parte da animação e serve em situações de bugs na animação
36+
self.__background_default = self.create_image(self.__width // 2, self.__height // 2, image=self.__bg_image)
37+
38+
# Cria as imagens que serão utilizadas na animação do background
39+
self.__background.append(self.create_image(self.__width // 2, self.__height // 2, image=self.__bg_image))
40+
self.__background.append(
41+
self.create_image(self.__width + (self.__width // 2), self.__height // 2, image=self.__bg_image))
42+
43+
def getBackgroundID(self):
44+
"""
45+
Retorna os id's das imagens de background
46+
"""
47+
return [self.__background_default, *self.__background]
48+
49+
@staticmethod
50+
def getPhotoImage(image=None, image_path=None, width=None, height=None, closeAfter=False):
51+
"""
52+
Retorna um objeto da classe PIL.ImageTk.PhotoImage de uma imagem e as imagens criadas de PIL.Image
53+
(photoImage, new, original)
54+
55+
@param image: Instância de PIL.Image.open
56+
@param image_path: Diretório da imagem
57+
@param width: Largura da imagem
58+
@param height: Altura da imagem
59+
@param closeAfter: Se True, a imagem será fechada após ser criado um PhotoImage da mesma
60+
"""
61+
62+
if not image:
63+
if not image_path: return
64+
65+
# Abre a imagem utilizando o caminho dela
66+
image = openImage(image_path)
67+
68+
# Será redimesionada a imagem somente se existir um width ou height
69+
if not width: width = image.width
70+
if not height: height = image.height
71+
72+
# Cria uma nova imagem já redimensionada
73+
newImage = image.resize([width, height])
74+
75+
# Cria um photoImage
76+
photoImage = PhotoImage(newImage)
77+
78+
# Se closeAfter for True, ele fecha as imagens
79+
if closeAfter:
80+
# Fecha a imagem nova
81+
newImage.close()
82+
newImage = None
83+
84+
# Fecha a imagem original
85+
image.close()
86+
image = None
87+
88+
# Retorna o PhotoImage da imagem,a nova imagem que foi utilizada e a imagem original
89+
return photoImage, newImage, image
90+
91+
def reset(self):
92+
"""
93+
Método para resetar o background, apagando todos os itens que não sejam o plano de fundo
94+
"""
95+
96+
# Deleta todos os itens do canvas
97+
self.delete("all")
98+
99+
# Para a animação passando False para o atributo "stop"
100+
self.__stop = False
101+
102+
# Limpa a lista de imagens usadas na animação
103+
self.__background.clear()
104+
105+
# Cria uma imagem que será fixa, ou seja, que não fará parte da animação e serve em situações de bugs na animação
106+
self.__background_default = self.create_image(self.__width // 2, self.__height // 2, image=self.__bg_image)
107+
108+
# Cria as imagens que serão utilizadas na animação do background
109+
self.__background.append(self.create_image(self.__width // 2, self.__height // 2, image=self.__bg_image))
110+
self.__background.append(
111+
self.create_image(self.__width + (self.__width // 2), self.__height // 2, image=self.__bg_image))
112+
113+
def run(self):
114+
"""
115+
Método para iniciar a animação do background
116+
"""
117+
118+
# Enquanto o atributo "stop" for False, a animação continuará em um loop infinito
119+
if not self.__stop:
120+
121+
# Move as imagens de background na posição X
122+
self.move(self.__background[0], -10, 0)
123+
self.move(self.__background[1], -10, 0)
124+
self.tag_lower(self.__background[0])
125+
self.tag_lower(self.__background[1])
126+
self.tag_lower(self.__background_default)
127+
128+
# Se a primeira imagem da lista tiver saído da área do widget, uma nova será criada depois da segunda imagem
129+
if self.bbox(self.__background[0])[2] <= 0:
130+
# Deleta a primeira imagem da lista (imagem que saiu da área do widget)
131+
self.delete(self.__background[0])
132+
self.__background.remove(self.__background[0])
133+
134+
# Cria uma nova imagem a partir da última imagem da animação
135+
width = self.bbox(self.__background[0])[2] + self.__width // 2
136+
self.__background.append(self.create_image(width, self.__height // 2, image=self.__bg_image))
137+
138+
# Executa novamente o método depois de um certo tempo
139+
self.after(self.animation_speed, self.run)
140+
141+
def stop(self):
142+
"""
143+
Método para parar a animação do background
144+
"""
145+
self.__stop = True
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
from threading import Thread
2+
3+
from Background import Background
4+
from PIL.Image import open as openImage
5+
from PIL.ImageTk import PhotoImage
6+
7+
8+
class Bird(Thread):
9+
"""
10+
Classe para criar um pássaro
11+
"""
12+
13+
__tag = "Bird"
14+
__isAlive = None
15+
__going_up = False
16+
__going_down = 0
17+
__times_skipped = 0
18+
__running = False
19+
20+
decends = 0.00390625
21+
climbsUp = 0.0911458333
22+
23+
def __init__(self, background, gameover_function, *screen_geometry, fp="bird.png", event="<Up>", descend_speed=5):
24+
25+
# Verifica se "background" é uma instância de Background e se o "gamerover_method" é chamável
26+
27+
if not isinstance(background, Background): raise TypeError(
28+
"The background argument must be an instance of Background.")
29+
if not callable(gameover_function): raise TypeError("The gameover_method argument must be a callable object.")
30+
31+
# Instância os parâmetros
32+
self.__canvas = background
33+
self.image_path = fp
34+
self.__descend_speed = descend_speed
35+
self.gameover_method = gameover_function
36+
37+
# Recebe a largura e altura do background
38+
self.__width = screen_geometry[0]
39+
self.__height = screen_geometry[1]
40+
41+
# Define a decida e subida do pássaro com base na altura do background
42+
self.decends *= self.__height
43+
self.decends = int(self.decends + 0.5)
44+
self.climbsUp *= self.__height
45+
self.climbsUp = int(self.climbsUp + 0.5)
46+
47+
# Invoca o método construtor de Thread
48+
Thread.__init__(self)
49+
50+
# Calcula o tamanho do pássaro com base na largura e altura da janela
51+
self.width = (self.__width // 100) * 6
52+
self.height = (self.__height // 100) * 11
53+
54+
# Carrega e cria a imagem do pássaro no background
55+
self.__canvas.bird_image = \
56+
self.getPhotoImage(image_path=self.image_path, width=self.width, height=self.height, closeAfter=True)[0]
57+
self.__birdID = self.__canvas.create_image(self.__width // 2, self.__height // 2,
58+
image=self.__canvas.bird_image, tag=self.__tag)
59+
60+
# Define evento para fazer o pássaro subir
61+
self.__canvas.focus_force()
62+
self.__canvas.bind(event, self.jumps)
63+
self.__isAlive = True
64+
65+
def birdIsAlive(self):
66+
"""
67+
Método para verificar se o pássaro está vivo
68+
"""
69+
70+
return self.__isAlive
71+
72+
def checkCollision(self):
73+
"""
74+
Método para verificar se o pássaro ultrapassou a borda da janela ou colidiu com algo
75+
"""
76+
77+
# Recebe a posição do pássaro no background
78+
position = list(self.__canvas.bbox(self.__tag))
79+
80+
# Se o pássaro tiver ultrapassado a borda de baixo do background, ele será declarado morto
81+
if position[3] >= self.__height + 20:
82+
self.__isAlive = False
83+
84+
# Se o pássaro tiver ultrapassado a borda de cima do background, ele será declarado morto
85+
if position[1] <= -20:
86+
self.__isAlive = False
87+
88+
# Dá uma margem de erro ao pássaro de X pixels
89+
position[0] += int(25 / 78 * self.width)
90+
position[1] += int(25 / 77 * self.height)
91+
position[2] -= int(20 / 78 * self.width)
92+
position[3] -= int(10 / 77 * self.width)
93+
94+
# Define os objetos a serem ignorados em colisões
95+
ignored_collisions = self.__canvas.getBackgroundID()
96+
ignored_collisions.append(self.__birdID)
97+
98+
# Verifica possíveis colisões com o pássaro
99+
possible_collisions = list(self.__canvas.find_overlapping(*position))
100+
101+
# Remove das possíveis colisões os objetos ignorados
102+
for _id in ignored_collisions:
103+
try:
104+
possible_collisions.remove(_id)
105+
except:
106+
continue
107+
108+
# Se houver alguma colisão o pássaro morre
109+
if len(possible_collisions) >= 1:
110+
self.__isAlive = False
111+
112+
return not self.__isAlive
113+
114+
def getTag(self):
115+
"""
116+
Método para retornar a tag do pássaro
117+
"""
118+
119+
return self.__tag
120+
121+
@staticmethod
122+
def getPhotoImage(image=None, image_path=None, width=None, height=None, closeAfter=False):
123+
"""
124+
Retorna um objeto da classe PIL.ImageTk.PhotoImage de uma imagem e as imagens criadas de PIL.Image
125+
(photoImage, new, original)
126+
127+
@param image: Instância de PIL.Image.open
128+
@param image_path: Diretório da imagem
129+
@param width: Largura da imagem
130+
@param height: Altura da imagem
131+
@param closeAfter: Se True, a imagem será fechada após ser criado um PhotoImage da mesma
132+
"""
133+
134+
if not image:
135+
if not image_path: return
136+
137+
# Abre a imagem utilizando o caminho dela
138+
image = openImage(image_path)
139+
140+
# Será redimesionada a imagem somente se existir um width ou height
141+
if not width: width = image.width
142+
if not height: height = image.height
143+
144+
# Cria uma nova imagem já redimensionada
145+
newImage = image.resize([width, height])
146+
147+
# Cria um photoImage
148+
photoImage = PhotoImage(newImage)
149+
150+
# Se closeAfter for True, ele fecha as imagens
151+
if closeAfter:
152+
# Fecha a imagem nova
153+
newImage.close()
154+
newImage = None
155+
156+
# Fecha a imagem original
157+
image.close()
158+
image = None
159+
160+
# Retorna o PhotoImage da imagem,a nova imagem que foi utilizada e a imagem original
161+
return photoImage, newImage, image
162+
163+
def jumps(self, event=None):
164+
"""
165+
Método para fazer o pássaro pular
166+
"""
167+
168+
# Verifica se o pássaro saiu da área do background
169+
self.checkCollision()
170+
171+
# Se o pássaro estiver morto, esse método não pode ser executado
172+
if not self.__isAlive or not self.__running:
173+
self.__going_up = False
174+
return
175+
176+
# Declara que o pássaro está subindo
177+
self.__going_up = True
178+
self.__going_down = 0
179+
180+
# Move o pássaro enquanto o limite de subida por animação não tiver excedido
181+
if self.__times_skipped < self.climbsUp:
182+
183+
# Move o pássaro para cima
184+
self.__canvas.move(self.__tag, 0, -1)
185+
self.__times_skipped += 1
186+
187+
# Executa o método novamente
188+
self.__canvas.after(3, self.jumps)
189+
190+
else:
191+
192+
# Declara que o pássaro não está mais subindo
193+
self.__going_up = False
194+
self.__times_skipped = 0
195+
196+
def kill(self):
197+
"""
198+
Método para matar o pássaro
199+
"""
200+
201+
self.__isAlive = False
202+
203+
def run(self):
204+
"""
205+
#Método para iniciar a animação do passáro caindo
206+
"""
207+
208+
self.__running = True
209+
210+
# Verifica se o pássaro saiu da área do background
211+
self.checkCollision()
212+
213+
# Enquanto o pássaro não tiver chegado em sua velocidade máxima, a velocidade aumentará em 0.05
214+
if self.__going_down < self.decends:
215+
self.__going_down += 0.05
216+
217+
# Executa a animação de descida somente se o pássaro estiver vivo
218+
if self.__isAlive:
219+
220+
# Executa a animação de descida somente se o pássaro não estiver subindo
221+
if not self.__going_up:
222+
# Move o pássaro para baixo
223+
self.__canvas.move(self.__tag, 0, self.__going_down)
224+
225+
# Executa novamente o método
226+
self.__canvas.after(self.__descend_speed, self.run)
227+
228+
# Se o pássaro estiver morto, será executado um método de fim de jogo
229+
else:
230+
self.__running = False
231+
self.gameover_method()

0 commit comments

Comments
 (0)