Este artículo se puede considerar la respuesta a este , donde se trata de escribir algo así en C ++, dirigido a principiantes, es decir, con énfasis en un código legible simple en lugar de un alto rendimiento.Después de leer el artículo, tuve la idea de repetir el programa escrito por el autor. Estoy familiarizado con C ++, pero nunca escribí ningún programa complicado en él, prefiero Python. Aquí nació la idea de escribir sobre ella. Estaba especialmente interesado en el rendimiento: estaba casi seguro de que un par de cuadros por segundo es el límite para Python. Estaba equivocado.El primer intento se puede encontrar aquí . Aquí el código está escrito en su totalidad, sin contar las diferencias de idioma, de acuerdo con el dehaqreu. Y debido a esto, la representación es O (n ^ 2), esencialmente bucles anidados en ángulo y distancia:
alpha = player.view - player.fov / 2
mapFB.drawRectangle(player.y - 1, player.x - 1, player.y + 1, player.x + 1, Color(255, 0, 0))
rayNum = 0
while alpha < player.fov / 2 + player.view:
dist = 0
x = player.x
y = player.y
while 0 < x < mapFB.w - 1 and 0 < y < mapFB.h - 1:
...
Debido a esto, el código es bastante lento (pude obtener menos de 3-4 cuadros por segundo en el Intel Core i5 de octava generación).Una forma obvia de acelerar las cosas y no complicar mucho el código es reemplazar el bucle interno con operaciones de complejidad lineal. Consideremos todo desde el punto de vista de las matemáticas: necesitamos determinar el punto de intersección del rayo dado por las coordenadas del jugador y el ángulo de visión, y el bloque especificado por las coordenadas y el tamaño (constante, por simplicidad). A continuación, debe seleccionar la transferencia más cercana y devolverla. A continuación se muestra el código correspondiente (el código completo está aquí ):def block_cross(i, j, k, y_0, alpha, player):
x_cell = i * H
y_cell = j * H
collisions = []
if k != 0:
x = (y_cell - y_0) / k
y = y_cell
if x_cell <= x <= x_cell + H and (x - player.x) / cos(alpha) < 0:
collisions.append((x, y))
if k != 0:
x = (y_cell + H - y_0) / k
y = y_cell + H
if x_cell <= x <= x_cell + H and (x - player.x) / cos(alpha) < 0:
collisions.append((x, y))
x = x_cell
y = y_0 + x * k
if y_cell <= y <= y_cell + H and (x - player.x) / cos(alpha) < 0:
collisions.append((x, y))
x = x_cell + H
y = y_0 + (x) * k
if y_cell <= y <= y_cell + H and (x - player.x) / cos(alpha) < 0:
collisions.append((x, y))
dist = 1000 * H
x = None
y = None
for collision in collisions:
tmp = sqrt((collision[0] - player.x) ** 2 + (collision[1] - player.y) ** 2)
if tmp < dist:
dist = tmp;
x = collision[0]
y = collision[1]
return x, y, dist
Tal cambio trivial de 10 líneas da una aceleración de más del doble, es decir, aproximadamente 5-6 cuadros por segundo. Esto ya no es tirones, sino una imagen en movimiento, pero sigue siendo bastante lento.Buscando ideas para acelerar el código, me encontré con Cython . En resumen, este es un proyecto que le permite acelerar significativamente el código de Python sin cambiarlo seriamente. Brevemente sobre él, debajo del spoiler.tyts cpdef int fun(int num, float val):
cdef int result
return result
result int( int, , ). , . python-, cdef — python, cython. , python — , :
cpdef int fun(int num, float val):
cdef int result
return result
cdef int fun2(int *arr, float* arr_2):
cdef int arr_3[10][10]
return result
fun2 python, - fun — .
Cython dio algo de aceleración, aunque insignificante, solo que no un par de cuadros por segundo. Sin embargo, en números relativos, esto no es tan pequeño: 8-9 imágenes por segundo, es decir, + 40% a la mejor opción en Python y + 200% a la opción con un algoritmo ingenuo. Esta sigue siendo una imagen muy nerviosa, pero normal para fines educativos. Al final, nuestro objetivo es escribirlo nosotros mismos y disfrutar del proceso, pero para un juego real es más fácil tomar una biblioteca como pygame, o en general posponer Python y tomar algo más adecuado.PD: Sería interesante ver otras opciones para optimizar el código en los comentarios.