Heightmap Collision Test...

本文介绍了HeightMap碰撞测试中遇到的问题及解决方案。作者通过优化高度插值函数,显著提升了角色在斜坡上移动的平滑度,误差缩小了1%~8%,解决了角色跳跃现象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

做了个HeightMap的碰撞测试,初步效果达到了,但精确度还不是太好貌似。。。

表现为人物在斜坡上移动起来会一跳一跳的

问题应该是根据高度图高度插值求当前高度的函数不太精确

-----------------------------------------------------------------------------

下午把估值函数认真地推导了一遍,测试了下,比原来的误差缩小了1%~8%左右,总之,精确度足够了

斜坡上移动时跳的现象不会出现

 

import pygame import random import math # 初始化 pygame.init() WIDTH, HEIGHT = 600, 670 SCREEN = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("Pac-Man") CLOCK = pygame.time.Clock() # 颜色定义 LIGHT_BLUE = (173, 216, 230) BEIGE = (245, 245, 220) YELLOW = (255, 255, 0) BLACK = (0, 0, 0) BLUE = (33, 33, 255) WHITE = (255, 255, 255) RED = (255, 0, 0) CYAN = (0, 255, 255) PINK = (255, 184, 255) ORANGE = (255, 184, 82) # 游戏状态 MENU = 0 PLAYING = 1 GAME_OVER = 2 current_state = MENU # 迷宫布局 maze = [ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,1], [1,2,1,1,2,1,1,1,2,1,2,1,1,1,2,1,1,2,1], [1,2,1,1,2,1,1,1,2,1,2,1,1,1,2,1,1,2,1], [1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1], [1,2,1,1,2,1,2,1,1,1,1,1,2,1,2,1,1,2,1], [1,2,2,2,2,1,2,2,2,1,2,2,2,1,2,2,2,2,1], [1,1,1,1,2,1,1,1,2,1,2,1,1,1,2,1,1,1,1], [0,0,0,1,2,1,2,2,2,2,2,2,2,1,2,1,0,0,0], [1,1,1,1,2,1,2,1,1,0,1,1,2,1,2,1,1,1,1], [2,2,2,2,2,2,2,1,0,0,0,1,2,2,2,2,2,2,2], [1,1,1,1,2,1,2,1,1,0,1,1,2,1,2,1,1,1,1], [0,0,0,1,2,1,2,2,2,2,2,2,2,1,2,1,0,0,0], [1,1,1,1,2,1,2,1,1,1,1,1,2,1,2,1,1,1,1], [1,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,1], [1,2,1,1,2,1,1,1,2,1,2,1,1,1,2,1,1,2,1], [1,2,2,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1], [1,1,2,2,2,1,2,1,1,1,1,1,2,1,2,2,2,1,1], [1,2,2,1,1,1,2,2,2,1,2,2,2,1,1,1,2,2,1], [1,2,2,2,2,2,2,1,2,2,2,1,2,2,2,2,2,2,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] ] class Pacman: def __init__(self): self.x = 9.0 self.y = 15.0 self.speed = 0.15 self.direction = 0 self.mouth_angle = 0 self.mouth_direction = 1 self.score = 0 self.hitbox = pygame.Rect(0, 0, 20, 20) def update_hitbox(self): self.hitbox.center = (self.x*30+15, self.y*30+15) def move(self): self.mouth_angle += self.mouth_direction * 6 if self.mouth_angle > 35 or self.mouth_angle < 0: self.mouth_direction *= -1 next_x = self.x next_y = self.y dir_map = { 1: (0, -self.speed), # 上 2: (0, self.speed), # 下 3: (-self.speed, 0), # 左 4: (self.speed, 0) # 右 } dx, dy = dir_map.get(self.direction, (0, 0)) # 精确碰撞检测 if dx != 0: test_y = self.y for offset in [-0.4, 0, 0.4]: if not self.check_collision(self.x + dx, test_y + offset): next_x += dx break if dy != 0: test_x = self.x for offset in [-0.4, 0, 0.4]: if not self.check_collision(test_x + offset, self.y + dy): next_y += dy break self.x = next_x self.y = next_y self.update_hitbox() # 吃豆子 if maze[int(self.y)][int(self.x)] == 2: maze[int(self.y)][int(self.x)] = 0 self.score += 10 def check_collision(self, x, y): if x < 0.4 or x >= 19.6 or y < 0.4 or y >= 20.6: return True grid_x = int(round(x)) grid_y = int(round(y)) try: return maze[grid_y][grid_x] == 1 except IndexError: return True def draw(self): direction_angle = { 1: 90, 2: 270, 3: 180, 4: 0 }.get(self.direction, 0) start_angle = math.radians(direction_angle + self.mouth_angle) end_angle = math.radians(direction_angle - self.mouth_angle) pygame.draw.arc(SCREEN, YELLOW, (self.x*30+3, self.y*30+3, 24, 24), start_angle, end_angle, 12) class Ghost: def __init__(self, color, start_pos): self.x, self.y = start_pos self.color = color self.direction = random.choice([1,2,3,4]) self.eye_direction = 4 self.speed = 0.08 self.hitbox = pygame.Rect(0, 0, 20, 20) def update_hitbox(self): self.hitbox.center = (self.x*30+15, self.y*30+15) def move(self): original_dir = self.direction if random.random() < 0.15: self.direction = random.choice([1,2,3,4]) dx, dy = 0, 0 dir_map = { 1: (0, -self.speed), 2: (0, self.speed), 3: (-self.speed, 0), 4: (self.speed, 0) } dx, dy = dir_map[self.direction] if not self.check_collision(self.x + dx, self.y + dy): self.x += dx self.y += dy else: self.direction = random.choice([1,2,3,4]) self.eye_direction = self.direction self.update_hitbox() def check_collision(self, x, y): grid_x = int(round(x)) grid_y = int(round(y)) try: return maze[grid_y][grid_x] == 1 except IndexError: return True def draw(self): pygame.draw.circle(SCREEN, self.color, (int(self.x*30+15), int(self.y*30+15)), 14) eye_pos = { 1: (0, -4), 2: (0, 4), 3: (-4, 0), 4: (4, 0) }[self.eye_direction] pygame.draw.circle(SCREEN, WHITE, (int(self.x*30+15)+eye_pos[0], int(self.y*30+15)+eye_pos[1]), 5) pygame.draw.circle(SCREEN, BLUE, (int(self.x*30+15)+eye_pos[0], int(self.y*30+15)+eye_pos[1]), 3) def draw_maze(): for y in range(len(maze)): for x in range(len(maze[y])): if maze[y][x] == 1: pygame.draw.rect(SCREEN, BLUE, (x*30, y*30, 30, 30), 2) elif maze[y][x] == 2: pygame.draw.circle(SCREEN, WHITE, (x*30+15, y*30+15), 3) def draw_gradient_background(): for i in range(HEIGHT): ratio = i / HEIGHT r = int(LIGHT_BLUE[0] * (1 - ratio) + BEIGE[0] * ratio) g = int(LIGHT_BLUE[1] * (1 - ratio) + BEIGE[1] * ratio) b = int(LIGHT_BLUE[2] * (1 - ratio) + BEIGE[2] * ratio) pygame.draw.line(SCREEN, (r, g, b), (0, i), (WIDTH, i)) def show_menu(): SCREEN.fill(LIGHT_BLUE) draw_gradient_background() title_font = pygame.font.SysFont('arial', 64, True) title_text = title_font.render("PAC-MAN", True, BLUE) SCREEN.blit(title_text, (WIDTH//2-120, HEIGHT//2-120)) mouse_pos = pygame.mouse.get_pos() btn_font = pygame.font.SysFont('arial', 32) # 开始按钮 start_btn = pygame.Rect(WIDTH//2-100, HEIGHT//2+50, 200, 50) btn_color = (100, 200, 100) if start_btn.collidepoint(mouse_pos) else (50, 150, 50) pygame.draw.rect(SCREEN, btn_color, start_btn, border_radius=25) btn_text = btn_font.render("Start Game", True, WHITE) SCREEN.blit(btn_text, (WIDTH//2-80, HEIGHT//2+60)) # 退出按钮 quit_btn = pygame.Rect(WIDTH//2-100, HEIGHT//2+120, 200, 50) btn_color = (200, 100, 100) if quit_btn.collidepoint(mouse_pos) else (150, 50, 50) pygame.draw.rect(SCREEN, btn_color, quit_btn, border_radius=25) btn_text = btn_font.render("Quit Game", True, WHITE) SCREEN.blit(btn_text, (WIDTH//2-75, HEIGHT//2+130)) pygame.display.update() return start_btn, quit_btn def game_loop(): global current_state pacman = Pacman() ghosts = [ Ghost(RED, (9, 7)), Ghost(CYAN, (9, 9)), Ghost(PINK, (10, 7)), Ghost(ORANGE, (10, 9)) ] while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() return if current_state == MENU: if event.type == pygame.MOUSEBUTTONDOWN: start_btn, quit_btn = show_menu() if start_btn.collidepoint(event.pos): current_state = PLAYING elif quit_btn.collidepoint(event.pos): pygame.quit() return elif current_state == PLAYING: if event.type == pygame.KEYDOWN: if event.key == pygame.K_UP: pacman.direction = 1 elif event.key == pygame.K_DOWN: pacman.direction = 2 elif event.key == pygame.K_LEFT: pacman.direction = 3 elif event.key == pygame.K_RIGHT: pacman.direction = 4 if current_state == MENU: show_menu() elif current_state == PLAYING: SCREEN.fill(BLACK) draw_maze() pacman.move() pacman.draw() for ghost in ghosts: ghost.move() ghost.draw() if ghost.hitbox.colliderect(pacman.hitbox): current_state = GAME_OVER # 显示分数 font = pygame.font.SysFont('Arial', 24) score_text = font.render(f'Score: {pacman.score}', True, WHITE) SCREEN.blit(score_text, (10, HEIGHT-40)) pygame.display.update() CLOCK.tick(60) elif current_state == GAME_OVER: SCREEN.fill(BLACK) font = pygame.font.SysFont('Arial', 48) text = font.render('GAME OVER', True, RED) SCREEN.blit(text, (WIDTH//2-120, HEIGHT//2-24)) pygame.display.update() if __name__ == "__main__": game_loop()这个代码中小球无法出来修改代码修正这个问题其他不变
06-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值