-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCar.py
144 lines (118 loc) · 5.09 KB
/
Car.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
from pygame.sprite import Sprite
import pygame
import math
import numpy
class Car(Sprite):
def __init__(self, simulation):
"""
Creates a car object, which is a circle
The car has a constant speed, it's direction can be altered using the ang_spd member variable
:param simulation: the Simulation object
"""
super().__init__()
self.screen = simulation.display
self.settings = simulation.settings
sz = self.settings.car_settings['size']
self.orig_img = pygame.Surface((sz, sz), pygame.SRCALPHA)
pygame.draw.circle(self.orig_img, (255, 0, 0), (int(sz/2), int(sz/2)), int(sz/2))
pygame.draw.circle(self.orig_img, (0, 0, 255), (int(sz/2), int(sz*1/3)), (int(sz/3)))
self.image = self.orig_img.copy()
self.rect = self.image.get_rect()
self.rect.center = self.settings.start_pos
self.orientation = 0.0
self.speed = self.settings.car_settings['speed']
self.ang_spd = 0.0
self.x, self.y = self.rect.center
def update(self, *args):
self.orientation += self.ang_spd
self.rect = self.image.get_rect()
x_spd = math.cos(math.radians(self.orientation + 90)) * self.speed
y_spd = -math.sin(math.radians(self.orientation + 90)) * self.speed
self.x += x_spd
self.y += y_spd
self.rect.center = (int(self.x), int(self.y))
def render(self) -> None:
self.image = pygame.transform.rotate(self.orig_img, self.orientation)
self.rect = self.image.get_rect()
self.rect.center = (int(self.x), int(self.y))
self.screen.blit(self.image, self.rect)
class Camera(Sprite):
def __init__(self, game):
"""
Camera used to watch a rectangle around a given point
The camera's size and offset from the pivot is defined in the .yaml file
:param game: Simulation object
"""
super().__init__()
self.screen = game.display
self.settings = game.settings
self.view_sz = self.settings.cam_settings['view_sz']
self.line_w = 3
sz = self.view_sz + 2*self.line_w
self.orig_img = pygame.Surface((sz, sz), pygame.SRCALPHA)
pygame.draw.rect(self.orig_img, (255, 0, 0), pygame.Rect(0, 0, sz, sz), self.line_w)
self.image = self.orig_img.copy()
self.rect = self.image.get_rect()
self.rect.center = self.settings.start_pos
self.rotation = 0
self.cam_view = None
self.cam_view_scaled = None
def update_pos(self, x: float, y: float, rot: float) -> None:
"""
Updates the position of the camera
:param x: x position of pivot(car)
:param y: y position of pivot(car)
:param rot: orientation of pivot(car)
:return:
"""
self.rotation = rot
self.rect = self.image.get_rect()
self.rect.center = (int(x), int(y))
self._update_cam()
def _update_cam(self):
"""Updates the camera's view"""
x, y = self.rect.center
cam_sz = self.view_sz / 2
x_min = int(x - cam_sz)
y_min = int(y - cam_sz)
x_max = int(x + cam_sz)
y_max = int(y + cam_sz)
# get pixels of camera view
arr = pygame.PixelArray(self.screen)
arr2 = arr[x_min:x_max, y_min:y_max]
arr.close()
# convert to surface
surf = arr2.make_surface()
arr2.close()
# rotate surface so car is always pointing in upward direction
surf.set_colorkey(pygame.Color(0)) # transform.rotate crops the image with pixels of this color
surf = pygame.transform.rotate(surf, -self.rotation)
# rotate() changes the size of the surface, crop the middle part
x, y = surf.get_rect().center
x_min = int(x - cam_sz)
y_min = int(y - cam_sz)
keep_ratio = 1 - self.settings.cam_settings['discard_ratio']
w = self.view_sz
h = int(self.view_sz*keep_ratio)
# cropping is done by blitting part of the surface to another surface
self.cam_view = pygame.Surface((self.view_sz, self.view_sz))
self.cam_view.blit(surf, (0, 0), (x_min, y_min, w, h))
# the image's resolution is too high, need to reduce it for easier processing
scaled_sz = self.settings.cam_settings['scaled_sz']
self.cam_view_scaled = pygame.transform.scale(self.cam_view, (scaled_sz, int(keep_ratio*scaled_sz)))
# in the window we show the scaled image, but make it bigger so it's visible
self.cam_view = pygame.transform.scale(self.cam_view_scaled, (w, h))
def render(self, window) -> None:
rect = self.cam_view.get_rect()
rect.topright = (self.settings.window_sz[0], 0)
self.screen.blit(self.image, self.rect)
window.blit(self.cam_view, rect)
def get_cam_arr(self) -> numpy.array:
"""
Returns a numpy array of the camera's view
:return: numpy.array
"""
np_arr = pygame.surfarray.array2d(self.cam_view_scaled)
threshold = 16777210 # white
np_arr[np_arr < threshold] = 0 # ignore non-white pixels
return np_arr