devpace 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- devPace/GlobalDebugger.py +53 -0
- devPace/__init__.py +39 -0
- devPace/_net.py +55 -0
- devPace/assets/animations.py +111 -0
- devPace/assets/cache.py +91 -0
- devPace/assets/images.py +48 -0
- devPace/assets/text.py +7 -0
- devPace/assets/tilemap.py +88 -0
- devPace/basics/camera.py +32 -0
- devPace/basics/input.py +135 -0
- devPace/basics/shapes.py +74 -0
- devPace/helpers/_tilemapEditor.py +340 -0
- devPace/helpers/_tilemap_files.py +154 -0
- devPace/helpers/utils.py +9 -0
- devPace/main.py +184 -0
- devPace/physics/KinematicPlatform.py +87 -0
- devPace/physics/StateManager.py +87 -0
- devPace/physics/collisions.py +40 -0
- devPace/physics/dynamicBody.py +135 -0
- devPace/tracker.txt +13 -0
- devpace-1.0.0.dist-info/METADATA +0 -0
- devpace-1.0.0.dist-info/RECORD +24 -0
- devpace-1.0.0.dist-info/WHEEL +4 -0
- devpace-1.0.0.dist-info/licenses/LICENSE +19 -0
devPace/basics/shapes.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import pygame
|
|
2
|
+
from .._net import Global
|
|
3
|
+
from ..physics.collisions import CollisionRect
|
|
4
|
+
from ..helpers.utils import change_layer
|
|
5
|
+
|
|
6
|
+
class _Shape:
|
|
7
|
+
def __init__(self, x, y, vx, vy, show):
|
|
8
|
+
self.x = x
|
|
9
|
+
self.y = y
|
|
10
|
+
self.vx = vx
|
|
11
|
+
self.vy = vy
|
|
12
|
+
self.show = show
|
|
13
|
+
|
|
14
|
+
self.collision: CollisionRect = None
|
|
15
|
+
|
|
16
|
+
def update(self):
|
|
17
|
+
self.x+=self.vx*Global.dt
|
|
18
|
+
self.y+=self.vy*Global.dt
|
|
19
|
+
if self.collision is not None:
|
|
20
|
+
self.collision.x = self.x
|
|
21
|
+
self.collision.y = self.y
|
|
22
|
+
|
|
23
|
+
class Rect(_Shape):
|
|
24
|
+
def __init__(self, x, y, width, height, color, _width=0, vx=0.0, vy=0.0, show=True, layer=3, enableCollision=False):
|
|
25
|
+
super().__init__(x, y, vx, vy, show)
|
|
26
|
+
self.layer = layer
|
|
27
|
+
self.width=width
|
|
28
|
+
self.height = height
|
|
29
|
+
self.color = color
|
|
30
|
+
self._width=_width
|
|
31
|
+
Global.add_object(layer, self)
|
|
32
|
+
if enableCollision:
|
|
33
|
+
self.collision: CollisionRect = CollisionRect(x, y, width, height, [layer])
|
|
34
|
+
|
|
35
|
+
def change_layer(self, new_layer):
|
|
36
|
+
change_layer(self, new_layer, self.layer)
|
|
37
|
+
self.layer = new_layer
|
|
38
|
+
|
|
39
|
+
def rect(self):
|
|
40
|
+
return pygame.Rect(self.x, self.y, self.width, self.height)
|
|
41
|
+
|
|
42
|
+
def enableCollision(self):
|
|
43
|
+
self.collision = CollisionRect(self.x, self.y, self.width, self.height, [self.layer])
|
|
44
|
+
|
|
45
|
+
def render(self):
|
|
46
|
+
if self.show:
|
|
47
|
+
rect = self.rect()
|
|
48
|
+
rect.x = self.x-Global.cam.x
|
|
49
|
+
rect.y = self.y-Global.cam.y
|
|
50
|
+
pygame.draw.rect(Global.screen, self.color, rect, self._width)
|
|
51
|
+
|
|
52
|
+
class Circle(_Shape):
|
|
53
|
+
def __init__(self, x, y, radius, color, _width=0, vx=0.0, vy=0.0, show=True, layer=3, enableCollision=False):
|
|
54
|
+
super().__init__(x, y, vx, vy, show)
|
|
55
|
+
self.layer = layer
|
|
56
|
+
self.r = radius
|
|
57
|
+
self.color = color
|
|
58
|
+
self._width=_width
|
|
59
|
+
Global.add_object(layer, self)
|
|
60
|
+
|
|
61
|
+
if enableCollision:
|
|
62
|
+
self.collision = CollisionRect(x, y, radius*2, radius*2, [layer])
|
|
63
|
+
|
|
64
|
+
def change_layer(self, new_layer):
|
|
65
|
+
change_layer(self, new_layer, self.layer)
|
|
66
|
+
self.layer = new_layer
|
|
67
|
+
|
|
68
|
+
def enableCollision(self):
|
|
69
|
+
self.collision = CollisionRect(self.x, self.y, self.r*2, self.r*2, [self.layer])
|
|
70
|
+
|
|
71
|
+
def render(self):
|
|
72
|
+
if self.show:
|
|
73
|
+
pygame.draw.circle(Global.screen, self.color, (self.x-Global.cam.x, self.y-Global.cam.y), self.r, self._width)
|
|
74
|
+
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import pygame
|
|
2
|
+
|
|
3
|
+
from ..basics.camera import Camera
|
|
4
|
+
from ..basics.input import Keys
|
|
5
|
+
from .._net import Global
|
|
6
|
+
|
|
7
|
+
def gen_collision_rects(width, height):
|
|
8
|
+
return {
|
|
9
|
+
1: pygame.Rect(0, 0, width, height),
|
|
10
|
+
2: pygame.Rect(0, 0, width, height//2),
|
|
11
|
+
3: pygame.Rect(0, height//2, width, height//2),
|
|
12
|
+
4: pygame.Rect(0, 0, width//2, height),
|
|
13
|
+
5: pygame.Rect(width//2, 0, width//2, height)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class _TileMapEditor:
|
|
17
|
+
def __init__(self, x, y, width, height, map, exit_key, pin=(0, 0)):
|
|
18
|
+
self.width, self.height = width, height
|
|
19
|
+
self.map = map
|
|
20
|
+
self.running = True
|
|
21
|
+
self.exit_key = exit_key
|
|
22
|
+
self._pin = pin
|
|
23
|
+
|
|
24
|
+
self.mode = "painting"
|
|
25
|
+
self.cooldown = False
|
|
26
|
+
|
|
27
|
+
self.cam = Camera(-width/2, -height/2)
|
|
28
|
+
self.cam_speed = 275
|
|
29
|
+
|
|
30
|
+
self.win = pygame.Window("Tilemap Editor", (width, height), (x, y))
|
|
31
|
+
self.screen = self.win.get_surface()
|
|
32
|
+
|
|
33
|
+
self.clock = pygame.time.Clock()
|
|
34
|
+
self.FPS = 60
|
|
35
|
+
self.dt = 0.0
|
|
36
|
+
|
|
37
|
+
self.selected_tile = (0, 0)
|
|
38
|
+
#get the dim of the original tileset
|
|
39
|
+
self.setDim = Global.assets._tileset_cache_data[self.map.name]
|
|
40
|
+
self.setDim = (self.setDim[0]-1, self.setDim[1]-1)
|
|
41
|
+
self.colTypes = gen_collision_rects(self.map.width, self.map.height)
|
|
42
|
+
self.current_col_type = 1
|
|
43
|
+
self.mapColType = 5
|
|
44
|
+
|
|
45
|
+
#keys
|
|
46
|
+
self.key_picking = Keys.tab
|
|
47
|
+
self.key_picking_exit = False
|
|
48
|
+
self.save_cam_pos = (0, 0)
|
|
49
|
+
self.can_click = True
|
|
50
|
+
self.key_collision = Keys.c
|
|
51
|
+
self.key_collision_exit = False
|
|
52
|
+
|
|
53
|
+
def run(self):
|
|
54
|
+
pygame.mouse.set_visible(False)
|
|
55
|
+
while self.running:
|
|
56
|
+
self.update()
|
|
57
|
+
if not self.running: break
|
|
58
|
+
self.render()
|
|
59
|
+
pygame.mouse.set_visible(True)
|
|
60
|
+
|
|
61
|
+
def update(self):
|
|
62
|
+
#if need to exit
|
|
63
|
+
if Keys.is_pressed(self.exit_key) and self.cooldown:
|
|
64
|
+
self.running = False
|
|
65
|
+
return
|
|
66
|
+
else: self.cooldown = True
|
|
67
|
+
|
|
68
|
+
self.change_title(self.mode)
|
|
69
|
+
#win updates
|
|
70
|
+
self.dt = self.clock.tick(self.FPS) / 1000
|
|
71
|
+
Global.events = pygame.event.get()
|
|
72
|
+
for event in Global.events:
|
|
73
|
+
if event.type == pygame.QUIT:
|
|
74
|
+
self.win.close()
|
|
75
|
+
self.running = False
|
|
76
|
+
if event.type == pygame.WINDOWCLOSE:
|
|
77
|
+
try:
|
|
78
|
+
event.window.destroy()
|
|
79
|
+
self.running = False
|
|
80
|
+
except:
|
|
81
|
+
pass
|
|
82
|
+
#other updates
|
|
83
|
+
if self.mode == "painting":
|
|
84
|
+
self.cam_movement()
|
|
85
|
+
self.tile_placing()
|
|
86
|
+
self.basic_tile_selecting()
|
|
87
|
+
if Keys.is_pressed(self.key_picking):
|
|
88
|
+
self.mode = "picking"
|
|
89
|
+
self.save_cam_pos = (self.cam.x, self.cam.y)
|
|
90
|
+
self.cam.x, self.cam.y = 0, 0
|
|
91
|
+
elif Keys.is_pressed(self.key_collision):
|
|
92
|
+
self.mode = "collision"
|
|
93
|
+
self.save_cam_pos = (self.cam.x, self.cam.y)
|
|
94
|
+
self.cam.x, self.cam.y = 0, 0
|
|
95
|
+
elif self.mode == "picking":
|
|
96
|
+
if Keys.is_pressed(self.key_picking) and self.key_picking_exit:
|
|
97
|
+
self.mode = "painting"
|
|
98
|
+
self.cam.x, self.cam.y = self.save_cam_pos
|
|
99
|
+
self.key_picking_exit = False
|
|
100
|
+
else: self.key_picking_exit = True
|
|
101
|
+
if Keys.is_pressed(self.key_collision):
|
|
102
|
+
self.mode = "collision"
|
|
103
|
+
self.save_cam_pos = (self.cam.x, self.cam.y)
|
|
104
|
+
self.cam.x, self.cam.y = 0, 0
|
|
105
|
+
#update logic
|
|
106
|
+
self.cam_movement()
|
|
107
|
+
self.picking_logic()
|
|
108
|
+
self.basic_tile_selecting()
|
|
109
|
+
elif self.mode == "collision":
|
|
110
|
+
if Keys.is_pressed(self.key_collision) and self.key_collision_exit:
|
|
111
|
+
self.mode = "painting"
|
|
112
|
+
self.key_collision_exit = False
|
|
113
|
+
self.cam.x, self.cam.y = self.save_cam_pos
|
|
114
|
+
else: self.key_collision_exit = True
|
|
115
|
+
self.cam_movement()
|
|
116
|
+
self.collision_logic()
|
|
117
|
+
|
|
118
|
+
def render(self):
|
|
119
|
+
self.screen.fill("black")
|
|
120
|
+
#render
|
|
121
|
+
if self.mode == "painting":
|
|
122
|
+
self.render_otherTilemaps()
|
|
123
|
+
self.render_tiles()
|
|
124
|
+
elif self.mode == "picking":
|
|
125
|
+
self.render_picking()
|
|
126
|
+
elif self.mode == "collision":
|
|
127
|
+
self.render_collision()
|
|
128
|
+
|
|
129
|
+
#update
|
|
130
|
+
self.win.flip()
|
|
131
|
+
|
|
132
|
+
def collision_logic(self):
|
|
133
|
+
#change col type based on mouse wheel
|
|
134
|
+
for event in Global.events:
|
|
135
|
+
if event.type == pygame.MOUSEWHEEL:
|
|
136
|
+
if event.y > 0: self.current_col_type += 1
|
|
137
|
+
else: self.current_col_type -= 1
|
|
138
|
+
#wrap around
|
|
139
|
+
if self.current_col_type < 1: self.current_col_type = 5
|
|
140
|
+
elif self.current_col_type > 5: self.current_col_type = 1
|
|
141
|
+
break
|
|
142
|
+
if event.type == pygame.MOUSEBUTTONDOWN:
|
|
143
|
+
mpos = pygame.mouse.get_pos()
|
|
144
|
+
tpos = point_world_to_tilemap(mpos[0]+self.cam.x, mpos[1]+self.cam.y, self.map.width, self.map.height)
|
|
145
|
+
if event.button == 1:
|
|
146
|
+
self.map.collDef[tpos] = self.current_col_type
|
|
147
|
+
elif event.button == 3:
|
|
148
|
+
self.map.collDef.pop(tpos, None)
|
|
149
|
+
def render_collision(self):
|
|
150
|
+
#render tileset
|
|
151
|
+
for pos, image in self.map.tileset.items():
|
|
152
|
+
tx = pos[0] * self.map.width
|
|
153
|
+
ty = pos[1] * self.map.height
|
|
154
|
+
self.screen.blit(image, (tx-self.cam.x, ty-self.cam.y))
|
|
155
|
+
#render existing collisions on tiles
|
|
156
|
+
for pos, num in self.map.collDef.items():
|
|
157
|
+
rect = self.colTypes[num].copy()
|
|
158
|
+
rect.x += pos[0] * self.map.width - self.cam.x
|
|
159
|
+
rect.y += pos[1] * self.map.height - self.cam.y
|
|
160
|
+
pygame.draw.rect(self.screen, "red", rect, 2)
|
|
161
|
+
#render col rect on mouse
|
|
162
|
+
#draw square around mouse
|
|
163
|
+
mpos = pygame.mouse.get_pos()
|
|
164
|
+
tpos = point_world_to_tilemap(mpos[0]+self.cam.x, mpos[1]+self.cam.y, self.map.width, self.map.height)
|
|
165
|
+
rect = self.colTypes[self.current_col_type].copy()
|
|
166
|
+
rect.x += tpos[0] * self.map.width - self.cam.x
|
|
167
|
+
rect.y += tpos[1] * self.map.height - self.cam.y
|
|
168
|
+
pygame.draw.rect(self.screen, "green", rect)
|
|
169
|
+
pygame.draw.rect(self.screen, "white", (tpos[0]*self.map.width-self.cam.x, tpos[1]*self.map.height-self.cam.y, self.map.width, self.map.height), 1)
|
|
170
|
+
|
|
171
|
+
def picking_logic(self):
|
|
172
|
+
if pygame.mouse.get_pressed()[0]:
|
|
173
|
+
mpos = pygame.mouse.get_pos()
|
|
174
|
+
tpos = point_world_to_tilemap(mpos[0]+self.cam.x, mpos[1]+self.cam.y, self.map.width, self.map.height)
|
|
175
|
+
self.selected_tile = tpos
|
|
176
|
+
self.mode = "painting"
|
|
177
|
+
self.cam.x, self.cam.y = self.save_cam_pos
|
|
178
|
+
self.key_picking_exit = False
|
|
179
|
+
self.can_click = False
|
|
180
|
+
elif Keys.is_pressed(Keys.enter):
|
|
181
|
+
self.mode = "painting"
|
|
182
|
+
self.cam.x, self.cam.y = self.save_cam_pos
|
|
183
|
+
self.key_picking_exit = False
|
|
184
|
+
self.can_click = False
|
|
185
|
+
|
|
186
|
+
def render_picking(self):
|
|
187
|
+
#render tileset
|
|
188
|
+
for pos, image in self.map.tileset.items():
|
|
189
|
+
tx = pos[0] * self.map.width
|
|
190
|
+
ty = pos[1] * self.map.height
|
|
191
|
+
self.screen.blit(image, (tx-self.cam.x, ty-self.cam.y))
|
|
192
|
+
#render box around selected tile
|
|
193
|
+
tx = self.selected_tile[0] * self.map.width - self.cam.x
|
|
194
|
+
ty = self.selected_tile[1] * self.map.height - self.cam.y
|
|
195
|
+
pygame.draw.rect(self.screen, "yellow", (tx, ty, self.map.width, self.map.height), 2)
|
|
196
|
+
#draw square around mouse
|
|
197
|
+
mpos = pygame.mouse.get_pos()
|
|
198
|
+
tpos = point_world_to_tilemap(mpos[0]+self.cam.x, mpos[1]+self.cam.y, self.map.width, self.map.height)
|
|
199
|
+
pygame.draw.rect(self.screen, "white", (tpos[0]*self.map.width-self.cam.x, tpos[1]*self.map.height-self.cam.y, self.map.width, self.map.height), 1)
|
|
200
|
+
|
|
201
|
+
def render_tiles(self):
|
|
202
|
+
#draw orgin
|
|
203
|
+
point = (self._pin[0]-self.cam.x, self._pin[1]-self.cam.y)
|
|
204
|
+
if point[0] > 0 and point[0] < self.width and point[1] > 0 and point[1] < self.height:
|
|
205
|
+
pygame.draw.circle(self.screen, "white", point, 5)
|
|
206
|
+
|
|
207
|
+
#render tiles
|
|
208
|
+
for pos, tile in self.map.tiles.items():
|
|
209
|
+
tx = pos[0] * self.map.width - self.cam.x
|
|
210
|
+
ty = pos[1] * self.map.height - self.cam.y
|
|
211
|
+
if tx > -self.map.width and tx < self.width+self.map.width and ty > -self.map.height and ty < self.height+self.map.height:
|
|
212
|
+
image = self.map.tileset[tile]
|
|
213
|
+
self.screen.blit(image, (tx, ty))
|
|
214
|
+
|
|
215
|
+
#draw box around mouse and selected tile
|
|
216
|
+
mpos = pygame.mouse.get_pos()
|
|
217
|
+
tpos = point_world_to_tilemap(mpos[0]+self.cam.x, mpos[1]+self.cam.y, self.map.width, self.map.height)
|
|
218
|
+
self.screen.blit(self.map.tileset[self.selected_tile], (tpos[0]*self.map.width-self.cam.x, tpos[1]*self.map.height-self.cam.y))
|
|
219
|
+
pygame.draw.rect(self.screen, "white", (tpos[0]*self.map.width-self.cam.x, tpos[1]*self.map.height-self.cam.y, self.map.width, self.map.height), 1)
|
|
220
|
+
|
|
221
|
+
def tile_placing(self):
|
|
222
|
+
#placing tile logic
|
|
223
|
+
if pygame.mouse.get_pressed()[0] and self.can_click and not Keys.is_held(Keys.f):
|
|
224
|
+
mpos = pygame.mouse.get_pos()
|
|
225
|
+
tpos = point_world_to_tilemap(mpos[0]+self.cam.x, mpos[1]+self.cam.y, self.map.width, self.map.height)
|
|
226
|
+
self.map.tiles[tpos] = self.selected_tile
|
|
227
|
+
elif not pygame.mouse.get_pressed()[0]: self.can_click = True
|
|
228
|
+
elif pygame.mouse.get_pressed()[0] and self.can_click and Keys.is_held(Keys.f):
|
|
229
|
+
#fill area logic
|
|
230
|
+
self.fillBrushLogic()
|
|
231
|
+
#erasing logic
|
|
232
|
+
if pygame.mouse.get_pressed()[2]:
|
|
233
|
+
mpos = pygame.mouse.get_pos()
|
|
234
|
+
tpos = point_world_to_tilemap(mpos[0]+self.cam.x, mpos[1]+self.cam.y, self.map.width, self.map.height)
|
|
235
|
+
self.map.tiles.pop(tpos, None)
|
|
236
|
+
|
|
237
|
+
def fillBrushLogic(self):
|
|
238
|
+
# 1. Get the mouse position in World Pixels
|
|
239
|
+
mpos = pygame.mouse.get_pos()
|
|
240
|
+
world_x = mpos[0] + self.cam.x
|
|
241
|
+
world_y = mpos[1] + self.cam.y
|
|
242
|
+
|
|
243
|
+
# 2. Convert to Grid/Tile coordinates (e.g., 0, 1, 2... NOT pixels like 32, 64)
|
|
244
|
+
start_tile = point_world_to_tilemap(world_x, world_y, self.map.width, self.map.height)
|
|
245
|
+
|
|
246
|
+
# If the starting tile is already occupied, don't fill anything
|
|
247
|
+
if start_tile in self.map.tiles:
|
|
248
|
+
return
|
|
249
|
+
|
|
250
|
+
# 3. Setup our Queue and Tracker sets
|
|
251
|
+
queue = [start_tile]
|
|
252
|
+
used = set([start_tile])
|
|
253
|
+
tiles_to_place = []
|
|
254
|
+
|
|
255
|
+
# Safety limit to prevent freezing if filling an unbounded open screen
|
|
256
|
+
MAX_FILL_TILES = 1000
|
|
257
|
+
|
|
258
|
+
# 4. The Flood Fill Loop
|
|
259
|
+
while len(queue) > 0:
|
|
260
|
+
if len(tiles_to_place) > MAX_FILL_TILES:
|
|
261
|
+
return # Cancel completely to avoid a system freeze
|
|
262
|
+
|
|
263
|
+
# Pop the first tile coordinate out of the front of our queue
|
|
264
|
+
current_tile = queue.pop(0)
|
|
265
|
+
tiles_to_place.append(current_tile)
|
|
266
|
+
|
|
267
|
+
# 5. Define 4-directional neighbors in Grid Space
|
|
268
|
+
cx, cy = current_tile
|
|
269
|
+
neighbors = [
|
|
270
|
+
(cx + 1, cy), # Right
|
|
271
|
+
(cx - 1, cy), # Left
|
|
272
|
+
(cx, cy + 1), # Down
|
|
273
|
+
(cx, cy - 1) # Up
|
|
274
|
+
]
|
|
275
|
+
|
|
276
|
+
for n in neighbors:
|
|
277
|
+
# Skip if we already evaluated or queued this tile position
|
|
278
|
+
if n in used:
|
|
279
|
+
continue
|
|
280
|
+
|
|
281
|
+
# Skip if there is an existing tile acting as a boundary wall
|
|
282
|
+
if n in self.map.tiles:
|
|
283
|
+
continue
|
|
284
|
+
|
|
285
|
+
# It's an open, unvisited tile! Mark it used and queue it up
|
|
286
|
+
used.add(n)
|
|
287
|
+
queue.append(n)
|
|
288
|
+
|
|
289
|
+
# 6. Execution Phase
|
|
290
|
+
# Commit all computed tiles straight to the engine map matrix array
|
|
291
|
+
for tile_pos in tiles_to_place:
|
|
292
|
+
# Matches your engine style: storing directly via grid tuples
|
|
293
|
+
self.map.tiles[tile_pos] = self.selected_tile
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def basic_tile_selecting(self):
|
|
297
|
+
#changing tile logic
|
|
298
|
+
if Keys.is_pressed(Keys.up): self.selected_tile = (self.selected_tile[0], self.selected_tile[1]-1)
|
|
299
|
+
if Keys.is_pressed(Keys.down): self.selected_tile = (self.selected_tile[0], self.selected_tile[1]+1)
|
|
300
|
+
if Keys.is_pressed(Keys.left): self.selected_tile = (self.selected_tile[0]-1, self.selected_tile[1])
|
|
301
|
+
if Keys.is_pressed(Keys.right): self.selected_tile = (self.selected_tile[0]+1, self.selected_tile[1])
|
|
302
|
+
#wrap around
|
|
303
|
+
if self.selected_tile[0]<0: self.selected_tile = (self.setDim[0]-1, self.selected_tile[1])
|
|
304
|
+
if self.selected_tile[0]>self.setDim[0]: self.selected_tile = (0, self.selected_tile[1])
|
|
305
|
+
if self.selected_tile[1]<0: self.selected_tile = (self.selected_tile[0], self.setDim[1])
|
|
306
|
+
if self.selected_tile[1]>self.setDim[1]: self.selected_tile = (self.selected_tile[0], 0)
|
|
307
|
+
def cam_movement(self):
|
|
308
|
+
#cam movement
|
|
309
|
+
if Keys.is_held(Keys.a): self.cam.x -= self.cam_speed*self.dt
|
|
310
|
+
if Keys.is_held(Keys.d): self.cam.x += self.cam_speed*self.dt
|
|
311
|
+
if Keys.is_held(Keys.w): self.cam.y -= self.cam_speed*self.dt
|
|
312
|
+
if Keys.is_held(Keys.s): self.cam.y += self.cam_speed*self.dt
|
|
313
|
+
self.cam.update()
|
|
314
|
+
|
|
315
|
+
def render_otherTilemaps(self):
|
|
316
|
+
#render tilemaps from Global with respective layers
|
|
317
|
+
layer = -5
|
|
318
|
+
max_layer = 10
|
|
319
|
+
while layer <= max_layer:
|
|
320
|
+
if layer in Global.tilemaps and layer != self.map.layer:
|
|
321
|
+
for map in Global.tilemaps[layer]:
|
|
322
|
+
for pos, tile in map.tiles.items():
|
|
323
|
+
tx = pos[0] * map.width - self.cam.x
|
|
324
|
+
ty = pos[1] * map.height - self.cam.y
|
|
325
|
+
if tx > -map.width and tx < self.width+map.width and ty > -map.height and ty < self.height+map.height:
|
|
326
|
+
image = map.tileset[tile]
|
|
327
|
+
self.screen.blit(image, (tx, ty))
|
|
328
|
+
layer += 1
|
|
329
|
+
|
|
330
|
+
def change_title(self, mode):
|
|
331
|
+
self.win.title = f"Tilemap Editor - {mode.capitalize()} Mode"
|
|
332
|
+
|
|
333
|
+
def point_world_to_tilemap(x, y, width, height):
|
|
334
|
+
return (int(x//width), int(y//height))
|
|
335
|
+
|
|
336
|
+
def around(pos):
|
|
337
|
+
return [(pos[0]-1, pos[1]), (pos[0]+1, pos[1]), (pos[0], pos[1]-1), (pos[0], pos[1]+1), (pos[0]-1, pos[1]-1), (pos[0]-1, pos[1]+1), (pos[0]+1, pos[1]-1), (pos[0]+1, pos[1]+1)]
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import pygame
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from .._net import Global
|
|
6
|
+
from ..physics.collisions import CollisionRect
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def __saveTileMap_json__(path, data:dict[tuple[int, int ], tuple[int, int]], collisions:dict[tuple[int, int], int]):
|
|
10
|
+
new_data = {}
|
|
11
|
+
#covert data into json arrays
|
|
12
|
+
for key, value in data.items():
|
|
13
|
+
new_data[str(key)] = [value[0], value[1]]
|
|
14
|
+
new_collisions = {}
|
|
15
|
+
for key, value in collisions.items():
|
|
16
|
+
new_collisions[str(key)] = value
|
|
17
|
+
#save file
|
|
18
|
+
with open(path, "w") as f:
|
|
19
|
+
json.dump({"map": new_data, "coll": new_collisions}, f)
|
|
20
|
+
|
|
21
|
+
def __loadTileMap_json__(path):
|
|
22
|
+
with open(path, "r") as f:
|
|
23
|
+
i = json.load(f)
|
|
24
|
+
data = i["map"]
|
|
25
|
+
coll = i["coll"]
|
|
26
|
+
info = {}
|
|
27
|
+
for key, value in data.items():
|
|
28
|
+
info[extract_tuple_from_str(key)] = tuple(value)
|
|
29
|
+
collisions = {}
|
|
30
|
+
for key, value in coll.items():
|
|
31
|
+
collisions[extract_tuple_from_str(key)] = value
|
|
32
|
+
return info, collisions
|
|
33
|
+
|
|
34
|
+
def extract_tuple_from_str(str):
|
|
35
|
+
return tuple(float(x) for x in str[1:-1].split(","))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def gen_collision_shapes(self, COL_FULL, COL_HALF_TOP, COL_HALF_BOTTOM, COL_HALF_LEFT, COL_HALF_RIGHT, SEARCH_TIME):
|
|
39
|
+
[t.Del() for t in self.collisions]
|
|
40
|
+
self.collisions.clear()
|
|
41
|
+
|
|
42
|
+
# Separate tiles into shapes
|
|
43
|
+
full = []
|
|
44
|
+
half_top = []
|
|
45
|
+
half_bottom = []
|
|
46
|
+
half_left = []
|
|
47
|
+
half_right = []
|
|
48
|
+
|
|
49
|
+
for key, value in self.tiles.items():
|
|
50
|
+
if value not in self.collDef:
|
|
51
|
+
continue
|
|
52
|
+
# CORRECTION: Appending 'key' (grid pos) instead of 'value' (tile type)
|
|
53
|
+
if self.collDef[value] == COL_FULL: full.append(key)
|
|
54
|
+
elif self.collDef[value] == COL_HALF_TOP: half_top.append(key)
|
|
55
|
+
elif self.collDef[value] == COL_HALF_BOTTOM: half_bottom.append(key)
|
|
56
|
+
elif self.collDef[value] == COL_HALF_LEFT: half_left.append(key)
|
|
57
|
+
elif self.collDef[value] == COL_HALF_RIGHT: half_right.append(key)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Gen collision shapes
|
|
61
|
+
_tiles = []
|
|
62
|
+
used = []
|
|
63
|
+
rows: list[CollisionRect] = _gen_tiles_left_right([], used, full, self, SEARCH_TIME, CollisionRect(0, 0, self.width, self.height, self.collisionLayers))
|
|
64
|
+
#join rows to form rects
|
|
65
|
+
for shape in rows:
|
|
66
|
+
if shape in used: continue
|
|
67
|
+
#else this is current shape to attempt and match
|
|
68
|
+
#used.append(shape)
|
|
69
|
+
_tiles.append(shape)
|
|
70
|
+
for i in range(SEARCH_TIME):
|
|
71
|
+
for other_shape in rows:
|
|
72
|
+
if other_shape in used: continue
|
|
73
|
+
#elif above, and width is the same, and x is the same
|
|
74
|
+
if other_shape.y == shape.y-other_shape.height and other_shape.width == shape.width and other_shape.x == shape.x:
|
|
75
|
+
shape.y -= other_shape.height
|
|
76
|
+
shape.height += other_shape.height
|
|
77
|
+
other_shape.Del()
|
|
78
|
+
used.append(other_shape)
|
|
79
|
+
#elif below, and width is the same, and x is the same
|
|
80
|
+
if other_shape.y == shape.y+shape.height and other_shape.width == shape.width and other_shape.x == shape.x:
|
|
81
|
+
shape.height += other_shape.height
|
|
82
|
+
other_shape.Del()
|
|
83
|
+
used.append(other_shape)
|
|
84
|
+
|
|
85
|
+
#half top tiles
|
|
86
|
+
_tiles = _gen_tiles_left_right(_tiles, used, half_top, self, SEARCH_TIME, CollisionRect(0, 0, self.width, self.height//2, self.collisionLayers))
|
|
87
|
+
#half bottom tiles
|
|
88
|
+
_tiles = _gen_tiles_left_right(_tiles, used, half_bottom, self, SEARCH_TIME, CollisionRect(0, self.height//2, self.width, self.height//2, self.collisionLayers))
|
|
89
|
+
#half left tiles
|
|
90
|
+
_tiles = _gen_tiles_top_bottom(_tiles, used, half_left, self, SEARCH_TIME, CollisionRect(0, 0, self.width//2, self.height, self.collisionLayers))
|
|
91
|
+
#half right tiles
|
|
92
|
+
_tiles = _gen_tiles_top_bottom(_tiles, used, half_right, self, SEARCH_TIME, CollisionRect(self.width//2, 0, self.width//2, self.height, self.collisionLayers))
|
|
93
|
+
|
|
94
|
+
# CORRECTION: Make sure generated rectangles are actually added to your active collisions list
|
|
95
|
+
for i in _tiles:
|
|
96
|
+
self.collisions.append(i)
|
|
97
|
+
#print(len(self.collisions))
|
|
98
|
+
#print(len(Global.collisions))
|
|
99
|
+
|
|
100
|
+
def _gen_tiles_left_right(_tiles: list[CollisionRect], used: list, _pos_list: list[tuple], self, SEARCH_TIME: int, shape: CollisionRect):
|
|
101
|
+
used.clear()
|
|
102
|
+
for pos in _pos_list:
|
|
103
|
+
if pos in used: continue
|
|
104
|
+
col = shape.copy()
|
|
105
|
+
#move shape to correct position
|
|
106
|
+
col.x += pos[0]*self.width
|
|
107
|
+
col.y += pos[1]*self.height
|
|
108
|
+
_tiles.append(col)
|
|
109
|
+
used.append(pos)
|
|
110
|
+
#run search through tiles
|
|
111
|
+
for i in range(SEARCH_TIME):
|
|
112
|
+
for tile in _pos_list:
|
|
113
|
+
if tile in used: continue
|
|
114
|
+
#else check left then right
|
|
115
|
+
if tile[0] == (col.x//self.width)-1 and tile[1] == pos[1]:
|
|
116
|
+
col.x -= self.width
|
|
117
|
+
col.width += self.width
|
|
118
|
+
used.append(tile)
|
|
119
|
+
elif tile[0] == (col.x+col.width)//self.width and tile[1] == pos[1]:
|
|
120
|
+
col.width += self.width
|
|
121
|
+
used.append(tile)
|
|
122
|
+
#else leave it be
|
|
123
|
+
#clear collisions shape used as template
|
|
124
|
+
shape.Del()
|
|
125
|
+
return _tiles
|
|
126
|
+
|
|
127
|
+
def _gen_tiles_top_bottom(_tiles: list[CollisionRect], used: list, _pos_list: list[tuple], self, SEARCH_TIME: int, shape: CollisionRect):
|
|
128
|
+
used.clear()
|
|
129
|
+
for pos in _pos_list:
|
|
130
|
+
if pos in used: continue
|
|
131
|
+
col = CollisionRect.copy(shape)
|
|
132
|
+
#move shape to correct position
|
|
133
|
+
col.x += pos[0]*self.width
|
|
134
|
+
col.y += pos[1]*self.height
|
|
135
|
+
_tiles.append(col)
|
|
136
|
+
used.append(pos)
|
|
137
|
+
#run search through tiles
|
|
138
|
+
for i in range(SEARCH_TIME):
|
|
139
|
+
for tile in _pos_list:
|
|
140
|
+
if tile in used: continue
|
|
141
|
+
#else check left then right
|
|
142
|
+
if tile[1] == (col.y//self.height)-1 and tile[0] == pos[0]:
|
|
143
|
+
col.y -= self.height
|
|
144
|
+
col.height += self.height
|
|
145
|
+
used.append(tile)
|
|
146
|
+
elif tile[1] == (col.y+col.height)//self.height and tile[0] == pos[0]:
|
|
147
|
+
col.height += self.height
|
|
148
|
+
used.append(tile)
|
|
149
|
+
#else leave it be
|
|
150
|
+
#clear collisions shape used as template
|
|
151
|
+
shape.Del()
|
|
152
|
+
return _tiles
|
|
153
|
+
|
|
154
|
+
|
devPace/helpers/utils.py
ADDED