Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/resources/2d/tile_set.cpp
9903 views
1
/**************************************************************************/
2
/* tile_set.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "tile_set.h"
32
#include "tile_set.compat.inc"
33
34
#include "core/io/marshalls.h"
35
#include "core/math/geometry_2d.h"
36
#include "core/templates/local_vector.h"
37
#include "core/templates/rb_set.h"
38
#include "scene/gui/control.h"
39
#include "scene/resources/image_texture.h"
40
41
#ifndef NAVIGATION_2D_DISABLED
42
#include "servers/navigation_server_2d.h"
43
#endif // NAVIGATION_2D_DISABLED
44
45
/////////////////////////////// TileMapPattern //////////////////////////////////////
46
47
void TileMapPattern::_set_tile_data(const Vector<int> &p_data) {
48
int c = p_data.size();
49
const int *r = p_data.ptr();
50
51
int offset = 3;
52
ERR_FAIL_COND_MSG(c % offset != 0, "Corrupted tile data.");
53
54
clear();
55
56
for (int i = 0; i < c; i += offset) {
57
const uint8_t *ptr = (const uint8_t *)&r[i];
58
uint8_t local[12];
59
for (int j = 0; j < 12; j++) {
60
local[j] = ptr[j];
61
}
62
63
#ifdef BIG_ENDIAN_ENABLED
64
SWAP(local[0], local[3]);
65
SWAP(local[1], local[2]);
66
SWAP(local[4], local[7]);
67
SWAP(local[5], local[6]);
68
SWAP(local[8], local[11]);
69
SWAP(local[9], local[10]);
70
#endif
71
72
int16_t x = decode_uint16(&local[0]);
73
int16_t y = decode_uint16(&local[2]);
74
uint16_t source_id = decode_uint16(&local[4]);
75
uint16_t atlas_coords_x = decode_uint16(&local[6]);
76
uint16_t atlas_coords_y = decode_uint16(&local[8]);
77
uint16_t alternative_tile = decode_uint16(&local[10]);
78
set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile);
79
}
80
emit_signal(CoreStringName(changed));
81
}
82
83
Vector<int> TileMapPattern::_get_tile_data() const {
84
// Export tile data to raw format
85
Vector<int> data;
86
data.resize(pattern.size() * 3);
87
int *w = data.ptrw();
88
89
// Save in highest format
90
91
int idx = 0;
92
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
93
uint8_t *ptr = (uint8_t *)&w[idx];
94
encode_uint16((int16_t)(E.key.x), &ptr[0]);
95
encode_uint16((int16_t)(E.key.y), &ptr[2]);
96
encode_uint16(E.value.source_id, &ptr[4]);
97
encode_uint16(E.value.coord_x, &ptr[6]);
98
encode_uint16(E.value.coord_y, &ptr[8]);
99
encode_uint16(E.value.alternative_tile, &ptr[10]);
100
idx += 3;
101
}
102
103
return data;
104
}
105
106
void TileMapPattern::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) {
107
ERR_FAIL_COND_MSG(p_coords.x < 0 || p_coords.y < 0, vformat("Cannot set cell with negative coords in a TileMapPattern. Wrong coords: %s", p_coords));
108
109
size = size.max(p_coords + Vector2i(1, 1));
110
pattern[p_coords] = TileMapCell(p_source_id, p_atlas_coords, p_alternative_tile);
111
emit_changed();
112
}
113
114
bool TileMapPattern::has_cell(const Vector2i &p_coords) const {
115
return pattern.has(p_coords);
116
}
117
118
void TileMapPattern::remove_cell(const Vector2i &p_coords, bool p_update_size) {
119
ERR_FAIL_COND(!pattern.has(p_coords));
120
121
pattern.erase(p_coords);
122
if (p_update_size) {
123
size = Size2i();
124
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
125
size = size.max(E.key + Vector2i(1, 1));
126
}
127
}
128
emit_changed();
129
}
130
131
int TileMapPattern::get_cell_source_id(const Vector2i &p_coords) const {
132
ERR_FAIL_COND_V(!pattern.has(p_coords), TileSet::INVALID_SOURCE);
133
134
return pattern[p_coords].source_id;
135
}
136
137
Vector2i TileMapPattern::get_cell_atlas_coords(const Vector2i &p_coords) const {
138
ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetSource::INVALID_ATLAS_COORDS);
139
140
return pattern[p_coords].get_atlas_coords();
141
}
142
143
int TileMapPattern::get_cell_alternative_tile(const Vector2i &p_coords) const {
144
ERR_FAIL_COND_V(!pattern.has(p_coords), TileSetSource::INVALID_TILE_ALTERNATIVE);
145
146
return pattern[p_coords].alternative_tile;
147
}
148
149
TypedArray<Vector2i> TileMapPattern::get_used_cells() const {
150
// Returns the cells used in the tilemap.
151
TypedArray<Vector2i> a;
152
a.resize(pattern.size());
153
int i = 0;
154
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
155
Vector2i p(E.key.x, E.key.y);
156
a[i++] = p;
157
}
158
159
return a;
160
}
161
162
Size2i TileMapPattern::get_size() const {
163
return size;
164
}
165
166
void TileMapPattern::set_size(const Size2i &p_size) {
167
for (const KeyValue<Vector2i, TileMapCell> &E : pattern) {
168
Vector2i coords = E.key;
169
if (p_size.x <= coords.x || p_size.y <= coords.y) {
170
ERR_FAIL_MSG(vformat("Cannot set pattern size to %s, it contains a tile at %s. Size can only be increased.", p_size, coords));
171
};
172
}
173
174
size = p_size;
175
emit_changed();
176
}
177
178
bool TileMapPattern::is_empty() const {
179
return pattern.is_empty();
180
}
181
182
void TileMapPattern::clear() {
183
size = Size2i();
184
pattern.clear();
185
emit_changed();
186
}
187
188
bool TileMapPattern::_set(const StringName &p_name, const Variant &p_value) {
189
if (p_name == "tile_data") {
190
if (p_value.is_array()) {
191
_set_tile_data(p_value);
192
return true;
193
}
194
return false;
195
}
196
return false;
197
}
198
199
bool TileMapPattern::_get(const StringName &p_name, Variant &r_ret) const {
200
if (p_name == "tile_data") {
201
r_ret = _get_tile_data();
202
return true;
203
}
204
return false;
205
}
206
207
void TileMapPattern::_get_property_list(List<PropertyInfo> *p_list) const {
208
p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
209
}
210
211
void TileMapPattern::_bind_methods() {
212
ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapPattern::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE));
213
ClassDB::bind_method(D_METHOD("has_cell", "coords"), &TileMapPattern::has_cell);
214
ClassDB::bind_method(D_METHOD("remove_cell", "coords", "update_size"), &TileMapPattern::remove_cell);
215
ClassDB::bind_method(D_METHOD("get_cell_source_id", "coords"), &TileMapPattern::get_cell_source_id);
216
ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "coords"), &TileMapPattern::get_cell_atlas_coords);
217
ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "coords"), &TileMapPattern::get_cell_alternative_tile);
218
219
ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMapPattern::get_used_cells);
220
ClassDB::bind_method(D_METHOD("get_size"), &TileMapPattern::get_size);
221
ClassDB::bind_method(D_METHOD("set_size", "size"), &TileMapPattern::set_size);
222
ClassDB::bind_method(D_METHOD("is_empty"), &TileMapPattern::is_empty);
223
}
224
225
/////////////////////////////// TileSet //////////////////////////////////////
226
227
bool TileSet::TerrainsPattern::is_valid() const {
228
return valid;
229
}
230
231
bool TileSet::TerrainsPattern::is_erase_pattern() const {
232
return not_empty_terrains_count == 0;
233
}
234
235
bool TileSet::TerrainsPattern::operator<(const TerrainsPattern &p_terrains_pattern) const {
236
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
237
if (is_valid_bit[i] != p_terrains_pattern.is_valid_bit[i]) {
238
return is_valid_bit[i] < p_terrains_pattern.is_valid_bit[i];
239
}
240
}
241
if (terrain != p_terrains_pattern.terrain) {
242
return terrain < p_terrains_pattern.terrain;
243
}
244
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
245
if (is_valid_bit[i] && bits[i] != p_terrains_pattern.bits[i]) {
246
return bits[i] < p_terrains_pattern.bits[i];
247
}
248
}
249
return false;
250
}
251
252
bool TileSet::TerrainsPattern::operator==(const TerrainsPattern &p_terrains_pattern) const {
253
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
254
if (is_valid_bit[i] != p_terrains_pattern.is_valid_bit[i]) {
255
return false;
256
}
257
if (is_valid_bit[i] && bits[i] != p_terrains_pattern.bits[i]) {
258
return false;
259
}
260
}
261
if (terrain != p_terrains_pattern.terrain) {
262
return false;
263
}
264
return true;
265
}
266
267
void TileSet::TerrainsPattern::set_terrain(int p_terrain) {
268
ERR_FAIL_COND(p_terrain < -1);
269
270
terrain = p_terrain;
271
}
272
273
int TileSet::TerrainsPattern::get_terrain() const {
274
return terrain;
275
}
276
277
void TileSet::TerrainsPattern::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain) {
278
ERR_FAIL_COND(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX);
279
ERR_FAIL_COND(!is_valid_bit[p_peering_bit]);
280
ERR_FAIL_COND(p_terrain < -1);
281
282
// Update the "is_erase_pattern" status.
283
if (p_terrain >= 0 && bits[p_peering_bit] < 0) {
284
not_empty_terrains_count++;
285
} else if (p_terrain < 0 && bits[p_peering_bit] >= 0) {
286
not_empty_terrains_count--;
287
}
288
289
bits[p_peering_bit] = p_terrain;
290
}
291
292
int TileSet::TerrainsPattern::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
293
ERR_FAIL_COND_V(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX, -1);
294
ERR_FAIL_COND_V(!is_valid_bit[p_peering_bit], -1);
295
return bits[p_peering_bit];
296
}
297
298
void TileSet::TerrainsPattern::from_array(Array p_terrains) {
299
set_terrain(p_terrains[0]);
300
int in_array_index = 1;
301
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
302
if (is_valid_bit[i]) {
303
ERR_FAIL_INDEX(in_array_index, p_terrains.size());
304
set_terrain_peering_bit(TileSet::CellNeighbor(i), p_terrains[in_array_index]);
305
in_array_index++;
306
}
307
}
308
}
309
310
Array TileSet::TerrainsPattern::as_array() const {
311
Array output = { get_terrain() };
312
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
313
if (is_valid_bit[i]) {
314
output.push_back(bits[i]);
315
}
316
}
317
return output;
318
}
319
320
TileSet::TerrainsPattern::TerrainsPattern(const TileSet *p_tile_set, int p_terrain_set) {
321
ERR_FAIL_COND(p_terrain_set < 0);
322
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
323
is_valid_bit[i] = (p_tile_set->is_valid_terrain_peering_bit(p_terrain_set, TileSet::CellNeighbor(i)));
324
bits[i] = -1;
325
}
326
valid = true;
327
}
328
329
const int TileSet::INVALID_SOURCE = -1;
330
331
const char *TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[] = {
332
PNAME("right_side"),
333
PNAME("right_corner"),
334
PNAME("bottom_right_side"),
335
PNAME("bottom_right_corner"),
336
PNAME("bottom_side"),
337
PNAME("bottom_corner"),
338
PNAME("bottom_left_side"),
339
PNAME("bottom_left_corner"),
340
PNAME("left_side"),
341
PNAME("left_corner"),
342
PNAME("top_left_side"),
343
PNAME("top_left_corner"),
344
PNAME("top_side"),
345
PNAME("top_corner"),
346
PNAME("top_right_side"),
347
PNAME("top_right_corner"),
348
};
349
350
// -- Shape and layout --
351
void TileSet::set_tile_shape(TileSet::TileShape p_shape) {
352
tile_shape = p_shape;
353
354
for (KeyValue<int, Ref<TileSetSource>> &E_source : sources) {
355
E_source.value->notify_tile_data_properties_should_change();
356
}
357
358
terrain_bits_meshes_dirty = true;
359
tile_meshes_dirty = true;
360
notify_property_list_changed();
361
emit_changed();
362
}
363
TileSet::TileShape TileSet::get_tile_shape() const {
364
return tile_shape;
365
}
366
367
void TileSet::set_tile_layout(TileSet::TileLayout p_layout) {
368
tile_layout = p_layout;
369
emit_changed();
370
}
371
TileSet::TileLayout TileSet::get_tile_layout() const {
372
return tile_layout;
373
}
374
375
void TileSet::set_tile_offset_axis(TileSet::TileOffsetAxis p_alignment) {
376
tile_offset_axis = p_alignment;
377
378
for (KeyValue<int, Ref<TileSetSource>> &E_source : sources) {
379
E_source.value->notify_tile_data_properties_should_change();
380
}
381
382
terrain_bits_meshes_dirty = true;
383
tile_meshes_dirty = true;
384
emit_changed();
385
}
386
TileSet::TileOffsetAxis TileSet::get_tile_offset_axis() const {
387
return tile_offset_axis;
388
}
389
390
void TileSet::set_tile_size(Size2i p_size) {
391
ERR_FAIL_COND(p_size.x < 1 || p_size.y < 1);
392
tile_size = p_size;
393
terrain_bits_meshes_dirty = true;
394
tile_meshes_dirty = true;
395
emit_changed();
396
}
397
Size2i TileSet::get_tile_size() const {
398
return tile_size;
399
}
400
401
int TileSet::get_next_source_id() const {
402
return next_source_id;
403
}
404
405
void TileSet::_update_terrains_cache() {
406
if (terrains_cache_dirty) {
407
// Organizes tiles into structures.
408
per_terrain_pattern_tiles.resize(terrain_sets.size());
409
for (RBMap<TileSet::TerrainsPattern, RBSet<TileMapCell>> &tiles : per_terrain_pattern_tiles) {
410
tiles.clear();
411
}
412
413
for (const KeyValue<int, Ref<TileSetSource>> &kv : sources) {
414
Ref<TileSetSource> source = kv.value;
415
Ref<TileSetAtlasSource> atlas_source = source;
416
if (atlas_source.is_valid()) {
417
for (int tile_index = 0; tile_index < source->get_tiles_count(); tile_index++) {
418
Vector2i tile_id = source->get_tile_id(tile_index);
419
for (int alternative_index = 0; alternative_index < source->get_alternative_tiles_count(tile_id); alternative_index++) {
420
int alternative_id = source->get_alternative_tile_id(tile_id, alternative_index);
421
422
// Executed for each tile_data.
423
TileData *tile_data = atlas_source->get_tile_data(tile_id, alternative_id);
424
int terrain_set = tile_data->get_terrain_set();
425
if (terrain_set >= 0) {
426
TileMapCell cell;
427
cell.source_id = kv.key;
428
cell.set_atlas_coords(tile_id);
429
cell.alternative_tile = alternative_id;
430
431
TileSet::TerrainsPattern terrains_pattern = tile_data->get_terrains_pattern();
432
433
// Main terrain.
434
if (terrains_pattern.get_terrain() >= 0) {
435
per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
436
}
437
438
// Terrain bits.
439
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
440
CellNeighbor bit = CellNeighbor(i);
441
if (is_valid_terrain_peering_bit(terrain_set, bit)) {
442
int terrain = terrains_pattern.get_terrain_peering_bit(bit);
443
if (terrain >= 0) {
444
per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
445
}
446
}
447
}
448
}
449
}
450
}
451
}
452
}
453
454
// Add the empty cell in the possible patterns and cells.
455
for (int i = 0; i < terrain_sets.size(); i++) {
456
TileSet::TerrainsPattern empty_pattern(this, i);
457
458
TileMapCell empty_cell;
459
empty_cell.source_id = TileSet::INVALID_SOURCE;
460
empty_cell.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
461
empty_cell.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
462
per_terrain_pattern_tiles[i][empty_pattern].insert(empty_cell);
463
}
464
terrains_cache_dirty = false;
465
}
466
}
467
468
void TileSet::_compute_next_source_id() {
469
while (sources.has(next_source_id)) {
470
next_source_id = (next_source_id + 1) % 1073741824; // 2 ** 30
471
};
472
}
473
474
// Sources management
475
int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source_id_override) {
476
ERR_FAIL_COND_V(p_tile_set_source.is_null(), TileSet::INVALID_SOURCE);
477
ERR_FAIL_COND_V_MSG(p_atlas_source_id_override >= 0 && (sources.has(p_atlas_source_id_override)), TileSet::INVALID_SOURCE, vformat("Cannot create TileSet atlas source. Another atlas source exists with id %d.", p_atlas_source_id_override));
478
ERR_FAIL_COND_V_MSG(p_atlas_source_id_override < 0 && p_atlas_source_id_override != TileSet::INVALID_SOURCE, TileSet::INVALID_SOURCE, vformat("Provided source ID %d is not valid. Negative source IDs are not allowed.", p_atlas_source_id_override));
479
480
int new_source_id = p_atlas_source_id_override >= 0 ? p_atlas_source_id_override : next_source_id;
481
sources[new_source_id] = p_tile_set_source;
482
source_ids.push_back(new_source_id);
483
source_ids.sort();
484
TileSet *old_tileset = p_tile_set_source->get_tile_set();
485
if (old_tileset != this && old_tileset != nullptr) {
486
// If the source is already in a TileSet (might happen when duplicating), remove it from the other TileSet.
487
old_tileset->remove_source_ptr(p_tile_set_source.ptr());
488
}
489
p_tile_set_source->set_tile_set(this);
490
_compute_next_source_id();
491
492
sources[new_source_id]->connect_changed(callable_mp(this, &TileSet::_source_changed));
493
494
terrains_cache_dirty = true;
495
emit_changed();
496
497
return new_source_id;
498
}
499
500
void TileSet::remove_source(int p_source_id) {
501
ERR_FAIL_COND_MSG(!sources.has(p_source_id), vformat("Cannot remove TileSet atlas source. No tileset atlas source with id %d.", p_source_id));
502
503
sources[p_source_id]->disconnect_changed(callable_mp(this, &TileSet::_source_changed));
504
505
sources[p_source_id]->set_tile_set(nullptr);
506
sources.erase(p_source_id);
507
source_ids.erase(p_source_id);
508
source_ids.sort();
509
510
terrains_cache_dirty = true;
511
emit_changed();
512
}
513
514
void TileSet::remove_source_ptr(TileSetSource *p_tile_set_source) {
515
for (const KeyValue<int, Ref<TileSetSource>> &kv : sources) {
516
if (kv.value.ptr() == p_tile_set_source) {
517
remove_source(kv.key);
518
return;
519
}
520
}
521
ERR_FAIL_MSG(vformat("Attempting to remove source from a tileset, but the tileset doesn't have it: %s", p_tile_set_source));
522
}
523
524
void TileSet::set_source_id(int p_source_id, int p_new_source_id) {
525
ERR_FAIL_COND(p_new_source_id < 0);
526
ERR_FAIL_COND_MSG(!sources.has(p_source_id), vformat("Cannot change TileSet atlas source ID. No tileset atlas source with id %d.", p_source_id));
527
if (p_source_id == p_new_source_id) {
528
return;
529
}
530
531
ERR_FAIL_COND_MSG(sources.has(p_new_source_id), vformat("Cannot change TileSet atlas source ID. Another atlas source exists with id %d.", p_new_source_id));
532
533
sources[p_new_source_id] = sources[p_source_id];
534
sources.erase(p_source_id);
535
536
source_ids.erase(p_source_id);
537
source_ids.push_back(p_new_source_id);
538
source_ids.sort();
539
540
_compute_next_source_id();
541
542
terrains_cache_dirty = true;
543
emit_changed();
544
}
545
546
bool TileSet::has_source(int p_source_id) const {
547
return sources.has(p_source_id);
548
}
549
550
Ref<TileSetSource> TileSet::get_source(int p_source_id) const {
551
ERR_FAIL_COND_V_MSG(!sources.has(p_source_id), nullptr, vformat("No TileSet atlas source with id %d.", p_source_id));
552
553
return sources[p_source_id];
554
}
555
556
int TileSet::get_source_count() const {
557
return source_ids.size();
558
}
559
560
int TileSet::get_source_id(int p_index) const {
561
ERR_FAIL_INDEX_V(p_index, source_ids.size(), TileSet::INVALID_SOURCE);
562
return source_ids[p_index];
563
}
564
565
// Rendering
566
void TileSet::set_uv_clipping(bool p_uv_clipping) {
567
if (uv_clipping == p_uv_clipping) {
568
return;
569
}
570
uv_clipping = p_uv_clipping;
571
emit_changed();
572
}
573
574
bool TileSet::is_uv_clipping() const {
575
return uv_clipping;
576
}
577
578
int TileSet::get_occlusion_layers_count() const {
579
return occlusion_layers.size();
580
}
581
582
void TileSet::add_occlusion_layer(int p_index) {
583
if (p_index < 0) {
584
p_index = occlusion_layers.size();
585
}
586
ERR_FAIL_INDEX(p_index, occlusion_layers.size() + 1);
587
occlusion_layers.insert(p_index, OcclusionLayer());
588
589
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
590
source.value->add_occlusion_layer(p_index);
591
}
592
593
notify_property_list_changed();
594
emit_changed();
595
}
596
597
void TileSet::move_occlusion_layer(int p_from_index, int p_to_pos) {
598
ERR_FAIL_INDEX(p_from_index, occlusion_layers.size());
599
ERR_FAIL_INDEX(p_to_pos, occlusion_layers.size() + 1);
600
occlusion_layers.insert(p_to_pos, occlusion_layers[p_from_index]);
601
occlusion_layers.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
602
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
603
source.value->move_occlusion_layer(p_from_index, p_to_pos);
604
}
605
notify_property_list_changed();
606
emit_changed();
607
}
608
609
void TileSet::remove_occlusion_layer(int p_index) {
610
ERR_FAIL_INDEX(p_index, occlusion_layers.size());
611
occlusion_layers.remove_at(p_index);
612
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
613
source.value->remove_occlusion_layer(p_index);
614
}
615
notify_property_list_changed();
616
emit_changed();
617
}
618
619
void TileSet::set_occlusion_layer_light_mask(int p_layer_index, int p_light_mask) {
620
ERR_FAIL_INDEX(p_layer_index, occlusion_layers.size());
621
occlusion_layers.write[p_layer_index].light_mask = p_light_mask;
622
emit_changed();
623
}
624
625
int TileSet::get_occlusion_layer_light_mask(int p_layer_index) const {
626
ERR_FAIL_INDEX_V(p_layer_index, occlusion_layers.size(), 0);
627
return occlusion_layers[p_layer_index].light_mask;
628
}
629
630
void TileSet::set_occlusion_layer_sdf_collision(int p_layer_index, bool p_sdf_collision) {
631
ERR_FAIL_INDEX(p_layer_index, occlusion_layers.size());
632
occlusion_layers.write[p_layer_index].sdf_collision = p_sdf_collision;
633
emit_changed();
634
}
635
636
bool TileSet::get_occlusion_layer_sdf_collision(int p_layer_index) const {
637
ERR_FAIL_INDEX_V(p_layer_index, occlusion_layers.size(), false);
638
return occlusion_layers[p_layer_index].sdf_collision;
639
}
640
641
#ifndef PHYSICS_2D_DISABLED
642
int TileSet::get_physics_layers_count() const {
643
return physics_layers.size();
644
}
645
646
void TileSet::add_physics_layer(int p_index) {
647
if (p_index < 0) {
648
p_index = physics_layers.size();
649
}
650
ERR_FAIL_INDEX(p_index, physics_layers.size() + 1);
651
physics_layers.insert(p_index, PhysicsLayer());
652
653
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
654
source.value->add_physics_layer(p_index);
655
}
656
657
notify_property_list_changed();
658
emit_changed();
659
}
660
661
void TileSet::move_physics_layer(int p_from_index, int p_to_pos) {
662
ERR_FAIL_INDEX(p_from_index, physics_layers.size());
663
ERR_FAIL_INDEX(p_to_pos, physics_layers.size() + 1);
664
physics_layers.insert(p_to_pos, physics_layers[p_from_index]);
665
physics_layers.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
666
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
667
source.value->move_physics_layer(p_from_index, p_to_pos);
668
}
669
notify_property_list_changed();
670
emit_changed();
671
}
672
673
void TileSet::remove_physics_layer(int p_index) {
674
ERR_FAIL_INDEX(p_index, physics_layers.size());
675
physics_layers.remove_at(p_index);
676
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
677
source.value->remove_physics_layer(p_index);
678
}
679
notify_property_list_changed();
680
emit_changed();
681
}
682
683
void TileSet::set_physics_layer_collision_layer(int p_layer_index, uint32_t p_layer) {
684
ERR_FAIL_INDEX(p_layer_index, physics_layers.size());
685
physics_layers.write[p_layer_index].collision_layer = p_layer;
686
emit_changed();
687
}
688
689
uint32_t TileSet::get_physics_layer_collision_layer(int p_layer_index) const {
690
ERR_FAIL_INDEX_V(p_layer_index, physics_layers.size(), 0);
691
return physics_layers[p_layer_index].collision_layer;
692
}
693
694
void TileSet::set_physics_layer_collision_mask(int p_layer_index, uint32_t p_mask) {
695
ERR_FAIL_INDEX(p_layer_index, physics_layers.size());
696
physics_layers.write[p_layer_index].collision_mask = p_mask;
697
emit_changed();
698
}
699
700
uint32_t TileSet::get_physics_layer_collision_mask(int p_layer_index) const {
701
ERR_FAIL_INDEX_V(p_layer_index, physics_layers.size(), 0);
702
return physics_layers[p_layer_index].collision_mask;
703
}
704
705
void TileSet::set_physics_layer_collision_priority(int p_layer_index, real_t p_priority) {
706
ERR_FAIL_INDEX(p_layer_index, physics_layers.size());
707
physics_layers.write[p_layer_index].collision_priority = p_priority;
708
emit_changed();
709
}
710
711
real_t TileSet::get_physics_layer_collision_priority(int p_layer_index) const {
712
ERR_FAIL_INDEX_V(p_layer_index, physics_layers.size(), 0);
713
return physics_layers[p_layer_index].collision_priority;
714
}
715
716
void TileSet::set_physics_layer_physics_material(int p_layer_index, Ref<PhysicsMaterial> p_physics_material) {
717
ERR_FAIL_INDEX(p_layer_index, physics_layers.size());
718
physics_layers.write[p_layer_index].physics_material = p_physics_material;
719
}
720
721
Ref<PhysicsMaterial> TileSet::get_physics_layer_physics_material(int p_layer_index) const {
722
ERR_FAIL_INDEX_V(p_layer_index, physics_layers.size(), Ref<PhysicsMaterial>());
723
return physics_layers[p_layer_index].physics_material;
724
}
725
#endif // PHYSICS_2D_DISABLED
726
727
// Terrains
728
int TileSet::get_terrain_sets_count() const {
729
return terrain_sets.size();
730
}
731
732
void TileSet::add_terrain_set(int p_index) {
733
if (p_index < 0) {
734
p_index = terrain_sets.size();
735
}
736
ERR_FAIL_INDEX(p_index, terrain_sets.size() + 1);
737
terrain_sets.insert(p_index, TerrainSet());
738
739
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
740
source.value->add_terrain_set(p_index);
741
}
742
743
notify_property_list_changed();
744
terrains_cache_dirty = true;
745
emit_changed();
746
}
747
748
void TileSet::move_terrain_set(int p_from_index, int p_to_pos) {
749
ERR_FAIL_INDEX(p_from_index, terrain_sets.size());
750
ERR_FAIL_INDEX(p_to_pos, terrain_sets.size() + 1);
751
terrain_sets.insert(p_to_pos, terrain_sets[p_from_index]);
752
terrain_sets.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
753
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
754
source.value->move_terrain_set(p_from_index, p_to_pos);
755
}
756
notify_property_list_changed();
757
terrains_cache_dirty = true;
758
emit_changed();
759
}
760
761
void TileSet::remove_terrain_set(int p_index) {
762
ERR_FAIL_INDEX(p_index, terrain_sets.size());
763
terrain_sets.remove_at(p_index);
764
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
765
source.value->remove_terrain_set(p_index);
766
}
767
notify_property_list_changed();
768
terrains_cache_dirty = true;
769
emit_changed();
770
}
771
772
void TileSet::set_terrain_set_mode(int p_terrain_set, TerrainMode p_terrain_mode) {
773
ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
774
terrain_sets.write[p_terrain_set].mode = p_terrain_mode;
775
for (KeyValue<int, Ref<TileSetSource>> &E_source : sources) {
776
E_source.value->notify_tile_data_properties_should_change();
777
}
778
779
notify_property_list_changed();
780
terrains_cache_dirty = true;
781
emit_changed();
782
}
783
784
TileSet::TerrainMode TileSet::get_terrain_set_mode(int p_terrain_set) const {
785
ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES);
786
return terrain_sets[p_terrain_set].mode;
787
}
788
789
int TileSet::get_terrains_count(int p_terrain_set) const {
790
ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), -1);
791
return terrain_sets[p_terrain_set].terrains.size();
792
}
793
794
void TileSet::add_terrain(int p_terrain_set, int p_index) {
795
ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
796
Vector<Terrain> &terrains = terrain_sets.write[p_terrain_set].terrains;
797
if (p_index < 0) {
798
p_index = terrains.size();
799
}
800
ERR_FAIL_INDEX(p_index, terrains.size() + 1);
801
terrains.insert(p_index, Terrain());
802
803
// Default name and color
804
float hue_rotate = (terrains.size() % 16) / 16.0;
805
Color c;
806
c.set_hsv(Math::fmod(float(hue_rotate), float(1.0)), 0.5, 0.5);
807
terrains.write[p_index].color = c;
808
terrains.write[p_index].name = String(vformat("Terrain %d", p_index));
809
810
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
811
source.value->add_terrain(p_terrain_set, p_index);
812
}
813
814
notify_property_list_changed();
815
terrains_cache_dirty = true;
816
emit_changed();
817
}
818
819
void TileSet::move_terrain(int p_terrain_set, int p_from_index, int p_to_pos) {
820
ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
821
Vector<Terrain> &terrains = terrain_sets.write[p_terrain_set].terrains;
822
823
ERR_FAIL_INDEX(p_from_index, terrains.size());
824
ERR_FAIL_INDEX(p_to_pos, terrains.size() + 1);
825
terrains.insert(p_to_pos, terrains[p_from_index]);
826
terrains.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
827
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
828
source.value->move_terrain(p_terrain_set, p_from_index, p_to_pos);
829
}
830
notify_property_list_changed();
831
terrains_cache_dirty = true;
832
emit_changed();
833
}
834
835
void TileSet::remove_terrain(int p_terrain_set, int p_index) {
836
ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
837
Vector<Terrain> &terrains = terrain_sets.write[p_terrain_set].terrains;
838
839
ERR_FAIL_INDEX(p_index, terrains.size());
840
terrains.remove_at(p_index);
841
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
842
source.value->remove_terrain(p_terrain_set, p_index);
843
}
844
notify_property_list_changed();
845
terrains_cache_dirty = true;
846
emit_changed();
847
}
848
849
void TileSet::set_terrain_name(int p_terrain_set, int p_terrain_index, String p_name) {
850
ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
851
ERR_FAIL_INDEX(p_terrain_index, terrain_sets[p_terrain_set].terrains.size());
852
terrain_sets.write[p_terrain_set].terrains.write[p_terrain_index].name = p_name;
853
emit_changed();
854
}
855
856
String TileSet::get_terrain_name(int p_terrain_set, int p_terrain_index) const {
857
ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), String());
858
ERR_FAIL_INDEX_V(p_terrain_index, terrain_sets[p_terrain_set].terrains.size(), String());
859
return terrain_sets[p_terrain_set].terrains[p_terrain_index].name;
860
}
861
862
void TileSet::set_terrain_color(int p_terrain_set, int p_terrain_index, Color p_color) {
863
ERR_FAIL_INDEX(p_terrain_set, terrain_sets.size());
864
ERR_FAIL_INDEX(p_terrain_index, terrain_sets[p_terrain_set].terrains.size());
865
if (p_color.a != 1.0) {
866
WARN_PRINT("Terrain color should have alpha == 1.0");
867
p_color.a = 1.0;
868
}
869
terrain_sets.write[p_terrain_set].terrains.write[p_terrain_index].color = p_color;
870
emit_changed();
871
}
872
873
Color TileSet::get_terrain_color(int p_terrain_set, int p_terrain_index) const {
874
ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), Color());
875
ERR_FAIL_INDEX_V(p_terrain_index, terrain_sets[p_terrain_set].terrains.size(), Color());
876
return terrain_sets[p_terrain_set].terrains[p_terrain_index].color;
877
}
878
879
bool TileSet::is_valid_terrain_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const {
880
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
881
if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
882
if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
883
p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
884
p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
885
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_SIDE) {
886
return true;
887
}
888
}
889
if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
890
if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
891
p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
892
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
893
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER) {
894
return true;
895
}
896
}
897
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
898
if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
899
if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
900
p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
901
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
902
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
903
return true;
904
}
905
}
906
if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
907
if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_CORNER ||
908
p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER ||
909
p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_CORNER ||
910
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
911
return true;
912
}
913
}
914
} else {
915
if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
916
if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
917
if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
918
p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
919
p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
920
p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
921
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
922
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
923
return true;
924
}
925
}
926
if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
927
if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
928
p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER ||
929
p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
930
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
931
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_CORNER ||
932
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER) {
933
return true;
934
}
935
}
936
} else {
937
if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) {
938
if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
939
p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
940
p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
941
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
942
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_SIDE ||
943
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
944
return true;
945
}
946
}
947
if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
948
if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_CORNER ||
949
p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
950
p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
951
p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_CORNER ||
952
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
953
p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER) {
954
return true;
955
}
956
}
957
}
958
}
959
return false;
960
}
961
962
bool TileSet::is_valid_terrain_peering_bit(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const {
963
if (p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count()) {
964
return false;
965
}
966
967
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
968
return is_valid_terrain_peering_bit_for_mode(terrain_mode, p_peering_bit);
969
}
970
971
#ifndef NAVIGATION_2D_DISABLED
972
// Navigation
973
int TileSet::get_navigation_layers_count() const {
974
return navigation_layers.size();
975
}
976
977
void TileSet::add_navigation_layer(int p_index) {
978
if (p_index < 0) {
979
p_index = navigation_layers.size();
980
}
981
ERR_FAIL_INDEX(p_index, navigation_layers.size() + 1);
982
navigation_layers.insert(p_index, NavigationLayer());
983
984
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
985
source.value->add_navigation_layer(p_index);
986
}
987
988
notify_property_list_changed();
989
emit_changed();
990
}
991
992
void TileSet::move_navigation_layer(int p_from_index, int p_to_pos) {
993
ERR_FAIL_INDEX(p_from_index, navigation_layers.size());
994
ERR_FAIL_INDEX(p_to_pos, navigation_layers.size() + 1);
995
navigation_layers.insert(p_to_pos, navigation_layers[p_from_index]);
996
navigation_layers.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
997
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
998
source.value->move_navigation_layer(p_from_index, p_to_pos);
999
}
1000
notify_property_list_changed();
1001
emit_changed();
1002
}
1003
1004
void TileSet::remove_navigation_layer(int p_index) {
1005
ERR_FAIL_INDEX(p_index, navigation_layers.size());
1006
navigation_layers.remove_at(p_index);
1007
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
1008
source.value->remove_navigation_layer(p_index);
1009
}
1010
notify_property_list_changed();
1011
emit_changed();
1012
}
1013
1014
void TileSet::set_navigation_layer_layers(int p_layer_index, uint32_t p_layers) {
1015
ERR_FAIL_INDEX(p_layer_index, navigation_layers.size());
1016
navigation_layers.write[p_layer_index].layers = p_layers;
1017
emit_changed();
1018
}
1019
1020
uint32_t TileSet::get_navigation_layer_layers(int p_layer_index) const {
1021
ERR_FAIL_INDEX_V(p_layer_index, navigation_layers.size(), 0);
1022
return navigation_layers[p_layer_index].layers;
1023
}
1024
1025
void TileSet::set_navigation_layer_layer_value(int p_layer_index, int p_layer_number, bool p_value) {
1026
ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive.");
1027
ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive.");
1028
1029
uint32_t _navigation_layers = get_navigation_layer_layers(p_layer_index);
1030
1031
if (p_value) {
1032
_navigation_layers |= 1 << (p_layer_number - 1);
1033
} else {
1034
_navigation_layers &= ~(1 << (p_layer_number - 1));
1035
}
1036
1037
set_navigation_layer_layers(p_layer_index, _navigation_layers);
1038
}
1039
1040
bool TileSet::get_navigation_layer_layer_value(int p_layer_index, int p_layer_number) const {
1041
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive.");
1042
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive.");
1043
1044
return get_navigation_layer_layers(p_layer_index) & (1 << (p_layer_number - 1));
1045
}
1046
#endif // NAVIGATION_2D_DISABLED
1047
1048
// Custom data.
1049
int TileSet::get_custom_data_layers_count() const {
1050
return custom_data_layers.size();
1051
}
1052
1053
void TileSet::add_custom_data_layer(int p_index) {
1054
if (p_index < 0) {
1055
p_index = custom_data_layers.size();
1056
}
1057
ERR_FAIL_INDEX(p_index, custom_data_layers.size() + 1);
1058
custom_data_layers.insert(p_index, CustomDataLayer());
1059
1060
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
1061
source.value->add_custom_data_layer(p_index);
1062
}
1063
1064
notify_property_list_changed();
1065
emit_changed();
1066
}
1067
1068
void TileSet::move_custom_data_layer(int p_from_index, int p_to_pos) {
1069
ERR_FAIL_INDEX(p_from_index, custom_data_layers.size());
1070
ERR_FAIL_INDEX(p_to_pos, custom_data_layers.size() + 1);
1071
custom_data_layers.insert(p_to_pos, custom_data_layers[p_from_index]);
1072
custom_data_layers.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
1073
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
1074
source.value->move_custom_data_layer(p_from_index, p_to_pos);
1075
}
1076
notify_property_list_changed();
1077
emit_changed();
1078
}
1079
1080
void TileSet::remove_custom_data_layer(int p_index) {
1081
ERR_FAIL_INDEX(p_index, custom_data_layers.size());
1082
custom_data_layers.remove_at(p_index);
1083
1084
String to_erase;
1085
for (KeyValue<String, int> &E : custom_data_layers_by_name) {
1086
if (E.value == p_index) {
1087
to_erase = E.key;
1088
} else if (E.value > p_index) {
1089
E.value--;
1090
}
1091
}
1092
custom_data_layers_by_name.erase(to_erase);
1093
1094
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
1095
source.value->remove_custom_data_layer(p_index);
1096
}
1097
notify_property_list_changed();
1098
emit_changed();
1099
}
1100
1101
int TileSet::get_custom_data_layer_by_name(String p_value) const {
1102
if (custom_data_layers_by_name.has(p_value)) {
1103
return custom_data_layers_by_name[p_value];
1104
} else {
1105
return -1;
1106
}
1107
}
1108
1109
void TileSet::set_custom_data_layer_name(int p_layer_id, String p_value) {
1110
ERR_FAIL_INDEX(p_layer_id, custom_data_layers.size());
1111
1112
// Exit if another property has the same name.
1113
if (!p_value.is_empty()) {
1114
for (int other_layer_id = 0; other_layer_id < get_custom_data_layers_count(); other_layer_id++) {
1115
if (other_layer_id != p_layer_id && get_custom_data_layer_name(other_layer_id) == p_value) {
1116
ERR_FAIL_MSG(vformat("There is already a custom property named %s", p_value));
1117
}
1118
}
1119
}
1120
1121
if (p_value.is_empty() && custom_data_layers_by_name.has(p_value)) {
1122
custom_data_layers_by_name.erase(p_value);
1123
} else {
1124
custom_data_layers_by_name[p_value] = p_layer_id;
1125
}
1126
1127
custom_data_layers.write[p_layer_id].name = p_value;
1128
emit_changed();
1129
}
1130
1131
bool TileSet::has_custom_data_layer_by_name(const String &p_value) const {
1132
return custom_data_layers_by_name.has(p_value);
1133
}
1134
1135
String TileSet::get_custom_data_layer_name(int p_layer_id) const {
1136
ERR_FAIL_INDEX_V(p_layer_id, custom_data_layers.size(), "");
1137
return custom_data_layers[p_layer_id].name;
1138
}
1139
1140
void TileSet::set_custom_data_layer_type(int p_layer_id, Variant::Type p_value) {
1141
ERR_FAIL_INDEX(p_layer_id, custom_data_layers.size());
1142
custom_data_layers.write[p_layer_id].type = p_value;
1143
1144
for (KeyValue<int, Ref<TileSetSource>> &E_source : sources) {
1145
E_source.value->notify_tile_data_properties_should_change();
1146
}
1147
1148
emit_changed();
1149
}
1150
1151
Variant::Type TileSet::get_custom_data_layer_type(int p_layer_id) const {
1152
ERR_FAIL_INDEX_V(p_layer_id, custom_data_layers.size(), Variant::NIL);
1153
return custom_data_layers[p_layer_id].type;
1154
}
1155
1156
void TileSet::set_source_level_tile_proxy(int p_source_from, int p_source_to) {
1157
ERR_FAIL_COND(p_source_from == TileSet::INVALID_SOURCE || p_source_to == TileSet::INVALID_SOURCE);
1158
1159
source_level_proxies[p_source_from] = p_source_to;
1160
1161
emit_changed();
1162
}
1163
1164
int TileSet::get_source_level_tile_proxy(int p_source_from) {
1165
ERR_FAIL_COND_V(!source_level_proxies.has(p_source_from), TileSet::INVALID_SOURCE);
1166
1167
return source_level_proxies[p_source_from];
1168
}
1169
1170
bool TileSet::has_source_level_tile_proxy(int p_source_from) {
1171
return source_level_proxies.has(p_source_from);
1172
}
1173
1174
void TileSet::remove_source_level_tile_proxy(int p_source_from) {
1175
ERR_FAIL_COND(!source_level_proxies.has(p_source_from));
1176
1177
source_level_proxies.erase(p_source_from);
1178
1179
emit_changed();
1180
}
1181
1182
void TileSet::set_coords_level_tile_proxy(int p_source_from, Vector2i p_coords_from, int p_source_to, Vector2i p_coords_to) {
1183
ERR_FAIL_COND(p_source_from == TileSet::INVALID_SOURCE || p_source_to == TileSet::INVALID_SOURCE);
1184
ERR_FAIL_COND(p_coords_from == TileSetSource::INVALID_ATLAS_COORDS || p_coords_to == TileSetSource::INVALID_ATLAS_COORDS);
1185
1186
Array from = { p_source_from, p_coords_from };
1187
Array to = { p_source_to, p_coords_to };
1188
coords_level_proxies[from] = to;
1189
1190
emit_changed();
1191
}
1192
1193
Array TileSet::get_coords_level_tile_proxy(int p_source_from, Vector2i p_coords_from) {
1194
Array from = { p_source_from, p_coords_from };
1195
ERR_FAIL_COND_V(!coords_level_proxies.has(from), Array());
1196
return coords_level_proxies[from];
1197
}
1198
1199
bool TileSet::has_coords_level_tile_proxy(int p_source_from, Vector2i p_coords_from) {
1200
Array from = { p_source_from, p_coords_from };
1201
return coords_level_proxies.has(from);
1202
}
1203
1204
void TileSet::remove_coords_level_tile_proxy(int p_source_from, Vector2i p_coords_from) {
1205
Array from = { p_source_from, p_coords_from };
1206
ERR_FAIL_COND(!coords_level_proxies.has(from));
1207
1208
coords_level_proxies.erase(from);
1209
1210
emit_changed();
1211
}
1212
1213
void TileSet::set_alternative_level_tile_proxy(int p_source_from, Vector2i p_coords_from, int p_alternative_from, int p_source_to, Vector2i p_coords_to, int p_alternative_to) {
1214
ERR_FAIL_COND(p_source_from == TileSet::INVALID_SOURCE || p_source_to == TileSet::INVALID_SOURCE);
1215
ERR_FAIL_COND(p_coords_from == TileSetSource::INVALID_ATLAS_COORDS || p_coords_to == TileSetSource::INVALID_ATLAS_COORDS);
1216
1217
Array from = { p_source_from, p_coords_from, p_alternative_from };
1218
Array to = { p_source_to, p_coords_to, p_alternative_to };
1219
alternative_level_proxies[from] = to;
1220
1221
emit_changed();
1222
}
1223
1224
Array TileSet::get_alternative_level_tile_proxy(int p_source_from, Vector2i p_coords_from, int p_alternative_from) {
1225
Array from = { p_source_from, p_coords_from, p_alternative_from };
1226
ERR_FAIL_COND_V(!alternative_level_proxies.has(from), Array());
1227
1228
return alternative_level_proxies[from];
1229
}
1230
1231
bool TileSet::has_alternative_level_tile_proxy(int p_source_from, Vector2i p_coords_from, int p_alternative_from) {
1232
Array from = { p_source_from, p_coords_from, p_alternative_from };
1233
return alternative_level_proxies.has(from);
1234
}
1235
1236
void TileSet::remove_alternative_level_tile_proxy(int p_source_from, Vector2i p_coords_from, int p_alternative_from) {
1237
Array from = { p_source_from, p_coords_from, p_alternative_from };
1238
ERR_FAIL_COND(!alternative_level_proxies.has(from));
1239
1240
alternative_level_proxies.erase(from);
1241
1242
emit_changed();
1243
}
1244
1245
Array TileSet::get_source_level_tile_proxies() const {
1246
Array output;
1247
for (const KeyValue<int, int> &E : source_level_proxies) {
1248
Array proxy;
1249
proxy.push_back(E.key);
1250
proxy.push_back(E.value);
1251
output.push_back(proxy);
1252
}
1253
return output;
1254
}
1255
1256
Array TileSet::get_coords_level_tile_proxies() const {
1257
Array output;
1258
for (const KeyValue<Array, Array> &E : coords_level_proxies) {
1259
Array proxy;
1260
proxy.append_array(E.key);
1261
proxy.append_array(E.value);
1262
output.push_back(proxy);
1263
}
1264
return output;
1265
}
1266
1267
Array TileSet::get_alternative_level_tile_proxies() const {
1268
Array output;
1269
for (const KeyValue<Array, Array> &E : alternative_level_proxies) {
1270
Array proxy;
1271
proxy.append_array(E.key);
1272
proxy.append_array(E.value);
1273
output.push_back(proxy);
1274
}
1275
return output;
1276
}
1277
1278
Array TileSet::map_tile_proxy(int p_source_from, Vector2i p_coords_from, int p_alternative_from) const {
1279
Array from = { p_source_from, p_coords_from, p_alternative_from };
1280
1281
// Check if the tile is valid, and if so, don't map the tile and return the input.
1282
if (has_source(p_source_from)) {
1283
Ref<TileSetSource> source = get_source(p_source_from);
1284
if (source->has_tile(p_coords_from) && source->has_alternative_tile(p_coords_from, p_alternative_from)) {
1285
return from;
1286
}
1287
}
1288
1289
// Source, coords and alternative match.
1290
if (alternative_level_proxies.has(from)) {
1291
return alternative_level_proxies[from].duplicate();
1292
}
1293
1294
// Source and coords match.
1295
from.pop_back();
1296
if (coords_level_proxies.has(from)) {
1297
Array output = coords_level_proxies[from].duplicate();
1298
output.push_back(p_alternative_from);
1299
return output;
1300
}
1301
1302
// Source matches.
1303
if (source_level_proxies.has(p_source_from)) {
1304
Array output = { source_level_proxies[p_source_from], p_coords_from, p_alternative_from };
1305
return output;
1306
}
1307
1308
Array output = { p_source_from, p_coords_from, p_alternative_from };
1309
return output;
1310
}
1311
1312
void TileSet::cleanup_invalid_tile_proxies() {
1313
// Source level.
1314
Vector<int> source_to_remove;
1315
for (const KeyValue<int, int> &E : source_level_proxies) {
1316
if (has_source(E.key)) {
1317
source_to_remove.push_back(E.key);
1318
}
1319
}
1320
for (int i = 0; i < source_to_remove.size(); i++) {
1321
remove_source_level_tile_proxy(source_to_remove[i]);
1322
}
1323
1324
// Coords level.
1325
Vector<Array> coords_to_remove;
1326
for (const KeyValue<Array, Array> &E : coords_level_proxies) {
1327
Array a = E.key;
1328
if (has_source(a[0]) && get_source(a[0])->has_tile(a[1])) {
1329
coords_to_remove.push_back(a);
1330
}
1331
}
1332
for (int i = 0; i < coords_to_remove.size(); i++) {
1333
Array a = coords_to_remove[i];
1334
remove_coords_level_tile_proxy(a[0], a[1]);
1335
}
1336
1337
// Alternative level.
1338
Vector<Array> alternative_to_remove;
1339
for (const KeyValue<Array, Array> &E : alternative_level_proxies) {
1340
Array a = E.key;
1341
if (has_source(a[0]) && get_source(a[0])->has_tile(a[1]) && get_source(a[0])->has_alternative_tile(a[1], a[2])) {
1342
alternative_to_remove.push_back(a);
1343
}
1344
}
1345
for (int i = 0; i < alternative_to_remove.size(); i++) {
1346
Array a = alternative_to_remove[i];
1347
remove_alternative_level_tile_proxy(a[0], a[1], a[2]);
1348
}
1349
}
1350
1351
void TileSet::clear_tile_proxies() {
1352
source_level_proxies.clear();
1353
coords_level_proxies.clear();
1354
alternative_level_proxies.clear();
1355
1356
emit_changed();
1357
}
1358
1359
int TileSet::add_pattern(Ref<TileMapPattern> p_pattern, int p_index) {
1360
ERR_FAIL_COND_V(p_pattern.is_null(), -1);
1361
ERR_FAIL_COND_V_MSG(p_pattern->is_empty(), -1, "Cannot add an empty pattern to the TileSet.");
1362
for (const Ref<TileMapPattern> &pattern : patterns) {
1363
ERR_FAIL_COND_V_MSG(pattern == p_pattern, -1, "TileSet has already this pattern.");
1364
}
1365
ERR_FAIL_COND_V(p_index > (int)patterns.size(), -1);
1366
if (p_index < 0) {
1367
p_index = patterns.size();
1368
}
1369
patterns.insert(p_index, p_pattern);
1370
emit_changed();
1371
return p_index;
1372
}
1373
1374
Ref<TileMapPattern> TileSet::get_pattern(int p_index) {
1375
ERR_FAIL_INDEX_V(p_index, (int)patterns.size(), Ref<TileMapPattern>());
1376
return patterns[p_index];
1377
}
1378
1379
void TileSet::remove_pattern(int p_index) {
1380
ERR_FAIL_INDEX(p_index, (int)patterns.size());
1381
patterns.remove_at(p_index);
1382
emit_changed();
1383
}
1384
1385
int TileSet::get_patterns_count() {
1386
return patterns.size();
1387
}
1388
1389
RBSet<TileSet::TerrainsPattern> TileSet::get_terrains_pattern_set(int p_terrain_set) {
1390
ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), RBSet<TileSet::TerrainsPattern>());
1391
_update_terrains_cache();
1392
1393
RBSet<TileSet::TerrainsPattern> output;
1394
for (KeyValue<TileSet::TerrainsPattern, RBSet<TileMapCell>> kv : per_terrain_pattern_tiles[p_terrain_set]) {
1395
output.insert(kv.key);
1396
}
1397
return output;
1398
}
1399
1400
RBSet<TileMapCell> TileSet::get_tiles_for_terrains_pattern(int p_terrain_set, TerrainsPattern p_terrain_tile_pattern) {
1401
ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), RBSet<TileMapCell>());
1402
_update_terrains_cache();
1403
return per_terrain_pattern_tiles[p_terrain_set][p_terrain_tile_pattern];
1404
}
1405
1406
TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, TileSet::TerrainsPattern p_terrain_tile_pattern) {
1407
ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), TileMapCell());
1408
_update_terrains_cache();
1409
1410
// Count the sum of probabilities.
1411
double sum = 0.0;
1412
RBSet<TileMapCell> set = per_terrain_pattern_tiles[p_terrain_set][p_terrain_tile_pattern];
1413
for (const TileMapCell &E : set) {
1414
if (E.source_id >= 0) {
1415
Ref<TileSetSource> source = sources[E.source_id];
1416
Ref<TileSetAtlasSource> atlas_source = source;
1417
if (atlas_source.is_valid()) {
1418
TileData *tile_data = atlas_source->get_tile_data(E.get_atlas_coords(), E.alternative_tile);
1419
sum += tile_data->get_probability();
1420
} else {
1421
sum += 1.0;
1422
}
1423
} else {
1424
sum += 1.0;
1425
}
1426
}
1427
1428
// Generate a random number.
1429
double count = 0.0;
1430
double picked = Math::random(0.0, sum);
1431
1432
// Pick the tile.
1433
for (const TileMapCell &E : set) {
1434
if (E.source_id >= 0) {
1435
Ref<TileSetSource> source = sources[E.source_id];
1436
1437
Ref<TileSetAtlasSource> atlas_source = source;
1438
if (atlas_source.is_valid()) {
1439
TileData *tile_data = atlas_source->get_tile_data(E.get_atlas_coords(), E.alternative_tile);
1440
count += tile_data->get_probability();
1441
} else {
1442
count += 1.0;
1443
}
1444
} else {
1445
count += 1.0;
1446
}
1447
1448
if (count >= picked) {
1449
return E;
1450
}
1451
}
1452
1453
ERR_FAIL_V(TileMapCell());
1454
}
1455
1456
Vector<Vector2> TileSet::get_tile_shape_polygon() const {
1457
Vector<Vector2> points;
1458
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
1459
points.push_back(Vector2(-0.5, -0.5));
1460
points.push_back(Vector2(0.5, -0.5));
1461
points.push_back(Vector2(0.5, 0.5));
1462
points.push_back(Vector2(-0.5, 0.5));
1463
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1464
points.push_back(Vector2(0.0, -0.5));
1465
points.push_back(Vector2(-0.5, 0.0));
1466
points.push_back(Vector2(0.0, 0.5));
1467
points.push_back(Vector2(0.5, 0.0));
1468
} else {
1469
float overlap = 0.0;
1470
switch (tile_shape) {
1471
case TileSet::TILE_SHAPE_HEXAGON:
1472
overlap = 0.25;
1473
break;
1474
case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
1475
overlap = 0.0;
1476
break;
1477
default:
1478
break;
1479
}
1480
1481
points.push_back(Vector2(0.0, -0.5));
1482
points.push_back(Vector2(-0.5, overlap - 0.5));
1483
points.push_back(Vector2(-0.5, 0.5 - overlap));
1484
points.push_back(Vector2(0.0, 0.5));
1485
points.push_back(Vector2(0.5, 0.5 - overlap));
1486
points.push_back(Vector2(0.5, overlap - 0.5));
1487
1488
if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
1489
for (int i = 0; i < points.size(); i++) {
1490
points.write[i] = Vector2(points[i].y, points[i].x);
1491
}
1492
}
1493
}
1494
return points;
1495
}
1496
1497
void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled, Ref<Texture2D> p_texture) const {
1498
if (tile_meshes_dirty) {
1499
Vector<Vector2> shape = get_tile_shape_polygon();
1500
Vector<Vector2> uvs;
1501
uvs.resize(shape.size());
1502
for (int i = 0; i < shape.size(); i++) {
1503
uvs.write[i] = shape[i] + Vector2(0.5, 0.5);
1504
}
1505
1506
Vector<Color> colors;
1507
colors.resize(shape.size());
1508
colors.fill(Color(1.0, 1.0, 1.0, 1.0));
1509
1510
// Filled mesh.
1511
tile_filled_mesh->clear_surfaces();
1512
Array a;
1513
a.resize(Mesh::ARRAY_MAX);
1514
a[Mesh::ARRAY_VERTEX] = shape;
1515
a[Mesh::ARRAY_TEX_UV] = uvs;
1516
a[Mesh::ARRAY_COLOR] = colors;
1517
a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(shape);
1518
tile_filled_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
1519
1520
// Lines mesh.
1521
tile_lines_mesh->clear_surfaces();
1522
a.clear();
1523
a.resize(Mesh::ARRAY_MAX);
1524
// Add the first point again when drawing lines.
1525
shape.push_back(shape[0]);
1526
colors.push_back(colors[0]);
1527
a[Mesh::ARRAY_VERTEX] = shape;
1528
a[Mesh::ARRAY_COLOR] = colors;
1529
tile_lines_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINE_STRIP, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
1530
1531
tile_meshes_dirty = false;
1532
}
1533
1534
if (p_filled) {
1535
p_canvas_item->draw_mesh(tile_filled_mesh, p_texture, p_transform, p_color);
1536
} else {
1537
p_canvas_item->draw_mesh(tile_lines_mesh, Ref<Texture2D>(), p_transform, p_color);
1538
}
1539
}
1540
1541
Vector2 TileSet::map_to_local(const Vector2i &p_pos) const {
1542
// SHOULD RETURN THE CENTER OF THE CELL.
1543
Vector2 ret = p_pos;
1544
1545
if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1546
// Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap.
1547
// square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap.
1548
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
1549
switch (tile_layout) {
1550
case TileSet::TILE_LAYOUT_STACKED:
1551
ret = Vector2(ret.x + (Math::posmod(ret.y, 2) == 0 ? 0.0 : 0.5), ret.y);
1552
break;
1553
case TileSet::TILE_LAYOUT_STACKED_OFFSET:
1554
ret = Vector2(ret.x + (Math::posmod(ret.y, 2) == 1 ? 0.0 : 0.5), ret.y);
1555
break;
1556
case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
1557
ret = Vector2(ret.x + ret.y / 2, ret.y);
1558
break;
1559
case TileSet::TILE_LAYOUT_STAIRS_DOWN:
1560
ret = Vector2(ret.x / 2, ret.y * 2 + ret.x);
1561
break;
1562
case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
1563
ret = Vector2((ret.x + ret.y) / 2, ret.y - ret.x);
1564
break;
1565
case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
1566
ret = Vector2((ret.x - ret.y) / 2, ret.y + ret.x);
1567
break;
1568
}
1569
} else { // TILE_OFFSET_AXIS_VERTICAL.
1570
switch (tile_layout) {
1571
case TileSet::TILE_LAYOUT_STACKED:
1572
ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 0 ? 0.0 : 0.5));
1573
break;
1574
case TileSet::TILE_LAYOUT_STACKED_OFFSET:
1575
ret = Vector2(ret.x, ret.y + (Math::posmod(ret.x, 2) == 1 ? 0.0 : 0.5));
1576
break;
1577
case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
1578
ret = Vector2(ret.x * 2 + ret.y, ret.y / 2);
1579
break;
1580
case TileSet::TILE_LAYOUT_STAIRS_DOWN:
1581
ret = Vector2(ret.x, ret.y + ret.x / 2);
1582
break;
1583
case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
1584
ret = Vector2(ret.x + ret.y, (ret.y - ret.x) / 2);
1585
break;
1586
case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
1587
ret = Vector2(ret.x - ret.y, (ret.y + ret.x) / 2);
1588
break;
1589
}
1590
}
1591
}
1592
1593
// Multiply by the overlapping ratio.
1594
double overlapping_ratio = 1.0;
1595
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
1596
if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1597
overlapping_ratio = 0.5;
1598
} else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
1599
overlapping_ratio = 0.75;
1600
}
1601
ret.y *= overlapping_ratio;
1602
} else { // TILE_OFFSET_AXIS_VERTICAL.
1603
if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1604
overlapping_ratio = 0.5;
1605
} else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
1606
overlapping_ratio = 0.75;
1607
}
1608
ret.x *= overlapping_ratio;
1609
}
1610
1611
return (ret + Vector2(0.5, 0.5)) * tile_size;
1612
}
1613
1614
Vector2i TileSet::local_to_map(const Vector2 &p_local_position) const {
1615
Vector2 ret = p_local_position;
1616
ret /= tile_size;
1617
1618
// Divide by the overlapping ratio.
1619
double overlapping_ratio = 1.0;
1620
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
1621
if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1622
overlapping_ratio = 0.5;
1623
} else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
1624
overlapping_ratio = 0.75;
1625
}
1626
ret.y /= overlapping_ratio;
1627
} else { // TILE_OFFSET_AXIS_VERTICAL.
1628
if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1629
overlapping_ratio = 0.5;
1630
} else if (tile_shape == TileSet::TILE_SHAPE_HEXAGON) {
1631
overlapping_ratio = 0.75;
1632
}
1633
ret.x /= overlapping_ratio;
1634
}
1635
1636
// For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the local position accordingly.
1637
if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1638
// Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap.
1639
// square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap.
1640
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
1641
// Smart floor of the position
1642
Vector2 raw_pos = ret;
1643
if (Math::posmod(Math::floor(ret.y), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) {
1644
ret = Vector2(Math::floor(ret.x + 0.5) - 0.5, Math::floor(ret.y));
1645
} else {
1646
ret = ret.floor();
1647
}
1648
1649
// Compute the tile offset, and if we might the output for a neighbor top tile.
1650
Vector2 in_tile_pos = raw_pos - ret;
1651
bool in_top_left_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(-0.5, 1.0 / overlapping_ratio - 1)) <= 0;
1652
bool in_top_right_triangle = (in_tile_pos - Vector2(0.5, 0.0)).cross(Vector2(0.5, 1.0 / overlapping_ratio - 1)) > 0;
1653
1654
switch (tile_layout) {
1655
case TileSet::TILE_LAYOUT_STACKED:
1656
ret = ret.floor();
1657
if (in_top_left_triangle) {
1658
ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 0 : -1, -1);
1659
} else if (in_top_right_triangle) {
1660
ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 1 : 0, -1);
1661
}
1662
break;
1663
case TileSet::TILE_LAYOUT_STACKED_OFFSET:
1664
ret = ret.floor();
1665
if (in_top_left_triangle) {
1666
ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? -1 : 0, -1);
1667
} else if (in_top_right_triangle) {
1668
ret += Vector2i(Math::posmod(Math::floor(ret.y), 2) ? 0 : 1, -1);
1669
}
1670
break;
1671
case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
1672
ret = Vector2(ret.x - ret.y / 2, ret.y).floor();
1673
if (in_top_left_triangle) {
1674
ret += Vector2i(0, -1);
1675
} else if (in_top_right_triangle) {
1676
ret += Vector2i(1, -1);
1677
}
1678
break;
1679
case TileSet::TILE_LAYOUT_STAIRS_DOWN:
1680
ret = Vector2(ret.x * 2, ret.y / 2 - ret.x).floor();
1681
if (in_top_left_triangle) {
1682
ret += Vector2i(-1, 0);
1683
} else if (in_top_right_triangle) {
1684
ret += Vector2i(1, -1);
1685
}
1686
break;
1687
case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
1688
ret = Vector2(ret.x - ret.y / 2, ret.y / 2 + ret.x).floor();
1689
if (in_top_left_triangle) {
1690
ret += Vector2i(0, -1);
1691
} else if (in_top_right_triangle) {
1692
ret += Vector2i(1, 0);
1693
}
1694
break;
1695
case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
1696
ret = Vector2(ret.x + ret.y / 2, ret.y / 2 - ret.x).floor();
1697
if (in_top_left_triangle) {
1698
ret += Vector2i(-1, 0);
1699
} else if (in_top_right_triangle) {
1700
ret += Vector2i(0, -1);
1701
}
1702
break;
1703
}
1704
} else { // TILE_OFFSET_AXIS_VERTICAL.
1705
// Smart floor of the position.
1706
Vector2 raw_pos = ret;
1707
if (Math::posmod(Math::floor(ret.x), 2) ^ (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET)) {
1708
ret = Vector2(Math::floor(ret.x), Math::floor(ret.y + 0.5) - 0.5);
1709
} else {
1710
ret = ret.floor();
1711
}
1712
1713
// Compute the tile offset, and if we might the output for a neighbor top tile.
1714
Vector2 in_tile_pos = raw_pos - ret;
1715
bool in_top_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, -0.5)) > 0;
1716
bool in_bottom_left_triangle = (in_tile_pos - Vector2(0.0, 0.5)).cross(Vector2(1.0 / overlapping_ratio - 1, 0.5)) <= 0;
1717
1718
switch (tile_layout) {
1719
case TileSet::TILE_LAYOUT_STACKED:
1720
ret = ret.floor();
1721
if (in_top_left_triangle) {
1722
ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 0 : -1);
1723
} else if (in_bottom_left_triangle) {
1724
ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 1 : 0);
1725
}
1726
break;
1727
case TileSet::TILE_LAYOUT_STACKED_OFFSET:
1728
ret = ret.floor();
1729
if (in_top_left_triangle) {
1730
ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? -1 : 0);
1731
} else if (in_bottom_left_triangle) {
1732
ret += Vector2i(-1, Math::posmod(Math::floor(ret.x), 2) ? 0 : 1);
1733
}
1734
break;
1735
case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
1736
ret = Vector2(ret.x / 2 - ret.y, ret.y * 2).floor();
1737
if (in_top_left_triangle) {
1738
ret += Vector2i(0, -1);
1739
} else if (in_bottom_left_triangle) {
1740
ret += Vector2i(-1, 1);
1741
}
1742
break;
1743
case TileSet::TILE_LAYOUT_STAIRS_DOWN:
1744
ret = Vector2(ret.x, ret.y - ret.x / 2).floor();
1745
if (in_top_left_triangle) {
1746
ret += Vector2i(-1, 0);
1747
} else if (in_bottom_left_triangle) {
1748
ret += Vector2i(-1, 1);
1749
}
1750
break;
1751
case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
1752
ret = Vector2(ret.x / 2 - ret.y, ret.y + ret.x / 2).floor();
1753
if (in_top_left_triangle) {
1754
ret += Vector2i(0, -1);
1755
} else if (in_bottom_left_triangle) {
1756
ret += Vector2i(-1, 0);
1757
}
1758
break;
1759
case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
1760
ret = Vector2(ret.x / 2 + ret.y, ret.y - ret.x / 2).floor();
1761
if (in_top_left_triangle) {
1762
ret += Vector2i(-1, 0);
1763
} else if (in_bottom_left_triangle) {
1764
ret += Vector2i(0, 1);
1765
}
1766
break;
1767
}
1768
}
1769
} else {
1770
ret = (ret + Vector2(0.00005, 0.00005)).floor();
1771
}
1772
return Vector2i(ret);
1773
}
1774
1775
bool TileSet::is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const {
1776
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
1777
return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
1778
p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER ||
1779
p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
1780
p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER ||
1781
p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
1782
p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER ||
1783
p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE ||
1784
p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER;
1785
1786
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
1787
return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER ||
1788
p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
1789
p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER ||
1790
p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
1791
p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER ||
1792
p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
1793
p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER ||
1794
p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
1795
} else {
1796
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
1797
return p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE ||
1798
p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
1799
p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
1800
p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE ||
1801
p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
1802
p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
1803
} else {
1804
return p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE ||
1805
p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE ||
1806
p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE ||
1807
p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE ||
1808
p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE ||
1809
p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE;
1810
}
1811
}
1812
}
1813
1814
Vector2i TileSet::get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const {
1815
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
1816
switch (p_cell_neighbor) {
1817
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
1818
return p_coords + Vector2i(1, 0);
1819
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
1820
return p_coords + Vector2i(1, 1);
1821
case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
1822
return p_coords + Vector2i(0, 1);
1823
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
1824
return p_coords + Vector2i(-1, 1);
1825
case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
1826
return p_coords + Vector2i(-1, 0);
1827
case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
1828
return p_coords + Vector2i(-1, -1);
1829
case TileSet::CELL_NEIGHBOR_TOP_SIDE:
1830
return p_coords + Vector2i(0, -1);
1831
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
1832
return p_coords + Vector2i(1, -1);
1833
default:
1834
ERR_FAIL_V(p_coords);
1835
}
1836
} else { // Half-offset shapes (square and hexagon).
1837
switch (tile_layout) {
1838
case TileSet::TILE_LAYOUT_STACKED: {
1839
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
1840
bool is_offset = p_coords.y % 2;
1841
if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
1842
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
1843
return p_coords + Vector2i(1, 0);
1844
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
1845
return p_coords + Vector2i(is_offset ? 1 : 0, 1);
1846
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
1847
return p_coords + Vector2i(0, 2);
1848
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
1849
return p_coords + Vector2i(is_offset ? 0 : -1, 1);
1850
} else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
1851
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
1852
return p_coords + Vector2i(-1, 0);
1853
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
1854
return p_coords + Vector2i(is_offset ? 0 : -1, -1);
1855
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
1856
return p_coords + Vector2i(0, -2);
1857
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
1858
return p_coords + Vector2i(is_offset ? 1 : 0, -1);
1859
} else {
1860
ERR_FAIL_V(p_coords);
1861
}
1862
} else {
1863
bool is_offset = p_coords.x % 2;
1864
1865
if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
1866
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
1867
return p_coords + Vector2i(0, 1);
1868
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
1869
return p_coords + Vector2i(1, is_offset ? 1 : 0);
1870
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
1871
return p_coords + Vector2i(2, 0);
1872
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
1873
return p_coords + Vector2i(1, is_offset ? 0 : -1);
1874
} else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
1875
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
1876
return p_coords + Vector2i(0, -1);
1877
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
1878
return p_coords + Vector2i(-1, is_offset ? 0 : -1);
1879
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
1880
return p_coords + Vector2i(-2, 0);
1881
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
1882
return p_coords + Vector2i(-1, is_offset ? 1 : 0);
1883
} else {
1884
ERR_FAIL_V(p_coords);
1885
}
1886
}
1887
} break;
1888
case TileSet::TILE_LAYOUT_STACKED_OFFSET: {
1889
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
1890
bool is_offset = p_coords.y % 2;
1891
1892
if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
1893
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
1894
return p_coords + Vector2i(1, 0);
1895
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
1896
return p_coords + Vector2i(is_offset ? 0 : 1, 1);
1897
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
1898
return p_coords + Vector2i(0, 2);
1899
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
1900
return p_coords + Vector2i(is_offset ? -1 : 0, 1);
1901
} else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
1902
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
1903
return p_coords + Vector2i(-1, 0);
1904
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
1905
return p_coords + Vector2i(is_offset ? -1 : 0, -1);
1906
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
1907
return p_coords + Vector2i(0, -2);
1908
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
1909
return p_coords + Vector2i(is_offset ? 0 : 1, -1);
1910
} else {
1911
ERR_FAIL_V(p_coords);
1912
}
1913
} else {
1914
bool is_offset = p_coords.x % 2;
1915
1916
if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
1917
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
1918
return p_coords + Vector2i(0, 1);
1919
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
1920
return p_coords + Vector2i(1, is_offset ? 0 : 1);
1921
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
1922
return p_coords + Vector2i(2, 0);
1923
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
1924
return p_coords + Vector2i(1, is_offset ? -1 : 0);
1925
} else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
1926
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
1927
return p_coords + Vector2i(0, -1);
1928
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
1929
return p_coords + Vector2i(-1, is_offset ? -1 : 0);
1930
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
1931
return p_coords + Vector2i(-2, 0);
1932
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
1933
return p_coords + Vector2i(-1, is_offset ? 0 : 1);
1934
} else {
1935
ERR_FAIL_V(p_coords);
1936
}
1937
}
1938
} break;
1939
case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
1940
case TileSet::TILE_LAYOUT_STAIRS_DOWN: {
1941
if ((tile_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
1942
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
1943
if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
1944
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
1945
return p_coords + Vector2i(1, 0);
1946
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
1947
return p_coords + Vector2i(0, 1);
1948
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
1949
return p_coords + Vector2i(-1, 2);
1950
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
1951
return p_coords + Vector2i(-1, 1);
1952
} else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
1953
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
1954
return p_coords + Vector2i(-1, 0);
1955
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
1956
return p_coords + Vector2i(0, -1);
1957
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
1958
return p_coords + Vector2i(1, -2);
1959
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
1960
return p_coords + Vector2i(1, -1);
1961
} else {
1962
ERR_FAIL_V(p_coords);
1963
}
1964
1965
} else {
1966
if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
1967
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
1968
return p_coords + Vector2i(0, 1);
1969
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
1970
return p_coords + Vector2i(1, 0);
1971
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
1972
return p_coords + Vector2i(2, -1);
1973
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
1974
return p_coords + Vector2i(1, -1);
1975
} else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
1976
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
1977
return p_coords + Vector2i(0, -1);
1978
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
1979
return p_coords + Vector2i(-1, 0);
1980
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
1981
return p_coords + Vector2i(-2, 1);
1982
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
1983
return p_coords + Vector2i(-1, 1);
1984
} else {
1985
ERR_FAIL_V(p_coords);
1986
}
1987
}
1988
} else {
1989
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
1990
if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
1991
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
1992
return p_coords + Vector2i(2, -1);
1993
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
1994
return p_coords + Vector2i(1, 0);
1995
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
1996
return p_coords + Vector2i(0, 1);
1997
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
1998
return p_coords + Vector2i(-1, 1);
1999
} else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
2000
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
2001
return p_coords + Vector2i(-2, 1);
2002
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
2003
return p_coords + Vector2i(-1, 0);
2004
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
2005
return p_coords + Vector2i(0, -1);
2006
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
2007
return p_coords + Vector2i(1, -1);
2008
} else {
2009
ERR_FAIL_V(p_coords);
2010
}
2011
2012
} else {
2013
if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
2014
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
2015
return p_coords + Vector2i(-1, 2);
2016
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
2017
return p_coords + Vector2i(0, 1);
2018
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
2019
return p_coords + Vector2i(1, 0);
2020
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
2021
return p_coords + Vector2i(1, -1);
2022
} else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
2023
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
2024
return p_coords + Vector2i(1, -2);
2025
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
2026
return p_coords + Vector2i(0, -1);
2027
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
2028
return p_coords + Vector2i(-1, 0);
2029
2030
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
2031
return p_coords + Vector2i(-1, 1);
2032
} else {
2033
ERR_FAIL_V(p_coords);
2034
}
2035
}
2036
}
2037
} break;
2038
case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
2039
case TileSet::TILE_LAYOUT_DIAMOND_DOWN: {
2040
if ((tile_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
2041
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
2042
if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
2043
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
2044
return p_coords + Vector2i(1, 1);
2045
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
2046
return p_coords + Vector2i(0, 1);
2047
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
2048
return p_coords + Vector2i(-1, 1);
2049
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
2050
return p_coords + Vector2i(-1, 0);
2051
} else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
2052
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
2053
return p_coords + Vector2i(-1, -1);
2054
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
2055
return p_coords + Vector2i(0, -1);
2056
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
2057
return p_coords + Vector2i(1, -1);
2058
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
2059
return p_coords + Vector2i(1, 0);
2060
} else {
2061
ERR_FAIL_V(p_coords);
2062
}
2063
2064
} else {
2065
if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
2066
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
2067
return p_coords + Vector2i(1, 1);
2068
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
2069
return p_coords + Vector2i(1, 0);
2070
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
2071
return p_coords + Vector2i(1, -1);
2072
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
2073
return p_coords + Vector2i(0, -1);
2074
} else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
2075
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
2076
return p_coords + Vector2i(-1, -1);
2077
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
2078
return p_coords + Vector2i(-1, 0);
2079
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
2080
return p_coords + Vector2i(-1, 1);
2081
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
2082
return p_coords + Vector2i(0, 1);
2083
} else {
2084
ERR_FAIL_V(p_coords);
2085
}
2086
}
2087
} else {
2088
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
2089
if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) ||
2090
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) {
2091
return p_coords + Vector2i(1, -1);
2092
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
2093
return p_coords + Vector2i(1, 0);
2094
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) {
2095
return p_coords + Vector2i(1, 1);
2096
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
2097
return p_coords + Vector2i(0, 1);
2098
} else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) ||
2099
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_SIDE)) {
2100
return p_coords + Vector2i(-1, 1);
2101
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
2102
return p_coords + Vector2i(-1, 0);
2103
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) {
2104
return p_coords + Vector2i(-1, -1);
2105
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
2106
return p_coords + Vector2i(0, -1);
2107
} else {
2108
ERR_FAIL_V(p_coords);
2109
}
2110
2111
} else {
2112
if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) ||
2113
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) {
2114
return p_coords + Vector2i(-1, 1);
2115
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) {
2116
return p_coords + Vector2i(0, 1);
2117
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_RIGHT_CORNER) {
2118
return p_coords + Vector2i(1, 1);
2119
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) {
2120
return p_coords + Vector2i(1, 0);
2121
} else if ((tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_CORNER) ||
2122
(tile_shape != TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_SIDE)) {
2123
return p_coords + Vector2i(1, -1);
2124
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) {
2125
return p_coords + Vector2i(0, -1);
2126
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC && p_cell_neighbor == TileSet::CELL_NEIGHBOR_LEFT_CORNER) {
2127
return p_coords + Vector2i(-1, -1);
2128
2129
} else if (p_cell_neighbor == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) {
2130
return p_coords + Vector2i(-1, 0);
2131
} else {
2132
ERR_FAIL_V(p_coords);
2133
}
2134
}
2135
}
2136
} break;
2137
default:
2138
ERR_FAIL_V(p_coords);
2139
}
2140
}
2141
}
2142
2143
TypedArray<Vector2i> TileSet::get_surrounding_cells(const Vector2i &p_coords) const {
2144
TypedArray<Vector2i> around;
2145
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
2146
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE));
2147
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE));
2148
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE));
2149
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_SIDE));
2150
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
2151
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE));
2152
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE));
2153
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE));
2154
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE));
2155
} else {
2156
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
2157
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_RIGHT_SIDE));
2158
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE));
2159
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE));
2160
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_LEFT_SIDE));
2161
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE));
2162
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE));
2163
} else {
2164
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE));
2165
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE));
2166
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE));
2167
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE));
2168
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_SIDE));
2169
around.push_back(get_neighbor_cell(p_coords, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE));
2170
}
2171
}
2172
2173
return around;
2174
}
2175
2176
Vector2i TileSet::map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern) const {
2177
ERR_FAIL_COND_V(p_pattern.is_null(), Vector2i());
2178
ERR_FAIL_COND_V(!p_pattern->has_cell(p_coords_in_pattern), Vector2i());
2179
2180
Vector2i output = p_position_in_tilemap + p_coords_in_pattern;
2181
if (tile_shape != TileSet::TILE_SHAPE_SQUARE) {
2182
if (tile_layout == TileSet::TILE_LAYOUT_STACKED) {
2183
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) {
2184
output.x += 1;
2185
} else if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) {
2186
output.y += 1;
2187
}
2188
} else if (tile_layout == TileSet::TILE_LAYOUT_STACKED_OFFSET) {
2189
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL && bool(p_position_in_tilemap.y % 2) && bool(p_coords_in_pattern.y % 2)) {
2190
output.x -= 1;
2191
} else if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL && bool(p_position_in_tilemap.x % 2) && bool(p_coords_in_pattern.x % 2)) {
2192
output.y -= 1;
2193
}
2194
}
2195
}
2196
2197
return output;
2198
}
2199
2200
void TileSet::draw_cells_outline(CanvasItem *p_canvas_item, const RBSet<Vector2i> &p_cells, Color p_color, Transform2D p_transform) const {
2201
Vector<Vector2> polygon = get_tile_shape_polygon();
2202
for (const Vector2i &E : p_cells) {
2203
Vector2 center = map_to_local(E);
2204
2205
#define DRAW_SIDE_IF_NEEDED(side, polygon_index_from, polygon_index_to) \
2206
if (!p_cells.has(get_neighbor_cell(E, side))) { \
2207
Vector2 from = p_transform.xform(center + polygon[polygon_index_from] * tile_size); \
2208
Vector2 to = p_transform.xform(center + polygon[polygon_index_to] * tile_size); \
2209
p_canvas_item->draw_line(from, to, p_color); \
2210
}
2211
2212
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
2213
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 1, 2);
2214
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 2, 3);
2215
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 3, 0);
2216
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 0, 1);
2217
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
2218
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 2, 3);
2219
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 1, 2);
2220
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
2221
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 3, 0);
2222
} else {
2223
if (tile_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
2224
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
2225
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3);
2226
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 1, 2);
2227
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
2228
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0);
2229
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 4, 5);
2230
} else {
2231
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
2232
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 4, 5);
2233
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0);
2234
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
2235
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 1, 2);
2236
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3);
2237
}
2238
}
2239
}
2240
#undef DRAW_SIDE_IF_NEEDED
2241
}
2242
2243
Vector<Point2> TileSet::get_terrain_polygon(int p_terrain_set) {
2244
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
2245
return _get_square_terrain_polygon(tile_size);
2246
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
2247
return _get_isometric_terrain_polygon(tile_size);
2248
} else {
2249
float overlap = 0.0;
2250
switch (tile_shape) {
2251
case TileSet::TILE_SHAPE_HEXAGON:
2252
overlap = 0.25;
2253
break;
2254
case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
2255
overlap = 0.0;
2256
break;
2257
default:
2258
break;
2259
}
2260
return _get_half_offset_terrain_polygon(tile_size, overlap, tile_offset_axis);
2261
}
2262
}
2263
2264
Vector<Point2> TileSet::get_terrain_peering_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit) {
2265
ERR_FAIL_COND_V(p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count(), Vector<Point2>());
2266
2267
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set);
2268
2269
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
2270
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
2271
return _get_square_corner_or_side_terrain_peering_bit_polygon(tile_size, p_bit);
2272
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
2273
return _get_square_corner_terrain_peering_bit_polygon(tile_size, p_bit);
2274
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
2275
return _get_square_side_terrain_peering_bit_polygon(tile_size, p_bit);
2276
}
2277
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
2278
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
2279
return _get_isometric_corner_or_side_terrain_peering_bit_polygon(tile_size, p_bit);
2280
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
2281
return _get_isometric_corner_terrain_peering_bit_polygon(tile_size, p_bit);
2282
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
2283
return _get_isometric_side_terrain_peering_bit_polygon(tile_size, p_bit);
2284
}
2285
} else {
2286
float overlap = 0.0;
2287
switch (tile_shape) {
2288
case TileSet::TILE_SHAPE_HEXAGON:
2289
overlap = 0.25;
2290
break;
2291
case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
2292
overlap = 0.0;
2293
break;
2294
default:
2295
break;
2296
}
2297
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
2298
return _get_half_offset_corner_or_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
2299
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
2300
return _get_half_offset_corner_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
2301
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
2302
return _get_half_offset_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, p_bit);
2303
}
2304
}
2305
}
2306
2307
#define TERRAIN_ALPHA 0.6
2308
2309
void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data) {
2310
ERR_FAIL_NULL(p_tile_data);
2311
2312
if (terrain_bits_meshes_dirty) {
2313
// Recompute the meshes.
2314
terrain_peering_bits_meshes.clear();
2315
2316
for (int terrain_mode_index = 0; terrain_mode_index < 3; terrain_mode_index++) {
2317
TerrainMode terrain_mode = TerrainMode(terrain_mode_index);
2318
2319
// Center terrain
2320
Vector<Vector2> polygon;
2321
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
2322
polygon = _get_square_terrain_polygon(tile_size);
2323
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
2324
polygon = _get_isometric_terrain_polygon(tile_size);
2325
} else {
2326
float overlap = 0.0;
2327
switch (tile_shape) {
2328
case TileSet::TILE_SHAPE_HEXAGON:
2329
overlap = 0.25;
2330
break;
2331
case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
2332
overlap = 0.0;
2333
break;
2334
default:
2335
break;
2336
}
2337
polygon = _get_half_offset_terrain_polygon(tile_size, overlap, tile_offset_axis);
2338
}
2339
{
2340
Ref<ArrayMesh> mesh;
2341
mesh.instantiate();
2342
Vector<Vector2> uvs;
2343
uvs.resize(polygon.size());
2344
Vector<Color> colors;
2345
colors.resize(polygon.size());
2346
colors.fill(Color(1.0, 1.0, 1.0, 1.0));
2347
Array a;
2348
a.resize(Mesh::ARRAY_MAX);
2349
a[Mesh::ARRAY_VERTEX] = polygon;
2350
a[Mesh::ARRAY_TEX_UV] = uvs;
2351
a[Mesh::ARRAY_COLOR] = colors;
2352
a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
2353
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
2354
terrain_meshes[terrain_mode] = mesh;
2355
}
2356
// Peering bits
2357
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
2358
CellNeighbor bit = CellNeighbor(i);
2359
2360
if (is_valid_terrain_peering_bit_for_mode(terrain_mode, bit)) {
2361
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
2362
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
2363
polygon = _get_square_corner_or_side_terrain_peering_bit_polygon(tile_size, bit);
2364
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
2365
polygon = _get_square_corner_terrain_peering_bit_polygon(tile_size, bit);
2366
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
2367
polygon = _get_square_side_terrain_peering_bit_polygon(tile_size, bit);
2368
}
2369
} else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) {
2370
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
2371
polygon = _get_isometric_corner_or_side_terrain_peering_bit_polygon(tile_size, bit);
2372
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
2373
polygon = _get_isometric_corner_terrain_peering_bit_polygon(tile_size, bit);
2374
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
2375
polygon = _get_isometric_side_terrain_peering_bit_polygon(tile_size, bit);
2376
}
2377
} else {
2378
float overlap = 0.0;
2379
switch (tile_shape) {
2380
case TileSet::TILE_SHAPE_HEXAGON:
2381
overlap = 0.25;
2382
break;
2383
case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
2384
overlap = 0.0;
2385
break;
2386
default:
2387
break;
2388
}
2389
if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) {
2390
polygon = _get_half_offset_corner_or_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
2391
} else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) {
2392
polygon = _get_half_offset_corner_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
2393
} else { // TileData::TERRAIN_MODE_MATCH_SIDES
2394
polygon = _get_half_offset_side_terrain_peering_bit_polygon(tile_size, overlap, tile_offset_axis, bit);
2395
}
2396
}
2397
{
2398
Ref<ArrayMesh> mesh;
2399
mesh.instantiate();
2400
Vector<Vector2> uvs;
2401
uvs.resize(polygon.size());
2402
Vector<Color> colors;
2403
colors.resize(polygon.size());
2404
colors.fill(Color(1.0, 1.0, 1.0, 1.0));
2405
Array a;
2406
a.resize(Mesh::ARRAY_MAX);
2407
a[Mesh::ARRAY_VERTEX] = polygon;
2408
a[Mesh::ARRAY_TEX_UV] = uvs;
2409
a[Mesh::ARRAY_COLOR] = colors;
2410
a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon);
2411
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES);
2412
terrain_peering_bits_meshes[terrain_mode][bit] = mesh;
2413
}
2414
}
2415
}
2416
}
2417
terrain_bits_meshes_dirty = false;
2418
}
2419
2420
int terrain_set = p_tile_data->get_terrain_set();
2421
if (terrain_set < 0) {
2422
return;
2423
}
2424
TileSet::TerrainMode terrain_mode = get_terrain_set_mode(terrain_set);
2425
2426
RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
2427
int terrain_id = p_tile_data->get_terrain();
2428
if (terrain_id >= 0) {
2429
Color color = get_terrain_color(terrain_set, terrain_id);
2430
color.a = TERRAIN_ALPHA;
2431
p_canvas_item->draw_mesh(terrain_meshes[terrain_mode], Ref<Texture2D>(), Transform2D(), color);
2432
}
2433
2434
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
2435
CellNeighbor bit = CellNeighbor(i);
2436
if (is_valid_terrain_peering_bit(terrain_set, bit)) {
2437
terrain_id = p_tile_data->get_terrain_peering_bit(bit);
2438
if (terrain_id >= 0) {
2439
Color color = get_terrain_color(terrain_set, terrain_id);
2440
color.a = TERRAIN_ALPHA;
2441
p_canvas_item->draw_mesh(terrain_peering_bits_meshes[terrain_mode][bit], Ref<Texture2D>(), Transform2D(), color);
2442
}
2443
}
2444
}
2445
RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D());
2446
}
2447
2448
Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) {
2449
// Counts the number of matching terrain tiles and find the best matching icon.
2450
struct Count {
2451
int count = 0;
2452
float probability = 0.0;
2453
Ref<Texture2D> texture;
2454
Rect2i region;
2455
};
2456
Vector<Vector<Ref<Texture2D>>> output;
2457
LocalVector<LocalVector<Count>> counts;
2458
output.resize(get_terrain_sets_count());
2459
counts.resize(get_terrain_sets_count());
2460
for (int terrain_set = 0; terrain_set < get_terrain_sets_count(); terrain_set++) {
2461
output.write[terrain_set].resize(get_terrains_count(terrain_set));
2462
counts[terrain_set].resize(get_terrains_count(terrain_set));
2463
}
2464
2465
for (int source_index = 0; source_index < get_source_count(); source_index++) {
2466
int source_id = get_source_id(source_index);
2467
Ref<TileSetSource> source = get_source(source_id);
2468
2469
Ref<TileSetAtlasSource> atlas_source = source;
2470
if (atlas_source.is_valid()) {
2471
for (int tile_index = 0; tile_index < source->get_tiles_count(); tile_index++) {
2472
Vector2i tile_id = source->get_tile_id(tile_index);
2473
for (int alternative_index = 0; alternative_index < source->get_alternative_tiles_count(tile_id); alternative_index++) {
2474
int alternative_id = source->get_alternative_tile_id(tile_id, alternative_index);
2475
2476
TileData *tile_data = atlas_source->get_tile_data(tile_id, alternative_id);
2477
int terrain_set = tile_data->get_terrain_set();
2478
if (terrain_set >= 0) {
2479
ERR_FAIL_INDEX_V(terrain_set, get_terrain_sets_count(), Vector<Vector<Ref<Texture2D>>>());
2480
2481
LocalVector<int> bit_counts;
2482
bit_counts.resize(get_terrains_count(terrain_set));
2483
for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) {
2484
bit_counts[terrain] = 0;
2485
}
2486
if (tile_data->get_terrain() >= 0) {
2487
bit_counts[tile_data->get_terrain()] += 10;
2488
}
2489
for (int terrain_bit = 0; terrain_bit < TileSet::CELL_NEIGHBOR_MAX; terrain_bit++) {
2490
TileSet::CellNeighbor cell_neighbor = TileSet::CellNeighbor(terrain_bit);
2491
if (is_valid_terrain_peering_bit(terrain_set, cell_neighbor)) {
2492
int terrain = tile_data->get_terrain_peering_bit(cell_neighbor);
2493
if (terrain >= 0) {
2494
if (terrain >= (int)bit_counts.size()) {
2495
WARN_PRINT(vformat("Invalid terrain peering bit: %d", terrain));
2496
} else {
2497
bit_counts[terrain] += 1;
2498
}
2499
}
2500
}
2501
}
2502
2503
for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) {
2504
if ((bit_counts[terrain] > counts[terrain_set][terrain].count) || (bit_counts[terrain] == counts[terrain_set][terrain].count && tile_data->get_probability() > counts[terrain_set][terrain].probability)) {
2505
counts[terrain_set][terrain].count = bit_counts[terrain];
2506
counts[terrain_set][terrain].probability = tile_data->get_probability();
2507
counts[terrain_set][terrain].texture = atlas_source->get_texture();
2508
counts[terrain_set][terrain].region = atlas_source->get_tile_texture_region(tile_id);
2509
}
2510
}
2511
}
2512
}
2513
}
2514
}
2515
}
2516
2517
// Generate the icons.
2518
for (int terrain_set = 0; terrain_set < get_terrain_sets_count(); terrain_set++) {
2519
for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) {
2520
Ref<Image> dst_image;
2521
dst_image.instantiate();
2522
if (counts[terrain_set][terrain].count > 0) {
2523
// Get the best tile.
2524
Ref<Texture2D> src_texture = counts[terrain_set][terrain].texture;
2525
ERR_FAIL_COND_V(src_texture.is_null(), output);
2526
Ref<Image> src_image = src_texture->get_image();
2527
ERR_FAIL_COND_V(src_image.is_null(), output);
2528
Rect2i region = counts[terrain_set][terrain].region;
2529
2530
dst_image->initialize_data(region.size.x, region.size.y, false, src_image->get_format());
2531
dst_image->blit_rect(src_image, region, Point2i());
2532
dst_image->convert(Image::FORMAT_RGBA8);
2533
dst_image->resize(p_size.x, p_size.y, Image::INTERPOLATE_NEAREST);
2534
} else {
2535
dst_image->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
2536
dst_image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain));
2537
}
2538
Ref<ImageTexture> icon = ImageTexture::create_from_image(dst_image);
2539
icon->set_size_override(p_size);
2540
output.write[terrain_set].write[terrain] = icon;
2541
}
2542
}
2543
return output;
2544
}
2545
2546
void TileSet::_source_changed() {
2547
terrains_cache_dirty = true;
2548
emit_changed();
2549
}
2550
2551
Vector<Point2> TileSet::_get_square_terrain_polygon(Vector2i p_size) {
2552
Rect2 rect(-Vector2(p_size) / 6.0, Vector2(p_size) / 3.0);
2553
return {
2554
rect.position,
2555
Vector2(rect.get_end().x, rect.position.y),
2556
rect.get_end(),
2557
Vector2(rect.position.x, rect.get_end().y)
2558
};
2559
}
2560
2561
Vector<Point2> TileSet::_get_square_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
2562
Rect2 bit_rect;
2563
bit_rect.size = Vector2(p_size) / 3;
2564
switch (p_bit) {
2565
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
2566
bit_rect.position = Vector2(1, -1);
2567
break;
2568
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
2569
bit_rect.position = Vector2(1, 1);
2570
break;
2571
case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
2572
bit_rect.position = Vector2(-1, 1);
2573
break;
2574
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
2575
bit_rect.position = Vector2(-3, 1);
2576
break;
2577
case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
2578
bit_rect.position = Vector2(-3, -1);
2579
break;
2580
case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
2581
bit_rect.position = Vector2(-3, -3);
2582
break;
2583
case TileSet::CELL_NEIGHBOR_TOP_SIDE:
2584
bit_rect.position = Vector2(-1, -3);
2585
break;
2586
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
2587
bit_rect.position = Vector2(1, -3);
2588
break;
2589
default:
2590
break;
2591
}
2592
bit_rect.position *= Vector2(p_size) / 6.0;
2593
2594
Vector<Vector2> polygon = {
2595
bit_rect.position,
2596
Vector2(bit_rect.get_end().x, bit_rect.position.y),
2597
bit_rect.get_end(),
2598
Vector2(bit_rect.position.x, bit_rect.get_end().y)
2599
};
2600
2601
return polygon;
2602
}
2603
2604
Vector<Point2> TileSet::_get_square_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
2605
Vector2 unit = Vector2(p_size) / 6.0;
2606
Vector<Vector2> polygon;
2607
switch (p_bit) {
2608
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
2609
polygon.push_back(Vector2(0, 3) * unit);
2610
polygon.push_back(Vector2(3, 3) * unit);
2611
polygon.push_back(Vector2(3, 0) * unit);
2612
polygon.push_back(Vector2(1, 0) * unit);
2613
polygon.push_back(Vector2(1, 1) * unit);
2614
polygon.push_back(Vector2(0, 1) * unit);
2615
break;
2616
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
2617
polygon.push_back(Vector2(0, 3) * unit);
2618
polygon.push_back(Vector2(-3, 3) * unit);
2619
polygon.push_back(Vector2(-3, 0) * unit);
2620
polygon.push_back(Vector2(-1, 0) * unit);
2621
polygon.push_back(Vector2(-1, 1) * unit);
2622
polygon.push_back(Vector2(0, 1) * unit);
2623
break;
2624
case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
2625
polygon.push_back(Vector2(0, -3) * unit);
2626
polygon.push_back(Vector2(-3, -3) * unit);
2627
polygon.push_back(Vector2(-3, 0) * unit);
2628
polygon.push_back(Vector2(-1, 0) * unit);
2629
polygon.push_back(Vector2(-1, -1) * unit);
2630
polygon.push_back(Vector2(0, -1) * unit);
2631
break;
2632
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
2633
polygon.push_back(Vector2(0, -3) * unit);
2634
polygon.push_back(Vector2(3, -3) * unit);
2635
polygon.push_back(Vector2(3, 0) * unit);
2636
polygon.push_back(Vector2(1, 0) * unit);
2637
polygon.push_back(Vector2(1, -1) * unit);
2638
polygon.push_back(Vector2(0, -1) * unit);
2639
break;
2640
default:
2641
break;
2642
}
2643
return polygon;
2644
}
2645
2646
Vector<Point2> TileSet::_get_square_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
2647
Vector2 unit = Vector2(p_size) / 6.0;
2648
Vector<Vector2> polygon;
2649
switch (p_bit) {
2650
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
2651
polygon.push_back(Vector2(1, -1) * unit);
2652
polygon.push_back(Vector2(3, -3) * unit);
2653
polygon.push_back(Vector2(3, 3) * unit);
2654
polygon.push_back(Vector2(1, 1) * unit);
2655
break;
2656
case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
2657
polygon.push_back(Vector2(-1, 1) * unit);
2658
polygon.push_back(Vector2(-3, 3) * unit);
2659
polygon.push_back(Vector2(3, 3) * unit);
2660
polygon.push_back(Vector2(1, 1) * unit);
2661
break;
2662
case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
2663
polygon.push_back(Vector2(-1, -1) * unit);
2664
polygon.push_back(Vector2(-3, -3) * unit);
2665
polygon.push_back(Vector2(-3, 3) * unit);
2666
polygon.push_back(Vector2(-1, 1) * unit);
2667
break;
2668
case TileSet::CELL_NEIGHBOR_TOP_SIDE:
2669
polygon.push_back(Vector2(-1, -1) * unit);
2670
polygon.push_back(Vector2(-3, -3) * unit);
2671
polygon.push_back(Vector2(3, -3) * unit);
2672
polygon.push_back(Vector2(1, -1) * unit);
2673
break;
2674
default:
2675
break;
2676
}
2677
return polygon;
2678
}
2679
2680
Vector<Point2> TileSet::_get_isometric_terrain_polygon(Vector2i p_size) {
2681
Vector2 unit = Vector2(p_size) / 6.0;
2682
return {
2683
Vector2(1, 0) * unit,
2684
Vector2(0, 1) * unit,
2685
Vector2(-1, 0) * unit,
2686
Vector2(0, -1) * unit,
2687
};
2688
}
2689
2690
Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
2691
Vector2 unit = Vector2(p_size) / 6.0;
2692
Vector<Vector2> polygon;
2693
switch (p_bit) {
2694
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
2695
polygon.push_back(Vector2(1, 0) * unit);
2696
polygon.push_back(Vector2(2, -1) * unit);
2697
polygon.push_back(Vector2(3, 0) * unit);
2698
polygon.push_back(Vector2(2, 1) * unit);
2699
break;
2700
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2701
polygon.push_back(Vector2(0, 1) * unit);
2702
polygon.push_back(Vector2(1, 2) * unit);
2703
polygon.push_back(Vector2(2, 1) * unit);
2704
polygon.push_back(Vector2(1, 0) * unit);
2705
break;
2706
case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
2707
polygon.push_back(Vector2(0, 1) * unit);
2708
polygon.push_back(Vector2(-1, 2) * unit);
2709
polygon.push_back(Vector2(0, 3) * unit);
2710
polygon.push_back(Vector2(1, 2) * unit);
2711
break;
2712
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2713
polygon.push_back(Vector2(0, 1) * unit);
2714
polygon.push_back(Vector2(-1, 2) * unit);
2715
polygon.push_back(Vector2(-2, 1) * unit);
2716
polygon.push_back(Vector2(-1, 0) * unit);
2717
break;
2718
case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
2719
polygon.push_back(Vector2(-1, 0) * unit);
2720
polygon.push_back(Vector2(-2, -1) * unit);
2721
polygon.push_back(Vector2(-3, 0) * unit);
2722
polygon.push_back(Vector2(-2, 1) * unit);
2723
break;
2724
case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2725
polygon.push_back(Vector2(0, -1) * unit);
2726
polygon.push_back(Vector2(-1, -2) * unit);
2727
polygon.push_back(Vector2(-2, -1) * unit);
2728
polygon.push_back(Vector2(-1, 0) * unit);
2729
break;
2730
case TileSet::CELL_NEIGHBOR_TOP_CORNER:
2731
polygon.push_back(Vector2(0, -1) * unit);
2732
polygon.push_back(Vector2(-1, -2) * unit);
2733
polygon.push_back(Vector2(0, -3) * unit);
2734
polygon.push_back(Vector2(1, -2) * unit);
2735
break;
2736
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2737
polygon.push_back(Vector2(0, -1) * unit);
2738
polygon.push_back(Vector2(1, -2) * unit);
2739
polygon.push_back(Vector2(2, -1) * unit);
2740
polygon.push_back(Vector2(1, 0) * unit);
2741
break;
2742
default:
2743
break;
2744
}
2745
return polygon;
2746
}
2747
2748
Vector<Point2> TileSet::_get_isometric_corner_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
2749
Vector2 unit = Vector2(p_size) / 6.0;
2750
Vector<Vector2> polygon;
2751
switch (p_bit) {
2752
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
2753
polygon.push_back(Vector2(0.5, -0.5) * unit);
2754
polygon.push_back(Vector2(1.5, -1.5) * unit);
2755
polygon.push_back(Vector2(3, 0) * unit);
2756
polygon.push_back(Vector2(1.5, 1.5) * unit);
2757
polygon.push_back(Vector2(0.5, 0.5) * unit);
2758
polygon.push_back(Vector2(1, 0) * unit);
2759
break;
2760
case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
2761
polygon.push_back(Vector2(-0.5, 0.5) * unit);
2762
polygon.push_back(Vector2(-1.5, 1.5) * unit);
2763
polygon.push_back(Vector2(0, 3) * unit);
2764
polygon.push_back(Vector2(1.5, 1.5) * unit);
2765
polygon.push_back(Vector2(0.5, 0.5) * unit);
2766
polygon.push_back(Vector2(0, 1) * unit);
2767
break;
2768
case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
2769
polygon.push_back(Vector2(-0.5, -0.5) * unit);
2770
polygon.push_back(Vector2(-1.5, -1.5) * unit);
2771
polygon.push_back(Vector2(-3, 0) * unit);
2772
polygon.push_back(Vector2(-1.5, 1.5) * unit);
2773
polygon.push_back(Vector2(-0.5, 0.5) * unit);
2774
polygon.push_back(Vector2(-1, 0) * unit);
2775
break;
2776
case TileSet::CELL_NEIGHBOR_TOP_CORNER:
2777
polygon.push_back(Vector2(-0.5, -0.5) * unit);
2778
polygon.push_back(Vector2(-1.5, -1.5) * unit);
2779
polygon.push_back(Vector2(0, -3) * unit);
2780
polygon.push_back(Vector2(1.5, -1.5) * unit);
2781
polygon.push_back(Vector2(0.5, -0.5) * unit);
2782
polygon.push_back(Vector2(0, -1) * unit);
2783
break;
2784
default:
2785
break;
2786
}
2787
return polygon;
2788
}
2789
2790
Vector<Point2> TileSet::_get_isometric_side_terrain_peering_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) {
2791
Vector2 unit = Vector2(p_size) / 6.0;
2792
Vector<Vector2> polygon;
2793
switch (p_bit) {
2794
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2795
polygon.push_back(Vector2(1, 0) * unit);
2796
polygon.push_back(Vector2(3, 0) * unit);
2797
polygon.push_back(Vector2(0, 3) * unit);
2798
polygon.push_back(Vector2(0, 1) * unit);
2799
break;
2800
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2801
polygon.push_back(Vector2(-1, 0) * unit);
2802
polygon.push_back(Vector2(-3, 0) * unit);
2803
polygon.push_back(Vector2(0, 3) * unit);
2804
polygon.push_back(Vector2(0, 1) * unit);
2805
break;
2806
case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2807
polygon.push_back(Vector2(-1, 0) * unit);
2808
polygon.push_back(Vector2(-3, 0) * unit);
2809
polygon.push_back(Vector2(0, -3) * unit);
2810
polygon.push_back(Vector2(0, -1) * unit);
2811
break;
2812
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2813
polygon.push_back(Vector2(1, 0) * unit);
2814
polygon.push_back(Vector2(3, 0) * unit);
2815
polygon.push_back(Vector2(0, -3) * unit);
2816
polygon.push_back(Vector2(0, -1) * unit);
2817
break;
2818
default:
2819
break;
2820
}
2821
return polygon;
2822
}
2823
2824
Vector<Point2> TileSet::_get_half_offset_terrain_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) {
2825
Vector2 unit = Vector2(p_size) / 6.0;
2826
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
2827
return {
2828
Vector2(1, 1.0 - p_overlap * 2.0) * unit,
2829
Vector2(0, 1) * unit,
2830
Vector2(-1, 1.0 - p_overlap * 2.0) * unit,
2831
Vector2(-1, -1.0 + p_overlap * 2.0) * unit,
2832
Vector2(0, -1) * unit,
2833
Vector2(1, -1.0 + p_overlap * 2.0) * unit,
2834
};
2835
} else {
2836
return {
2837
Vector2(1, 0) * unit,
2838
Vector2(1.0 - p_overlap * 2.0, -1) * unit,
2839
Vector2(-1.0 + p_overlap * 2.0, -1) * unit,
2840
Vector2(-1, 0) * unit,
2841
Vector2(-1.0 + p_overlap * 2.0, 1) * unit,
2842
Vector2(1.0 - p_overlap * 2.0, 1) * unit,
2843
};
2844
}
2845
}
2846
2847
Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
2848
Vector<Vector2> point_list = {
2849
Vector2(3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0),
2850
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
2851
Vector2(2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0)),
2852
Vector2(1, 3.0 - p_overlap * 2.0),
2853
Vector2(0, 3),
2854
Vector2(-1, 3.0 - p_overlap * 2.0),
2855
Vector2(-2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0)),
2856
Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0)),
2857
Vector2(-3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0),
2858
Vector2(-3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0),
2859
Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0)),
2860
Vector2(-2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0)),
2861
Vector2(-1, -(3.0 - p_overlap * 2.0)),
2862
Vector2(0, -3),
2863
Vector2(1, -(3.0 - p_overlap * 2.0)),
2864
Vector2(2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0)),
2865
Vector2(3, -3.0 * (1.0 - p_overlap * 2.0)),
2866
Vector2(3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0)
2867
};
2868
2869
Vector2 unit = Vector2(p_size) / 6.0;
2870
Vector<Vector2> polygon;
2871
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
2872
for (int i = 0; i < point_list.size(); i++) {
2873
point_list.write[i] = point_list[i] * unit;
2874
}
2875
switch (p_bit) {
2876
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
2877
polygon.push_back(point_list[17]);
2878
polygon.push_back(point_list[0]);
2879
break;
2880
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
2881
polygon.push_back(point_list[0]);
2882
polygon.push_back(point_list[1]);
2883
polygon.push_back(point_list[2]);
2884
break;
2885
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2886
polygon.push_back(point_list[2]);
2887
polygon.push_back(point_list[3]);
2888
break;
2889
case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
2890
polygon.push_back(point_list[3]);
2891
polygon.push_back(point_list[4]);
2892
polygon.push_back(point_list[5]);
2893
break;
2894
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2895
polygon.push_back(point_list[5]);
2896
polygon.push_back(point_list[6]);
2897
break;
2898
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
2899
polygon.push_back(point_list[6]);
2900
polygon.push_back(point_list[7]);
2901
polygon.push_back(point_list[8]);
2902
break;
2903
case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
2904
polygon.push_back(point_list[8]);
2905
polygon.push_back(point_list[9]);
2906
break;
2907
case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
2908
polygon.push_back(point_list[9]);
2909
polygon.push_back(point_list[10]);
2910
polygon.push_back(point_list[11]);
2911
break;
2912
case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2913
polygon.push_back(point_list[11]);
2914
polygon.push_back(point_list[12]);
2915
break;
2916
case TileSet::CELL_NEIGHBOR_TOP_CORNER:
2917
polygon.push_back(point_list[12]);
2918
polygon.push_back(point_list[13]);
2919
polygon.push_back(point_list[14]);
2920
break;
2921
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2922
polygon.push_back(point_list[14]);
2923
polygon.push_back(point_list[15]);
2924
break;
2925
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
2926
polygon.push_back(point_list[15]);
2927
polygon.push_back(point_list[16]);
2928
polygon.push_back(point_list[17]);
2929
break;
2930
default:
2931
break;
2932
}
2933
} else {
2934
for (int i = 0; i < point_list.size(); i++) {
2935
point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
2936
}
2937
switch (p_bit) {
2938
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
2939
polygon.push_back(point_list[3]);
2940
polygon.push_back(point_list[4]);
2941
polygon.push_back(point_list[5]);
2942
break;
2943
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
2944
polygon.push_back(point_list[2]);
2945
polygon.push_back(point_list[3]);
2946
break;
2947
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
2948
polygon.push_back(point_list[0]);
2949
polygon.push_back(point_list[1]);
2950
polygon.push_back(point_list[2]);
2951
break;
2952
case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
2953
polygon.push_back(point_list[17]);
2954
polygon.push_back(point_list[0]);
2955
break;
2956
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
2957
polygon.push_back(point_list[15]);
2958
polygon.push_back(point_list[16]);
2959
polygon.push_back(point_list[17]);
2960
break;
2961
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
2962
polygon.push_back(point_list[14]);
2963
polygon.push_back(point_list[15]);
2964
break;
2965
case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
2966
polygon.push_back(point_list[12]);
2967
polygon.push_back(point_list[13]);
2968
polygon.push_back(point_list[14]);
2969
break;
2970
case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
2971
polygon.push_back(point_list[11]);
2972
polygon.push_back(point_list[12]);
2973
break;
2974
case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
2975
polygon.push_back(point_list[9]);
2976
polygon.push_back(point_list[10]);
2977
polygon.push_back(point_list[11]);
2978
break;
2979
case TileSet::CELL_NEIGHBOR_TOP_SIDE:
2980
polygon.push_back(point_list[8]);
2981
polygon.push_back(point_list[9]);
2982
break;
2983
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
2984
polygon.push_back(point_list[6]);
2985
polygon.push_back(point_list[7]);
2986
polygon.push_back(point_list[8]);
2987
break;
2988
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
2989
polygon.push_back(point_list[5]);
2990
polygon.push_back(point_list[6]);
2991
break;
2992
default:
2993
break;
2994
}
2995
}
2996
2997
int half_polygon_size = polygon.size();
2998
for (int i = 0; i < half_polygon_size; i++) {
2999
polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0);
3000
}
3001
3002
return polygon;
3003
}
3004
3005
Vector<Point2> TileSet::_get_half_offset_corner_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
3006
Vector<Vector2> point_list = {
3007
Vector2(3, 0),
3008
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
3009
Vector2(1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0),
3010
Vector2(0, 3),
3011
Vector2(-1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0),
3012
Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0)),
3013
Vector2(-3, 0),
3014
Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0)),
3015
Vector2(-1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0),
3016
Vector2(0, -3),
3017
Vector2(1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0),
3018
Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))
3019
};
3020
3021
Vector2 unit = Vector2(p_size) / 6.0;
3022
Vector<Vector2> polygon;
3023
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
3024
for (int i = 0; i < point_list.size(); i++) {
3025
point_list.write[i] = point_list[i] * unit;
3026
}
3027
switch (p_bit) {
3028
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
3029
polygon.push_back(point_list[0]);
3030
polygon.push_back(point_list[1]);
3031
polygon.push_back(point_list[2]);
3032
break;
3033
case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER:
3034
polygon.push_back(point_list[2]);
3035
polygon.push_back(point_list[3]);
3036
polygon.push_back(point_list[4]);
3037
break;
3038
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
3039
polygon.push_back(point_list[4]);
3040
polygon.push_back(point_list[5]);
3041
polygon.push_back(point_list[6]);
3042
break;
3043
case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
3044
polygon.push_back(point_list[6]);
3045
polygon.push_back(point_list[7]);
3046
polygon.push_back(point_list[8]);
3047
break;
3048
case TileSet::CELL_NEIGHBOR_TOP_CORNER:
3049
polygon.push_back(point_list[8]);
3050
polygon.push_back(point_list[9]);
3051
polygon.push_back(point_list[10]);
3052
break;
3053
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
3054
polygon.push_back(point_list[10]);
3055
polygon.push_back(point_list[11]);
3056
polygon.push_back(point_list[0]);
3057
break;
3058
default:
3059
break;
3060
}
3061
} else {
3062
for (int i = 0; i < point_list.size(); i++) {
3063
point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
3064
}
3065
switch (p_bit) {
3066
case TileSet::CELL_NEIGHBOR_RIGHT_CORNER:
3067
polygon.push_back(point_list[2]);
3068
polygon.push_back(point_list[3]);
3069
polygon.push_back(point_list[4]);
3070
break;
3071
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER:
3072
polygon.push_back(point_list[0]);
3073
polygon.push_back(point_list[1]);
3074
polygon.push_back(point_list[2]);
3075
break;
3076
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER:
3077
polygon.push_back(point_list[10]);
3078
polygon.push_back(point_list[11]);
3079
polygon.push_back(point_list[0]);
3080
break;
3081
case TileSet::CELL_NEIGHBOR_LEFT_CORNER:
3082
polygon.push_back(point_list[8]);
3083
polygon.push_back(point_list[9]);
3084
polygon.push_back(point_list[10]);
3085
break;
3086
case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER:
3087
polygon.push_back(point_list[6]);
3088
polygon.push_back(point_list[7]);
3089
polygon.push_back(point_list[8]);
3090
break;
3091
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER:
3092
polygon.push_back(point_list[4]);
3093
polygon.push_back(point_list[5]);
3094
polygon.push_back(point_list[6]);
3095
break;
3096
default:
3097
break;
3098
}
3099
}
3100
3101
int half_polygon_size = polygon.size();
3102
for (int i = 0; i < half_polygon_size; i++) {
3103
polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0);
3104
}
3105
3106
return polygon;
3107
}
3108
3109
Vector<Point2> TileSet::_get_half_offset_side_terrain_peering_bit_polygon(Vector2i p_size, float p_overlap, TileSet::TileOffsetAxis p_offset_axis, TileSet::CellNeighbor p_bit) {
3110
Vector<Vector2> point_list = {
3111
Vector2(3, 3.0 * (1.0 - p_overlap * 2.0)),
3112
Vector2(0, 3),
3113
Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0)),
3114
Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0)),
3115
Vector2(0, -3),
3116
Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))
3117
};
3118
3119
Vector2 unit = Vector2(p_size) / 6.0;
3120
Vector<Vector2> polygon;
3121
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
3122
for (int i = 0; i < point_list.size(); i++) {
3123
point_list.write[i] = point_list[i] * unit;
3124
}
3125
switch (p_bit) {
3126
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
3127
polygon.push_back(point_list[5]);
3128
polygon.push_back(point_list[0]);
3129
break;
3130
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
3131
polygon.push_back(point_list[0]);
3132
polygon.push_back(point_list[1]);
3133
break;
3134
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
3135
polygon.push_back(point_list[1]);
3136
polygon.push_back(point_list[2]);
3137
break;
3138
case TileSet::CELL_NEIGHBOR_LEFT_SIDE:
3139
polygon.push_back(point_list[2]);
3140
polygon.push_back(point_list[3]);
3141
break;
3142
case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
3143
polygon.push_back(point_list[3]);
3144
polygon.push_back(point_list[4]);
3145
break;
3146
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
3147
polygon.push_back(point_list[4]);
3148
polygon.push_back(point_list[5]);
3149
break;
3150
default:
3151
break;
3152
}
3153
} else {
3154
for (int i = 0; i < point_list.size(); i++) {
3155
point_list.write[i] = Vector2(point_list[i].y, point_list[i].x) * unit;
3156
}
3157
switch (p_bit) {
3158
case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE:
3159
polygon.push_back(point_list[0]);
3160
polygon.push_back(point_list[1]);
3161
break;
3162
case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE:
3163
polygon.push_back(point_list[5]);
3164
polygon.push_back(point_list[0]);
3165
break;
3166
case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE:
3167
polygon.push_back(point_list[4]);
3168
polygon.push_back(point_list[5]);
3169
break;
3170
case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE:
3171
polygon.push_back(point_list[3]);
3172
polygon.push_back(point_list[4]);
3173
break;
3174
case TileSet::CELL_NEIGHBOR_TOP_SIDE:
3175
polygon.push_back(point_list[2]);
3176
polygon.push_back(point_list[3]);
3177
break;
3178
case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE:
3179
polygon.push_back(point_list[1]);
3180
polygon.push_back(point_list[2]);
3181
break;
3182
default:
3183
break;
3184
}
3185
}
3186
3187
int half_polygon_size = polygon.size();
3188
for (int i = 0; i < half_polygon_size; i++) {
3189
polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0);
3190
}
3191
3192
return polygon;
3193
}
3194
3195
void TileSet::reset_state() {
3196
// Rendering
3197
occlusion_layers.clear();
3198
tile_lines_mesh.instantiate();
3199
tile_filled_mesh.instantiate();
3200
tile_meshes_dirty = true;
3201
3202
#ifndef PHYSICS_2D_DISABLED
3203
// Physics
3204
physics_layers.clear();
3205
#endif // PHYSICS_2D_DISABLED
3206
3207
// Terrains
3208
terrain_sets.clear();
3209
terrain_meshes.clear();
3210
terrain_peering_bits_meshes.clear();
3211
per_terrain_pattern_tiles.clear();
3212
terrains_cache_dirty = true;
3213
3214
// Navigation
3215
navigation_layers.clear();
3216
3217
custom_data_layers.clear();
3218
custom_data_layers_by_name.clear();
3219
3220
// Proxies
3221
source_level_proxies.clear();
3222
coords_level_proxies.clear();
3223
alternative_level_proxies.clear();
3224
3225
#ifndef DISABLE_DEPRECATED
3226
for (const KeyValue<int, CompatibilityTileData *> &E : compatibility_data) {
3227
memdelete(E.value);
3228
}
3229
compatibility_data.clear();
3230
#endif // DISABLE_DEPRECATED
3231
while (!source_ids.is_empty()) {
3232
remove_source(source_ids[0]);
3233
}
3234
3235
tile_shape = TILE_SHAPE_SQUARE;
3236
tile_layout = TILE_LAYOUT_STACKED;
3237
tile_offset_axis = TILE_OFFSET_AXIS_HORIZONTAL;
3238
tile_size = Size2i(16, 16);
3239
}
3240
3241
Vector2i TileSet::transform_coords_layout(const Vector2i &p_coords, TileSet::TileOffsetAxis p_offset_axis, TileSet::TileLayout p_from_layout, TileSet::TileLayout p_to_layout) {
3242
// Transform to stacked layout.
3243
Vector2i output = p_coords;
3244
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
3245
SWAP(output.x, output.y);
3246
}
3247
switch (p_from_layout) {
3248
case TileSet::TILE_LAYOUT_STACKED:
3249
break;
3250
case TileSet::TILE_LAYOUT_STACKED_OFFSET:
3251
if (output.y % 2) {
3252
output.x -= 1;
3253
}
3254
break;
3255
case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
3256
case TileSet::TILE_LAYOUT_STAIRS_DOWN:
3257
if ((p_from_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
3258
if (output.y < 0 && bool(output.y % 2)) {
3259
output = Vector2i(output.x + output.y / 2 - 1, output.y);
3260
} else {
3261
output = Vector2i(output.x + output.y / 2, output.y);
3262
}
3263
} else {
3264
if (output.x < 0 && bool(output.x % 2)) {
3265
output = Vector2i(output.x / 2 - 1, output.x + output.y * 2);
3266
} else {
3267
output = Vector2i(output.x / 2, output.x + output.y * 2);
3268
}
3269
}
3270
break;
3271
case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
3272
case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
3273
if ((p_from_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
3274
if ((output.x + output.y) < 0 && (output.x - output.y) % 2) {
3275
output = Vector2i((output.x + output.y) / 2 - 1, output.y - output.x);
3276
} else {
3277
output = Vector2i((output.x + output.y) / 2, -output.x + output.y);
3278
}
3279
} else {
3280
if ((output.x - output.y) < 0 && (output.x + output.y) % 2) {
3281
output = Vector2i((output.x - output.y) / 2 - 1, output.x + output.y);
3282
} else {
3283
output = Vector2i((output.x - output.y) / 2, output.x + output.y);
3284
}
3285
}
3286
break;
3287
}
3288
3289
switch (p_to_layout) {
3290
case TileSet::TILE_LAYOUT_STACKED:
3291
break;
3292
case TileSet::TILE_LAYOUT_STACKED_OFFSET:
3293
if (output.y % 2) {
3294
output.x += 1;
3295
}
3296
break;
3297
case TileSet::TILE_LAYOUT_STAIRS_RIGHT:
3298
case TileSet::TILE_LAYOUT_STAIRS_DOWN:
3299
if ((p_to_layout == TileSet::TILE_LAYOUT_STAIRS_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
3300
if (output.y < 0 && (output.y % 2)) {
3301
output = Vector2i(output.x - output.y / 2 + 1, output.y);
3302
} else {
3303
output = Vector2i(output.x - output.y / 2, output.y);
3304
}
3305
} else {
3306
if (output.y % 2) {
3307
if (output.y < 0) {
3308
output = Vector2i(2 * output.x + 1, -output.x + output.y / 2 - 1);
3309
} else {
3310
output = Vector2i(2 * output.x + 1, -output.x + output.y / 2);
3311
}
3312
} else {
3313
output = Vector2i(2 * output.x, -output.x + output.y / 2);
3314
}
3315
}
3316
break;
3317
case TileSet::TILE_LAYOUT_DIAMOND_RIGHT:
3318
case TileSet::TILE_LAYOUT_DIAMOND_DOWN:
3319
if ((p_to_layout == TileSet::TILE_LAYOUT_DIAMOND_RIGHT) ^ (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL)) {
3320
if (output.y % 2) {
3321
if (output.y > 0) {
3322
output = Vector2i(output.x - output.y / 2, output.x + output.y / 2 + 1);
3323
} else {
3324
output = Vector2i(output.x - output.y / 2 + 1, output.x + output.y / 2);
3325
}
3326
} else {
3327
output = Vector2i(output.x - output.y / 2, output.x + output.y / 2);
3328
}
3329
} else {
3330
if (output.y % 2) {
3331
if (output.y < 0) {
3332
output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2 - 1);
3333
} else {
3334
output = Vector2i(output.x + output.y / 2 + 1, -output.x + output.y / 2);
3335
}
3336
} else {
3337
output = Vector2i(output.x + output.y / 2, -output.x + output.y / 2);
3338
}
3339
}
3340
break;
3341
}
3342
3343
if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
3344
SWAP(output.x, output.y);
3345
}
3346
3347
return output;
3348
}
3349
3350
const Vector2i TileSetSource::INVALID_ATLAS_COORDS = Vector2i(-1, -1);
3351
const int TileSetSource::INVALID_TILE_ALTERNATIVE = -1;
3352
3353
#ifndef DISABLE_DEPRECATED
3354
void TileSet::_compatibility_conversion() {
3355
for (KeyValue<int, CompatibilityTileData *> &E : compatibility_data) {
3356
CompatibilityTileData *ctd = E.value;
3357
3358
// Add the texture
3359
TileSetAtlasSource *atlas_source = memnew(TileSetAtlasSource);
3360
int source_id = add_source(Ref<TileSetSource>(atlas_source));
3361
3362
atlas_source->set_texture(ctd->texture);
3363
3364
// Handle each tile as a new source. Not optimal but at least it should stay compatible.
3365
switch (ctd->tile_mode) {
3366
case COMPATIBILITY_TILE_MODE_SINGLE_TILE: {
3367
atlas_source->set_margins(ctd->region.get_position());
3368
atlas_source->set_texture_region_size(ctd->region.get_size());
3369
3370
Vector2i coords;
3371
for (int flags = 0; flags < 8; flags++) {
3372
bool flip_h = flags & 1;
3373
bool flip_v = flags & 2;
3374
bool transpose = flags & 4;
3375
3376
Transform2D xform;
3377
xform = flip_h ? xform.scaled(Size2(-1, 1)) : xform;
3378
xform = flip_v ? xform.scaled(Size2(1, -1)) : xform;
3379
xform = transpose ? Transform2D(xform[1], xform[0], Vector2()) : xform;
3380
3381
int alternative_tile = 0;
3382
if (!atlas_source->has_tile(coords)) {
3383
atlas_source->create_tile(coords);
3384
} else {
3385
alternative_tile = atlas_source->create_alternative_tile(coords);
3386
}
3387
3388
// Add to the mapping.
3389
Array key_array = { flip_h, flip_v, transpose };
3390
Array value_array = { source_id, coords, alternative_tile };
3391
3392
if (!compatibility_tilemap_mapping.has(E.key)) {
3393
compatibility_tilemap_mapping[E.key] = RBMap<Array, Array>();
3394
}
3395
compatibility_tilemap_mapping[E.key][key_array] = value_array;
3396
compatibility_tilemap_mapping_tile_modes[E.key] = COMPATIBILITY_TILE_MODE_SINGLE_TILE;
3397
3398
TileData *tile_data = atlas_source->get_tile_data(coords, alternative_tile);
3399
ERR_CONTINUE(!tile_data);
3400
3401
tile_data->set_flip_h(flip_h);
3402
tile_data->set_flip_v(flip_v);
3403
tile_data->set_transpose(transpose);
3404
tile_data->set_material(ctd->material);
3405
tile_data->set_modulate(ctd->modulate);
3406
tile_data->set_z_index(ctd->z_index);
3407
3408
if (ctd->occluder.is_valid()) {
3409
if (get_occlusion_layers_count() < 1) {
3410
add_occlusion_layer();
3411
};
3412
Ref<OccluderPolygon2D> occluder = ctd->occluder->duplicate();
3413
Vector<Vector2> polygon = ctd->occluder->get_polygon();
3414
for (int index = 0; index < polygon.size(); index++) {
3415
polygon.write[index] = xform.xform(polygon[index] - ctd->region.get_size() / 2.0);
3416
}
3417
occluder->set_polygon(polygon);
3418
tile_data->add_occluder_polygon(0);
3419
tile_data->set_occluder_polygon(0, 0, occluder);
3420
}
3421
#ifndef NAVIGATION_2D_DISABLED
3422
if (ctd->navigation.is_valid()) {
3423
if (get_navigation_layers_count() < 1) {
3424
add_navigation_layer();
3425
}
3426
Ref<NavigationPolygon> navigation = ctd->navigation->duplicate();
3427
Vector<Vector2> vertices = navigation->get_vertices();
3428
for (int index = 0; index < vertices.size(); index++) {
3429
vertices.write[index] = xform.xform(vertices[index] - ctd->region.get_size() / 2.0);
3430
}
3431
navigation->set_vertices(vertices);
3432
tile_data->set_navigation_polygon(0, navigation);
3433
}
3434
#endif // NAVIGATION_2D_DISABLED
3435
3436
tile_data->set_z_index(ctd->z_index);
3437
3438
#ifndef PHYSICS_2D_DISABLED
3439
// Add the shapes.
3440
if (ctd->shapes.size() > 0) {
3441
if (get_physics_layers_count() < 1) {
3442
add_physics_layer();
3443
}
3444
}
3445
for (int k = 0; k < ctd->shapes.size(); k++) {
3446
CompatibilityShapeData csd = ctd->shapes[k];
3447
if (csd.autotile_coords == coords) {
3448
Ref<ConvexPolygonShape2D> convex_shape = csd.shape; // Only ConvexPolygonShape2D are supported, which is the default type used by the 3.x editor
3449
if (convex_shape.is_valid()) {
3450
Vector<Vector2> polygon = convex_shape->get_points();
3451
for (int point_index = 0; point_index < polygon.size(); point_index++) {
3452
polygon.write[point_index] = xform.xform(csd.transform.xform(polygon[point_index]) - ctd->region.get_size() / 2.0);
3453
}
3454
tile_data->set_collision_polygons_count(0, tile_data->get_collision_polygons_count(0) + 1);
3455
int index = tile_data->get_collision_polygons_count(0) - 1;
3456
tile_data->set_collision_polygon_one_way(0, index, csd.one_way);
3457
tile_data->set_collision_polygon_one_way_margin(0, index, csd.one_way_margin);
3458
tile_data->set_collision_polygon_points(0, index, polygon);
3459
}
3460
}
3461
}
3462
#endif // PHYSICS_2D_DISABLED
3463
}
3464
// Update the size count.
3465
if (!compatibility_size_count.has(ctd->region.get_size())) {
3466
compatibility_size_count[ctd->region.get_size()] = 0;
3467
}
3468
compatibility_size_count[ctd->region.get_size()]++;
3469
} break;
3470
case COMPATIBILITY_TILE_MODE_AUTO_TILE: {
3471
// Not supported. It would need manual conversion.
3472
WARN_PRINT_ONCE("Could not convert 3.x autotiles to 4.x. This operation cannot be done automatically, autotiles must be re-created using the terrain system.");
3473
} break;
3474
case COMPATIBILITY_TILE_MODE_ATLAS_TILE: {
3475
atlas_source->set_margins(ctd->region.get_position());
3476
atlas_source->set_separation(Vector2i(ctd->autotile_spacing, ctd->autotile_spacing));
3477
atlas_source->set_texture_region_size(ctd->autotile_tile_size);
3478
3479
Size2i atlas_size = ctd->region.get_size() / (ctd->autotile_tile_size + atlas_source->get_separation());
3480
for (int i = 0; i < atlas_size.x; i++) {
3481
for (int j = 0; j < atlas_size.y; j++) {
3482
Vector2i coords = Vector2i(i, j);
3483
3484
for (int flags = 0; flags < 8; flags++) {
3485
bool flip_h = flags & 1;
3486
bool flip_v = flags & 2;
3487
bool transpose = flags & 4;
3488
3489
Transform2D xform;
3490
xform = flip_h ? xform.scaled(Size2(-1, 1)) : xform;
3491
xform = flip_v ? xform.scaled(Size2(1, -1)) : xform;
3492
xform = transpose ? Transform2D(xform[1], xform[0], Vector2()) : xform;
3493
3494
int alternative_tile = 0;
3495
if (!atlas_source->has_tile(coords)) {
3496
atlas_source->create_tile(coords);
3497
} else {
3498
alternative_tile = atlas_source->create_alternative_tile(coords);
3499
}
3500
3501
// Add to the mapping.
3502
Array key_array = { coords, flip_h, flip_v, transpose };
3503
Array value_array = { source_id, coords, alternative_tile };
3504
3505
if (!compatibility_tilemap_mapping.has(E.key)) {
3506
compatibility_tilemap_mapping[E.key] = RBMap<Array, Array>();
3507
}
3508
compatibility_tilemap_mapping[E.key][key_array] = value_array;
3509
compatibility_tilemap_mapping_tile_modes[E.key] = COMPATIBILITY_TILE_MODE_ATLAS_TILE;
3510
3511
TileData *tile_data = atlas_source->get_tile_data(coords, alternative_tile);
3512
ERR_CONTINUE(!tile_data);
3513
3514
tile_data->set_flip_h(flip_h);
3515
tile_data->set_flip_v(flip_v);
3516
tile_data->set_transpose(transpose);
3517
tile_data->set_material(ctd->material);
3518
tile_data->set_modulate(ctd->modulate);
3519
tile_data->set_z_index(ctd->z_index);
3520
if (ctd->autotile_occluder_map.has(coords)) {
3521
if (get_occlusion_layers_count() < 1) {
3522
add_occlusion_layer();
3523
}
3524
Ref<OccluderPolygon2D> occluder = ctd->autotile_occluder_map[coords]->duplicate();
3525
Vector<Vector2> polygon = ctd->occluder->get_polygon();
3526
for (int index = 0; index < polygon.size(); index++) {
3527
polygon.write[index] = xform.xform(polygon[index] - ctd->region.get_size() / 2.0);
3528
}
3529
occluder->set_polygon(polygon);
3530
tile_data->add_occluder_polygon(0);
3531
tile_data->set_occluder_polygon(0, 0, occluder);
3532
}
3533
#ifndef NAVIGATION_2D_DISABLED
3534
if (ctd->autotile_navpoly_map.has(coords)) {
3535
if (get_navigation_layers_count() < 1) {
3536
add_navigation_layer();
3537
}
3538
Ref<NavigationPolygon> navigation = ctd->autotile_navpoly_map[coords]->duplicate();
3539
Vector<Vector2> vertices = navigation->get_vertices();
3540
for (int index = 0; index < vertices.size(); index++) {
3541
vertices.write[index] = xform.xform(vertices[index] - ctd->region.get_size() / 2.0);
3542
}
3543
navigation->set_vertices(vertices);
3544
tile_data->set_navigation_polygon(0, navigation);
3545
}
3546
#endif // NAVIGATION_2D_DISABLED
3547
if (ctd->autotile_priority_map.has(coords)) {
3548
tile_data->set_probability(ctd->autotile_priority_map[coords]);
3549
}
3550
if (ctd->autotile_z_index_map.has(coords)) {
3551
tile_data->set_z_index(ctd->autotile_z_index_map[coords]);
3552
}
3553
3554
#ifndef PHYSICS_2D_DISABLED
3555
// Add the shapes.
3556
if (ctd->shapes.size() > 0) {
3557
if (get_physics_layers_count() < 1) {
3558
add_physics_layer();
3559
}
3560
}
3561
for (int k = 0; k < ctd->shapes.size(); k++) {
3562
CompatibilityShapeData csd = ctd->shapes[k];
3563
if (csd.autotile_coords == coords) {
3564
Ref<ConvexPolygonShape2D> convex_shape = csd.shape; // Only ConvexPolygonShape2D are supported, which is the default type used by the 3.x editor
3565
if (convex_shape.is_valid()) {
3566
Vector<Vector2> polygon = convex_shape->get_points();
3567
for (int point_index = 0; point_index < polygon.size(); point_index++) {
3568
polygon.write[point_index] = xform.xform(csd.transform.xform(polygon[point_index]) - ctd->autotile_tile_size / 2.0);
3569
}
3570
tile_data->set_collision_polygons_count(0, tile_data->get_collision_polygons_count(0) + 1);
3571
int index = tile_data->get_collision_polygons_count(0) - 1;
3572
tile_data->set_collision_polygon_one_way(0, index, csd.one_way);
3573
tile_data->set_collision_polygon_one_way_margin(0, index, csd.one_way_margin);
3574
tile_data->set_collision_polygon_points(0, index, polygon);
3575
}
3576
}
3577
}
3578
#endif // PHYSICS_2D_DISABLED
3579
3580
// -- TODO: handle --
3581
// Those are offset for the whole atlas, they are likely useless for the atlases, but might make sense for single tiles.
3582
// texture offset
3583
// occluder_offset
3584
// navigation_offset
3585
3586
// For terrains, ignored for now?
3587
// bitmask_mode
3588
// bitmask_flags
3589
}
3590
}
3591
}
3592
3593
// Update the size count.
3594
if (!compatibility_size_count.has(ctd->region.get_size())) {
3595
compatibility_size_count[ctd->autotile_tile_size] = 0;
3596
}
3597
compatibility_size_count[ctd->autotile_tile_size] += atlas_size.x * atlas_size.y;
3598
} break;
3599
}
3600
3601
#ifndef PHYSICS_2D_DISABLED
3602
// Offset all shapes
3603
for (int k = 0; k < ctd->shapes.size(); k++) {
3604
Ref<ConvexPolygonShape2D> convex = ctd->shapes[k].shape;
3605
if (convex.is_valid()) {
3606
Vector<Vector2> points = convex->get_points();
3607
for (int i_point = 0; i_point < points.size(); i_point++) {
3608
points.write[i_point] = points[i_point] - get_tile_size() / 2;
3609
}
3610
convex->set_points(points);
3611
}
3612
}
3613
#endif // PHYSICS_2D_DISABLED
3614
}
3615
3616
// Update the TileSet tile_size according to the most common size found.
3617
Vector2i max_size = get_tile_size();
3618
int max_count = 0;
3619
for (KeyValue<Vector2i, int> kv : compatibility_size_count) {
3620
if (kv.value > max_count) {
3621
max_size = kv.key;
3622
max_count = kv.value;
3623
}
3624
}
3625
set_tile_size(max_size);
3626
3627
// Reset compatibility data (besides the histogram counts)
3628
for (const KeyValue<int, CompatibilityTileData *> &E : compatibility_data) {
3629
memdelete(E.value);
3630
}
3631
compatibility_data = HashMap<int, CompatibilityTileData *>();
3632
}
3633
3634
Array TileSet::compatibility_tilemap_map(int p_tile_id, Vector2i p_coords, bool p_flip_h, bool p_flip_v, bool p_transpose) {
3635
Array cannot_convert_array = {
3636
TileSet::INVALID_SOURCE,
3637
TileSetAtlasSource::INVALID_ATLAS_COORDS,
3638
TileSetAtlasSource::INVALID_TILE_ALTERNATIVE
3639
};
3640
3641
if (!compatibility_tilemap_mapping.has(p_tile_id)) {
3642
return cannot_convert_array;
3643
}
3644
3645
int tile_mode = compatibility_tilemap_mapping_tile_modes[p_tile_id];
3646
switch (tile_mode) {
3647
case COMPATIBILITY_TILE_MODE_SINGLE_TILE: {
3648
Array a = { p_flip_h, p_flip_v, p_transpose };
3649
return compatibility_tilemap_mapping[p_tile_id][a];
3650
}
3651
case COMPATIBILITY_TILE_MODE_AUTO_TILE:
3652
return cannot_convert_array;
3653
break;
3654
case COMPATIBILITY_TILE_MODE_ATLAS_TILE: {
3655
Array a = { p_coords, p_flip_h, p_flip_v, p_transpose };
3656
return compatibility_tilemap_mapping[p_tile_id][a];
3657
}
3658
default:
3659
return cannot_convert_array;
3660
break;
3661
}
3662
}
3663
3664
#endif // DISABLE_DEPRECATED
3665
3666
bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
3667
Vector<String> components = String(p_name).split("/", true, 2);
3668
3669
#ifndef DISABLE_DEPRECATED
3670
// TODO: This should be moved to a dedicated conversion system (see #50691)
3671
if (components.size() >= 1 && components[0].is_valid_int()) {
3672
int id = components[0].to_int();
3673
3674
// Get or create the compatibility object
3675
CompatibilityTileData *ctd;
3676
HashMap<int, CompatibilityTileData *>::Iterator E = compatibility_data.find(id);
3677
if (!E) {
3678
ctd = memnew(CompatibilityTileData);
3679
compatibility_data.insert(id, ctd);
3680
} else {
3681
ctd = E->value;
3682
}
3683
3684
if (components.size() < 2) {
3685
return false;
3686
}
3687
3688
String what = components[1];
3689
3690
if (what == "name") {
3691
ctd->name = p_value;
3692
} else if (what == "texture") {
3693
ctd->texture = p_value;
3694
} else if (what == "tex_offset") {
3695
ctd->tex_offset = p_value;
3696
} else if (what == "material") {
3697
ctd->material = p_value;
3698
} else if (what == "modulate") {
3699
ctd->modulate = p_value;
3700
} else if (what == "region") {
3701
ctd->region = p_value;
3702
} else if (what == "tile_mode") {
3703
ctd->tile_mode = p_value;
3704
} else if (what.left(9) == "autotile") {
3705
what = what.substr(9);
3706
if (what == "bitmask_mode") {
3707
ctd->autotile_bitmask_mode = p_value;
3708
} else if (what == "icon_coordinate") {
3709
ctd->autotile_icon_coordinate = p_value;
3710
} else if (what == "tile_size") {
3711
ctd->autotile_tile_size = p_value;
3712
} else if (what == "spacing") {
3713
ctd->autotile_spacing = p_value;
3714
} else if (what == "bitmask_flags") {
3715
if (p_value.is_array()) {
3716
Array p = p_value;
3717
Vector2i last_coord;
3718
while (p.size() > 0) {
3719
if (p[0].get_type() == Variant::VECTOR2) {
3720
last_coord = p[0];
3721
} else if (p[0].get_type() == Variant::INT) {
3722
ctd->autotile_bitmask_flags.insert(last_coord, p[0]);
3723
}
3724
p.pop_front();
3725
}
3726
}
3727
} else if (what == "occluder_map") {
3728
Array p = p_value;
3729
Vector2 last_coord;
3730
while (p.size() > 0) {
3731
if (p[0].get_type() == Variant::VECTOR2) {
3732
last_coord = p[0];
3733
} else if (p[0].get_type() == Variant::OBJECT) {
3734
ctd->autotile_occluder_map.insert(last_coord, p[0]);
3735
}
3736
p.pop_front();
3737
}
3738
} else if (what == "navpoly_map") {
3739
Array p = p_value;
3740
Vector2 last_coord;
3741
while (p.size() > 0) {
3742
if (p[0].get_type() == Variant::VECTOR2) {
3743
last_coord = p[0];
3744
} else if (p[0].get_type() == Variant::OBJECT) {
3745
#ifndef NAVIGATION_2D_DISABLED
3746
ctd->autotile_navpoly_map.insert(last_coord, p[0]);
3747
#endif // NAVIGATION_2D_DISABLED
3748
}
3749
p.pop_front();
3750
}
3751
} else if (what == "priority_map") {
3752
Array p = p_value;
3753
Vector3 val;
3754
Vector2 v;
3755
int priority;
3756
while (p.size() > 0) {
3757
val = p[0];
3758
if (val.z > 1) {
3759
v.x = val.x;
3760
v.y = val.y;
3761
priority = (int)val.z;
3762
ctd->autotile_priority_map.insert(v, priority);
3763
}
3764
p.pop_front();
3765
}
3766
} else if (what == "z_index_map") {
3767
Array p = p_value;
3768
Vector3 val;
3769
Vector2 v;
3770
int z_index;
3771
while (p.size() > 0) {
3772
val = p[0];
3773
if (val.z != 0) {
3774
v.x = val.x;
3775
v.y = val.y;
3776
z_index = (int)val.z;
3777
ctd->autotile_z_index_map.insert(v, z_index);
3778
}
3779
p.pop_front();
3780
}
3781
}
3782
3783
} else if (what == "shapes") {
3784
Array p = p_value;
3785
for (int i = 0; i < p.size(); i++) {
3786
CompatibilityShapeData csd;
3787
Dictionary d = p[i];
3788
for (const KeyValue<Variant, Variant> &kv : d) {
3789
String key = kv.key;
3790
if (key == "autotile_coord") {
3791
csd.autotile_coords = kv.value;
3792
} else if (key == "one_way") {
3793
csd.one_way = kv.value;
3794
} else if (key == "one_way_margin") {
3795
csd.one_way_margin = kv.value;
3796
} else if (key == "shape") {
3797
#ifndef PHYSICS_2D_DISABLED
3798
csd.shape = kv.value;
3799
#endif // PHYSICS_2D_DISABLED
3800
} else if (key == "shape_transform") {
3801
csd.transform = kv.value;
3802
}
3803
}
3804
ctd->shapes.push_back(csd);
3805
}
3806
} else if (what == "occluder") {
3807
ctd->occluder = p_value;
3808
} else if (what == "navigation") {
3809
#ifndef NAVIGATION_2D_DISABLED
3810
ctd->navigation = p_value;
3811
#endif // NAVIGATION_2D_DISABLED
3812
3813
/*
3814
// IGNORED FOR NOW, they seem duplicated data compared to the shapes array
3815
} else if (what == "shape") {
3816
} else if (what == "shape_offset") {
3817
} else if (what == "shape_transform") {
3818
} else if (what == "shape_one_way") {
3819
} else if (what == "shape_one_way_margin") {
3820
}
3821
// IGNORED FOR NOW, maybe useless ?
3822
else if (what == "occluder_offset") {
3823
// Not
3824
} else if (what == "navigation_offset") {
3825
}
3826
*/
3827
3828
} else if (what == "z_index") {
3829
ctd->z_index = p_value;
3830
3831
// TODO: remove the conversion from here, it's not where it should be done (see #50691)
3832
_compatibility_conversion();
3833
} else {
3834
return false;
3835
}
3836
} else {
3837
#endif // DISABLE_DEPRECATED
3838
3839
// This is now a new property.
3840
if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
3841
// Occlusion layers.
3842
int index = components[0].trim_prefix("occlusion_layer_").to_int();
3843
ERR_FAIL_COND_V(index < 0, false);
3844
if (components[1] == "light_mask") {
3845
ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
3846
while (index >= occlusion_layers.size()) {
3847
add_occlusion_layer();
3848
}
3849
set_occlusion_layer_light_mask(index, p_value);
3850
return true;
3851
} else if (components[1] == "sdf_collision") {
3852
ERR_FAIL_COND_V(p_value.get_type() != Variant::BOOL, false);
3853
while (index >= occlusion_layers.size()) {
3854
add_occlusion_layer();
3855
}
3856
set_occlusion_layer_sdf_collision(index, p_value);
3857
return true;
3858
}
3859
#ifndef PHYSICS_2D_DISABLED
3860
} else if (components.size() == 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
3861
// Physics layers.
3862
int index = components[0].trim_prefix("physics_layer_").to_int();
3863
ERR_FAIL_COND_V(index < 0, false);
3864
if (components[1] == "collision_layer") {
3865
ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
3866
while (index >= physics_layers.size()) {
3867
add_physics_layer();
3868
}
3869
set_physics_layer_collision_layer(index, p_value);
3870
return true;
3871
} else if (components[1] == "collision_mask") {
3872
ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
3873
while (index >= physics_layers.size()) {
3874
add_physics_layer();
3875
}
3876
set_physics_layer_collision_mask(index, p_value);
3877
return true;
3878
} else if (components[1] == "collision_priority") {
3879
ERR_FAIL_COND_V(p_value.get_type() != Variant::FLOAT, false);
3880
while (index >= physics_layers.size()) {
3881
add_physics_layer();
3882
}
3883
set_physics_layer_collision_priority(index, p_value);
3884
return true;
3885
} else if (components[1] == "physics_material") {
3886
Ref<PhysicsMaterial> physics_material = p_value;
3887
while (index >= physics_layers.size()) {
3888
add_physics_layer();
3889
}
3890
set_physics_layer_physics_material(index, physics_material);
3891
return true;
3892
}
3893
#endif // PHYSICS_2D_DISABLED
3894
} else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int()) {
3895
// Terrains.
3896
int terrain_set_index = components[0].trim_prefix("terrain_set_").to_int();
3897
ERR_FAIL_COND_V(terrain_set_index < 0, false);
3898
if (components[1] == "mode") {
3899
ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
3900
while (terrain_set_index >= terrain_sets.size()) {
3901
add_terrain_set();
3902
}
3903
set_terrain_set_mode(terrain_set_index, TerrainMode(int(p_value)));
3904
} else if (components.size() >= 3 && components[1].begins_with("terrain_") && components[1].trim_prefix("terrain_").is_valid_int()) {
3905
int terrain_index = components[1].trim_prefix("terrain_").to_int();
3906
ERR_FAIL_COND_V(terrain_index < 0, false);
3907
if (components[2] == "name") {
3908
ERR_FAIL_COND_V(!p_value.is_string(), false);
3909
while (terrain_set_index >= terrain_sets.size()) {
3910
add_terrain_set();
3911
}
3912
while (terrain_index >= terrain_sets[terrain_set_index].terrains.size()) {
3913
add_terrain(terrain_set_index);
3914
}
3915
set_terrain_name(terrain_set_index, terrain_index, p_value);
3916
return true;
3917
} else if (components[2] == "color") {
3918
ERR_FAIL_COND_V(p_value.get_type() != Variant::COLOR, false);
3919
while (terrain_set_index >= terrain_sets.size()) {
3920
add_terrain_set();
3921
}
3922
while (terrain_index >= terrain_sets[terrain_set_index].terrains.size()) {
3923
add_terrain(terrain_set_index);
3924
}
3925
set_terrain_color(terrain_set_index, terrain_index, p_value);
3926
return true;
3927
}
3928
}
3929
} else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) {
3930
#ifndef NAVIGATION_2D_DISABLED
3931
// Navigation layers.
3932
int index = components[0].trim_prefix("navigation_layer_").to_int();
3933
ERR_FAIL_COND_V(index < 0, false);
3934
if (components[1] == "layers") {
3935
ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
3936
while (index >= navigation_layers.size()) {
3937
add_navigation_layer();
3938
}
3939
set_navigation_layer_layers(index, p_value);
3940
return true;
3941
}
3942
#endif // NAVIGATION_2D_DISABLED
3943
} else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_int()) {
3944
// Custom data layers.
3945
int index = components[0].trim_prefix("custom_data_layer_").to_int();
3946
ERR_FAIL_COND_V(index < 0, false);
3947
if (components[1] == "name") {
3948
ERR_FAIL_COND_V(!p_value.is_string(), false);
3949
while (index >= custom_data_layers.size()) {
3950
add_custom_data_layer();
3951
}
3952
set_custom_data_layer_name(index, p_value);
3953
return true;
3954
} else if (components[1] == "type") {
3955
ERR_FAIL_COND_V(p_value.get_type() != Variant::INT, false);
3956
while (index >= custom_data_layers.size()) {
3957
add_custom_data_layer();
3958
}
3959
set_custom_data_layer_type(index, Variant::Type(int(p_value)));
3960
return true;
3961
}
3962
} else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_int()) {
3963
// Create source only if it does not exists.
3964
int source_id = components[1].to_int();
3965
3966
if (has_source(source_id)) {
3967
remove_source(source_id);
3968
}
3969
add_source(p_value, source_id);
3970
return true;
3971
} else if (components.size() == 2 && components[0] == "tile_proxies") {
3972
ERR_FAIL_COND_V(p_value.get_type() != Variant::ARRAY, false);
3973
Array a = p_value;
3974
ERR_FAIL_COND_V(a.size() % 2 != 0, false);
3975
if (components[1] == "source_level") {
3976
for (int i = 0; i < a.size(); i += 2) {
3977
set_source_level_tile_proxy(a[i], a[i + 1]);
3978
}
3979
return true;
3980
} else if (components[1] == "coords_level") {
3981
for (int i = 0; i < a.size(); i += 2) {
3982
Array key = a[i];
3983
Array value = a[i + 1];
3984
set_coords_level_tile_proxy(key[0], key[1], value[0], value[1]);
3985
}
3986
return true;
3987
} else if (components[1] == "alternative_level") {
3988
for (int i = 0; i < a.size(); i += 2) {
3989
Array key = a[i];
3990
Array value = a[i + 1];
3991
set_alternative_level_tile_proxy(key[0], key[1], key[2], value[0], value[1], value[2]);
3992
}
3993
return true;
3994
}
3995
return false;
3996
} else if (components.size() == 1 && components[0].begins_with("pattern_") && components[0].trim_prefix("pattern_").is_valid_int()) {
3997
int pattern_index = components[0].trim_prefix("pattern_").to_int();
3998
for (int i = patterns.size(); i <= pattern_index; i++) {
3999
add_pattern(p_value);
4000
}
4001
return true;
4002
}
4003
4004
#ifndef DISABLE_DEPRECATED
4005
}
4006
#endif // DISABLE_DEPRECATED
4007
4008
return false;
4009
}
4010
4011
bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
4012
Vector<String> components = String(p_name).split("/", true, 2);
4013
4014
if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
4015
// Occlusion layers.
4016
int index = components[0].trim_prefix("occlusion_layer_").to_int();
4017
if (index < 0 || index >= occlusion_layers.size()) {
4018
return false;
4019
}
4020
if (components[1] == "light_mask") {
4021
r_ret = get_occlusion_layer_light_mask(index);
4022
return true;
4023
} else if (components[1] == "sdf_collision") {
4024
r_ret = get_occlusion_layer_sdf_collision(index);
4025
return true;
4026
}
4027
#ifndef PHYSICS_2D_DISABLED
4028
} else if (components.size() == 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
4029
// Physics layers.
4030
int index = components[0].trim_prefix("physics_layer_").to_int();
4031
if (index < 0 || index >= physics_layers.size()) {
4032
return false;
4033
}
4034
if (components[1] == "collision_layer") {
4035
r_ret = get_physics_layer_collision_layer(index);
4036
return true;
4037
} else if (components[1] == "collision_mask") {
4038
r_ret = get_physics_layer_collision_mask(index);
4039
return true;
4040
} else if (components[1] == "collision_priority") {
4041
r_ret = get_physics_layer_collision_priority(index);
4042
return true;
4043
} else if (components[1] == "physics_material") {
4044
r_ret = get_physics_layer_physics_material(index);
4045
return true;
4046
}
4047
#endif // PHYSICS_2D_DISABLED
4048
} else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int()) {
4049
// Terrains.
4050
int terrain_set_index = components[0].trim_prefix("terrain_set_").to_int();
4051
if (terrain_set_index < 0 || terrain_set_index >= terrain_sets.size()) {
4052
return false;
4053
}
4054
if (components[1] == "mode") {
4055
r_ret = get_terrain_set_mode(terrain_set_index);
4056
return true;
4057
} else if (components.size() >= 3 && components[1].begins_with("terrain_") && components[1].trim_prefix("terrain_").is_valid_int()) {
4058
int terrain_index = components[1].trim_prefix("terrain_").to_int();
4059
if (terrain_index < 0 || terrain_index >= terrain_sets[terrain_set_index].terrains.size()) {
4060
return false;
4061
}
4062
if (components[2] == "name") {
4063
r_ret = get_terrain_name(terrain_set_index, terrain_index);
4064
return true;
4065
} else if (components[2] == "color") {
4066
r_ret = get_terrain_color(terrain_set_index, terrain_index);
4067
return true;
4068
}
4069
}
4070
} else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) {
4071
// navigation layers.
4072
int index = components[0].trim_prefix("navigation_layer_").to_int();
4073
if (index < 0 || index >= navigation_layers.size()) {
4074
return false;
4075
}
4076
#ifndef NAVIGATION_2D_DISABLED
4077
if (components[1] == "layers") {
4078
r_ret = get_navigation_layer_layers(index);
4079
return true;
4080
}
4081
#endif // NAVIGATION_2D_DISABLED
4082
} else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_int()) {
4083
// Custom data layers.
4084
int index = components[0].trim_prefix("custom_data_layer_").to_int();
4085
if (index < 0 || index >= custom_data_layers.size()) {
4086
return false;
4087
}
4088
if (components[1] == "name") {
4089
r_ret = get_custom_data_layer_name(index);
4090
return true;
4091
} else if (components[1] == "type") {
4092
r_ret = get_custom_data_layer_type(index);
4093
return true;
4094
}
4095
} else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_int()) {
4096
// Atlases data.
4097
int source_id = components[1].to_int();
4098
4099
if (has_source(source_id)) {
4100
r_ret = get_source(source_id);
4101
return true;
4102
} else {
4103
return false;
4104
}
4105
} else if (components.size() == 2 && components[0] == "tile_proxies") {
4106
if (components[1] == "source_level") {
4107
Array a;
4108
for (const KeyValue<int, int> &E : source_level_proxies) {
4109
a.push_back(E.key);
4110
a.push_back(E.value);
4111
}
4112
r_ret = a;
4113
return true;
4114
} else if (components[1] == "coords_level") {
4115
Array a;
4116
for (const KeyValue<Array, Array> &E : coords_level_proxies) {
4117
a.push_back(E.key);
4118
a.push_back(E.value);
4119
}
4120
r_ret = a;
4121
return true;
4122
} else if (components[1] == "alternative_level") {
4123
Array a;
4124
for (const KeyValue<Array, Array> &E : alternative_level_proxies) {
4125
a.push_back(E.key);
4126
a.push_back(E.value);
4127
}
4128
r_ret = a;
4129
return true;
4130
}
4131
return false;
4132
} else if (components.size() == 1 && components[0].begins_with("pattern_") && components[0].trim_prefix("pattern_").is_valid_int()) {
4133
int pattern_index = components[0].trim_prefix("pattern_").to_int();
4134
if (pattern_index < 0 || pattern_index >= (int)patterns.size()) {
4135
return false;
4136
}
4137
r_ret = patterns[pattern_index];
4138
return true;
4139
}
4140
4141
return false;
4142
}
4143
4144
void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
4145
PropertyInfo property_info;
4146
// Rendering.
4147
p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Rendering", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
4148
for (int i = 0; i < occlusion_layers.size(); i++) {
4149
p_list->push_back(PropertyInfo(Variant::INT, vformat("occlusion_layer_%d/light_mask", i), PROPERTY_HINT_LAYERS_2D_RENDER));
4150
4151
// occlusion_layer_%d/sdf_collision
4152
property_info = PropertyInfo(Variant::BOOL, vformat("occlusion_layer_%d/sdf_collision", i));
4153
if (occlusion_layers[i].sdf_collision == false) {
4154
property_info.usage ^= PROPERTY_USAGE_STORAGE;
4155
}
4156
p_list->push_back(property_info);
4157
}
4158
4159
#ifndef PHYSICS_2D_DISABLED
4160
// Physics.
4161
p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Physics", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
4162
for (int i = 0; i < physics_layers.size(); i++) {
4163
p_list->push_back(PropertyInfo(Variant::INT, vformat("physics_layer_%d/collision_layer", i), PROPERTY_HINT_LAYERS_2D_PHYSICS));
4164
4165
// physics_layer_%d/collision_mask
4166
property_info = PropertyInfo(Variant::INT, vformat("physics_layer_%d/collision_mask", i), PROPERTY_HINT_LAYERS_2D_PHYSICS);
4167
if (physics_layers[i].collision_mask == 1) {
4168
property_info.usage ^= PROPERTY_USAGE_STORAGE;
4169
}
4170
p_list->push_back(property_info);
4171
4172
// physics_layer_%d/collision_priority
4173
property_info = PropertyInfo(Variant::FLOAT, vformat("physics_layer_%d/collision_priority", i));
4174
if (physics_layers[i].collision_priority == 1.0) {
4175
property_info.usage ^= PROPERTY_USAGE_STORAGE;
4176
}
4177
p_list->push_back(property_info);
4178
4179
// physics_layer_%d/physics_material
4180
property_info = PropertyInfo(Variant::OBJECT, vformat("physics_layer_%d/physics_material", i), PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial");
4181
if (physics_layers[i].physics_material.is_null()) {
4182
property_info.usage ^= PROPERTY_USAGE_STORAGE;
4183
}
4184
p_list->push_back(property_info);
4185
}
4186
#endif // PHYSICS_2D_DISABLED
4187
4188
// Terrains.
4189
p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Terrains", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
4190
for (int terrain_set_index = 0; terrain_set_index < terrain_sets.size(); terrain_set_index++) {
4191
p_list->push_back(PropertyInfo(Variant::INT, vformat("terrain_set_%d/mode", terrain_set_index), PROPERTY_HINT_ENUM, "Match Corners and Sides,Match Corners,Match Sides"));
4192
p_list->push_back(PropertyInfo(Variant::NIL, vformat("terrain_set_%d/terrains", terrain_set_index), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, vformat("terrain_set_%d/terrain_", terrain_set_index)));
4193
for (int terrain_index = 0; terrain_index < terrain_sets[terrain_set_index].terrains.size(); terrain_index++) {
4194
p_list->push_back(PropertyInfo(Variant::STRING, vformat("terrain_set_%d/terrain_%d/name", terrain_set_index, terrain_index)));
4195
p_list->push_back(PropertyInfo(Variant::COLOR, vformat("terrain_set_%d/terrain_%d/color", terrain_set_index, terrain_index)));
4196
}
4197
}
4198
4199
// Navigation.
4200
p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Navigation", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
4201
for (int i = 0; i < navigation_layers.size(); i++) {
4202
p_list->push_back(PropertyInfo(Variant::INT, vformat("navigation_layer_%d/layers", i), PROPERTY_HINT_LAYERS_2D_NAVIGATION));
4203
}
4204
4205
// Custom data.
4206
String argt = "Any";
4207
for (int i = 1; i < Variant::VARIANT_MAX; i++) {
4208
argt += "," + Variant::get_type_name(Variant::Type(i));
4209
}
4210
p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Custom Data", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
4211
for (int i = 0; i < custom_data_layers.size(); i++) {
4212
p_list->push_back(PropertyInfo(Variant::STRING, vformat("custom_data_layer_%d/name", i)));
4213
p_list->push_back(PropertyInfo(Variant::INT, vformat("custom_data_layer_%d/type", i), PROPERTY_HINT_ENUM, argt));
4214
}
4215
4216
// Sources.
4217
// Note: sources have to be listed in at the end as some TileData rely on the TileSet properties being initialized first.
4218
for (const KeyValue<int, Ref<TileSetSource>> &E_source : sources) {
4219
p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("sources/%d", E_source.key), PROPERTY_HINT_RESOURCE_TYPE, "TileSetAtlasSource", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_ALWAYS_DUPLICATE));
4220
}
4221
4222
// Tile Proxies.
4223
// Note: proxies need to be set after sources are set.
4224
p_list->push_back(PropertyInfo(Variant::NIL, "Tile Proxies", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
4225
p_list->push_back(PropertyInfo(Variant::ARRAY, "tile_proxies/source_level", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
4226
p_list->push_back(PropertyInfo(Variant::ARRAY, "tile_proxies/coords_level", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
4227
p_list->push_back(PropertyInfo(Variant::ARRAY, "tile_proxies/alternative_level", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
4228
4229
// Patterns.
4230
for (unsigned int pattern_index = 0; pattern_index < patterns.size(); pattern_index++) {
4231
p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("pattern_%d", pattern_index), PROPERTY_HINT_RESOURCE_TYPE, "TileMapPattern", PROPERTY_USAGE_NO_EDITOR));
4232
}
4233
}
4234
4235
void TileSet::_validate_property(PropertyInfo &p_property) const {
4236
if (!Engine::get_singleton()->is_editor_hint()) {
4237
return;
4238
}
4239
if (p_property.name == "tile_layout" && tile_shape == TILE_SHAPE_SQUARE) {
4240
p_property.usage ^= PROPERTY_USAGE_READ_ONLY;
4241
} else if (p_property.name == "tile_offset_axis" && tile_shape == TILE_SHAPE_SQUARE) {
4242
p_property.usage ^= PROPERTY_USAGE_READ_ONLY;
4243
}
4244
}
4245
4246
void TileSet::_bind_methods() {
4247
// Sources management.
4248
ClassDB::bind_method(D_METHOD("get_next_source_id"), &TileSet::get_next_source_id);
4249
ClassDB::bind_method(D_METHOD("add_source", "source", "atlas_source_id_override"), &TileSet::add_source, DEFVAL(TileSet::INVALID_SOURCE));
4250
ClassDB::bind_method(D_METHOD("remove_source", "source_id"), &TileSet::remove_source);
4251
ClassDB::bind_method(D_METHOD("set_source_id", "source_id", "new_source_id"), &TileSet::set_source_id);
4252
ClassDB::bind_method(D_METHOD("get_source_count"), &TileSet::get_source_count);
4253
ClassDB::bind_method(D_METHOD("get_source_id", "index"), &TileSet::get_source_id);
4254
ClassDB::bind_method(D_METHOD("has_source", "source_id"), &TileSet::has_source);
4255
ClassDB::bind_method(D_METHOD("get_source", "source_id"), &TileSet::get_source);
4256
4257
// Shape and layout.
4258
ClassDB::bind_method(D_METHOD("set_tile_shape", "shape"), &TileSet::set_tile_shape);
4259
ClassDB::bind_method(D_METHOD("get_tile_shape"), &TileSet::get_tile_shape);
4260
ClassDB::bind_method(D_METHOD("set_tile_layout", "layout"), &TileSet::set_tile_layout);
4261
ClassDB::bind_method(D_METHOD("get_tile_layout"), &TileSet::get_tile_layout);
4262
ClassDB::bind_method(D_METHOD("set_tile_offset_axis", "alignment"), &TileSet::set_tile_offset_axis);
4263
ClassDB::bind_method(D_METHOD("get_tile_offset_axis"), &TileSet::get_tile_offset_axis);
4264
ClassDB::bind_method(D_METHOD("set_tile_size", "size"), &TileSet::set_tile_size);
4265
ClassDB::bind_method(D_METHOD("get_tile_size"), &TileSet::get_tile_size);
4266
4267
ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_shape", PROPERTY_HINT_ENUM, "Square,Isometric,Half-Offset Square,Hexagon"), "set_tile_shape", "get_tile_shape");
4268
ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_layout", PROPERTY_HINT_ENUM, "Stacked,Stacked Offset,Stairs Right,Stairs Down,Diamond Right,Diamond Down"), "set_tile_layout", "get_tile_layout");
4269
ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_offset_axis", PROPERTY_HINT_ENUM, "Horizontal Offset,Vertical Offset"), "set_tile_offset_axis", "get_tile_offset_axis");
4270
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_size", PROPERTY_HINT_NONE, "suffix:px"), "set_tile_size", "get_tile_size");
4271
4272
// Rendering.
4273
ClassDB::bind_method(D_METHOD("set_uv_clipping", "uv_clipping"), &TileSet::set_uv_clipping);
4274
ClassDB::bind_method(D_METHOD("is_uv_clipping"), &TileSet::is_uv_clipping);
4275
4276
ClassDB::bind_method(D_METHOD("get_occlusion_layers_count"), &TileSet::get_occlusion_layers_count);
4277
ClassDB::bind_method(D_METHOD("add_occlusion_layer", "to_position"), &TileSet::add_occlusion_layer, DEFVAL(-1));
4278
ClassDB::bind_method(D_METHOD("move_occlusion_layer", "layer_index", "to_position"), &TileSet::move_occlusion_layer);
4279
ClassDB::bind_method(D_METHOD("remove_occlusion_layer", "layer_index"), &TileSet::remove_occlusion_layer);
4280
ClassDB::bind_method(D_METHOD("set_occlusion_layer_light_mask", "layer_index", "light_mask"), &TileSet::set_occlusion_layer_light_mask);
4281
ClassDB::bind_method(D_METHOD("get_occlusion_layer_light_mask", "layer_index"), &TileSet::get_occlusion_layer_light_mask);
4282
ClassDB::bind_method(D_METHOD("set_occlusion_layer_sdf_collision", "layer_index", "sdf_collision"), &TileSet::set_occlusion_layer_sdf_collision);
4283
ClassDB::bind_method(D_METHOD("get_occlusion_layer_sdf_collision", "layer_index"), &TileSet::get_occlusion_layer_sdf_collision);
4284
4285
#ifndef PHYSICS_2D_DISABLED
4286
// Physics
4287
ClassDB::bind_method(D_METHOD("get_physics_layers_count"), &TileSet::get_physics_layers_count);
4288
ClassDB::bind_method(D_METHOD("add_physics_layer", "to_position"), &TileSet::add_physics_layer, DEFVAL(-1));
4289
ClassDB::bind_method(D_METHOD("move_physics_layer", "layer_index", "to_position"), &TileSet::move_physics_layer);
4290
ClassDB::bind_method(D_METHOD("remove_physics_layer", "layer_index"), &TileSet::remove_physics_layer);
4291
ClassDB::bind_method(D_METHOD("set_physics_layer_collision_layer", "layer_index", "layer"), &TileSet::set_physics_layer_collision_layer);
4292
ClassDB::bind_method(D_METHOD("get_physics_layer_collision_layer", "layer_index"), &TileSet::get_physics_layer_collision_layer);
4293
ClassDB::bind_method(D_METHOD("set_physics_layer_collision_mask", "layer_index", "mask"), &TileSet::set_physics_layer_collision_mask);
4294
ClassDB::bind_method(D_METHOD("get_physics_layer_collision_mask", "layer_index"), &TileSet::get_physics_layer_collision_mask);
4295
ClassDB::bind_method(D_METHOD("set_physics_layer_collision_priority", "layer_index", "priority"), &TileSet::set_physics_layer_collision_priority);
4296
ClassDB::bind_method(D_METHOD("get_physics_layer_collision_priority", "layer_index"), &TileSet::get_physics_layer_collision_priority);
4297
ClassDB::bind_method(D_METHOD("set_physics_layer_physics_material", "layer_index", "physics_material"), &TileSet::set_physics_layer_physics_material);
4298
ClassDB::bind_method(D_METHOD("get_physics_layer_physics_material", "layer_index"), &TileSet::get_physics_layer_physics_material);
4299
#endif // PHYSICS_2D_DISABLED
4300
4301
// Terrains
4302
ClassDB::bind_method(D_METHOD("get_terrain_sets_count"), &TileSet::get_terrain_sets_count);
4303
ClassDB::bind_method(D_METHOD("add_terrain_set", "to_position"), &TileSet::add_terrain_set, DEFVAL(-1));
4304
ClassDB::bind_method(D_METHOD("move_terrain_set", "terrain_set", "to_position"), &TileSet::move_terrain_set);
4305
ClassDB::bind_method(D_METHOD("remove_terrain_set", "terrain_set"), &TileSet::remove_terrain_set);
4306
ClassDB::bind_method(D_METHOD("set_terrain_set_mode", "terrain_set", "mode"), &TileSet::set_terrain_set_mode);
4307
ClassDB::bind_method(D_METHOD("get_terrain_set_mode", "terrain_set"), &TileSet::get_terrain_set_mode);
4308
4309
ClassDB::bind_method(D_METHOD("get_terrains_count", "terrain_set"), &TileSet::get_terrains_count);
4310
ClassDB::bind_method(D_METHOD("add_terrain", "terrain_set", "to_position"), &TileSet::add_terrain, DEFVAL(-1));
4311
ClassDB::bind_method(D_METHOD("move_terrain", "terrain_set", "terrain_index", "to_position"), &TileSet::move_terrain);
4312
ClassDB::bind_method(D_METHOD("remove_terrain", "terrain_set", "terrain_index"), &TileSet::remove_terrain);
4313
ClassDB::bind_method(D_METHOD("set_terrain_name", "terrain_set", "terrain_index", "name"), &TileSet::set_terrain_name);
4314
ClassDB::bind_method(D_METHOD("get_terrain_name", "terrain_set", "terrain_index"), &TileSet::get_terrain_name);
4315
ClassDB::bind_method(D_METHOD("set_terrain_color", "terrain_set", "terrain_index", "color"), &TileSet::set_terrain_color);
4316
ClassDB::bind_method(D_METHOD("get_terrain_color", "terrain_set", "terrain_index"), &TileSet::get_terrain_color);
4317
4318
#ifndef NAVIGATION_2D_DISABLED
4319
// Navigation
4320
ClassDB::bind_method(D_METHOD("get_navigation_layers_count"), &TileSet::get_navigation_layers_count);
4321
ClassDB::bind_method(D_METHOD("add_navigation_layer", "to_position"), &TileSet::add_navigation_layer, DEFVAL(-1));
4322
ClassDB::bind_method(D_METHOD("move_navigation_layer", "layer_index", "to_position"), &TileSet::move_navigation_layer);
4323
ClassDB::bind_method(D_METHOD("remove_navigation_layer", "layer_index"), &TileSet::remove_navigation_layer);
4324
ClassDB::bind_method(D_METHOD("set_navigation_layer_layers", "layer_index", "layers"), &TileSet::set_navigation_layer_layers);
4325
ClassDB::bind_method(D_METHOD("get_navigation_layer_layers", "layer_index"), &TileSet::get_navigation_layer_layers);
4326
ClassDB::bind_method(D_METHOD("set_navigation_layer_layer_value", "layer_index", "layer_number", "value"), &TileSet::set_navigation_layer_layer_value);
4327
ClassDB::bind_method(D_METHOD("get_navigation_layer_layer_value", "layer_index", "layer_number"), &TileSet::get_navigation_layer_layer_value);
4328
#endif // NAVIGATION_2D_DISABLED
4329
4330
// Custom data
4331
ClassDB::bind_method(D_METHOD("get_custom_data_layers_count"), &TileSet::get_custom_data_layers_count);
4332
ClassDB::bind_method(D_METHOD("add_custom_data_layer", "to_position"), &TileSet::add_custom_data_layer, DEFVAL(-1));
4333
ClassDB::bind_method(D_METHOD("move_custom_data_layer", "layer_index", "to_position"), &TileSet::move_custom_data_layer);
4334
ClassDB::bind_method(D_METHOD("remove_custom_data_layer", "layer_index"), &TileSet::remove_custom_data_layer);
4335
ClassDB::bind_method(D_METHOD("get_custom_data_layer_by_name", "layer_name"), &TileSet::get_custom_data_layer_by_name);
4336
ClassDB::bind_method(D_METHOD("set_custom_data_layer_name", "layer_index", "layer_name"), &TileSet::set_custom_data_layer_name);
4337
ClassDB::bind_method(D_METHOD("has_custom_data_layer_by_name", "layer_name"), &TileSet::has_custom_data_layer_by_name);
4338
ClassDB::bind_method(D_METHOD("get_custom_data_layer_name", "layer_index"), &TileSet::get_custom_data_layer_name);
4339
ClassDB::bind_method(D_METHOD("set_custom_data_layer_type", "layer_index", "layer_type"), &TileSet::set_custom_data_layer_type);
4340
ClassDB::bind_method(D_METHOD("get_custom_data_layer_type", "layer_index"), &TileSet::get_custom_data_layer_type);
4341
4342
// Tile proxies
4343
ClassDB::bind_method(D_METHOD("set_source_level_tile_proxy", "source_from", "source_to"), &TileSet::set_source_level_tile_proxy);
4344
ClassDB::bind_method(D_METHOD("get_source_level_tile_proxy", "source_from"), &TileSet::get_source_level_tile_proxy);
4345
ClassDB::bind_method(D_METHOD("has_source_level_tile_proxy", "source_from"), &TileSet::has_source_level_tile_proxy);
4346
ClassDB::bind_method(D_METHOD("remove_source_level_tile_proxy", "source_from"), &TileSet::remove_source_level_tile_proxy);
4347
4348
ClassDB::bind_method(D_METHOD("set_coords_level_tile_proxy", "p_source_from", "coords_from", "source_to", "coords_to"), &TileSet::set_coords_level_tile_proxy);
4349
ClassDB::bind_method(D_METHOD("get_coords_level_tile_proxy", "source_from", "coords_from"), &TileSet::get_coords_level_tile_proxy);
4350
ClassDB::bind_method(D_METHOD("has_coords_level_tile_proxy", "source_from", "coords_from"), &TileSet::has_coords_level_tile_proxy);
4351
ClassDB::bind_method(D_METHOD("remove_coords_level_tile_proxy", "source_from", "coords_from"), &TileSet::remove_coords_level_tile_proxy);
4352
4353
ClassDB::bind_method(D_METHOD("set_alternative_level_tile_proxy", "source_from", "coords_from", "alternative_from", "source_to", "coords_to", "alternative_to"), &TileSet::set_alternative_level_tile_proxy);
4354
ClassDB::bind_method(D_METHOD("get_alternative_level_tile_proxy", "source_from", "coords_from", "alternative_from"), &TileSet::get_alternative_level_tile_proxy);
4355
ClassDB::bind_method(D_METHOD("has_alternative_level_tile_proxy", "source_from", "coords_from", "alternative_from"), &TileSet::has_alternative_level_tile_proxy);
4356
ClassDB::bind_method(D_METHOD("remove_alternative_level_tile_proxy", "source_from", "coords_from", "alternative_from"), &TileSet::remove_alternative_level_tile_proxy);
4357
4358
ClassDB::bind_method(D_METHOD("map_tile_proxy", "source_from", "coords_from", "alternative_from"), &TileSet::map_tile_proxy);
4359
4360
ClassDB::bind_method(D_METHOD("cleanup_invalid_tile_proxies"), &TileSet::cleanup_invalid_tile_proxies);
4361
ClassDB::bind_method(D_METHOD("clear_tile_proxies"), &TileSet::clear_tile_proxies);
4362
4363
// Patterns
4364
ClassDB::bind_method(D_METHOD("add_pattern", "pattern", "index"), &TileSet::add_pattern, DEFVAL(-1));
4365
ClassDB::bind_method(D_METHOD("get_pattern", "index"), &TileSet::get_pattern, DEFVAL(-1));
4366
ClassDB::bind_method(D_METHOD("remove_pattern", "index"), &TileSet::remove_pattern);
4367
ClassDB::bind_method(D_METHOD("get_patterns_count"), &TileSet::get_patterns_count);
4368
4369
ADD_GROUP("Rendering", "");
4370
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uv_clipping"), "set_uv_clipping", "is_uv_clipping");
4371
ADD_ARRAY("occlusion_layers", "occlusion_layer_");
4372
4373
ADD_GROUP("", "");
4374
ADD_ARRAY("physics_layers", "physics_layer_");
4375
ADD_ARRAY("terrain_sets", "terrain_set_");
4376
#ifndef NAVIGATION_2D_DISABLED
4377
ADD_ARRAY("navigation_layers", "navigation_layer_");
4378
#endif // NAVIGATION_2D_DISABLED
4379
ADD_ARRAY("custom_data_layers", "custom_data_layer_");
4380
4381
// -- Enum binding --
4382
BIND_ENUM_CONSTANT(TILE_SHAPE_SQUARE);
4383
BIND_ENUM_CONSTANT(TILE_SHAPE_ISOMETRIC);
4384
BIND_ENUM_CONSTANT(TILE_SHAPE_HALF_OFFSET_SQUARE);
4385
BIND_ENUM_CONSTANT(TILE_SHAPE_HEXAGON);
4386
4387
BIND_ENUM_CONSTANT(TILE_LAYOUT_STACKED);
4388
BIND_ENUM_CONSTANT(TILE_LAYOUT_STACKED_OFFSET);
4389
BIND_ENUM_CONSTANT(TILE_LAYOUT_STAIRS_RIGHT);
4390
BIND_ENUM_CONSTANT(TILE_LAYOUT_STAIRS_DOWN);
4391
BIND_ENUM_CONSTANT(TILE_LAYOUT_DIAMOND_RIGHT);
4392
BIND_ENUM_CONSTANT(TILE_LAYOUT_DIAMOND_DOWN);
4393
4394
BIND_ENUM_CONSTANT(TILE_OFFSET_AXIS_HORIZONTAL);
4395
BIND_ENUM_CONSTANT(TILE_OFFSET_AXIS_VERTICAL);
4396
4397
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_RIGHT_SIDE);
4398
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_RIGHT_CORNER);
4399
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE);
4400
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER);
4401
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_SIDE);
4402
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_CORNER);
4403
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_LEFT_SIDE);
4404
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_LEFT_CORNER);
4405
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_LEFT_SIDE);
4406
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_LEFT_CORNER);
4407
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_LEFT_SIDE);
4408
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_LEFT_CORNER);
4409
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_SIDE);
4410
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_CORNER);
4411
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_RIGHT_SIDE);
4412
BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_RIGHT_CORNER);
4413
4414
BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_CORNERS_AND_SIDES);
4415
BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_CORNERS);
4416
BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_SIDES);
4417
}
4418
4419
TileSet::TileSet() {
4420
// Instantiate the tile meshes.
4421
tile_lines_mesh.instantiate();
4422
tile_filled_mesh.instantiate();
4423
}
4424
4425
TileSet::~TileSet() {
4426
#ifndef DISABLE_DEPRECATED
4427
for (const KeyValue<int, CompatibilityTileData *> &E : compatibility_data) {
4428
memdelete(E.value);
4429
}
4430
#endif // DISABLE_DEPRECATED
4431
while (!source_ids.is_empty()) {
4432
remove_source(source_ids[0]);
4433
}
4434
}
4435
4436
/////////////////////////////// TileSetSource //////////////////////////////////////
4437
4438
void TileSetSource::set_tile_set(const TileSet *p_tile_set) {
4439
tile_set = p_tile_set;
4440
}
4441
4442
TileSet *TileSetSource::get_tile_set() const {
4443
return (TileSet *)tile_set;
4444
}
4445
4446
void TileSetSource::reset_state() {
4447
tile_set = nullptr;
4448
}
4449
4450
void TileSetSource::_bind_methods() {
4451
// Base tiles
4452
ClassDB::bind_method(D_METHOD("get_tiles_count"), &TileSetSource::get_tiles_count);
4453
ClassDB::bind_method(D_METHOD("get_tile_id", "index"), &TileSetSource::get_tile_id);
4454
ClassDB::bind_method(D_METHOD("has_tile", "atlas_coords"), &TileSetSource::has_tile);
4455
4456
// Alternative tiles
4457
ClassDB::bind_method(D_METHOD("get_alternative_tiles_count", "atlas_coords"), &TileSetSource::get_alternative_tiles_count);
4458
ClassDB::bind_method(D_METHOD("get_alternative_tile_id", "atlas_coords", "index"), &TileSetSource::get_alternative_tile_id);
4459
ClassDB::bind_method(D_METHOD("has_alternative_tile", "atlas_coords", "alternative_tile"), &TileSetSource::has_alternative_tile);
4460
}
4461
4462
/////////////////////////////// TileSetAtlasSource //////////////////////////////////////
4463
4464
void TileSetAtlasSource::set_tile_set(const TileSet *p_tile_set) {
4465
tile_set = p_tile_set;
4466
4467
// Set the TileSet on all TileData.
4468
for (KeyValue<Vector2i, TileAlternativesData> &E_tile : tiles) {
4469
for (KeyValue<int, TileData *> &E_alternative : E_tile.value.alternatives) {
4470
E_alternative.value->set_tile_set(tile_set);
4471
}
4472
}
4473
}
4474
4475
const TileSet *TileSetAtlasSource::get_tile_set() const {
4476
return tile_set;
4477
}
4478
4479
void TileSetAtlasSource::notify_tile_data_properties_should_change() {
4480
// Set the TileSet on all TileData.
4481
for (KeyValue<Vector2i, TileAlternativesData> &E_tile : tiles) {
4482
for (KeyValue<int, TileData *> &E_alternative : E_tile.value.alternatives) {
4483
E_alternative.value->notify_tile_data_properties_should_change();
4484
}
4485
}
4486
}
4487
4488
void TileSetAtlasSource::add_occlusion_layer(int p_to_pos) {
4489
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4490
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4491
E_alternative.value->add_occlusion_layer(p_to_pos);
4492
}
4493
}
4494
}
4495
4496
void TileSetAtlasSource::move_occlusion_layer(int p_from_index, int p_to_pos) {
4497
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4498
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4499
E_alternative.value->move_occlusion_layer(p_from_index, p_to_pos);
4500
}
4501
}
4502
}
4503
4504
void TileSetAtlasSource::remove_occlusion_layer(int p_index) {
4505
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4506
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4507
E_alternative.value->remove_occlusion_layer(p_index);
4508
}
4509
}
4510
}
4511
4512
#ifndef PHYSICS_2D_DISABLED
4513
void TileSetAtlasSource::add_physics_layer(int p_to_pos) {
4514
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4515
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4516
E_alternative.value->add_physics_layer(p_to_pos);
4517
}
4518
}
4519
}
4520
4521
void TileSetAtlasSource::move_physics_layer(int p_from_index, int p_to_pos) {
4522
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4523
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4524
E_alternative.value->move_physics_layer(p_from_index, p_to_pos);
4525
}
4526
}
4527
}
4528
4529
void TileSetAtlasSource::remove_physics_layer(int p_index) {
4530
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4531
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4532
E_alternative.value->remove_physics_layer(p_index);
4533
}
4534
}
4535
}
4536
#endif // PHYSICS_2D_DISABLED
4537
4538
void TileSetAtlasSource::add_terrain_set(int p_to_pos) {
4539
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4540
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4541
E_alternative.value->add_terrain_set(p_to_pos);
4542
}
4543
}
4544
}
4545
4546
void TileSetAtlasSource::move_terrain_set(int p_from_index, int p_to_pos) {
4547
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4548
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4549
E_alternative.value->move_terrain_set(p_from_index, p_to_pos);
4550
}
4551
}
4552
}
4553
4554
void TileSetAtlasSource::remove_terrain_set(int p_index) {
4555
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4556
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4557
E_alternative.value->remove_terrain_set(p_index);
4558
}
4559
}
4560
}
4561
4562
void TileSetAtlasSource::add_terrain(int p_terrain_set, int p_to_pos) {
4563
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4564
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4565
E_alternative.value->add_terrain(p_terrain_set, p_to_pos);
4566
}
4567
}
4568
}
4569
4570
void TileSetAtlasSource::move_terrain(int p_terrain_set, int p_from_index, int p_to_pos) {
4571
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4572
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4573
E_alternative.value->move_terrain(p_terrain_set, p_from_index, p_to_pos);
4574
}
4575
}
4576
}
4577
4578
void TileSetAtlasSource::remove_terrain(int p_terrain_set, int p_index) {
4579
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4580
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4581
E_alternative.value->remove_terrain(p_terrain_set, p_index);
4582
}
4583
}
4584
}
4585
4586
#ifndef NAVIGATION_2D_DISABLED
4587
void TileSetAtlasSource::add_navigation_layer(int p_to_pos) {
4588
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4589
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4590
E_alternative.value->add_navigation_layer(p_to_pos);
4591
}
4592
}
4593
}
4594
4595
void TileSetAtlasSource::move_navigation_layer(int p_from_index, int p_to_pos) {
4596
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4597
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4598
E_alternative.value->move_navigation_layer(p_from_index, p_to_pos);
4599
}
4600
}
4601
}
4602
4603
void TileSetAtlasSource::remove_navigation_layer(int p_index) {
4604
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4605
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4606
E_alternative.value->remove_navigation_layer(p_index);
4607
}
4608
}
4609
}
4610
#endif // NAVIGATION_2D_DISABLED
4611
4612
void TileSetAtlasSource::add_custom_data_layer(int p_to_pos) {
4613
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4614
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4615
E_alternative.value->add_custom_data_layer(p_to_pos);
4616
}
4617
}
4618
}
4619
4620
void TileSetAtlasSource::move_custom_data_layer(int p_from_index, int p_to_pos) {
4621
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4622
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4623
E_alternative.value->move_custom_data_layer(p_from_index, p_to_pos);
4624
}
4625
}
4626
}
4627
4628
void TileSetAtlasSource::remove_custom_data_layer(int p_index) {
4629
for (KeyValue<Vector2i, TileAlternativesData> E_tile : tiles) {
4630
for (KeyValue<int, TileData *> E_alternative : E_tile.value.alternatives) {
4631
E_alternative.value->remove_custom_data_layer(p_index);
4632
}
4633
}
4634
}
4635
4636
void TileSetAtlasSource::reset_state() {
4637
tile_set = nullptr;
4638
4639
for (KeyValue<Vector2i, TileAlternativesData> &E_tile : tiles) {
4640
for (const KeyValue<int, TileData *> &E_tile_data : E_tile.value.alternatives) {
4641
memdelete(E_tile_data.value);
4642
}
4643
}
4644
_coords_mapping_cache.clear();
4645
tiles.clear();
4646
tiles_ids.clear();
4647
_queue_update_padded_texture();
4648
}
4649
4650
void TileSetAtlasSource::set_texture(Ref<Texture2D> p_texture) {
4651
if (texture.is_valid()) {
4652
texture->disconnect_changed(callable_mp(this, &TileSetAtlasSource::_queue_update_padded_texture));
4653
}
4654
4655
texture = p_texture;
4656
4657
if (texture.is_valid()) {
4658
texture->connect_changed(callable_mp(this, &TileSetAtlasSource::_queue_update_padded_texture));
4659
}
4660
4661
_queue_update_padded_texture();
4662
emit_changed();
4663
}
4664
4665
Ref<Texture2D> TileSetAtlasSource::get_texture() const {
4666
return texture;
4667
}
4668
4669
void TileSetAtlasSource::set_margins(Vector2i p_margins) {
4670
if (p_margins.x < 0 || p_margins.y < 0) {
4671
WARN_PRINT("Atlas source margins should be positive.");
4672
margins = p_margins.maxi(0);
4673
} else {
4674
margins = p_margins;
4675
}
4676
4677
_queue_update_padded_texture();
4678
emit_changed();
4679
}
4680
4681
Vector2i TileSetAtlasSource::get_margins() const {
4682
return margins;
4683
}
4684
4685
void TileSetAtlasSource::set_separation(Vector2i p_separation) {
4686
if (p_separation.x < 0 || p_separation.y < 0) {
4687
WARN_PRINT("Atlas source separation should be positive.");
4688
separation = p_separation.maxi(0);
4689
} else {
4690
separation = p_separation;
4691
}
4692
4693
_queue_update_padded_texture();
4694
emit_changed();
4695
}
4696
4697
Vector2i TileSetAtlasSource::get_separation() const {
4698
return separation;
4699
}
4700
4701
void TileSetAtlasSource::set_texture_region_size(Vector2i p_tile_size) {
4702
if (p_tile_size.x <= 0 || p_tile_size.y <= 0) {
4703
WARN_PRINT("Atlas source tile_size should be strictly positive.");
4704
texture_region_size = p_tile_size.maxi(1);
4705
} else {
4706
texture_region_size = p_tile_size;
4707
}
4708
4709
_queue_update_padded_texture();
4710
emit_changed();
4711
}
4712
4713
Vector2i TileSetAtlasSource::get_texture_region_size() const {
4714
return texture_region_size;
4715
}
4716
4717
void TileSetAtlasSource::set_use_texture_padding(bool p_use_padding) {
4718
if (use_texture_padding == p_use_padding) {
4719
return;
4720
}
4721
use_texture_padding = p_use_padding;
4722
_queue_update_padded_texture();
4723
emit_changed();
4724
}
4725
4726
bool TileSetAtlasSource::get_use_texture_padding() const {
4727
return use_texture_padding;
4728
}
4729
4730
Vector2i TileSetAtlasSource::get_atlas_grid_size() const {
4731
Ref<Texture2D> txt = get_texture();
4732
if (txt.is_null()) {
4733
return Vector2i();
4734
}
4735
4736
ERR_FAIL_COND_V(texture_region_size.x <= 0 || texture_region_size.y <= 0, Vector2i());
4737
4738
Size2i valid_area = txt->get_size() - margins;
4739
4740
// Compute the number of valid tiles in the tiles atlas
4741
Size2i grid_size;
4742
if (valid_area.x >= texture_region_size.x && valid_area.y >= texture_region_size.y) {
4743
valid_area -= texture_region_size;
4744
grid_size = Size2i(1, 1) + valid_area / (texture_region_size + separation);
4745
}
4746
return grid_size;
4747
}
4748
4749
bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value) {
4750
Vector<String> components = String(p_name).split("/", true, 2);
4751
4752
// Compute the vector2i if we have coordinates.
4753
Vector<String> coords_split = components[0].split(":");
4754
Vector2i coords = TileSetSource::INVALID_ATLAS_COORDS;
4755
if (coords_split.size() == 2 && coords_split[0].is_valid_int() && coords_split[1].is_valid_int()) {
4756
coords = Vector2i(coords_split[0].to_int(), coords_split[1].to_int());
4757
}
4758
4759
// Properties.
4760
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
4761
// Create the tile if needed.
4762
if (!has_tile(coords)) {
4763
create_tile(coords);
4764
}
4765
if (components.size() >= 2) {
4766
// Properties.
4767
if (components[1] == "size_in_atlas") {
4768
move_tile_in_atlas(coords, coords, p_value);
4769
return true;
4770
} else if (components[1] == "next_alternative_id") {
4771
tiles[coords].next_alternative_id = p_value;
4772
return true;
4773
} else if (components[1] == "animation_columns") {
4774
set_tile_animation_columns(coords, p_value);
4775
return true;
4776
} else if (components[1] == "animation_separation") {
4777
set_tile_animation_separation(coords, p_value);
4778
return true;
4779
} else if (components[1] == "animation_speed") {
4780
set_tile_animation_speed(coords, p_value);
4781
return true;
4782
} else if (components[1] == "animation_mode") {
4783
set_tile_animation_mode(coords, VariantCaster<TileSetAtlasSource::TileAnimationMode>::cast(p_value));
4784
return true;
4785
} else if (components[1] == "animation_frames_count") {
4786
set_tile_animation_frames_count(coords, p_value);
4787
return true;
4788
} else if (components.size() >= 3 && components[1].begins_with("animation_frame_") && components[1].trim_prefix("animation_frame_").is_valid_int()) {
4789
int frame = components[1].trim_prefix("animation_frame_").to_int();
4790
if (components[2] == "duration") {
4791
if (frame >= get_tile_animation_frames_count(coords)) {
4792
set_tile_animation_frames_count(coords, frame + 1);
4793
}
4794
set_tile_animation_frame_duration(coords, frame, p_value);
4795
return true;
4796
}
4797
return false;
4798
} else if (components[1].is_valid_int()) {
4799
int alternative_id = components[1].to_int();
4800
if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) {
4801
// Create the alternative if needed ?
4802
if (!has_alternative_tile(coords, alternative_id)) {
4803
create_alternative_tile(coords, alternative_id);
4804
}
4805
if (!tiles[coords].alternatives.has(alternative_id)) {
4806
tiles[coords].alternatives[alternative_id] = memnew(TileData);
4807
tiles[coords].alternatives[alternative_id]->set_tile_set(tile_set);
4808
tiles[coords].alternatives[alternative_id]->set_allow_transform(alternative_id > 0);
4809
tiles[coords].alternatives_ids.push_back(alternative_id);
4810
}
4811
if (components.size() >= 3) {
4812
bool valid;
4813
tiles[coords].alternatives[alternative_id]->set(components[2], p_value, &valid);
4814
return valid;
4815
} else {
4816
// Only create the alternative if it did not exist yet.
4817
return true;
4818
}
4819
}
4820
}
4821
}
4822
}
4823
4824
return false;
4825
}
4826
4827
bool TileSetAtlasSource::_get(const StringName &p_name, Variant &r_ret) const {
4828
Vector<String> components = String(p_name).split("/", true, 2);
4829
4830
// Properties.
4831
Vector<String> coords_split = components[0].split(":");
4832
if (coords_split.size() == 2 && coords_split[0].is_valid_int() && coords_split[1].is_valid_int()) {
4833
Vector2i coords = Vector2i(coords_split[0].to_int(), coords_split[1].to_int());
4834
if (tiles.has(coords)) {
4835
if (components.size() >= 2) {
4836
// Properties.
4837
if (components[1] == "size_in_atlas") {
4838
r_ret = tiles[coords].size_in_atlas;
4839
return true;
4840
} else if (components[1] == "next_alternative_id") {
4841
r_ret = tiles[coords].next_alternative_id;
4842
return true;
4843
} else if (components[1] == "animation_columns") {
4844
r_ret = get_tile_animation_columns(coords);
4845
return true;
4846
} else if (components[1] == "animation_separation") {
4847
r_ret = get_tile_animation_separation(coords);
4848
return true;
4849
} else if (components[1] == "animation_speed") {
4850
r_ret = get_tile_animation_speed(coords);
4851
return true;
4852
} else if (components[1] == "animation_mode") {
4853
r_ret = get_tile_animation_mode(coords);
4854
return true;
4855
} else if (components[1] == "animation_frames_count") {
4856
r_ret = get_tile_animation_frames_count(coords);
4857
return true;
4858
} else if (components.size() >= 3 && components[1].begins_with("animation_frame_") && components[1].trim_prefix("animation_frame_").is_valid_int()) {
4859
int frame = components[1].trim_prefix("animation_frame_").to_int();
4860
if (frame < 0 || frame >= get_tile_animation_frames_count(coords)) {
4861
return false;
4862
}
4863
if (components[2] == "duration") {
4864
r_ret = get_tile_animation_frame_duration(coords, frame);
4865
return true;
4866
}
4867
return false;
4868
} else if (components[1].is_valid_int()) {
4869
int alternative_id = components[1].to_int();
4870
if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE && tiles[coords].alternatives.has(alternative_id)) {
4871
if (components.size() >= 3) {
4872
bool valid;
4873
r_ret = tiles[coords].alternatives[alternative_id]->get(components[2], &valid);
4874
return valid;
4875
} else {
4876
// Only to notify the tile alternative exists.
4877
r_ret = alternative_id;
4878
return true;
4879
}
4880
}
4881
}
4882
}
4883
}
4884
}
4885
4886
return false;
4887
}
4888
4889
void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
4890
// Atlases data.
4891
PropertyInfo property_info;
4892
for (const KeyValue<Vector2i, TileAlternativesData> &E_tile : tiles) {
4893
List<PropertyInfo> tile_property_list;
4894
4895
// size_in_atlas
4896
property_info = PropertyInfo(Variant::VECTOR2I, "size_in_atlas", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4897
if (E_tile.value.size_in_atlas == Vector2i(1, 1)) {
4898
property_info.usage ^= PROPERTY_USAGE_STORAGE;
4899
}
4900
tile_property_list.push_back(property_info);
4901
4902
// next_alternative_id
4903
property_info = PropertyInfo(Variant::INT, "next_alternative_id", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4904
if (E_tile.value.next_alternative_id == 1) {
4905
property_info.usage ^= PROPERTY_USAGE_STORAGE;
4906
}
4907
tile_property_list.push_back(property_info);
4908
4909
// animation_columns.
4910
property_info = PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4911
if (E_tile.value.animation_columns == 0) {
4912
property_info.usage ^= PROPERTY_USAGE_STORAGE;
4913
}
4914
tile_property_list.push_back(property_info);
4915
4916
// animation_separation.
4917
property_info = PropertyInfo(Variant::INT, "animation_separation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4918
if (E_tile.value.animation_separation == Vector2i()) {
4919
property_info.usage ^= PROPERTY_USAGE_STORAGE;
4920
}
4921
tile_property_list.push_back(property_info);
4922
4923
// animation_speed.
4924
property_info = PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4925
if (E_tile.value.animation_speed == 1.0) {
4926
property_info.usage ^= PROPERTY_USAGE_STORAGE;
4927
}
4928
tile_property_list.push_back(property_info);
4929
4930
// animation_mode.
4931
property_info = PropertyInfo(Variant::INT, "animation_mode", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4932
if (E_tile.value.animation_mode == TILE_ANIMATION_MODE_DEFAULT) {
4933
property_info.usage ^= PROPERTY_USAGE_STORAGE;
4934
}
4935
tile_property_list.push_back(property_info);
4936
4937
// animation_frames_count.
4938
tile_property_list.push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
4939
4940
// animation_frame_*.
4941
bool store_durations = tiles[E_tile.key].animation_frames_durations.size() >= 2;
4942
for (int i = 0; i < (int)tiles[E_tile.key].animation_frames_durations.size(); i++) {
4943
property_info = PropertyInfo(Variant::FLOAT, vformat("animation_frame_%d/duration", i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
4944
if (!store_durations) {
4945
property_info.usage ^= PROPERTY_USAGE_STORAGE;
4946
}
4947
tile_property_list.push_back(property_info);
4948
}
4949
4950
for (const KeyValue<int, TileData *> &E_alternative : E_tile.value.alternatives) {
4951
const String formatted_key = itos(E_alternative.key);
4952
4953
// Add a dummy property to show the alternative exists.
4954
tile_property_list.push_back(PropertyInfo(Variant::INT, formatted_key, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
4955
4956
// Get the alternative tile's properties and append them to the list of properties.
4957
const String alternative_property_info_prefix = formatted_key + '/';
4958
List<PropertyInfo> alternative_property_list;
4959
E_alternative.value->get_property_list(&alternative_property_list);
4960
for (PropertyInfo &alternative_property_info : alternative_property_list) {
4961
Variant default_value = ClassDB::class_get_default_property_value("TileData", alternative_property_info.name);
4962
Variant value = E_alternative.value->get(alternative_property_info.name);
4963
if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) {
4964
alternative_property_info.usage ^= PROPERTY_USAGE_STORAGE;
4965
}
4966
alternative_property_info.name = alternative_property_info_prefix + alternative_property_info.name;
4967
tile_property_list.push_back(alternative_property_info);
4968
}
4969
}
4970
4971
// Add all alternative.
4972
const String property_info_prefix = vformat("%d:%d/", E_tile.key.x, E_tile.key.y);
4973
for (PropertyInfo &tile_property_info : tile_property_list) {
4974
tile_property_info.name = property_info_prefix + tile_property_info.name;
4975
p_list->push_back(tile_property_info);
4976
}
4977
}
4978
}
4979
4980
void TileSetAtlasSource::create_tile(const Vector2i p_atlas_coords, const Vector2i p_size) {
4981
// Create a tile if it does not exists.
4982
ERR_FAIL_COND(p_atlas_coords.x < 0 || p_atlas_coords.y < 0);
4983
ERR_FAIL_COND(p_size.x <= 0 || p_size.y <= 0);
4984
4985
bool room_for_tile = has_room_for_tile(p_atlas_coords, p_size, 1, Vector2i(), 1);
4986
ERR_FAIL_COND_MSG(!room_for_tile, "Cannot create tile. The tile is outside the texture or tiles are already present in the space the tile would cover.");
4987
4988
// Initialize the tile data.
4989
TileAlternativesData tad;
4990
tad.size_in_atlas = p_size;
4991
tad.animation_frames_durations.push_back(1.0);
4992
tad.alternatives[0] = memnew(TileData);
4993
tad.alternatives[0]->set_tile_set(tile_set);
4994
tad.alternatives[0]->set_allow_transform(false);
4995
tad.alternatives[0]->connect(CoreStringName(changed), callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed));
4996
tad.alternatives[0]->notify_property_list_changed();
4997
tad.alternatives_ids.push_back(0);
4998
4999
// Create and resize the tile.
5000
tiles.insert(p_atlas_coords, tad);
5001
tiles_ids.push_back(p_atlas_coords);
5002
tiles_ids.sort();
5003
5004
_create_coords_mapping_cache(p_atlas_coords);
5005
_queue_update_padded_texture();
5006
5007
_try_emit_changed();
5008
}
5009
5010
void TileSetAtlasSource::remove_tile(Vector2i p_atlas_coords) {
5011
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
5012
5013
// Remove all covered positions from the mapping cache
5014
_clear_coords_mapping_cache(p_atlas_coords);
5015
5016
// Free tile data.
5017
for (const KeyValue<int, TileData *> &E_tile_data : tiles[p_atlas_coords].alternatives) {
5018
memdelete(E_tile_data.value);
5019
}
5020
5021
// Delete the tile
5022
tiles.erase(p_atlas_coords);
5023
tiles_ids.erase(p_atlas_coords);
5024
tiles_ids.sort();
5025
5026
_queue_update_padded_texture();
5027
5028
_try_emit_changed();
5029
}
5030
5031
bool TileSetAtlasSource::has_tile(Vector2i p_atlas_coords) const {
5032
return tiles.has(p_atlas_coords);
5033
}
5034
5035
Vector2i TileSetAtlasSource::get_tile_at_coords(Vector2i p_atlas_coords) const {
5036
if (!_coords_mapping_cache.has(p_atlas_coords)) {
5037
return INVALID_ATLAS_COORDS;
5038
}
5039
5040
return _coords_mapping_cache[p_atlas_coords];
5041
}
5042
5043
void TileSetAtlasSource::set_tile_animation_columns(const Vector2i p_atlas_coords, int p_frame_columns) {
5044
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5045
ERR_FAIL_COND(p_frame_columns < 0);
5046
5047
TileAlternativesData &tad = tiles[p_atlas_coords];
5048
bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, p_frame_columns, tad.animation_separation, tad.animation_frames_durations.size(), p_atlas_coords);
5049
ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover.");
5050
5051
_clear_coords_mapping_cache(p_atlas_coords);
5052
5053
tiles[p_atlas_coords].animation_columns = p_frame_columns;
5054
5055
_create_coords_mapping_cache(p_atlas_coords);
5056
_queue_update_padded_texture();
5057
5058
_try_emit_changed();
5059
}
5060
5061
int TileSetAtlasSource::get_tile_animation_columns(const Vector2i p_atlas_coords) const {
5062
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5063
return tiles[p_atlas_coords].animation_columns;
5064
}
5065
5066
void TileSetAtlasSource::set_tile_animation_separation(const Vector2i p_atlas_coords, const Vector2i p_separation) {
5067
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5068
ERR_FAIL_COND(p_separation.x < 0 || p_separation.y < 0);
5069
5070
TileAlternativesData &tad = tiles[p_atlas_coords];
5071
bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, tad.animation_columns, p_separation, tad.animation_frames_durations.size(), p_atlas_coords);
5072
ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover.");
5073
5074
_clear_coords_mapping_cache(p_atlas_coords);
5075
5076
tiles[p_atlas_coords].animation_separation = p_separation;
5077
5078
_create_coords_mapping_cache(p_atlas_coords);
5079
_queue_update_padded_texture();
5080
5081
_try_emit_changed();
5082
}
5083
5084
Vector2i TileSetAtlasSource::get_tile_animation_separation(const Vector2i p_atlas_coords) const {
5085
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5086
return tiles[p_atlas_coords].animation_separation;
5087
}
5088
5089
void TileSetAtlasSource::set_tile_animation_speed(const Vector2i p_atlas_coords, real_t p_speed) {
5090
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5091
ERR_FAIL_COND(p_speed <= 0);
5092
5093
tiles[p_atlas_coords].animation_speed = p_speed;
5094
5095
_try_emit_changed();
5096
}
5097
5098
real_t TileSetAtlasSource::get_tile_animation_speed(const Vector2i p_atlas_coords) const {
5099
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1.0, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5100
return tiles[p_atlas_coords].animation_speed;
5101
}
5102
5103
void TileSetAtlasSource::set_tile_animation_mode(const Vector2i p_atlas_coords, TileSetAtlasSource::TileAnimationMode p_mode) {
5104
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5105
5106
tiles[p_atlas_coords].animation_mode = p_mode;
5107
5108
_try_emit_changed();
5109
}
5110
5111
TileSetAtlasSource::TileAnimationMode TileSetAtlasSource::get_tile_animation_mode(const Vector2i p_atlas_coords) const {
5112
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TILE_ANIMATION_MODE_DEFAULT, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5113
5114
return tiles[p_atlas_coords].animation_mode;
5115
}
5116
5117
void TileSetAtlasSource::set_tile_animation_frames_count(const Vector2i p_atlas_coords, int p_frames_count) {
5118
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5119
ERR_FAIL_COND(p_frames_count < 1);
5120
5121
int old_size = tiles[p_atlas_coords].animation_frames_durations.size();
5122
if (p_frames_count == old_size) {
5123
return;
5124
}
5125
5126
TileAlternativesData &tad = tiles[p_atlas_coords];
5127
bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, tad.animation_columns, tad.animation_separation, p_frames_count, p_atlas_coords);
5128
ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover.");
5129
5130
_clear_coords_mapping_cache(p_atlas_coords);
5131
5132
tiles[p_atlas_coords].animation_frames_durations.resize(p_frames_count);
5133
for (int i = old_size; i < p_frames_count; i++) {
5134
tiles[p_atlas_coords].animation_frames_durations[i] = 1.0;
5135
}
5136
5137
_create_coords_mapping_cache(p_atlas_coords);
5138
_queue_update_padded_texture();
5139
5140
notify_property_list_changed();
5141
5142
_try_emit_changed();
5143
}
5144
5145
int TileSetAtlasSource::get_tile_animation_frames_count(const Vector2i p_atlas_coords) const {
5146
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5147
return tiles[p_atlas_coords].animation_frames_durations.size();
5148
}
5149
5150
void TileSetAtlasSource::set_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index, real_t p_duration) {
5151
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5152
ERR_FAIL_INDEX(p_frame_index, (int)tiles[p_atlas_coords].animation_frames_durations.size());
5153
ERR_FAIL_COND(p_duration <= 0.0);
5154
5155
tiles[p_atlas_coords].animation_frames_durations[p_frame_index] = p_duration;
5156
5157
_try_emit_changed();
5158
}
5159
5160
real_t TileSetAtlasSource::get_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index) const {
5161
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5162
ERR_FAIL_INDEX_V(p_frame_index, (int)tiles[p_atlas_coords].animation_frames_durations.size(), 0.0);
5163
return tiles[p_atlas_coords].animation_frames_durations[p_frame_index];
5164
}
5165
5166
real_t TileSetAtlasSource::get_tile_animation_total_duration(const Vector2i p_atlas_coords) const {
5167
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5168
5169
real_t sum = 0.0;
5170
for (const real_t &duration : tiles[p_atlas_coords].animation_frames_durations) {
5171
sum += duration;
5172
}
5173
return sum;
5174
}
5175
5176
Vector2i TileSetAtlasSource::get_tile_size_in_atlas(Vector2i p_atlas_coords) const {
5177
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(-1, -1), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
5178
5179
return tiles[p_atlas_coords].size_in_atlas;
5180
}
5181
5182
int TileSetAtlasSource::get_tiles_count() const {
5183
return tiles_ids.size();
5184
}
5185
5186
Vector2i TileSetAtlasSource::get_tile_id(int p_index) const {
5187
ERR_FAIL_INDEX_V(p_index, tiles_ids.size(), TileSetSource::INVALID_ATLAS_COORDS);
5188
return tiles_ids[p_index];
5189
}
5190
5191
bool TileSetAtlasSource::has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_size, int p_animation_columns, Vector2i p_animation_separation, int p_frames_count, Vector2i p_ignored_tile) const {
5192
if (p_atlas_coords.x < 0 || p_atlas_coords.y < 0) {
5193
return false;
5194
}
5195
if (p_size.x <= 0 || p_size.y <= 0) {
5196
return false;
5197
}
5198
if (p_frames_count <= 0) {
5199
return false;
5200
}
5201
Size2i atlas_grid_size = get_atlas_grid_size();
5202
for (int frame = 0; frame < p_frames_count; frame++) {
5203
Vector2i frame_coords = p_atlas_coords + (p_size + p_animation_separation) * ((p_animation_columns > 0) ? Vector2i(frame % p_animation_columns, frame / p_animation_columns) : Vector2i(frame, 0));
5204
for (int x = 0; x < p_size.x; x++) {
5205
for (int y = 0; y < p_size.y; y++) {
5206
Vector2i coords = frame_coords + Vector2i(x, y);
5207
if (_coords_mapping_cache.has(coords) && _coords_mapping_cache[coords] != p_ignored_tile) {
5208
return false;
5209
}
5210
if (coords.x >= atlas_grid_size.x || coords.y >= atlas_grid_size.y) {
5211
return false;
5212
}
5213
}
5214
}
5215
}
5216
return true;
5217
}
5218
5219
bool TileSetAtlasSource::has_tiles_outside_texture() const {
5220
for (const KeyValue<Vector2i, TileSetAtlasSource::TileAlternativesData> &E : tiles) {
5221
if (!has_room_for_tile(E.key, E.value.size_in_atlas, E.value.animation_columns, E.value.animation_separation, E.value.animation_frames_durations.size(), E.key)) {
5222
return true;
5223
}
5224
}
5225
return false;
5226
}
5227
5228
Vector<Vector2i> TileSetAtlasSource::get_tiles_outside_texture() const {
5229
Vector<Vector2i> to_return;
5230
5231
for (const KeyValue<Vector2i, TileSetAtlasSource::TileAlternativesData> &E : tiles) {
5232
if (!has_room_for_tile(E.key, E.value.size_in_atlas, E.value.animation_columns, E.value.animation_separation, E.value.animation_frames_durations.size(), E.key)) {
5233
to_return.push_back(E.key);
5234
}
5235
}
5236
return to_return;
5237
}
5238
5239
void TileSetAtlasSource::clear_tiles_outside_texture() {
5240
LocalVector<Vector2i> to_remove;
5241
5242
for (const KeyValue<Vector2i, TileSetAtlasSource::TileAlternativesData> &E : tiles) {
5243
if (!has_room_for_tile(E.key, E.value.size_in_atlas, E.value.animation_columns, E.value.animation_separation, E.value.animation_frames_durations.size(), E.key)) {
5244
to_remove.push_back(E.key);
5245
}
5246
}
5247
5248
for (const Vector2i &v : to_remove) {
5249
remove_tile(v);
5250
}
5251
}
5252
5253
PackedVector2Array TileSetAtlasSource::get_tiles_to_be_removed_on_change(Ref<Texture2D> p_texture, Vector2i p_margins, Vector2i p_separation, Vector2i p_texture_region_size) {
5254
ERR_FAIL_COND_V(p_margins.x < 0 || p_margins.y < 0, PackedVector2Array());
5255
ERR_FAIL_COND_V(p_separation.x < 0 || p_separation.y < 0, PackedVector2Array());
5256
ERR_FAIL_COND_V(p_texture_region_size.x <= 0 || p_texture_region_size.y <= 0, PackedVector2Array());
5257
5258
// Compute the new atlas grid size.
5259
Size2 new_grid_size;
5260
if (p_texture.is_valid()) {
5261
Size2i valid_area = p_texture->get_size() - p_margins;
5262
5263
// Compute the number of valid tiles in the tiles atlas
5264
if (valid_area.x >= p_texture_region_size.x && valid_area.y >= p_texture_region_size.y) {
5265
valid_area -= p_texture_region_size;
5266
new_grid_size = Size2i(1, 1) + valid_area / (p_texture_region_size + p_separation);
5267
}
5268
}
5269
5270
Vector<Vector2> output;
5271
for (KeyValue<Vector2i, TileAlternativesData> &E : tiles) {
5272
for (unsigned int frame = 0; frame < E.value.animation_frames_durations.size(); frame++) {
5273
Vector2i frame_coords = E.key + (E.value.size_in_atlas + E.value.animation_separation) * ((E.value.animation_columns > 0) ? Vector2i(frame % E.value.animation_columns, frame / E.value.animation_columns) : Vector2i(frame, 0));
5274
frame_coords += E.value.size_in_atlas;
5275
if (frame_coords.x > new_grid_size.x || frame_coords.y > new_grid_size.y) {
5276
output.push_back(E.key);
5277
break;
5278
}
5279
}
5280
}
5281
return output;
5282
}
5283
5284
Rect2i TileSetAtlasSource::get_tile_texture_region(Vector2i p_atlas_coords, int p_frame) const {
5285
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Rect2i(), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
5286
ERR_FAIL_INDEX_V(p_frame, (int)tiles[p_atlas_coords].animation_frames_durations.size(), Rect2i());
5287
5288
const TileAlternativesData &tad = tiles[p_atlas_coords];
5289
5290
Vector2i size_in_atlas = tad.size_in_atlas;
5291
Vector2 region_size = texture_region_size * size_in_atlas + separation * (size_in_atlas - Vector2i(1, 1));
5292
5293
Vector2i frame_coords = p_atlas_coords + (size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(p_frame % tad.animation_columns, p_frame / tad.animation_columns) : Vector2i(p_frame, 0));
5294
Vector2 origin = margins + (frame_coords * (texture_region_size + separation));
5295
5296
return Rect2(origin, region_size);
5297
}
5298
5299
bool TileSetAtlasSource::is_position_in_tile_texture_region(const Vector2i p_atlas_coords, int p_alternative_tile, Vector2 p_position) const {
5300
Size2 size = get_tile_texture_region(p_atlas_coords).size;
5301
TileData *tile_data = get_tile_data(p_atlas_coords, p_alternative_tile);
5302
if (tile_data->get_transpose()) {
5303
size = Size2(size.y, size.x);
5304
}
5305
Rect2 rect = Rect2(-size / 2 - tile_data->get_texture_origin(), size);
5306
5307
return rect.has_point(p_position);
5308
}
5309
5310
bool TileSetAtlasSource::is_rect_in_tile_texture_region(const Vector2i p_atlas_coords, int p_alternative_tile, Rect2 p_rect) const {
5311
Size2 size = get_tile_texture_region(p_atlas_coords).size;
5312
TileData *tile_data = get_tile_data(p_atlas_coords, p_alternative_tile);
5313
if (tile_data->get_transpose()) {
5314
size = Size2(size.y, size.x);
5315
}
5316
Rect2 rect = Rect2(-size / 2 - tile_data->get_texture_origin(), size);
5317
5318
return p_rect.intersection(rect) == p_rect;
5319
}
5320
5321
int TileSetAtlasSource::alternative_no_transform(int p_alternative_id) {
5322
return p_alternative_id & ~(TRANSFORM_FLIP_H | TRANSFORM_FLIP_V | TRANSFORM_TRANSPOSE);
5323
}
5324
5325
// Getters for texture and tile region (padded or not)
5326
Ref<Texture2D> TileSetAtlasSource::get_runtime_texture() const {
5327
if (use_texture_padding) {
5328
return padded_texture;
5329
} else {
5330
return texture;
5331
}
5332
}
5333
5334
Rect2i TileSetAtlasSource::get_runtime_tile_texture_region(Vector2i p_atlas_coords, int p_frame) const {
5335
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Rect2i(), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
5336
ERR_FAIL_INDEX_V(p_frame, (int)tiles[p_atlas_coords].animation_frames_durations.size(), Rect2i());
5337
5338
Rect2i src_rect = get_tile_texture_region(p_atlas_coords, p_frame);
5339
if (use_texture_padding) {
5340
const TileAlternativesData &tad = tiles[p_atlas_coords];
5341
Vector2i frame_coords = p_atlas_coords + (tad.size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(p_frame % tad.animation_columns, p_frame / tad.animation_columns) : Vector2i(p_frame, 0));
5342
Vector2i base_pos = frame_coords * (texture_region_size + Vector2i(2, 2)) + Vector2i(1, 1);
5343
5344
return Rect2i(base_pos, src_rect.size);
5345
} else {
5346
return src_rect;
5347
}
5348
}
5349
5350
void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords, Vector2i p_new_size) {
5351
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
5352
5353
TileAlternativesData &tad = tiles[p_atlas_coords];
5354
5355
// Compute the actual new rect from arguments.
5356
Vector2i new_atlas_coords = (p_new_atlas_coords != INVALID_ATLAS_COORDS) ? p_new_atlas_coords : p_atlas_coords;
5357
Vector2i new_size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tad.size_in_atlas;
5358
5359
if (new_atlas_coords == p_atlas_coords && new_size == tad.size_in_atlas) {
5360
return;
5361
}
5362
5363
bool room_for_tile = has_room_for_tile(new_atlas_coords, new_size, tad.animation_columns, tad.animation_separation, tad.animation_frames_durations.size(), p_atlas_coords);
5364
ERR_FAIL_COND_MSG(!room_for_tile, vformat("Cannot move tile at position %s with size %s. Tile already present.", new_atlas_coords, new_size));
5365
5366
_clear_coords_mapping_cache(p_atlas_coords);
5367
5368
// Move the tile and update its size.
5369
if (new_atlas_coords != p_atlas_coords) {
5370
tiles[new_atlas_coords] = tiles[p_atlas_coords];
5371
tiles.erase(p_atlas_coords);
5372
5373
tiles_ids.erase(p_atlas_coords);
5374
tiles_ids.push_back(new_atlas_coords);
5375
tiles_ids.sort();
5376
}
5377
tiles[new_atlas_coords].size_in_atlas = new_size;
5378
5379
_create_coords_mapping_cache(new_atlas_coords);
5380
_queue_update_padded_texture();
5381
5382
_try_emit_changed();
5383
}
5384
5385
int TileSetAtlasSource::create_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_id_override) {
5386
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
5387
ERR_FAIL_COND_V_MSG(p_alternative_id_override >= 0 && tiles[p_atlas_coords].alternatives.has(p_alternative_id_override), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("Cannot create alternative tile. Another alternative exists with id %d.", p_alternative_id_override));
5388
5389
int new_alternative_id = p_alternative_id_override >= 0 ? p_alternative_id_override : tiles[p_atlas_coords].next_alternative_id;
5390
5391
tiles[p_atlas_coords].alternatives[new_alternative_id] = memnew(TileData);
5392
tiles[p_atlas_coords].alternatives[new_alternative_id]->set_tile_set(tile_set);
5393
tiles[p_atlas_coords].alternatives[new_alternative_id]->set_allow_transform(true);
5394
tiles[p_atlas_coords].alternatives[new_alternative_id]->connect(CoreStringName(changed), callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed));
5395
tiles[p_atlas_coords].alternatives[new_alternative_id]->notify_property_list_changed();
5396
tiles[p_atlas_coords].alternatives_ids.push_back(new_alternative_id);
5397
tiles[p_atlas_coords].alternatives_ids.sort();
5398
_compute_next_alternative_id(p_atlas_coords);
5399
5400
_try_emit_changed();
5401
5402
return new_alternative_id;
5403
}
5404
5405
void TileSetAtlasSource::remove_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) {
5406
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
5407
ERR_FAIL_COND_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
5408
p_alternative_tile = alternative_no_transform(p_alternative_tile);
5409
ERR_FAIL_COND_MSG(p_alternative_tile == 0, "Cannot remove the alternative with id 0, the base tile alternative cannot be removed.");
5410
5411
memdelete(tiles[p_atlas_coords].alternatives[p_alternative_tile]);
5412
tiles[p_atlas_coords].alternatives.erase(p_alternative_tile);
5413
tiles[p_atlas_coords].alternatives_ids.erase(p_alternative_tile);
5414
tiles[p_atlas_coords].alternatives_ids.sort();
5415
5416
_try_emit_changed();
5417
}
5418
5419
void TileSetAtlasSource::set_alternative_tile_id(const Vector2i p_atlas_coords, int p_alternative_tile, int p_new_id) {
5420
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
5421
ERR_FAIL_COND_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
5422
p_alternative_tile = alternative_no_transform(p_alternative_tile);
5423
ERR_FAIL_COND_MSG(p_alternative_tile == 0, "Cannot change the alternative with id 0, the base tile alternative cannot be modified.");
5424
5425
ERR_FAIL_COND_MSG(tiles[p_atlas_coords].alternatives.has(p_new_id), vformat("TileSetAtlasSource has already an alternative with id %d at %s.", p_new_id, String(p_atlas_coords)));
5426
5427
tiles[p_atlas_coords].alternatives[p_new_id] = tiles[p_atlas_coords].alternatives[p_alternative_tile];
5428
tiles[p_atlas_coords].alternatives_ids.push_back(p_new_id);
5429
5430
tiles[p_atlas_coords].alternatives.erase(p_alternative_tile);
5431
tiles[p_atlas_coords].alternatives_ids.erase(p_alternative_tile);
5432
tiles[p_atlas_coords].alternatives_ids.sort();
5433
5434
_try_emit_changed();
5435
}
5436
5437
bool TileSetAtlasSource::has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const {
5438
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), false, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
5439
return tiles[p_atlas_coords].alternatives.has(alternative_no_transform(p_alternative_tile));
5440
}
5441
5442
int TileSetAtlasSource::get_next_alternative_tile_id(const Vector2i p_atlas_coords) const {
5443
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
5444
return tiles[p_atlas_coords].next_alternative_id;
5445
}
5446
5447
int TileSetAtlasSource::get_alternative_tiles_count(const Vector2i p_atlas_coords) const {
5448
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), -1, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
5449
return tiles[p_atlas_coords].alternatives_ids.size();
5450
}
5451
5452
int TileSetAtlasSource::get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const {
5453
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
5454
p_index = alternative_no_transform(p_index);
5455
ERR_FAIL_INDEX_V(p_index, tiles[p_atlas_coords].alternatives_ids.size(), TileSetSource::INVALID_TILE_ALTERNATIVE);
5456
5457
return tiles[p_atlas_coords].alternatives_ids[p_index];
5458
}
5459
5460
TileData *TileSetAtlasSource::get_tile_data(const Vector2i p_atlas_coords, int p_alternative_tile) const {
5461
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), nullptr, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
5462
p_alternative_tile = alternative_no_transform(p_alternative_tile);
5463
ERR_FAIL_COND_V_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), nullptr, vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
5464
5465
return tiles[p_atlas_coords].alternatives[p_alternative_tile];
5466
}
5467
5468
void TileSetAtlasSource::_notification(int p_notification) {
5469
if (p_notification == NOTIFICATION_POSTINITIALIZE) {
5470
initializing = false;
5471
}
5472
}
5473
5474
void TileSetAtlasSource::_bind_methods() {
5475
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &TileSetAtlasSource::set_texture);
5476
ClassDB::bind_method(D_METHOD("get_texture"), &TileSetAtlasSource::get_texture);
5477
ClassDB::bind_method(D_METHOD("set_margins", "margins"), &TileSetAtlasSource::set_margins);
5478
ClassDB::bind_method(D_METHOD("get_margins"), &TileSetAtlasSource::get_margins);
5479
ClassDB::bind_method(D_METHOD("set_separation", "separation"), &TileSetAtlasSource::set_separation);
5480
ClassDB::bind_method(D_METHOD("get_separation"), &TileSetAtlasSource::get_separation);
5481
ClassDB::bind_method(D_METHOD("set_texture_region_size", "texture_region_size"), &TileSetAtlasSource::set_texture_region_size);
5482
ClassDB::bind_method(D_METHOD("get_texture_region_size"), &TileSetAtlasSource::get_texture_region_size);
5483
ClassDB::bind_method(D_METHOD("set_use_texture_padding", "use_texture_padding"), &TileSetAtlasSource::set_use_texture_padding);
5484
ClassDB::bind_method(D_METHOD("get_use_texture_padding"), &TileSetAtlasSource::get_use_texture_padding);
5485
5486
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NO_EDITOR), "set_texture", "get_texture");
5487
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NO_EDITOR), "set_margins", "get_margins");
5488
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NO_EDITOR), "set_separation", "get_separation");
5489
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NO_EDITOR), "set_texture_region_size", "get_texture_region_size");
5490
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_texture_padding", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_texture_padding", "get_use_texture_padding");
5491
5492
// Base tiles
5493
ClassDB::bind_method(D_METHOD("create_tile", "atlas_coords", "size"), &TileSetAtlasSource::create_tile, DEFVAL(Vector2i(1, 1)));
5494
ClassDB::bind_method(D_METHOD("remove_tile", "atlas_coords"), &TileSetAtlasSource::remove_tile); // Remove a tile. If p_tile_key.alternative_tile if different from 0, remove the alternative
5495
ClassDB::bind_method(D_METHOD("move_tile_in_atlas", "atlas_coords", "new_atlas_coords", "new_size"), &TileSetAtlasSource::move_tile_in_atlas, DEFVAL(INVALID_ATLAS_COORDS), DEFVAL(Vector2i(-1, -1)));
5496
ClassDB::bind_method(D_METHOD("get_tile_size_in_atlas", "atlas_coords"), &TileSetAtlasSource::get_tile_size_in_atlas);
5497
5498
ClassDB::bind_method(D_METHOD("has_room_for_tile", "atlas_coords", "size", "animation_columns", "animation_separation", "frames_count", "ignored_tile"), &TileSetAtlasSource::has_room_for_tile, DEFVAL(INVALID_ATLAS_COORDS));
5499
ClassDB::bind_method(D_METHOD("get_tiles_to_be_removed_on_change", "texture", "margins", "separation", "texture_region_size"), &TileSetAtlasSource::get_tiles_to_be_removed_on_change);
5500
ClassDB::bind_method(D_METHOD("get_tile_at_coords", "atlas_coords"), &TileSetAtlasSource::get_tile_at_coords);
5501
5502
ClassDB::bind_method(D_METHOD("has_tiles_outside_texture"), &TileSetAtlasSource::has_tiles_outside_texture);
5503
ClassDB::bind_method(D_METHOD("clear_tiles_outside_texture"), &TileSetAtlasSource::clear_tiles_outside_texture);
5504
5505
ClassDB::bind_method(D_METHOD("set_tile_animation_columns", "atlas_coords", "frame_columns"), &TileSetAtlasSource::set_tile_animation_columns);
5506
ClassDB::bind_method(D_METHOD("get_tile_animation_columns", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_columns);
5507
ClassDB::bind_method(D_METHOD("set_tile_animation_separation", "atlas_coords", "separation"), &TileSetAtlasSource::set_tile_animation_separation);
5508
ClassDB::bind_method(D_METHOD("get_tile_animation_separation", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_separation);
5509
ClassDB::bind_method(D_METHOD("set_tile_animation_speed", "atlas_coords", "speed"), &TileSetAtlasSource::set_tile_animation_speed);
5510
ClassDB::bind_method(D_METHOD("get_tile_animation_speed", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_speed);
5511
ClassDB::bind_method(D_METHOD("set_tile_animation_mode", "atlas_coords", "mode"), &TileSetAtlasSource::set_tile_animation_mode);
5512
ClassDB::bind_method(D_METHOD("get_tile_animation_mode", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_mode);
5513
ClassDB::bind_method(D_METHOD("set_tile_animation_frames_count", "atlas_coords", "frames_count"), &TileSetAtlasSource::set_tile_animation_frames_count);
5514
ClassDB::bind_method(D_METHOD("get_tile_animation_frames_count", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_frames_count);
5515
ClassDB::bind_method(D_METHOD("set_tile_animation_frame_duration", "atlas_coords", "frame_index", "duration"), &TileSetAtlasSource::set_tile_animation_frame_duration);
5516
ClassDB::bind_method(D_METHOD("get_tile_animation_frame_duration", "atlas_coords", "frame_index"), &TileSetAtlasSource::get_tile_animation_frame_duration);
5517
ClassDB::bind_method(D_METHOD("get_tile_animation_total_duration", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_total_duration);
5518
5519
// Alternative tiles
5520
ClassDB::bind_method(D_METHOD("create_alternative_tile", "atlas_coords", "alternative_id_override"), &TileSetAtlasSource::create_alternative_tile, DEFVAL(INVALID_TILE_ALTERNATIVE));
5521
ClassDB::bind_method(D_METHOD("remove_alternative_tile", "atlas_coords", "alternative_tile"), &TileSetAtlasSource::remove_alternative_tile);
5522
ClassDB::bind_method(D_METHOD("set_alternative_tile_id", "atlas_coords", "alternative_tile", "new_id"), &TileSetAtlasSource::set_alternative_tile_id);
5523
ClassDB::bind_method(D_METHOD("get_next_alternative_tile_id", "atlas_coords"), &TileSetAtlasSource::get_next_alternative_tile_id);
5524
5525
ClassDB::bind_method(D_METHOD("get_tile_data", "atlas_coords", "alternative_tile"), &TileSetAtlasSource::get_tile_data);
5526
5527
// Helpers.
5528
ClassDB::bind_method(D_METHOD("get_atlas_grid_size"), &TileSetAtlasSource::get_atlas_grid_size);
5529
ClassDB::bind_method(D_METHOD("get_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_tile_texture_region, DEFVAL(0));
5530
5531
// Getters for texture and tile region (padded or not)
5532
ClassDB::bind_method(D_METHOD("get_runtime_texture"), &TileSetAtlasSource::get_runtime_texture);
5533
ClassDB::bind_method(D_METHOD("get_runtime_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_runtime_tile_texture_region);
5534
5535
BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_DEFAULT)
5536
BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_RANDOM_START_TIMES)
5537
BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_MAX)
5538
5539
BIND_CONSTANT(TRANSFORM_FLIP_H)
5540
BIND_CONSTANT(TRANSFORM_FLIP_V)
5541
BIND_CONSTANT(TRANSFORM_TRANSPOSE)
5542
}
5543
5544
TileSetAtlasSource::~TileSetAtlasSource() {
5545
// Free everything needed.
5546
for (KeyValue<Vector2i, TileAlternativesData> &E_alternatives : tiles) {
5547
for (KeyValue<int, TileData *> &E_tile_data : E_alternatives.value.alternatives) {
5548
memdelete(E_tile_data.value);
5549
}
5550
}
5551
}
5552
5553
TileData *TileSetAtlasSource::_get_atlas_tile_data(Vector2i p_atlas_coords, int p_alternative_tile) {
5554
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), nullptr, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
5555
p_alternative_tile = alternative_no_transform(p_alternative_tile);
5556
ERR_FAIL_COND_V_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), nullptr, vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
5557
5558
return tiles[p_atlas_coords].alternatives[p_alternative_tile];
5559
}
5560
5561
const TileData *TileSetAtlasSource::_get_atlas_tile_data(Vector2i p_atlas_coords, int p_alternative_tile) const {
5562
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), nullptr, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
5563
ERR_FAIL_COND_V_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), nullptr, vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
5564
5565
return tiles[p_atlas_coords].alternatives[p_alternative_tile];
5566
}
5567
5568
void TileSetAtlasSource::_compute_next_alternative_id(const Vector2i p_atlas_coords) {
5569
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
5570
5571
while (tiles[p_atlas_coords].alternatives.has(tiles[p_atlas_coords].next_alternative_id)) {
5572
tiles[p_atlas_coords].next_alternative_id = (tiles[p_atlas_coords].next_alternative_id % 1073741823) + 1; // 2 ** 30
5573
};
5574
}
5575
5576
void TileSetAtlasSource::_clear_coords_mapping_cache(Vector2i p_atlas_coords) {
5577
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5578
TileAlternativesData &tad = tiles[p_atlas_coords];
5579
for (int frame = 0; frame < (int)tad.animation_frames_durations.size(); frame++) {
5580
Vector2i frame_coords = p_atlas_coords + (tad.size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(frame % tad.animation_columns, frame / tad.animation_columns) : Vector2i(frame, 0));
5581
for (int x = 0; x < tad.size_in_atlas.x; x++) {
5582
for (int y = 0; y < tad.size_in_atlas.y; y++) {
5583
Vector2i coords = frame_coords + Vector2i(x, y);
5584
if (!_coords_mapping_cache.has(coords)) {
5585
WARN_PRINT(vformat("TileSetAtlasSource has no cached tile at position %s, the position cache might be corrupted.", coords));
5586
} else {
5587
if (_coords_mapping_cache[coords] != p_atlas_coords) {
5588
WARN_PRINT(vformat("The position cache at position %s is pointing to a wrong tile, the position cache might be corrupted.", coords));
5589
}
5590
_coords_mapping_cache.erase(coords);
5591
}
5592
}
5593
}
5594
}
5595
}
5596
5597
void TileSetAtlasSource::_create_coords_mapping_cache(Vector2i p_atlas_coords) {
5598
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
5599
5600
TileAlternativesData &tad = tiles[p_atlas_coords];
5601
for (int frame = 0; frame < (int)tad.animation_frames_durations.size(); frame++) {
5602
Vector2i frame_coords = p_atlas_coords + (tad.size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(frame % tad.animation_columns, frame / tad.animation_columns) : Vector2i(frame, 0));
5603
for (int x = 0; x < tad.size_in_atlas.x; x++) {
5604
for (int y = 0; y < tad.size_in_atlas.y; y++) {
5605
Vector2i coords = frame_coords + Vector2i(x, y);
5606
if (_coords_mapping_cache.has(coords)) {
5607
WARN_PRINT(vformat("The cache already has a tile for position %s, the position cache might be corrupted.", coords));
5608
}
5609
_coords_mapping_cache[coords] = p_atlas_coords;
5610
}
5611
}
5612
}
5613
}
5614
5615
void TileSetAtlasSource::_queue_update_padded_texture() {
5616
if (padded_texture_needs_update) {
5617
return;
5618
}
5619
padded_texture_needs_update = true;
5620
callable_mp(this, &TileSetAtlasSource::_update_padded_texture).call_deferred();
5621
}
5622
5623
Ref<ImageTexture> TileSetAtlasSource::_create_padded_image_texture(const Ref<Texture2D> &p_source) {
5624
ERR_FAIL_COND_V(p_source.is_null(), Ref<ImageTexture>());
5625
5626
Ref<Image> src_image = p_source->get_image();
5627
if (src_image.is_null()) {
5628
Ref<ImageTexture> ret;
5629
ret.instantiate();
5630
return ret;
5631
}
5632
if (src_image->is_compressed()) {
5633
src_image = src_image->duplicate();
5634
Error err = src_image->decompress();
5635
ERR_FAIL_COND_V_MSG(err != OK, Ref<ImageTexture>(), "Unable to decompress image.");
5636
}
5637
5638
Size2 size = get_atlas_grid_size() * (texture_region_size + Vector2i(2, 2));
5639
Ref<Image> image = Image::create_empty(size.x, size.y, false, src_image->get_format());
5640
5641
for (KeyValue<Vector2i, TileAlternativesData> kv : tiles) {
5642
for (int frame = 0; frame < (int)kv.value.animation_frames_durations.size(); frame++) {
5643
// Compute the source rects.
5644
Rect2i src_rect = get_tile_texture_region(kv.key, frame);
5645
5646
Rect2i top_src_rect = Rect2i(src_rect.position, Vector2i(src_rect.size.x, 1));
5647
Rect2i bottom_src_rect = Rect2i(src_rect.position + Vector2i(0, src_rect.size.y - 1), Vector2i(src_rect.size.x, 1));
5648
Rect2i left_src_rect = Rect2i(src_rect.position, Vector2i(1, src_rect.size.y));
5649
Rect2i right_src_rect = Rect2i(src_rect.position + Vector2i(src_rect.size.x - 1, 0), Vector2i(1, src_rect.size.y));
5650
5651
// Copy the tile and the paddings.
5652
Vector2i frame_coords = kv.key + (kv.value.size_in_atlas + kv.value.animation_separation) * ((kv.value.animation_columns > 0) ? Vector2i(frame % kv.value.animation_columns, frame / kv.value.animation_columns) : Vector2i(frame, 0));
5653
Vector2i base_pos = frame_coords * (texture_region_size + Vector2i(2, 2)) + Vector2i(1, 1);
5654
5655
image->blit_rect(*src_image, src_rect, base_pos);
5656
5657
// Sides
5658
image->blit_rect(*src_image, top_src_rect, base_pos + Vector2i(0, -1));
5659
image->blit_rect(*src_image, bottom_src_rect, base_pos + Vector2i(0, src_rect.size.y));
5660
image->blit_rect(*src_image, left_src_rect, base_pos + Vector2i(-1, 0));
5661
image->blit_rect(*src_image, right_src_rect, base_pos + Vector2i(src_rect.size.x, 0));
5662
5663
// Corners
5664
image->blit_rect(*src_image, Rect2i(src_rect.position, Vector2i(1, 1)), base_pos + Vector2i(-1, -1));
5665
image->blit_rect(*src_image, Rect2i(src_rect.position + Vector2i(src_rect.size.x - 1, 0), Vector2i(1, 1)), base_pos + Vector2i(src_rect.size.x, -1));
5666
image->blit_rect(*src_image, Rect2i(src_rect.position + Vector2i(0, src_rect.size.y - 1), Vector2i(1, 1)), base_pos + Vector2i(-1, src_rect.size.y));
5667
image->blit_rect(*src_image, Rect2i(src_rect.position + Vector2i(src_rect.size.x - 1, src_rect.size.y - 1), Vector2i(1, 1)), base_pos + Vector2i(src_rect.size.x, src_rect.size.y));
5668
}
5669
}
5670
5671
return ImageTexture::create_from_image(image);
5672
}
5673
5674
void TileSetAtlasSource::_update_padded_texture() {
5675
if (!padded_texture_needs_update) {
5676
return;
5677
}
5678
padded_texture_needs_update = false;
5679
5680
if (padded_texture.is_valid()) {
5681
padded_texture->disconnect_changed(callable_mp(this, &TileSetAtlasSource::_queue_update_padded_texture));
5682
}
5683
5684
padded_texture = Ref<CanvasTexture>();
5685
5686
if (texture.is_null()) {
5687
return;
5688
}
5689
5690
if (!use_texture_padding) {
5691
return;
5692
}
5693
5694
padded_texture.instantiate();
5695
5696
Ref<CanvasTexture> src_canvas_texture = texture;
5697
if (src_canvas_texture.is_valid()) {
5698
// Use all textures.
5699
// Diffuse
5700
Ref<Texture2D> src = src_canvas_texture->get_diffuse_texture();
5701
Ref<ImageTexture> image_texture;
5702
if (src.is_valid()) {
5703
padded_texture->set_diffuse_texture(_create_padded_image_texture(src));
5704
}
5705
5706
// Normal
5707
src = src_canvas_texture->get_normal_texture();
5708
if (src.is_valid()) {
5709
padded_texture->set_normal_texture(_create_padded_image_texture(src));
5710
}
5711
5712
// Specular
5713
src = src_canvas_texture->get_specular_texture();
5714
if (src.is_valid()) {
5715
padded_texture->set_specular_texture(_create_padded_image_texture(src));
5716
}
5717
5718
// Other properties.
5719
padded_texture->set_specular_color(src_canvas_texture->get_specular_color());
5720
padded_texture->set_specular_shininess(src_canvas_texture->get_specular_shininess());
5721
padded_texture->set_texture_filter(src_canvas_texture->get_texture_filter());
5722
padded_texture->set_texture_repeat(src_canvas_texture->get_texture_repeat());
5723
} else {
5724
// Use only diffuse.
5725
Ref<ImageTexture> image_texture = _create_padded_image_texture(texture);
5726
padded_texture->set_diffuse_texture(image_texture);
5727
}
5728
padded_texture->connect_changed(callable_mp(this, &TileSetAtlasSource::_queue_update_padded_texture));
5729
emit_changed();
5730
}
5731
5732
void TileSetAtlasSource::_try_emit_changed() {
5733
if (!initializing) {
5734
emit_changed();
5735
}
5736
}
5737
5738
/////////////////////////////// TileSetScenesCollectionSource //////////////////////////////////////
5739
5740
void TileSetScenesCollectionSource::_compute_next_alternative_id() {
5741
while (scenes.has(next_scene_id)) {
5742
next_scene_id = (next_scene_id % 1073741823) + 1; // 2 ** 30
5743
};
5744
}
5745
5746
void TileSetScenesCollectionSource::_try_emit_changed() {
5747
if (!initializing) {
5748
emit_changed();
5749
}
5750
}
5751
5752
int TileSetScenesCollectionSource::get_tiles_count() const {
5753
return 1;
5754
}
5755
5756
Vector2i TileSetScenesCollectionSource::get_tile_id(int p_tile_index) const {
5757
ERR_FAIL_COND_V(p_tile_index != 0, TileSetSource::INVALID_ATLAS_COORDS);
5758
return Vector2i();
5759
}
5760
5761
bool TileSetScenesCollectionSource::has_tile(Vector2i p_atlas_coords) const {
5762
return p_atlas_coords == Vector2i();
5763
}
5764
5765
int TileSetScenesCollectionSource::get_alternative_tiles_count(const Vector2i p_atlas_coords) const {
5766
return scenes_ids.size();
5767
}
5768
5769
int TileSetScenesCollectionSource::get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const {
5770
ERR_FAIL_COND_V(p_atlas_coords != Vector2i(), TileSetSource::INVALID_TILE_ALTERNATIVE);
5771
ERR_FAIL_INDEX_V(p_index, scenes_ids.size(), TileSetSource::INVALID_TILE_ALTERNATIVE);
5772
5773
return scenes_ids[p_index];
5774
}
5775
5776
bool TileSetScenesCollectionSource::has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const {
5777
ERR_FAIL_COND_V(p_atlas_coords != Vector2i(), false);
5778
return scenes.has(p_alternative_tile);
5779
}
5780
5781
int TileSetScenesCollectionSource::create_scene_tile(Ref<PackedScene> p_packed_scene, int p_id_override) {
5782
ERR_FAIL_COND_V_MSG(p_id_override >= 0 && scenes.has(p_id_override), INVALID_TILE_ALTERNATIVE, vformat("Cannot create scene tile. Another scene tile exists with id %d.", p_id_override));
5783
5784
int new_scene_id = p_id_override >= 0 ? p_id_override : next_scene_id;
5785
5786
scenes[new_scene_id] = SceneData();
5787
scenes_ids.push_back(new_scene_id);
5788
scenes_ids.sort();
5789
set_scene_tile_scene(new_scene_id, p_packed_scene);
5790
_compute_next_alternative_id();
5791
5792
_try_emit_changed();
5793
5794
return new_scene_id;
5795
}
5796
5797
void TileSetScenesCollectionSource::set_scene_tile_id(int p_id, int p_new_id) {
5798
ERR_FAIL_COND(p_new_id < 0);
5799
ERR_FAIL_COND(!has_scene_tile_id(p_id));
5800
ERR_FAIL_COND(has_scene_tile_id(p_new_id));
5801
5802
scenes[p_new_id] = SceneData();
5803
scenes[p_new_id] = scenes[p_id];
5804
scenes_ids.push_back(p_new_id);
5805
scenes_ids.sort();
5806
5807
_compute_next_alternative_id();
5808
5809
scenes.erase(p_id);
5810
scenes_ids.erase(p_id);
5811
5812
_try_emit_changed();
5813
}
5814
5815
void TileSetScenesCollectionSource::set_scene_tile_scene(int p_id, Ref<PackedScene> p_packed_scene) {
5816
ERR_FAIL_COND(!scenes.has(p_id));
5817
if (p_packed_scene.is_valid()) {
5818
// Check if it extends CanvasItem.
5819
Ref<SceneState> scene_state = p_packed_scene->get_state();
5820
String type;
5821
while (scene_state.is_valid() && type.is_empty()) {
5822
// Make sure we have a root node. Supposed to be at 0 index because find_node_by_path() does not seem to work.
5823
ERR_FAIL_COND(scene_state->get_node_count() < 1);
5824
5825
type = scene_state->get_node_type(0);
5826
scene_state = scene_state->get_base_scene_state();
5827
}
5828
ERR_FAIL_COND_EDMSG(type.is_empty(), vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Could not get the type of the root node.", p_packed_scene->get_path()));
5829
bool extends_correct_class = ClassDB::is_parent_class(type, "CanvasItem");
5830
ERR_FAIL_COND_EDMSG(!extends_correct_class, vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Root node should extend CanvasItem. Found %s instead.", p_packed_scene->get_path(), type));
5831
5832
scenes[p_id].scene = p_packed_scene;
5833
} else {
5834
scenes[p_id].scene = Ref<PackedScene>();
5835
}
5836
_try_emit_changed();
5837
}
5838
5839
Ref<PackedScene> TileSetScenesCollectionSource::get_scene_tile_scene(int p_id) const {
5840
ERR_FAIL_COND_V(!scenes.has(p_id), Ref<PackedScene>());
5841
return scenes[p_id].scene;
5842
}
5843
5844
void TileSetScenesCollectionSource::set_scene_tile_display_placeholder(int p_id, bool p_display_placeholder) {
5845
ERR_FAIL_COND(!scenes.has(p_id));
5846
5847
scenes[p_id].display_placeholder = p_display_placeholder;
5848
5849
_try_emit_changed();
5850
}
5851
5852
bool TileSetScenesCollectionSource::get_scene_tile_display_placeholder(int p_id) const {
5853
ERR_FAIL_COND_V(!scenes.has(p_id), false);
5854
return scenes[p_id].display_placeholder;
5855
}
5856
5857
void TileSetScenesCollectionSource::remove_scene_tile(int p_id) {
5858
ERR_FAIL_COND(!scenes.has(p_id));
5859
5860
scenes.erase(p_id);
5861
scenes_ids.erase(p_id);
5862
_try_emit_changed();
5863
}
5864
5865
int TileSetScenesCollectionSource::get_next_scene_tile_id() const {
5866
return next_scene_id;
5867
}
5868
5869
bool TileSetScenesCollectionSource::_set(const StringName &p_name, const Variant &p_value) {
5870
Vector<String> components = String(p_name).split("/", true, 2);
5871
5872
if (components.size() >= 2 && components[0] == "scenes" && components[1].is_valid_int()) {
5873
int scene_id = components[1].to_int();
5874
if (components.size() >= 3 && components[2] == "scene") {
5875
if (has_scene_tile_id(scene_id)) {
5876
set_scene_tile_scene(scene_id, p_value);
5877
} else {
5878
create_scene_tile(p_value, scene_id);
5879
}
5880
return true;
5881
} else if (components.size() >= 3 && components[2] == "display_placeholder") {
5882
if (!has_scene_tile_id(scene_id)) {
5883
create_scene_tile(p_value, scene_id);
5884
}
5885
5886
return true;
5887
}
5888
}
5889
5890
return false;
5891
}
5892
5893
bool TileSetScenesCollectionSource::_get(const StringName &p_name, Variant &r_ret) const {
5894
Vector<String> components = String(p_name).split("/", true, 2);
5895
5896
if (components.size() >= 2 && components[0] == "scenes" && components[1].is_valid_int() && scenes.has(components[1].to_int())) {
5897
if (components.size() >= 3 && components[2] == "scene") {
5898
r_ret = scenes[components[1].to_int()].scene;
5899
return true;
5900
} else if (components.size() >= 3 && components[2] == "display_placeholder") {
5901
r_ret = scenes[components[1].to_int()].scene;
5902
return true;
5903
}
5904
}
5905
5906
return false;
5907
}
5908
5909
void TileSetScenesCollectionSource::_get_property_list(List<PropertyInfo> *p_list) const {
5910
for (int i = 0; i < scenes_ids.size(); i++) {
5911
p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("%s/%d/%s", PNAME("scenes"), scenes_ids[i], PNAME("scene")), PROPERTY_HINT_RESOURCE_TYPE, "TileSetScenesCollectionSource"));
5912
5913
PropertyInfo property_info = PropertyInfo(Variant::BOOL, vformat("%s/%d/%s", PNAME("scenes"), scenes_ids[i], PNAME("display_placeholder")));
5914
if (scenes[scenes_ids[i]].display_placeholder == false) {
5915
property_info.usage ^= PROPERTY_USAGE_STORAGE;
5916
}
5917
p_list->push_back(property_info);
5918
}
5919
}
5920
5921
void TileSetScenesCollectionSource::_notification(int p_notification) {
5922
if (p_notification == NOTIFICATION_POSTINITIALIZE) {
5923
initializing = false;
5924
}
5925
}
5926
5927
void TileSetScenesCollectionSource::_bind_methods() {
5928
ClassDB::bind_method(D_METHOD("get_scene_tiles_count"), &TileSetScenesCollectionSource::get_scene_tiles_count);
5929
ClassDB::bind_method(D_METHOD("get_scene_tile_id", "index"), &TileSetScenesCollectionSource::get_scene_tile_id);
5930
ClassDB::bind_method(D_METHOD("has_scene_tile_id", "id"), &TileSetScenesCollectionSource::has_scene_tile_id);
5931
ClassDB::bind_method(D_METHOD("create_scene_tile", "packed_scene", "id_override"), &TileSetScenesCollectionSource::create_scene_tile, DEFVAL(INVALID_TILE_ALTERNATIVE));
5932
ClassDB::bind_method(D_METHOD("set_scene_tile_id", "id", "new_id"), &TileSetScenesCollectionSource::set_scene_tile_id);
5933
ClassDB::bind_method(D_METHOD("set_scene_tile_scene", "id", "packed_scene"), &TileSetScenesCollectionSource::set_scene_tile_scene);
5934
ClassDB::bind_method(D_METHOD("get_scene_tile_scene", "id"), &TileSetScenesCollectionSource::get_scene_tile_scene);
5935
ClassDB::bind_method(D_METHOD("set_scene_tile_display_placeholder", "id", "display_placeholder"), &TileSetScenesCollectionSource::set_scene_tile_display_placeholder);
5936
ClassDB::bind_method(D_METHOD("get_scene_tile_display_placeholder", "id"), &TileSetScenesCollectionSource::get_scene_tile_display_placeholder);
5937
ClassDB::bind_method(D_METHOD("remove_scene_tile", "id"), &TileSetScenesCollectionSource::remove_scene_tile);
5938
ClassDB::bind_method(D_METHOD("get_next_scene_tile_id"), &TileSetScenesCollectionSource::get_next_scene_tile_id);
5939
}
5940
5941
/////////////////////////////// TileData //////////////////////////////////////
5942
5943
void TileData::set_tile_set(const TileSet *p_tile_set) {
5944
tile_set = p_tile_set;
5945
notify_tile_data_properties_should_change();
5946
}
5947
5948
void TileData::notify_tile_data_properties_should_change() {
5949
if (!tile_set) {
5950
return;
5951
}
5952
5953
occluders.resize(tile_set->get_occlusion_layers_count());
5954
#ifndef PHYSICS_2D_DISABLED
5955
physics.resize(tile_set->get_physics_layers_count());
5956
#endif // PHYSICS_2D_DISABLED
5957
for (int bit_index = 0; bit_index < 16; bit_index++) {
5958
if (terrain_set < 0 || terrain_peering_bits[bit_index] >= tile_set->get_terrains_count(terrain_set)) {
5959
terrain_peering_bits[bit_index] = -1;
5960
}
5961
}
5962
#ifndef NAVIGATION_2D_DISABLED
5963
navigation.resize(tile_set->get_navigation_layers_count());
5964
#endif // NAVIGATION_2D_DISABLED
5965
5966
// Convert custom data to the new type.
5967
custom_data.resize(tile_set->get_custom_data_layers_count());
5968
for (int i = 0; i < custom_data.size(); i++) {
5969
if (custom_data[i].get_type() != tile_set->get_custom_data_layer_type(i)) {
5970
Variant new_val;
5971
Callable::CallError error;
5972
if (Variant::can_convert(custom_data[i].get_type(), tile_set->get_custom_data_layer_type(i))) {
5973
const Variant *args[] = { &custom_data[i] };
5974
Variant::construct(tile_set->get_custom_data_layer_type(i), new_val, args, 1, error);
5975
} else {
5976
Variant::construct(tile_set->get_custom_data_layer_type(i), new_val, nullptr, 0, error);
5977
}
5978
custom_data.write[i] = new_val;
5979
}
5980
}
5981
5982
notify_property_list_changed();
5983
emit_signal(CoreStringName(changed));
5984
}
5985
5986
void TileData::add_occlusion_layer(int p_to_pos) {
5987
if (p_to_pos < 0) {
5988
p_to_pos = occluders.size();
5989
}
5990
ERR_FAIL_INDEX(p_to_pos, occluders.size() + 1);
5991
occluders.insert(p_to_pos, OcclusionLayerTileData());
5992
}
5993
5994
void TileData::move_occlusion_layer(int p_from_index, int p_to_pos) {
5995
ERR_FAIL_INDEX(p_from_index, occluders.size());
5996
ERR_FAIL_INDEX(p_to_pos, occluders.size() + 1);
5997
occluders.insert(p_to_pos, occluders[p_from_index]);
5998
occluders.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
5999
}
6000
6001
void TileData::remove_occlusion_layer(int p_index) {
6002
ERR_FAIL_INDEX(p_index, occluders.size());
6003
occluders.remove_at(p_index);
6004
}
6005
6006
#ifndef PHYSICS_2D_DISABLED
6007
void TileData::add_physics_layer(int p_to_pos) {
6008
if (p_to_pos < 0) {
6009
p_to_pos = physics.size();
6010
}
6011
ERR_FAIL_INDEX(p_to_pos, physics.size() + 1);
6012
physics.insert(p_to_pos, PhysicsLayerTileData());
6013
}
6014
6015
void TileData::move_physics_layer(int p_from_index, int p_to_pos) {
6016
ERR_FAIL_INDEX(p_from_index, physics.size());
6017
ERR_FAIL_INDEX(p_to_pos, physics.size() + 1);
6018
physics.insert(p_to_pos, physics[p_from_index]);
6019
physics.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
6020
}
6021
6022
void TileData::remove_physics_layer(int p_index) {
6023
ERR_FAIL_INDEX(p_index, physics.size());
6024
physics.remove_at(p_index);
6025
}
6026
#endif // PHYSICS_2D_DISABLED
6027
6028
void TileData::add_terrain_set(int p_to_pos) {
6029
if (p_to_pos >= 0 && p_to_pos <= terrain_set) {
6030
terrain_set += 1;
6031
}
6032
}
6033
6034
void TileData::move_terrain_set(int p_from_index, int p_to_pos) {
6035
if (p_from_index == terrain_set) {
6036
terrain_set = (p_from_index < p_to_pos) ? p_to_pos - 1 : p_to_pos;
6037
} else {
6038
if (p_from_index < terrain_set) {
6039
terrain_set -= 1;
6040
}
6041
if (p_to_pos <= terrain_set) {
6042
terrain_set += 1;
6043
}
6044
}
6045
}
6046
6047
void TileData::remove_terrain_set(int p_index) {
6048
if (p_index == terrain_set) {
6049
terrain_set = -1;
6050
for (int i = 0; i < 16; i++) {
6051
terrain_peering_bits[i] = -1;
6052
}
6053
} else if (terrain_set > p_index) {
6054
terrain_set -= 1;
6055
}
6056
}
6057
6058
void TileData::add_terrain(int p_terrain_set, int p_to_pos) {
6059
if (terrain_set == p_terrain_set) {
6060
for (int i = 0; i < 16; i++) {
6061
if (p_to_pos >= 0 && p_to_pos <= terrain_peering_bits[i]) {
6062
terrain_peering_bits[i] += 1;
6063
}
6064
}
6065
}
6066
}
6067
6068
void TileData::move_terrain(int p_terrain_set, int p_from_index, int p_to_pos) {
6069
if (terrain_set == p_terrain_set) {
6070
for (int i = 0; i < 16; i++) {
6071
if (p_from_index == terrain_peering_bits[i]) {
6072
terrain_peering_bits[i] = (p_from_index < p_to_pos) ? p_to_pos - 1 : p_to_pos;
6073
} else {
6074
if (p_from_index < terrain_peering_bits[i]) {
6075
terrain_peering_bits[i] -= 1;
6076
}
6077
if (p_to_pos <= terrain_peering_bits[i]) {
6078
terrain_peering_bits[i] += 1;
6079
}
6080
}
6081
}
6082
}
6083
}
6084
6085
void TileData::remove_terrain(int p_terrain_set, int p_index) {
6086
if (terrain_set == p_terrain_set) {
6087
if (terrain == p_index) {
6088
terrain = -1;
6089
} else if (terrain > p_index) {
6090
terrain -= 1;
6091
}
6092
6093
for (int i = 0; i < 16; i++) {
6094
if (terrain_peering_bits[i] == p_index) {
6095
terrain_peering_bits[i] = -1;
6096
} else if (terrain_peering_bits[i] > p_index) {
6097
terrain_peering_bits[i] -= 1;
6098
}
6099
}
6100
}
6101
}
6102
6103
#ifndef NAVIGATION_2D_DISABLED
6104
void TileData::add_navigation_layer(int p_to_pos) {
6105
if (p_to_pos < 0) {
6106
p_to_pos = navigation.size();
6107
}
6108
ERR_FAIL_INDEX(p_to_pos, navigation.size() + 1);
6109
navigation.insert(p_to_pos, NavigationLayerTileData());
6110
}
6111
6112
void TileData::move_navigation_layer(int p_from_index, int p_to_pos) {
6113
ERR_FAIL_INDEX(p_from_index, navigation.size());
6114
ERR_FAIL_INDEX(p_to_pos, navigation.size() + 1);
6115
navigation.insert(p_to_pos, navigation[p_from_index]);
6116
navigation.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
6117
}
6118
6119
void TileData::remove_navigation_layer(int p_index) {
6120
ERR_FAIL_INDEX(p_index, navigation.size());
6121
navigation.remove_at(p_index);
6122
}
6123
#endif // NAVIGATION_2D_DISABLED
6124
6125
void TileData::add_custom_data_layer(int p_to_pos) {
6126
if (p_to_pos < 0) {
6127
p_to_pos = custom_data.size();
6128
}
6129
ERR_FAIL_INDEX(p_to_pos, custom_data.size() + 1);
6130
custom_data.insert(p_to_pos, Variant());
6131
}
6132
6133
void TileData::move_custom_data_layer(int p_from_index, int p_to_pos) {
6134
ERR_FAIL_INDEX(p_from_index, custom_data.size());
6135
ERR_FAIL_INDEX(p_to_pos, custom_data.size() + 1);
6136
custom_data.insert(p_to_pos, custom_data[p_from_index]);
6137
custom_data.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
6138
}
6139
6140
void TileData::remove_custom_data_layer(int p_index) {
6141
ERR_FAIL_INDEX(p_index, custom_data.size());
6142
custom_data.remove_at(p_index);
6143
}
6144
6145
void TileData::set_allow_transform(bool p_allow_transform) {
6146
allow_transform = p_allow_transform;
6147
}
6148
6149
bool TileData::is_allowing_transform() const {
6150
return allow_transform;
6151
}
6152
6153
TileData *TileData::duplicate() {
6154
TileData *output = memnew(TileData);
6155
output->tile_set = tile_set;
6156
6157
output->allow_transform = allow_transform;
6158
6159
// Rendering
6160
output->flip_h = flip_h;
6161
output->flip_v = flip_v;
6162
output->transpose = transpose;
6163
output->texture_origin = texture_origin;
6164
output->material = material;
6165
output->modulate = modulate;
6166
output->z_index = z_index;
6167
output->y_sort_origin = y_sort_origin;
6168
output->occluders = occluders;
6169
#ifndef PHYSICS_2D_DISABLED
6170
// Physics
6171
output->physics = physics;
6172
#endif // PHYSICS_2D_DISABLED
6173
// Terrain
6174
output->terrain_set = -1;
6175
memcpy(output->terrain_peering_bits, terrain_peering_bits, 16 * sizeof(int));
6176
#ifndef NAVIGATION_2D_DISABLED
6177
// Navigation
6178
output->navigation = navigation;
6179
#endif // NAVIGATION_2D_DISABLED
6180
// Misc
6181
output->probability = probability;
6182
// Custom data
6183
output->custom_data = custom_data;
6184
6185
return output;
6186
}
6187
6188
// Rendering
6189
void TileData::set_flip_h(bool p_flip_h) {
6190
ERR_FAIL_COND_MSG(!allow_transform && p_flip_h, "Transform is only allowed for alternative tiles (with its alternative_id != 0)");
6191
flip_h = p_flip_h;
6192
emit_signal(CoreStringName(changed));
6193
}
6194
bool TileData::get_flip_h() const {
6195
return flip_h;
6196
}
6197
6198
void TileData::set_flip_v(bool p_flip_v) {
6199
ERR_FAIL_COND_MSG(!allow_transform && p_flip_v, "Transform is only allowed for alternative tiles (with its alternative_id != 0)");
6200
flip_v = p_flip_v;
6201
emit_signal(CoreStringName(changed));
6202
}
6203
6204
bool TileData::get_flip_v() const {
6205
return flip_v;
6206
}
6207
6208
void TileData::set_transpose(bool p_transpose) {
6209
ERR_FAIL_COND_MSG(!allow_transform && p_transpose, "Transform is only allowed for alternative tiles (with its alternative_id != 0)");
6210
transpose = p_transpose;
6211
emit_signal(CoreStringName(changed));
6212
}
6213
bool TileData::get_transpose() const {
6214
return transpose;
6215
}
6216
6217
void TileData::set_texture_origin(Vector2i p_texture_origin) {
6218
texture_origin = p_texture_origin;
6219
emit_signal(CoreStringName(changed));
6220
}
6221
6222
Vector2i TileData::get_texture_origin() const {
6223
return texture_origin;
6224
}
6225
6226
void TileData::set_material(Ref<Material> p_material) {
6227
material = p_material;
6228
emit_signal(CoreStringName(changed));
6229
}
6230
Ref<Material> TileData::get_material() const {
6231
return material;
6232
}
6233
6234
void TileData::set_modulate(Color p_modulate) {
6235
modulate = p_modulate;
6236
emit_signal(CoreStringName(changed));
6237
}
6238
Color TileData::get_modulate() const {
6239
return modulate;
6240
}
6241
6242
void TileData::set_z_index(int p_z_index) {
6243
z_index = p_z_index;
6244
emit_signal(CoreStringName(changed));
6245
}
6246
int TileData::get_z_index() const {
6247
return z_index;
6248
}
6249
6250
void TileData::set_y_sort_origin(int p_y_sort_origin) {
6251
y_sort_origin = p_y_sort_origin;
6252
emit_signal(CoreStringName(changed));
6253
}
6254
int TileData::get_y_sort_origin() const {
6255
return y_sort_origin;
6256
}
6257
6258
#ifndef DISABLE_DEPRECATED
6259
void TileData::set_occluder(int p_layer_id, Ref<OccluderPolygon2D> p_occluder_polygon) {
6260
ERR_FAIL_INDEX(p_layer_id, occluders.size());
6261
if (get_occluder_polygons_count(p_layer_id) == 0) {
6262
add_occluder_polygon(p_layer_id);
6263
}
6264
set_occluder_polygon(p_layer_id, 0, p_occluder_polygon);
6265
emit_signal(CoreStringName(changed));
6266
}
6267
6268
Ref<OccluderPolygon2D> TileData::get_occluder(int p_layer_id, bool p_flip_h, bool p_flip_v, bool p_transpose) const {
6269
ERR_FAIL_INDEX_V(p_layer_id, occluders.size(), Ref<OccluderPolygon2D>());
6270
if (get_occluder_polygons_count(p_layer_id) == 0) {
6271
return Ref<OccluderPolygon2D>();
6272
}
6273
return get_occluder_polygon(p_layer_id, 0, p_flip_h, p_flip_v, p_transpose);
6274
}
6275
#endif // DISABLE_DEPRECATED
6276
6277
void TileData::set_occluder_polygons_count(int p_layer_id, int p_polygons_count) {
6278
ERR_FAIL_INDEX(p_layer_id, occluders.size());
6279
ERR_FAIL_COND(p_polygons_count < 0);
6280
if (p_polygons_count == occluders.write[p_layer_id].polygons.size()) {
6281
return;
6282
}
6283
occluders.write[p_layer_id].polygons.resize(p_polygons_count);
6284
notify_property_list_changed();
6285
emit_signal(CoreStringName(changed));
6286
}
6287
6288
int TileData::get_occluder_polygons_count(int p_layer_id) const {
6289
ERR_FAIL_INDEX_V(p_layer_id, occluders.size(), 0);
6290
return occluders[p_layer_id].polygons.size();
6291
}
6292
6293
void TileData::add_occluder_polygon(int p_layer_id) {
6294
ERR_FAIL_INDEX(p_layer_id, occluders.size());
6295
occluders.write[p_layer_id].polygons.push_back(OcclusionLayerTileData::PolygonOccluderTileData());
6296
emit_signal(CoreStringName(changed));
6297
}
6298
6299
void TileData::remove_occluder_polygon(int p_layer_id, int p_polygon_index) {
6300
ERR_FAIL_INDEX(p_layer_id, occluders.size());
6301
ERR_FAIL_INDEX(p_polygon_index, occluders[p_layer_id].polygons.size());
6302
occluders.write[p_layer_id].polygons.remove_at(p_polygon_index);
6303
emit_signal(CoreStringName(changed));
6304
}
6305
6306
void TileData::set_occluder_polygon(int p_layer_id, int p_polygon_index, const Ref<OccluderPolygon2D> &p_occluder_polygon) {
6307
ERR_FAIL_INDEX(p_layer_id, occluders.size());
6308
ERR_FAIL_INDEX(p_polygon_index, occluders[p_layer_id].polygons.size());
6309
6310
OcclusionLayerTileData::PolygonOccluderTileData &polygon_occluder_tile_data = occluders.write[p_layer_id].polygons.write[p_polygon_index];
6311
polygon_occluder_tile_data.occluder_polygon = p_occluder_polygon;
6312
polygon_occluder_tile_data.transformed_polygon_occluders.clear();
6313
emit_signal(CoreStringName(changed));
6314
}
6315
6316
Ref<OccluderPolygon2D> TileData::get_occluder_polygon(int p_layer_id, int p_polygon_index, bool p_flip_h, bool p_flip_v, bool p_transpose) const {
6317
ERR_FAIL_INDEX_V(p_layer_id, occluders.size(), Ref<OccluderPolygon2D>());
6318
ERR_FAIL_INDEX_V(p_polygon_index, occluders[p_layer_id].polygons.size(), Ref<OccluderPolygon2D>());
6319
6320
const OcclusionLayerTileData &layer_tile_data = occluders[p_layer_id];
6321
const Ref<OccluderPolygon2D> &occluder_polygon = layer_tile_data.polygons[p_polygon_index].occluder_polygon;
6322
6323
int key = int(p_flip_h) | int(p_flip_v) << 1 | int(p_transpose) << 2;
6324
if (key == 0) {
6325
return occluder_polygon;
6326
}
6327
6328
if (occluder_polygon.is_null()) {
6329
return Ref<OccluderPolygon2D>();
6330
}
6331
6332
HashMap<int, Ref<OccluderPolygon2D>>::Iterator I = layer_tile_data.polygons[p_polygon_index].transformed_polygon_occluders.find(key);
6333
if (!I) {
6334
Ref<OccluderPolygon2D> transformed_polygon;
6335
transformed_polygon.instantiate();
6336
transformed_polygon->set_polygon(get_transformed_vertices(occluder_polygon->get_polygon(), p_flip_h, p_flip_v, p_transpose));
6337
layer_tile_data.polygons[p_polygon_index].transformed_polygon_occluders[key] = transformed_polygon;
6338
return transformed_polygon;
6339
} else {
6340
return I->value;
6341
}
6342
}
6343
6344
#ifndef PHYSICS_2D_DISABLED
6345
// Physics
6346
void TileData::set_constant_linear_velocity(int p_layer_id, const Vector2 &p_velocity) {
6347
ERR_FAIL_INDEX(p_layer_id, physics.size());
6348
physics.write[p_layer_id].linear_velocity = p_velocity;
6349
emit_signal(CoreStringName(changed));
6350
}
6351
6352
Vector2 TileData::get_constant_linear_velocity(int p_layer_id) const {
6353
ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Vector2());
6354
return physics[p_layer_id].linear_velocity;
6355
}
6356
6357
void TileData::set_constant_angular_velocity(int p_layer_id, real_t p_velocity) {
6358
ERR_FAIL_INDEX(p_layer_id, physics.size());
6359
physics.write[p_layer_id].angular_velocity = p_velocity;
6360
emit_signal(CoreStringName(changed));
6361
}
6362
6363
real_t TileData::get_constant_angular_velocity(int p_layer_id) const {
6364
ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0.0);
6365
return physics[p_layer_id].angular_velocity;
6366
}
6367
6368
void TileData::set_collision_polygons_count(int p_layer_id, int p_polygons_count) {
6369
ERR_FAIL_INDEX(p_layer_id, physics.size());
6370
ERR_FAIL_COND(p_polygons_count < 0);
6371
if (p_polygons_count == physics.write[p_layer_id].polygons.size()) {
6372
return;
6373
}
6374
physics.write[p_layer_id].polygons.resize(p_polygons_count);
6375
notify_property_list_changed();
6376
emit_signal(CoreStringName(changed));
6377
}
6378
6379
int TileData::get_collision_polygons_count(int p_layer_id) const {
6380
ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0);
6381
return physics[p_layer_id].polygons.size();
6382
}
6383
6384
void TileData::add_collision_polygon(int p_layer_id) {
6385
ERR_FAIL_INDEX(p_layer_id, physics.size());
6386
physics.write[p_layer_id].polygons.push_back(PhysicsLayerTileData::PolygonShapeTileData());
6387
emit_signal(CoreStringName(changed));
6388
}
6389
6390
void TileData::remove_collision_polygon(int p_layer_id, int p_polygon_index) {
6391
ERR_FAIL_INDEX(p_layer_id, physics.size());
6392
ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size());
6393
physics.write[p_layer_id].polygons.remove_at(p_polygon_index);
6394
emit_signal(CoreStringName(changed));
6395
}
6396
6397
void TileData::set_collision_polygon_points(int p_layer_id, int p_polygon_index, Vector<Vector2> p_polygon) {
6398
ERR_FAIL_INDEX(p_layer_id, physics.size());
6399
ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size());
6400
ERR_FAIL_COND_MSG(p_polygon.size() != 0 && p_polygon.size() < 3, "Invalid polygon. Needs either 0 or more than 3 points.");
6401
6402
TileData::PhysicsLayerTileData::PolygonShapeTileData &polygon_shape_tile_data = physics.write[p_layer_id].polygons.write[p_polygon_index];
6403
6404
if (p_polygon.is_empty()) {
6405
polygon_shape_tile_data.shapes.clear();
6406
} else {
6407
// Decompose into convex shapes.
6408
Vector<Vector<Vector2>> decomp = Geometry2D::decompose_polygon_in_convex(p_polygon);
6409
ERR_FAIL_COND_MSG(decomp.is_empty(), "Could not decompose the polygon into convex shapes.");
6410
6411
polygon_shape_tile_data.shapes.resize(decomp.size());
6412
for (int i = 0; i < decomp.size(); i++) {
6413
Ref<ConvexPolygonShape2D> shape;
6414
shape.instantiate();
6415
shape->set_points(decomp[i]);
6416
polygon_shape_tile_data.shapes[i] = shape;
6417
}
6418
}
6419
polygon_shape_tile_data.transformed_shapes.clear();
6420
polygon_shape_tile_data.polygon = p_polygon;
6421
emit_signal(CoreStringName(changed));
6422
}
6423
6424
Vector<Vector2> TileData::get_collision_polygon_points(int p_layer_id, int p_polygon_index) const {
6425
ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Vector<Vector2>());
6426
ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), Vector<Vector2>());
6427
return physics[p_layer_id].polygons[p_polygon_index].polygon;
6428
}
6429
6430
void TileData::set_collision_polygon_one_way(int p_layer_id, int p_polygon_index, bool p_one_way) {
6431
ERR_FAIL_INDEX(p_layer_id, physics.size());
6432
ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size());
6433
physics.write[p_layer_id].polygons.write[p_polygon_index].one_way = p_one_way;
6434
emit_signal(CoreStringName(changed));
6435
}
6436
6437
bool TileData::is_collision_polygon_one_way(int p_layer_id, int p_polygon_index) const {
6438
ERR_FAIL_INDEX_V(p_layer_id, physics.size(), false);
6439
ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), false);
6440
return physics[p_layer_id].polygons[p_polygon_index].one_way;
6441
}
6442
6443
void TileData::set_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index, float p_one_way_margin) {
6444
ERR_FAIL_INDEX(p_layer_id, physics.size());
6445
ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size());
6446
physics.write[p_layer_id].polygons.write[p_polygon_index].one_way_margin = p_one_way_margin;
6447
emit_signal(CoreStringName(changed));
6448
}
6449
6450
float TileData::get_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index) const {
6451
ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0.0);
6452
ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), 0.0);
6453
return physics[p_layer_id].polygons[p_polygon_index].one_way_margin;
6454
}
6455
6456
int TileData::get_collision_polygon_shapes_count(int p_layer_id, int p_polygon_index) const {
6457
ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0);
6458
ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), 0);
6459
return physics[p_layer_id].polygons[p_polygon_index].shapes.size();
6460
}
6461
6462
Ref<ConvexPolygonShape2D> TileData::get_collision_polygon_shape(int p_layer_id, int p_polygon_index, int shape_index, bool p_flip_h, bool p_flip_v, bool p_transpose) const {
6463
ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Ref<ConvexPolygonShape2D>());
6464
ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), Ref<ConvexPolygonShape2D>());
6465
ERR_FAIL_INDEX_V(shape_index, (int)physics[p_layer_id].polygons[p_polygon_index].shapes.size(), Ref<ConvexPolygonShape2D>());
6466
6467
const PhysicsLayerTileData &layer_tile_data = physics[p_layer_id];
6468
const PhysicsLayerTileData::PolygonShapeTileData &shapes_data = layer_tile_data.polygons[p_polygon_index];
6469
6470
int key = int(p_flip_h) | int(p_flip_v) << 1 | int(p_transpose) << 2;
6471
if (key == 0) {
6472
return shapes_data.shapes[shape_index];
6473
}
6474
if (shapes_data.shapes[shape_index].is_null()) {
6475
return Ref<ConvexPolygonShape2D>();
6476
}
6477
6478
HashMap<int, LocalVector<Ref<ConvexPolygonShape2D>>>::Iterator I = shapes_data.transformed_shapes.find(key);
6479
if (!I) {
6480
int size = shapes_data.shapes.size();
6481
shapes_data.transformed_shapes[key].resize(size);
6482
for (int i = 0; i < size; i++) {
6483
Ref<ConvexPolygonShape2D> transformed_polygon;
6484
transformed_polygon.instantiate();
6485
transformed_polygon->set_points(get_transformed_vertices(shapes_data.shapes[i]->get_points(), p_flip_h, p_flip_v, p_transpose));
6486
shapes_data.transformed_shapes[key][i] = transformed_polygon;
6487
}
6488
return shapes_data.transformed_shapes[key][shape_index];
6489
} else {
6490
return I->value[shape_index];
6491
}
6492
}
6493
#endif // PHYSICS_2D_DISABLED
6494
6495
// Terrain
6496
void TileData::set_terrain_set(int p_terrain_set) {
6497
ERR_FAIL_COND(p_terrain_set < -1);
6498
if (p_terrain_set == terrain_set) {
6499
return;
6500
}
6501
if (tile_set) {
6502
ERR_FAIL_COND(p_terrain_set >= tile_set->get_terrain_sets_count());
6503
terrain = -1;
6504
for (int i = 0; i < 16; i++) {
6505
terrain_peering_bits[i] = -1;
6506
}
6507
}
6508
terrain_set = p_terrain_set;
6509
notify_property_list_changed();
6510
emit_signal(CoreStringName(changed));
6511
}
6512
6513
int TileData::get_terrain_set() const {
6514
return terrain_set;
6515
}
6516
6517
void TileData::set_terrain(int p_terrain) {
6518
ERR_FAIL_COND(p_terrain < -1);
6519
ERR_FAIL_COND(terrain_set < 0 && p_terrain != -1);
6520
if (tile_set && terrain_set >= 0) {
6521
ERR_FAIL_COND(p_terrain >= tile_set->get_terrains_count(terrain_set));
6522
}
6523
terrain = p_terrain;
6524
emit_signal(CoreStringName(changed));
6525
}
6526
6527
int TileData::get_terrain() const {
6528
return terrain;
6529
}
6530
6531
void TileData::set_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) {
6532
ERR_FAIL_INDEX(p_peering_bit, TileSet::CellNeighbor::CELL_NEIGHBOR_MAX);
6533
ERR_FAIL_COND(p_terrain_index < -1);
6534
ERR_FAIL_COND(terrain_set < 0 && p_terrain_index != -1);
6535
if (tile_set && terrain_set >= 0) {
6536
ERR_FAIL_COND(p_terrain_index >= tile_set->get_terrains_count(terrain_set));
6537
ERR_FAIL_COND(!is_valid_terrain_peering_bit(p_peering_bit));
6538
}
6539
terrain_peering_bits[p_peering_bit] = p_terrain_index;
6540
emit_signal(CoreStringName(changed));
6541
}
6542
6543
int TileData::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
6544
ERR_FAIL_COND_V(!is_valid_terrain_peering_bit(p_peering_bit), -1);
6545
return terrain_peering_bits[p_peering_bit];
6546
}
6547
6548
bool TileData::is_valid_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
6549
ERR_FAIL_NULL_V(tile_set, false);
6550
6551
return tile_set->is_valid_terrain_peering_bit(terrain_set, p_peering_bit);
6552
}
6553
6554
TileSet::TerrainsPattern TileData::get_terrains_pattern() const {
6555
ERR_FAIL_NULL_V(tile_set, TileSet::TerrainsPattern());
6556
6557
TileSet::TerrainsPattern output(tile_set, terrain_set);
6558
output.set_terrain(terrain);
6559
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
6560
if (tile_set->is_valid_terrain_peering_bit(terrain_set, TileSet::CellNeighbor(i))) {
6561
output.set_terrain_peering_bit(TileSet::CellNeighbor(i), get_terrain_peering_bit(TileSet::CellNeighbor(i)));
6562
}
6563
}
6564
return output;
6565
}
6566
6567
#ifndef NAVIGATION_2D_DISABLED
6568
// Navigation
6569
void TileData::set_navigation_polygon(int p_layer_id, Ref<NavigationPolygon> p_navigation_polygon) {
6570
ERR_FAIL_INDEX(p_layer_id, navigation.size());
6571
navigation.write[p_layer_id].navigation_polygon = p_navigation_polygon;
6572
navigation.write[p_layer_id].transformed_navigation_polygon.clear();
6573
emit_signal(CoreStringName(changed));
6574
}
6575
6576
Ref<NavigationPolygon> TileData::get_navigation_polygon(int p_layer_id, bool p_flip_h, bool p_flip_v, bool p_transpose) const {
6577
ERR_FAIL_INDEX_V(p_layer_id, navigation.size(), Ref<NavigationPolygon>());
6578
6579
const NavigationLayerTileData &layer_tile_data = navigation[p_layer_id];
6580
6581
int key = int(p_flip_h) | int(p_flip_v) << 1 | int(p_transpose) << 2;
6582
if (key == 0) {
6583
return layer_tile_data.navigation_polygon;
6584
}
6585
6586
if (layer_tile_data.navigation_polygon.is_null()) {
6587
return Ref<NavigationPolygon>();
6588
}
6589
6590
HashMap<int, Ref<NavigationPolygon>>::Iterator I = layer_tile_data.transformed_navigation_polygon.find(key);
6591
if (!I) {
6592
Ref<NavigationPolygon> transformed_polygon;
6593
transformed_polygon.instantiate();
6594
6595
PackedVector2Array new_points = get_transformed_vertices(layer_tile_data.navigation_polygon->get_vertices(), p_flip_h, p_flip_v, p_transpose);
6596
6597
const Vector<Vector<Vector2>> outlines = layer_tile_data.navigation_polygon->get_outlines();
6598
int outline_count = outlines.size();
6599
6600
Vector<Vector<Vector2>> new_outlines;
6601
new_outlines.resize(outline_count);
6602
6603
for (int i = 0; i < outline_count; i++) {
6604
new_outlines.write[i] = get_transformed_vertices(outlines[i], p_flip_h, p_flip_v, p_transpose);
6605
}
6606
6607
transformed_polygon->set_data(new_points, layer_tile_data.navigation_polygon->get_polygons(), new_outlines);
6608
6609
layer_tile_data.transformed_navigation_polygon[key] = transformed_polygon;
6610
return transformed_polygon;
6611
} else {
6612
return I->value;
6613
}
6614
}
6615
#endif // NAVIGATION_2D_DISABLED
6616
6617
// Misc
6618
void TileData::set_probability(float p_probability) {
6619
ERR_FAIL_COND(p_probability < 0.0);
6620
probability = p_probability;
6621
emit_signal(CoreStringName(changed));
6622
}
6623
float TileData::get_probability() const {
6624
return probability;
6625
}
6626
6627
// Custom data
6628
void TileData::set_custom_data(String p_layer_name, Variant p_value) {
6629
ERR_FAIL_NULL(tile_set);
6630
int p_layer_id = tile_set->get_custom_data_layer_by_name(p_layer_name);
6631
ERR_FAIL_COND_MSG(p_layer_id < 0, vformat("TileSet has no layer with name: %s", p_layer_name));
6632
set_custom_data_by_layer_id(p_layer_id, p_value);
6633
}
6634
6635
Variant TileData::get_custom_data(String p_layer_name) const {
6636
ERR_FAIL_NULL_V(tile_set, Variant());
6637
int p_layer_id = tile_set->get_custom_data_layer_by_name(p_layer_name);
6638
ERR_FAIL_COND_V_MSG(p_layer_id < 0, Variant(), vformat("TileSet has no layer with name: %s", p_layer_name));
6639
return get_custom_data_by_layer_id(p_layer_id);
6640
}
6641
6642
bool TileData::has_custom_data(const String &p_layer_name) const {
6643
ERR_FAIL_NULL_V(tile_set, false);
6644
return tile_set->has_custom_data_layer_by_name(p_layer_name);
6645
}
6646
6647
void TileData::set_custom_data_by_layer_id(int p_layer_id, Variant p_value) {
6648
ERR_FAIL_INDEX(p_layer_id, custom_data.size());
6649
custom_data.write[p_layer_id] = p_value;
6650
emit_signal(CoreStringName(changed));
6651
}
6652
6653
Variant TileData::get_custom_data_by_layer_id(int p_layer_id) const {
6654
ERR_FAIL_INDEX_V(p_layer_id, custom_data.size(), Variant());
6655
return custom_data[p_layer_id];
6656
}
6657
6658
PackedVector2Array TileData::get_transformed_vertices(const PackedVector2Array &p_vertices, bool p_flip_h, bool p_flip_v, bool p_transpose) {
6659
const Vector2 *r = p_vertices.ptr();
6660
int size = p_vertices.size();
6661
6662
PackedVector2Array new_points;
6663
new_points.resize(size);
6664
Vector2 *w = new_points.ptrw();
6665
6666
for (int i = 0; i < size; i++) {
6667
Vector2 v;
6668
if (p_transpose) {
6669
v = Vector2(r[i].y, r[i].x);
6670
} else {
6671
v = r[i];
6672
}
6673
6674
if (p_flip_h) {
6675
v.x *= -1;
6676
}
6677
if (p_flip_v) {
6678
v.y *= -1;
6679
}
6680
w[i] = v;
6681
}
6682
return new_points;
6683
}
6684
6685
bool TileData::_set(const StringName &p_name, const Variant &p_value) {
6686
#ifndef DISABLE_DEPRECATED
6687
if (p_name == "texture_offset") {
6688
texture_origin = p_value;
6689
return true;
6690
}
6691
#endif
6692
6693
Vector<String> components = String(p_name).split("/", true, 2);
6694
if (components.size() >= 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
6695
// Occlusion layers.
6696
int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
6697
ERR_FAIL_COND_V(layer_index < 0, false);
6698
if (components.size() == 2) {
6699
if (components[1] == "polygon") {
6700
// Kept for compatibility.
6701
Ref<OccluderPolygon2D> polygon = p_value;
6702
if (layer_index >= occluders.size()) {
6703
if (tile_set) {
6704
return false;
6705
} else {
6706
occluders.resize(layer_index + 1);
6707
}
6708
}
6709
if (get_occluder_polygons_count(layer_index) == 0) {
6710
add_occluder_polygon(layer_index);
6711
}
6712
set_occluder_polygon(layer_index, 0, polygon);
6713
return true;
6714
} else if (components[1] == "polygons_count") {
6715
if (p_value.get_type() != Variant::INT) {
6716
return false;
6717
}
6718
set_occluder_polygons_count(layer_index, p_value);
6719
return true;
6720
}
6721
} else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
6722
// Polygons.
6723
int polygon_index = components[1].trim_prefix("polygon_").to_int();
6724
ERR_FAIL_COND_V(polygon_index < 0, false);
6725
6726
if (layer_index >= occluders.size()) {
6727
if (tile_set) {
6728
return false;
6729
} else {
6730
occluders.resize(layer_index + 1);
6731
}
6732
}
6733
6734
if (polygon_index >= occluders[layer_index].polygons.size()) {
6735
occluders.write[layer_index].polygons.resize(polygon_index + 1);
6736
}
6737
6738
if (components[2] == "polygon") {
6739
Ref<OccluderPolygon2D> polygon = p_value;
6740
set_occluder_polygon(layer_index, polygon_index, polygon);
6741
return true;
6742
}
6743
}
6744
}
6745
#ifndef PHYSICS_2D_DISABLED
6746
else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
6747
// Physics layers.
6748
int layer_index = components[0].trim_prefix("physics_layer_").to_int();
6749
ERR_FAIL_COND_V(layer_index < 0, false);
6750
if (components.size() == 2) {
6751
if (layer_index >= physics.size()) {
6752
if (tile_set) {
6753
return false;
6754
} else {
6755
physics.resize(layer_index + 1);
6756
}
6757
}
6758
if (components[1] == "linear_velocity") {
6759
set_constant_linear_velocity(layer_index, p_value);
6760
return true;
6761
} else if (components[1] == "angular_velocity") {
6762
set_constant_angular_velocity(layer_index, p_value);
6763
return true;
6764
} else if (components[1] == "polygons_count") {
6765
if (p_value.get_type() != Variant::INT) {
6766
return false;
6767
}
6768
set_collision_polygons_count(layer_index, p_value);
6769
return true;
6770
}
6771
} else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
6772
// Polygons.
6773
int polygon_index = components[1].trim_prefix("polygon_").to_int();
6774
ERR_FAIL_COND_V(polygon_index < 0, false);
6775
6776
if (components[2] == "points" || components[2] == "one_way" || components[2] == "one_way_margin") {
6777
if (layer_index >= physics.size()) {
6778
if (tile_set) {
6779
return false;
6780
} else {
6781
physics.resize(layer_index + 1);
6782
}
6783
}
6784
6785
if (polygon_index >= physics[layer_index].polygons.size()) {
6786
physics.write[layer_index].polygons.resize(polygon_index + 1);
6787
}
6788
}
6789
if (components[2] == "points") {
6790
Vector<Vector2> polygon = p_value;
6791
set_collision_polygon_points(layer_index, polygon_index, polygon);
6792
return true;
6793
} else if (components[2] == "one_way") {
6794
set_collision_polygon_one_way(layer_index, polygon_index, p_value);
6795
return true;
6796
} else if (components[2] == "one_way_margin") {
6797
set_collision_polygon_one_way_margin(layer_index, polygon_index, p_value);
6798
return true;
6799
}
6800
}
6801
}
6802
#endif // PHYSICS_2D_DISABLED
6803
#ifndef NAVIGATION_2D_DISABLED
6804
else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) {
6805
// Navigation layers.
6806
int layer_index = components[0].trim_prefix("navigation_layer_").to_int();
6807
ERR_FAIL_COND_V(layer_index < 0, false);
6808
if (components[1] == "polygon") {
6809
Ref<NavigationPolygon> polygon = p_value;
6810
6811
if (layer_index >= navigation.size()) {
6812
if (tile_set) {
6813
return false;
6814
} else {
6815
navigation.resize(layer_index + 1);
6816
}
6817
}
6818
set_navigation_polygon(layer_index, polygon);
6819
return true;
6820
}
6821
}
6822
#endif // NAVIGATION_2D_DISABLED
6823
else if (components.size() == 2 && components[0] == "terrains_peering_bit") {
6824
// Terrains.
6825
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
6826
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
6827
if (components[1] == TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]) {
6828
set_terrain_peering_bit(bit, p_value);
6829
return true;
6830
}
6831
}
6832
return false;
6833
} else if (components.size() == 1 && components[0].begins_with("custom_data_") && components[0].trim_prefix("custom_data_").is_valid_int()) {
6834
// Custom data layers.
6835
int layer_index = components[0].trim_prefix("custom_data_").to_int();
6836
ERR_FAIL_COND_V(layer_index < 0, false);
6837
6838
if (layer_index >= custom_data.size()) {
6839
if (tile_set) {
6840
return false;
6841
} else {
6842
custom_data.resize(layer_index + 1);
6843
}
6844
}
6845
set_custom_data_by_layer_id(layer_index, p_value);
6846
6847
return true;
6848
}
6849
6850
return false;
6851
}
6852
6853
bool TileData::_get(const StringName &p_name, Variant &r_ret) const {
6854
#ifndef DISABLE_DEPRECATED
6855
if (p_name == "texture_offset") {
6856
r_ret = texture_origin;
6857
return true;
6858
}
6859
#endif
6860
6861
Vector<String> components = String(p_name).split("/", true, 2);
6862
6863
if (tile_set) {
6864
if (components.size() >= 2 && components[0].begins_with("occlusion_layer") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
6865
// Occlusion layers.
6866
int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
6867
ERR_FAIL_COND_V(layer_index < 0, false);
6868
if (layer_index >= occluders.size()) {
6869
return false;
6870
}
6871
if (components.size() == 2) {
6872
if (components[1] == "polygon") {
6873
// Kept for compatibility.
6874
if (occluders[layer_index].polygons.is_empty()) {
6875
return false;
6876
}
6877
r_ret = get_occluder_polygon(layer_index, 0);
6878
return true;
6879
} else if (components[1] == "polygons_count") {
6880
r_ret = get_occluder_polygons_count(layer_index);
6881
return true;
6882
}
6883
} else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
6884
// Polygons.
6885
int polygon_index = components[1].trim_prefix("polygon_").to_int();
6886
ERR_FAIL_COND_V(polygon_index < 0, false);
6887
if (polygon_index >= occluders[layer_index].polygons.size()) {
6888
return false;
6889
}
6890
if (components[2] == "polygon") {
6891
r_ret = get_occluder_polygon(layer_index, polygon_index);
6892
return true;
6893
}
6894
}
6895
}
6896
#ifndef PHYSICS_2D_DISABLED
6897
else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
6898
// Physics layers.
6899
int layer_index = components[0].trim_prefix("physics_layer_").to_int();
6900
ERR_FAIL_COND_V(layer_index < 0, false);
6901
if (layer_index >= physics.size()) {
6902
return false;
6903
}
6904
6905
if (components.size() == 2) {
6906
if (components[1] == "linear_velocity") {
6907
r_ret = get_constant_linear_velocity(layer_index);
6908
return true;
6909
} else if (components[1] == "angular_velocity") {
6910
r_ret = get_constant_angular_velocity(layer_index);
6911
return true;
6912
} else if (components[1] == "polygons_count") {
6913
r_ret = get_collision_polygons_count(layer_index);
6914
return true;
6915
}
6916
} else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
6917
int polygon_index = components[1].trim_prefix("polygon_").to_int();
6918
ERR_FAIL_COND_V(polygon_index < 0, false);
6919
if (polygon_index >= physics[layer_index].polygons.size()) {
6920
return false;
6921
}
6922
if (components[2] == "points") {
6923
r_ret = get_collision_polygon_points(layer_index, polygon_index);
6924
return true;
6925
} else if (components[2] == "one_way") {
6926
r_ret = is_collision_polygon_one_way(layer_index, polygon_index);
6927
return true;
6928
} else if (components[2] == "one_way_margin") {
6929
r_ret = get_collision_polygon_one_way_margin(layer_index, polygon_index);
6930
return true;
6931
}
6932
}
6933
}
6934
#endif // PHYSICS_2D_DISABLED
6935
else if (components.size() == 2 && components[0] == "terrains_peering_bit") {
6936
// Terrains.
6937
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
6938
if (components[1] == TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]) {
6939
r_ret = terrain_peering_bits[i];
6940
return true;
6941
}
6942
}
6943
return false;
6944
}
6945
#ifndef NAVIGATION_2D_DISABLED
6946
else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) {
6947
// Occlusion layers.
6948
int layer_index = components[0].trim_prefix("navigation_layer_").to_int();
6949
ERR_FAIL_COND_V(layer_index < 0, false);
6950
if (layer_index >= navigation.size()) {
6951
return false;
6952
}
6953
if (components[1] == "polygon") {
6954
r_ret = get_navigation_polygon(layer_index);
6955
return true;
6956
}
6957
}
6958
#endif // NAVIGATION_2D_DISABLED
6959
else if (components.size() == 1 && components[0].begins_with("custom_data_") && components[0].trim_prefix("custom_data_").is_valid_int()) {
6960
// Custom data layers.
6961
int layer_index = components[0].trim_prefix("custom_data_").to_int();
6962
ERR_FAIL_COND_V(layer_index < 0, false);
6963
if (layer_index >= custom_data.size()) {
6964
return false;
6965
}
6966
r_ret = get_custom_data_by_layer_id(layer_index);
6967
return true;
6968
}
6969
}
6970
6971
return false;
6972
}
6973
6974
void TileData::_get_property_list(List<PropertyInfo> *p_list) const {
6975
PropertyInfo property_info;
6976
// Add the groups manually.
6977
if (tile_set) {
6978
// Occlusion layers.
6979
p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Rendering", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
6980
for (int i = 0; i < occluders.size(); i++) {
6981
p_list->push_back(PropertyInfo(Variant::INT, vformat("occlusion_layer_%d/%s", i, PNAME("polygons_count")), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
6982
for (int j = 0; j < occluders[i].polygons.size(); j++) {
6983
// occlusion_layer_%d/polygon_%d/polygon
6984
property_info = PropertyInfo(Variant::OBJECT, vformat("occlusion_layer_%d/polygon_%d/%s", i, j, PNAME("polygon")), PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D", PROPERTY_USAGE_DEFAULT);
6985
if (occluders[i].polygons[j].occluder_polygon.is_null()) {
6986
property_info.usage ^= PROPERTY_USAGE_STORAGE;
6987
}
6988
p_list->push_back(property_info);
6989
}
6990
}
6991
6992
#ifndef PHYSICS_2D_DISABLED
6993
// Physics layers.
6994
p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Physics", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
6995
for (int i = 0; i < physics.size(); i++) {
6996
// physics_layer_%d/linear_velocity
6997
property_info = PropertyInfo(Variant::VECTOR2, vformat("physics_layer_%d/%s", i, PNAME("linear_velocity")), PROPERTY_HINT_NONE);
6998
if (physics[i].linear_velocity == Vector2()) {
6999
property_info.usage ^= PROPERTY_USAGE_STORAGE;
7000
}
7001
p_list->push_back(property_info);
7002
7003
// physics_layer_%d/angular_velocity
7004
property_info = PropertyInfo(Variant::FLOAT, vformat("physics_layer_%d/%s", i, PNAME("angular_velocity")), PROPERTY_HINT_NONE);
7005
if (physics[i].angular_velocity == 0.0) {
7006
property_info.usage ^= PROPERTY_USAGE_STORAGE;
7007
}
7008
p_list->push_back(property_info);
7009
7010
p_list->push_back(PropertyInfo(Variant::INT, vformat("physics_layer_%d/%s", i, PNAME("polygons_count")), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
7011
7012
for (int j = 0; j < physics[i].polygons.size(); j++) {
7013
// physics_layer_%d/points
7014
property_info = PropertyInfo(Variant::ARRAY, vformat("physics_layer_%d/polygon_%d/%s", i, j, PNAME("points")), PROPERTY_HINT_ARRAY_TYPE, "Vector2", PROPERTY_USAGE_DEFAULT);
7015
if (physics[i].polygons[j].polygon.is_empty()) {
7016
property_info.usage ^= PROPERTY_USAGE_STORAGE;
7017
}
7018
p_list->push_back(property_info);
7019
7020
// physics_layer_%d/polygon_%d/one_way
7021
property_info = PropertyInfo(Variant::BOOL, vformat("physics_layer_%d/polygon_%d/%s", i, j, PNAME("one_way")));
7022
if (physics[i].polygons[j].one_way == false) {
7023
property_info.usage ^= PROPERTY_USAGE_STORAGE;
7024
}
7025
p_list->push_back(property_info);
7026
7027
// physics_layer_%d/polygon_%d/one_way_margin
7028
property_info = PropertyInfo(Variant::FLOAT, vformat("physics_layer_%d/polygon_%d/%s", i, j, PNAME("one_way_margin")));
7029
if (physics[i].polygons[j].one_way_margin == 1.0) {
7030
property_info.usage ^= PROPERTY_USAGE_STORAGE;
7031
}
7032
p_list->push_back(property_info);
7033
}
7034
}
7035
#endif // PHYSICS_2D_DISABLED
7036
7037
// Terrain data
7038
if (terrain_set >= 0) {
7039
p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Terrains", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
7040
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
7041
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
7042
if (is_valid_terrain_peering_bit(bit)) {
7043
property_info = PropertyInfo(Variant::INT, vformat("%s/%s", PNAME("terrains_peering_bit"), TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
7044
if (get_terrain_peering_bit(bit) == -1) {
7045
property_info.usage ^= PROPERTY_USAGE_STORAGE;
7046
}
7047
p_list->push_back(property_info);
7048
}
7049
}
7050
}
7051
7052
#ifndef NAVIGATION_2D_DISABLED
7053
// Navigation layers.
7054
p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Navigation", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP));
7055
for (int i = 0; i < navigation.size(); i++) {
7056
property_info = PropertyInfo(Variant::OBJECT, vformat("navigation_layer_%d/%s", i, PNAME("polygon")), PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon", PROPERTY_USAGE_DEFAULT);
7057
if (navigation[i].navigation_polygon.is_null()) {
7058
property_info.usage ^= PROPERTY_USAGE_STORAGE;
7059
}
7060
p_list->push_back(property_info);
7061
}
7062
#endif // NAVIGATION_2D_DISABLED
7063
7064
// Custom data layers.
7065
p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Custom Data", "custom_data_"), PROPERTY_HINT_NONE, "custom_data_", PROPERTY_USAGE_GROUP));
7066
for (int i = 0; i < custom_data.size(); i++) {
7067
Variant default_val;
7068
Callable::CallError error;
7069
Variant::construct(custom_data[i].get_type(), default_val, nullptr, 0, error);
7070
property_info = PropertyInfo(tile_set->get_custom_data_layer_type(i), vformat("custom_data_%d", i), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
7071
if (custom_data[i] == default_val) {
7072
property_info.usage ^= PROPERTY_USAGE_STORAGE;
7073
}
7074
p_list->push_back(property_info);
7075
}
7076
}
7077
}
7078
7079
void TileData::_bind_methods() {
7080
// Rendering.
7081
ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &TileData::set_flip_h);
7082
ClassDB::bind_method(D_METHOD("get_flip_h"), &TileData::get_flip_h);
7083
ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &TileData::set_flip_v);
7084
ClassDB::bind_method(D_METHOD("get_flip_v"), &TileData::get_flip_v);
7085
ClassDB::bind_method(D_METHOD("set_transpose", "transpose"), &TileData::set_transpose);
7086
ClassDB::bind_method(D_METHOD("get_transpose"), &TileData::get_transpose);
7087
ClassDB::bind_method(D_METHOD("set_material", "material"), &TileData::set_material);
7088
ClassDB::bind_method(D_METHOD("get_material"), &TileData::get_material);
7089
ClassDB::bind_method(D_METHOD("set_texture_origin", "texture_origin"), &TileData::set_texture_origin);
7090
ClassDB::bind_method(D_METHOD("get_texture_origin"), &TileData::get_texture_origin);
7091
ClassDB::bind_method(D_METHOD("set_modulate", "modulate"), &TileData::set_modulate);
7092
ClassDB::bind_method(D_METHOD("get_modulate"), &TileData::get_modulate);
7093
ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &TileData::set_z_index);
7094
ClassDB::bind_method(D_METHOD("get_z_index"), &TileData::get_z_index);
7095
ClassDB::bind_method(D_METHOD("set_y_sort_origin", "y_sort_origin"), &TileData::set_y_sort_origin);
7096
ClassDB::bind_method(D_METHOD("get_y_sort_origin"), &TileData::get_y_sort_origin);
7097
7098
ClassDB::bind_method(D_METHOD("set_occluder_polygons_count", "layer_id", "polygons_count"), &TileData::set_occluder_polygons_count);
7099
ClassDB::bind_method(D_METHOD("get_occluder_polygons_count", "layer_id"), &TileData::get_occluder_polygons_count);
7100
ClassDB::bind_method(D_METHOD("add_occluder_polygon", "layer_id"), &TileData::add_occluder_polygon);
7101
ClassDB::bind_method(D_METHOD("remove_occluder_polygon", "layer_id", "polygon_index"), &TileData::remove_occluder_polygon);
7102
ClassDB::bind_method(D_METHOD("set_occluder_polygon", "layer_id", "polygon_index", "polygon"), &TileData::set_occluder_polygon);
7103
ClassDB::bind_method(D_METHOD("get_occluder_polygon", "layer_id", "polygon_index", "flip_h", "flip_v", "transpose"), &TileData::get_occluder_polygon, DEFVAL(false), DEFVAL(false), DEFVAL(false));
7104
7105
#ifndef DISABLE_DEPRECATED
7106
ClassDB::bind_method(D_METHOD("set_occluder", "layer_id", "occluder_polygon"), &TileData::set_occluder);
7107
ClassDB::bind_method(D_METHOD("get_occluder", "layer_id", "flip_h", "flip_v", "transpose"), &TileData::get_occluder, DEFVAL(false), DEFVAL(false), DEFVAL(false));
7108
#endif // DISABLE_DEPRECATED
7109
7110
#ifndef PHYSICS_2D_DISABLED
7111
// Physics.
7112
ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "layer_id", "velocity"), &TileData::set_constant_linear_velocity);
7113
ClassDB::bind_method(D_METHOD("get_constant_linear_velocity", "layer_id"), &TileData::get_constant_linear_velocity);
7114
ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "layer_id", "velocity"), &TileData::set_constant_angular_velocity);
7115
ClassDB::bind_method(D_METHOD("get_constant_angular_velocity", "layer_id"), &TileData::get_constant_angular_velocity);
7116
ClassDB::bind_method(D_METHOD("set_collision_polygons_count", "layer_id", "polygons_count"), &TileData::set_collision_polygons_count);
7117
ClassDB::bind_method(D_METHOD("get_collision_polygons_count", "layer_id"), &TileData::get_collision_polygons_count);
7118
ClassDB::bind_method(D_METHOD("add_collision_polygon", "layer_id"), &TileData::add_collision_polygon);
7119
ClassDB::bind_method(D_METHOD("remove_collision_polygon", "layer_id", "polygon_index"), &TileData::remove_collision_polygon);
7120
ClassDB::bind_method(D_METHOD("set_collision_polygon_points", "layer_id", "polygon_index", "polygon"), &TileData::set_collision_polygon_points);
7121
ClassDB::bind_method(D_METHOD("get_collision_polygon_points", "layer_id", "polygon_index"), &TileData::get_collision_polygon_points);
7122
ClassDB::bind_method(D_METHOD("set_collision_polygon_one_way", "layer_id", "polygon_index", "one_way"), &TileData::set_collision_polygon_one_way);
7123
ClassDB::bind_method(D_METHOD("is_collision_polygon_one_way", "layer_id", "polygon_index"), &TileData::is_collision_polygon_one_way);
7124
ClassDB::bind_method(D_METHOD("set_collision_polygon_one_way_margin", "layer_id", "polygon_index", "one_way_margin"), &TileData::set_collision_polygon_one_way_margin);
7125
ClassDB::bind_method(D_METHOD("get_collision_polygon_one_way_margin", "layer_id", "polygon_index"), &TileData::get_collision_polygon_one_way_margin);
7126
#endif // PHYSICS_2D_DISABLED
7127
7128
// Terrain
7129
ClassDB::bind_method(D_METHOD("set_terrain_set", "terrain_set"), &TileData::set_terrain_set);
7130
ClassDB::bind_method(D_METHOD("get_terrain_set"), &TileData::get_terrain_set);
7131
ClassDB::bind_method(D_METHOD("set_terrain", "terrain"), &TileData::set_terrain);
7132
ClassDB::bind_method(D_METHOD("get_terrain"), &TileData::get_terrain);
7133
ClassDB::bind_method(D_METHOD("set_terrain_peering_bit", "peering_bit", "terrain"), &TileData::set_terrain_peering_bit);
7134
ClassDB::bind_method(D_METHOD("get_terrain_peering_bit", "peering_bit"), &TileData::get_terrain_peering_bit);
7135
ClassDB::bind_method(D_METHOD("is_valid_terrain_peering_bit", "peering_bit"), &TileData::is_valid_terrain_peering_bit);
7136
7137
#ifndef NAVIGATION_2D_DISABLED
7138
// Navigation
7139
ClassDB::bind_method(D_METHOD("set_navigation_polygon", "layer_id", "navigation_polygon"), &TileData::set_navigation_polygon);
7140
ClassDB::bind_method(D_METHOD("get_navigation_polygon", "layer_id", "flip_h", "flip_v", "transpose"), &TileData::get_navigation_polygon, DEFVAL(false), DEFVAL(false), DEFVAL(false));
7141
#endif // NAVIGATION_2D_DISABLED
7142
7143
// Misc.
7144
ClassDB::bind_method(D_METHOD("set_probability", "probability"), &TileData::set_probability);
7145
ClassDB::bind_method(D_METHOD("get_probability"), &TileData::get_probability);
7146
7147
// Custom data.
7148
ClassDB::bind_method(D_METHOD("set_custom_data", "layer_name", "value"), &TileData::set_custom_data);
7149
ClassDB::bind_method(D_METHOD("get_custom_data", "layer_name"), &TileData::get_custom_data);
7150
ClassDB::bind_method(D_METHOD("has_custom_data", "layer_name"), &TileData::has_custom_data);
7151
ClassDB::bind_method(D_METHOD("set_custom_data_by_layer_id", "layer_id", "value"), &TileData::set_custom_data_by_layer_id);
7152
ClassDB::bind_method(D_METHOD("get_custom_data_by_layer_id", "layer_id"), &TileData::get_custom_data_by_layer_id);
7153
7154
ADD_GROUP("Rendering", "");
7155
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "get_flip_h");
7156
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "get_flip_v");
7157
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transpose"), "set_transpose", "get_transpose");
7158
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "texture_origin", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_origin", "get_texture_origin");
7159
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
7160
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial"), "set_material", "get_material");
7161
ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index"), "set_z_index", "get_z_index");
7162
ADD_PROPERTY(PropertyInfo(Variant::INT, "y_sort_origin"), "set_y_sort_origin", "get_y_sort_origin");
7163
7164
ADD_GROUP("Terrains", "");
7165
ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain_set"), "set_terrain_set", "get_terrain_set");
7166
ADD_PROPERTY(PropertyInfo(Variant::INT, "terrain"), "set_terrain", "get_terrain");
7167
7168
ADD_GROUP("Miscellaneous", "");
7169
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "probability"), "set_probability", "get_probability");
7170
7171
ADD_SIGNAL(MethodInfo("changed"));
7172
}
7173
7174