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