我在看这个视频:https://www.youtube.com/watch?v=ECqUrT7IdqQ&t=405s 我环顾四周,没有看到这个问题。 (我在光线投射部分的末尾)这是我的代码:
main.py:
import pygame as pg
import sys
from settings import *
from map import *
from player import *
from raycasting import *
class Game:
def __init__(self) -> object:
pg.init()
self.screen = pg.display.set_mode(RES)
self.clock = pg.time.Clock()
self.delta_time = 1
self.new_game()
def new_game(self):
self.map = Map(self)
self.player = Player(self)
self.raycasting = RayCasting(self)
def update(self):
self.player.update()
self.raycasting.update()
pg.display.flip()
self.delta_time = self.clock.tick(FPS)
pg.display.set_caption(f'{self.clock.get_fps() :.1f}')
def draw(self):
self.screen.fill('black')
self.map.draw()
self.player.draw()
def check_events(self):
for event in pg.event.get():
if event.type == pg.QUIT or (event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE):
pg.quit()
sys.exit()
def run(self):
while True:
self.check_events()
self.update()
self.draw()
if __name__ == '__main__':
game = Game()
game.run()
player.py:
from settings import *
import pygame as pg
import math
class Player:
def __init__(self, game):
self.game = game
self.x, self.y = PLAYER_POS
self.angle = PLAYER_ANGLE
def movement(self):
sin_a = math.sin(self.angle)
cos_a = math.cos(self.angle)
dx, dy = 0, 0
speed = PLAYER_SPEED * self.game.delta_time
speed_sin = speed * sin_a
speed_cos = speed * cos_a
keys = pg.key.get_pressed()
if keys[pg.K_w]:
dx += speed_cos
dy += speed_sin
if keys[pg.K_s]:
dx += -speed_cos
dy += -speed_sin
if keys[pg.K_a]:
dx += speed_sin
dy += -speed_cos
if keys [pg.K_d]:
dx += -speed_sin
dy += speed_cos
self.check_wall_collision(dx, dy)
if keys[pg.K_LEFT]:
self.angle -= PLAYER_ROT_SPEED * self.game.delta_time
if keys[pg.K_RIGHT]:
self.angle += PLAYER_ROT_SPEED * self.game.delta_time
self.angle %= math.tau
def check_wall(self, x,y):
return (x, y) not in self.game.map.world_map
def check_wall_collision(self, dx, dy):
if self.check_wall(int(self.x + dx), int(self.y)):
self.x += dx
if self.check_wall(int(self.x), int(self.y + dy)):
self.y += dy
def draw(self):
pg.draw.line(self.game.screen, 'yellow', (self.x * 100, self.y * 100),
(self.x * 100 + WIDTH * math.cos(self.angle),
self.y * 100 + WIDTH * math.sin(self.angle)), 2)
pg.draw.circle(self.game.screen, 'green', (self.x * 100, self.y * 100),15)
def update(self):
self.movement()
@property
def pos(self):
return self.x, self.y
@property
def map_pos(self):
return int(self.x),
地图.py:
import pygame as pg
_ = False
mini_map = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, _, _, _, _, _, _, _, _, _, _, _, _, _, _, 1],
[1, _, _, 1, 1, 1, 1, _, _, _, 1, 1, 1, _, _, 1],
[1, _, _, _, _, _, 1, _, _, _, _, _, 1, _, _, 1],
[1, _, _, _, _, _, 1, _, _, _, _, _, 1, _, _, 1],
[1, _, _, 1, 1, 1, 1, _, _, _, _, _, _, _, _, 1],
[1, _, _, _, _, _, _, _, _, _, _, 1, 1, _, _, 1],
[1, _, _, 1, _, _, _, _, _, _, _, 1, _, _, _, 1],
[1, 1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1],
]
class Map:
def __init__(self, game):
self.game = game
self.mini_map = mini_map
self.world_map = {}
self.get_map()
def get_map(self):
for j, row in enumerate(self.mini_map):
for i, value in enumerate(row):
if value:
self.world_map[(i, j)] = value
def draw(self):
[pg.draw.rect(self.game.screen, 'darkgray', (pos[0] * 100, pos[1] * 100, 100, 100),2)
for pos in self.world_map]
光线投射.py:
import pygame as pg
import math
from settings import *
class RayCasting:
def __init__(self, game):
self.game = game
def ray_cast(self):
ox, oy = self.game.player.pos
x_map = self.game.player.map_pos
y_map = self.game.player.map_pos
ray_angle = self.game.player.angle - HALF_FOV + 0.0001
for ray in range(NUM_RAYS):
sin_a = math.sin(ray_angle)
cos_a = math.cos(ray_angle)
# horizontals
y_hor: object
y_hor, dy = (y_map + 1, 1) if sin_a > 0 else (y_map - 1e-6, -1)
depth_hor = (y_hor - oy) / sin_a
x_hor = ox + depth_hor * cos_a
delta_depth = dy / sin_a
dx = delta_depth * cos_a
for i in range(MAX_DEPTH):
tile_hor = int(x_hor), int(y_hor)
if tile_hor in self.game.map.world_map:
break
x_hor += dx
y_hor += dy
depth_hor += delta_depth
# verticals
x_vert, dx = (x_map + 1, 1) if cos_a > 0 else (x_map - 1e-6, -1)
depth_vert = (x_vert - ox) / cos_a
y_vert = oy + depth_vert * sin_a
delta_depth = dx / cos_a
dy = delta_depth * sin_a
for i in range(MAX_DEPTH):
tile_vert = int(x_vert), int(y_vert)
if tile_vert in self.game.map.world_map:
break
x_vert += dx
y_vert += dy
depth_vert += delta_depth
# depth
if depth_vert < depth_hor:
depth = depth_vert
else:
depth = depth_hor
# drawing for debug
pg.draw.line(self.game.screen, 'blue', (100 * ox, 100 * oy),
(100 * ox + 100 * depth * cos_a, 100 * oy + 100 * depth * sin_a), 2)
ray_angle += DELTA_ANGLE
def update(self):
self.ray_cast()
设置.py:
RES = WIDTH, HEIGHT = 1600, 900
FPS = 60
PLAYER_POS = 1.5, 5 #mini map
PLAYER_ANGLE = 0
PLAYER_SPEED = 0.004
PLAYER_ROT_SPEED = 0.002
FOV = math.pi / 3
HALF_FOV = FOV / 2
NUM_RAYS = WIDTH // 2
HALF_NUM_RAYS = NUM_RAYS // 2
DELTA_ANGLE = FOV / NUM_RAYS
MAX_DEPTH = 20
我已经尝试查看他的视频中有错误的区域并比较两者,但我没有发现任何问题。我曾尝试使用 Pycharm 的调试功能,但它只是针对其中一个问题(第 22 行,raycasting.py)“TypeError: unsupported operand type(s) for -: 'tuple' and 'float'”,但我不是确定如何解决这个问题。 Pycharm 给我的其他错误只是说出该行及其上的内容,调试器不执行任何操作。我可能只是遗漏了一些可以修复错误的东西。谁能帮帮我?