Open gon-park opened 4 years ago
- 키보드 방향키의 입력에 따라 track에서 자동차를 주행하는 게임
- 자동차가 track과 충돌시 자동차는 죽는다
- 머신러닝에 사용할 게임으로 track과 충돌하지 않고 주행을 완료하는것이 목표인 게임
- user input 에 따라 car acceleration&steering을 결정
- car position&angle 갱신
- K_UP&K_DOWN -> acceleration (속도)
- K_RIGHT&K_LEFT -> steering (진행방향)
- reset screen
- draw car new position
- draw beam
- 자동차의 진행방향 기준으로 track image mask 까지 직선거리를 beam으로 표현
- https://stackoverflow.com/questions/62008457/overlap-between-mask-and-fired-beams-in-pygame-ai-car-model-vision
- print beam length
- beam의 길이를 출력
- 자동차가 track image와 충돌하는지를 판단
- 충돌했다면 자동차를 멈춤
- 충돌 판단 방식
- mask overlap api 를 통해 충돌 체크
- pixel perfect collision detection
- http://renesd.blogspot.com/2017/03/pixel-perfect-collision-detection-in.html
- 자동차의 위치, 속도 출력
https://github.com/29-75/running-car/blob/ByeongJu-Min/game.py 방향키에 따라 차량 운행.
방향전환, 속도는 가속 존재
self.velocity += (self.acceleration * dt, 0)
self.velocity.x = max(-self.max_velocity, min(self.velocity.x, self.max_velocity))
if pressed[pygame.K_RIGHT]:
car.steering -= 30 * dt
elif pressed[pygame.K_LEFT]:
car.steering += 30 * dt
else:
car.steering = 0
if car.position[0] < 0 or car.position[1] < 0 or car.position[0] * ppu > self.width or car.position[1] * ppu > self.height :
car.reset(0)
def crash(self, rotated, car_pos):
iscrash = track_mask.overlap(car_mask, (int(car_pos.x), int(car_pos.y)))
if iscrash:
print(iscrash)
fontObj = pygame.font.Font('HoonWhitecatR.ttf', 30)
carCrashText = " c r a s h ! ( {0[0]} , {0[1]} )".format(iscrash)
carCrashTextObj = fontObj.render(carCrashText, True, RED)
carCrashRect = carCrashTextObj.get_rect();
carCrashRect.topleft = (100, 100)
self.screen.blit(carCrashTextObj, carCrashRect)
rotatedRect = self.screen.blit(rotated, car_pos)
pygame.draw.rect(self.screen, RED, rotatedRect, 2)
return True
else:
return False
@sungwon-ahn
동작 순서
flag 에 따라서 game 의 초기 동작시 차량의 초기 위치 를 지정한다.
if car.flag:
print("start car")
car.flag = False
car.carinit_position.x = 0 / PPU
car.carinit_position.y = 322 / PPU
car.position.x = 0 / PPU
car.position.y = 322 / PPU
if self.game_start:
car.steering = random.uniform(0, car.max_steering) * dt
car.acceleration = random.uniform(0, car.max_acceleration)
car.update(dt)
동작 순서
변경된 차량의 위치에서 rect 를 추출하여 draw_beam 한다.
# Rotated
rotated = pygame.transform.rotate(car.car_image, car.angle)
rect = rotated.get_rect()
carNewPos = Vector2(car.position.x * PPU + rect.width / 2, car.position.y * PPU + rect.height / 2)
pygame.draw.line(self.screen,BLACK,car.carinit_position,car.position)
self.draw_beam(car.angle - 15, carNewPos)
self.draw_beam(car.angle, carNewPos)
self.draw_beam(car.angle + 15, carNewPos)
self.screen.blit(rotated, carNewPos)
pygame.display.flip()
self.clock.tick(self.ticks)
def draw_beam(self, angle, pos):
x_dest = pos[0] + MAX_BEAM_LEN * math.cos(-math.radians(angle))
y_dest = pos[1] + MAX_BEAM_LEN * math.sin(-math.radians(angle))
self.beam_surface.fill((0, 0, 0, 0))
# draw a single beam to the beam surface based on computed final point
pygame.draw.line(self.beam_surface, BLUE, pos, (x_dest, y_dest))
beam_mask = pygame.mask.from_surface(self.beam_surface)
hit = self.map_mask.overlap(beam_mask, (0, 0))
# pygame.draw.circle(self.screen, RED, pos, 5)
if hit is not None:
# hx = self.width - start_position.x if flip_x else start_position.x
# hy = self.height - start_position.y if flip_y else start_position.y
# hit_pos = (hx, hy)
pygame.draw.line(self.screen, WHITE, pos, hit)
pygame.draw.circle(self.screen, RED, hit, 3)
else:
pygame.draw.line(self.screen, WHITE, pos, (x_dest, y_dest))
## update func
- 차량의 속도와 각도에 따라 차량의 위치를 매 round 별로 update 하는 함수.
```py
self.velocity += (self.acceleration * dt, 0)
self.velocity.x = max(-self.max_velocity,
min(self.velocity.x, self.max_velocity))
if self.steering:
turning_radius = self.length / sin(radians(self.steering))
angular_velocity = self.velocity.x / turning_radius
else:
angular_velocity = 0
self.position += self.velocity.rotate(-self.angle) * dt
self.angle += degrees(angular_velocity) * dt
# Make car rect
self.rotated = pygame.transform.rotate(self.car_image, self.angle)
rotated_rect = self.rotated.get_rect()
# Calculate position
self.real_position = self.position * PPU
self.center_position.x = self.real_position.x + rotated_rect.width / 2
self.center_position.y = self.real_position.y + rotated_rect.height / 2
- 특정값을 화면에 출력해주는 함수.
# Drawing
self.screen.fill((0, 0, 0, 0))
self.screen.blit(self.map_surface, (0, 0))
self.printText("car position: " + str(car.position), 3, 3)
self.printText("car steering: " + str(car.steering), 3, 20)
self.printText("car velocity: " + str(car.velocity[0]), 3, 37)
self.printText("car acceleration: " + str(car.acceleration), 3, 54)
self.printText("car angle : " + str(car.angle), 3, 71)
@gon-park
if __name__ == "__main__":
# Declare game
race_game = game.Game(auto=True)
# Run car in builded map
race_game.run_car()
map_path = os.path.join(RESOURCE_DIR, "map.png")
self.map_surface = pygame.image.load(map_path)
self.map_mask = pygame.mask.from_surface(self.map_surface)
mask_fx = pygame.mask.from_surface(
pygame.transform.flip(self.map_surface, True, False))
mask_fy = pygame.mask.from_surface(
pygame.transform.flip(self.map_surface, False, True))
mask_fx_fy = pygame.mask.from_surface(
pygame.transform.flip(self.map_surface, True, True))
self.flipped_masks = [[self.map_mask, mask_fy], [mask_fx, mask_fx_fy]]
self.car = car.Car(*START_POINT)
run_car()
함수를 통해 실제 car 달리는 것 표현 while(true) :
# init screen
self.init_screen()
# Event queue
event = pygame.event.poll()
if event.type == pygame.QUIT:
self.action_status = EXIT
# Process moving
self.process_moving_car()
# Car update
self.car.update(self.dt)
# Car check position
self.check_position_and_reset_position()
# Calculate distance
self.car.point_zero_angle = self.calculate_distance(
self.car.center_position, self.car.angle)
self.car.point_plus_45_angle = self.calculate_distance(
self.car.center_position, self.car.angle + 45)
self.car.point_minus_45_angle = self.calculate_distance(
self.car.center_position, self.car.angle - 45)
# Car check distance and reset position
if self.car.center_position.distance_to(self.car.point_zero_angle) < 5:
self.car.__init__(*START_POINT, angle=0)
elif self.car.center_position.distance_to(self.car.point_minus_45_angle) < 5:
self.car.__init__(*START_POINT, angle=0)
elif self.car.center_position.distance_to(self.car.point_plus_45_angle) < 5:
self.car.__init__(*START_POINT, angle=0)
# Draw
self.draw_screen()
self.clock.tick(self.ticks)
running-car/gon-park/race/car.py
running을 표현하는 지표
)를 포함하고 있는 클래스 self.car_image = pygame.image.load(image_path)
self.position = Vector2(x / PPU, y / PPU)
self.real_position = Vector2(x, y)
self.angle = angle
self.length = length
self.max_acceleration = MAX_ACCELERATION
self.max_steering = MAX_STEERING
self.max_velocity = MAX_VELOCITY
self.free_deceleration = FREE_DECELERATION
self.break_deceleration = BREAK_DECELERATION
self.velocity = Vector2(*ZERO_XY)
self.acceleration = 0.0
self.steering = 0.0
self.rotated = pygame.transform.rotate(self.car_image, self.angle)
self.center_position = Vector2(
self.real_position.x + self.car_image.get_rect().width / 2,
self.real_position.y + self.car_image.get_rect().height / 2)
# line
self.point_minus_45_angle = ZERO_XY
self.point_zero_angle = ZERO_XY
self.point_plus_45_angle = ZERO_XY
update()
함수를 통해 차량의 다양한 지표를 계산하고 업데이트 수행 self.velocity += (self.acceleration * dt, 0)
self.velocity.x = max(-self.max_velocity,
min(self.velocity.x, self.max_velocity))
# >> 속도 업데이트
if self.steering:
turning_radius = self.length / sin(radians(self.steering))
angular_velocity = self.velocity.x / turning_radius
else:
angular_velocity = 0
# >> 방향 업데이트
self.position += self.velocity.rotate(-self.angle) * dt
self.angle += degrees(angular_velocity) * dt
# >> 위치 업데이트
# Make car rect
self.rotated = pygame.transform.rotate(self.car_image, self.angle)
rotated_rect = self.rotated.get_rect()
# >> 방향 전환 된 차 형태 업데이트
# Calculate position
self.real_position = self.position * PPU
self.center_position.x = self.real_position.x + rotated_rect.width / 2
self.center_position.y = self.real_position.y + rotated_rect.height / 2
# >> Car 중앙 위치 업데이트
개인별로 각자 정리 해봅시다.