1 /*************************************************************************/
2 /* tile_map.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
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 #include "tile_map.h"
31 #include "io/marshalls.h"
32 #include "method_bind_ext.gen.inc"
33 #include "os/os.h"
34 #include "servers/physics_2d_server.h"
35
_get_quadrant_size() const36 int TileMap::_get_quadrant_size() const {
37
38 if (y_sort_mode)
39 return 1;
40 else
41 return quadrant_size;
42 }
43
_notification(int p_what)44 void TileMap::_notification(int p_what) {
45
46 switch (p_what) {
47
48 case NOTIFICATION_ENTER_TREE: {
49
50 Node2D *c = this;
51 while (c) {
52
53 navigation = c->cast_to<Navigation2D>();
54 if (navigation) {
55 break;
56 }
57
58 c = c->get_parent()->cast_to<Node2D>();
59 }
60
61 pending_update = true;
62 _update_dirty_quadrants();
63 RID space = get_world_2d()->get_space();
64 _update_quadrant_transform();
65 _update_quadrant_space(space);
66
67 } break;
68 case NOTIFICATION_EXIT_TREE: {
69
70 _update_quadrant_space(RID());
71 for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
72
73 Quadrant &q = E->get();
74 if (navigation) {
75 for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) {
76
77 navigation->navpoly_remove(E->get().id);
78 }
79 q.navpoly_ids.clear();
80 }
81
82 for (Map<PosKey, Quadrant::Occluder>::Element *E = q.occluder_instances.front(); E; E = E->next()) {
83 VS::get_singleton()->free(E->get().id);
84 }
85 q.occluder_instances.clear();
86 }
87
88 navigation = NULL;
89
90 } break;
91 case NOTIFICATION_TRANSFORM_CHANGED: {
92
93 //move stuff
94 _update_quadrant_transform();
95
96 } break;
97 }
98 }
99
_update_quadrant_space(const RID & p_space)100 void TileMap::_update_quadrant_space(const RID &p_space) {
101
102 for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
103
104 Quadrant &q = E->get();
105 for (int i = q.bodies.size() - 1; i >= 0; i--) {
106 Physics2DServer::get_singleton()->body_set_space(q.bodies[i], p_space);
107 }
108 }
109 }
110
_update_quadrant_transform()111 void TileMap::_update_quadrant_transform() {
112
113 if (!is_inside_tree())
114 return;
115
116 Matrix32 global_transform = get_global_transform();
117
118 Matrix32 nav_rel;
119 if (navigation)
120 nav_rel = get_relative_transform_to_parent(navigation);
121
122 for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
123
124 Quadrant &q = E->get();
125 Matrix32 xform;
126 xform.set_origin(q.pos);
127 xform = global_transform * xform;
128 for (int i = q.bodies.size() - 1; i >= 0; i--) {
129 Physics2DServer::get_singleton()->body_set_state(q.bodies[i], Physics2DServer::BODY_STATE_TRANSFORM, xform);
130 }
131
132 if (navigation) {
133 for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) {
134
135 navigation->navpoly_set_transform(E->get().id, nav_rel * E->get().xform);
136 }
137 }
138
139 for (Map<PosKey, Quadrant::Occluder>::Element *E = q.occluder_instances.front(); E; E = E->next()) {
140 VS::get_singleton()->canvas_light_occluder_set_transform(E->get().id, global_transform * E->get().xform);
141 }
142 }
143 }
144
set_tileset(const Ref<TileSet> & p_tileset)145 void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
146
147 if (tile_set.is_valid())
148 tile_set->disconnect("changed", this, "_recreate_quadrants");
149
150 _clear_quadrants();
151 tile_set = p_tileset;
152
153 if (tile_set.is_valid())
154 tile_set->connect("changed", this, "_recreate_quadrants");
155 else
156 clear();
157
158 _recreate_quadrants();
159 emit_signal("settings_changed");
160 }
161
get_tileset() const162 Ref<TileSet> TileMap::get_tileset() const {
163
164 return tile_set;
165 }
166
set_cell_size(Size2 p_size)167 void TileMap::set_cell_size(Size2 p_size) {
168
169 ERR_FAIL_COND(p_size.x < 1 || p_size.y < 1);
170
171 _clear_quadrants();
172 cell_size = p_size;
173 _recreate_quadrants();
174 emit_signal("settings_changed");
175 }
get_cell_size() const176 Size2 TileMap::get_cell_size() const {
177
178 return cell_size;
179 }
set_quadrant_size(int p_size)180 void TileMap::set_quadrant_size(int p_size) {
181
182 ERR_FAIL_COND(p_size < 1);
183
184 _clear_quadrants();
185 quadrant_size = p_size;
186 _recreate_quadrants();
187 emit_signal("settings_changed");
188 }
get_quadrant_size() const189 int TileMap::get_quadrant_size() const {
190
191 return quadrant_size;
192 }
193
set_center_x(bool p_enable)194 void TileMap::set_center_x(bool p_enable) {
195
196 center_x = p_enable;
197 _recreate_quadrants();
198 emit_signal("settings_changed");
199 }
get_center_x() const200 bool TileMap::get_center_x() const {
201
202 return center_x;
203 }
set_center_y(bool p_enable)204 void TileMap::set_center_y(bool p_enable) {
205
206 center_y = p_enable;
207 _recreate_quadrants();
208 emit_signal("settings_changed");
209 }
get_center_y() const210 bool TileMap::get_center_y() const {
211
212 return center_y;
213 }
214
_fix_cell_transform(Matrix32 & xform,const Cell & p_cell,const Vector2 & p_offset,const Size2 & p_sc)215 void TileMap::_fix_cell_transform(Matrix32 &xform, const Cell &p_cell, const Vector2 &p_offset, const Size2 &p_sc) {
216
217 Size2 s = p_sc;
218 Vector2 offset = p_offset;
219
220 if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT)
221 offset.y += cell_size.y;
222
223 if (s.y > s.x) {
224 if ((p_cell.flip_h && (p_cell.flip_v || p_cell.transpose)) || (p_cell.flip_v && !p_cell.transpose))
225 offset.y += s.y - s.x;
226 } else if (s.y < s.x) {
227 if ((p_cell.flip_v && (p_cell.flip_h || p_cell.transpose)) || (p_cell.flip_h && !p_cell.transpose))
228 offset.x += s.x - s.y;
229 }
230
231 if (p_cell.transpose) {
232 SWAP(xform.elements[0].x, xform.elements[0].y);
233 SWAP(xform.elements[1].x, xform.elements[1].y);
234 SWAP(offset.x, offset.y);
235 SWAP(s.x, s.y);
236 }
237 if (p_cell.flip_h) {
238 xform.elements[0].x = -xform.elements[0].x;
239 xform.elements[1].x = -xform.elements[1].x;
240 if (tile_origin == TILE_ORIGIN_TOP_LEFT || tile_origin == TILE_ORIGIN_BOTTOM_LEFT)
241 offset.x = s.x - offset.x;
242 }
243 if (p_cell.flip_v) {
244 xform.elements[0].y = -xform.elements[0].y;
245 xform.elements[1].y = -xform.elements[1].y;
246 if (tile_origin == TILE_ORIGIN_TOP_LEFT)
247 offset.y = s.y - offset.y;
248 else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) {
249 if (p_cell.transpose)
250 offset.y += s.y;
251 else
252 offset.y -= s.y;
253 }
254 }
255 xform.elements[2].x += offset.x;
256 xform.elements[2].y += offset.y;
257 }
258
259 namespace {
260
261 struct _BodyParams {
262 Vector2 one_way_direction;
263 float one_way_max_depth;
264
operator <__anonebb233390111::_BodyParams265 bool operator<(const _BodyParams &p_rhs) const {
266 return p_rhs.one_way_direction < one_way_direction || p_rhs.one_way_max_depth < one_way_max_depth;
267 }
268
operator ==__anonebb233390111::_BodyParams269 bool operator==(const _BodyParams &p_rhs) const {
270 return p_rhs.one_way_direction == one_way_direction && p_rhs.one_way_max_depth == one_way_max_depth;
271 }
272 };
273 } // namespace
274
_update_dirty_quadrants()275 void TileMap::_update_dirty_quadrants() {
276
277 if (!pending_update)
278 return;
279 if (!is_inside_tree() || !tile_set.is_valid()) {
280 pending_update = false;
281 return;
282 }
283
284 VisualServer *vs = VisualServer::get_singleton();
285 Physics2DServer *ps = Physics2DServer::get_singleton();
286 Vector2 tofs = get_cell_draw_offset();
287 Vector2 tcenter = cell_size / 2;
288 Matrix32 nav_rel;
289 if (navigation)
290 nav_rel = get_relative_transform_to_parent(navigation);
291
292 Vector2 qofs;
293
294 SceneTree *st = SceneTree::get_singleton();
295 Color debug_collision_color;
296
297 bool debug_shapes = st && st->is_debugging_collisions_hint();
298 if (debug_shapes) {
299 debug_collision_color = st->get_debug_collisions_color();
300 }
301
302 while (dirty_quadrant_list.first()) {
303
304 Quadrant &q = *dirty_quadrant_list.first()->self();
305
306 for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
307
308 vs->free(E->get());
309 }
310
311 q.canvas_items.clear();
312
313 Map<_BodyParams, int> params_bodies;
314 int num_bodies_used = 0;
315
316 if (navigation) {
317 for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) {
318
319 navigation->navpoly_remove(E->get().id);
320 }
321 q.navpoly_ids.clear();
322 }
323
324 for (Map<PosKey, Quadrant::Occluder>::Element *E = q.occluder_instances.front(); E; E = E->next()) {
325 VS::get_singleton()->free(E->get().id);
326 }
327 q.occluder_instances.clear();
328 Ref<CanvasItemMaterial> prev_material;
329 RID prev_canvas_item;
330 RID prev_debug_canvas_item;
331
332 for (int i = 0; i < q.cells.size(); i++) {
333
334 Map<PosKey, Cell>::Element *E = tile_map.find(q.cells[i]);
335 Cell &c = E->get();
336 //moment of truth
337 if (!tile_set->has_tile(c.id))
338 continue;
339 Ref<Texture> tex = tile_set->tile_get_texture(c.id);
340 Vector2 tile_ofs = tile_set->tile_get_texture_offset(c.id);
341
342 Vector2 wofs = _map_to_world(E->key().x, E->key().y);
343 Vector2 offset = wofs - q.pos + tofs;
344
345 if (!tex.is_valid())
346 continue;
347
348 Ref<CanvasItemMaterial> mat = tile_set->tile_get_material(c.id);
349
350 RID canvas_item;
351 RID debug_canvas_item;
352
353 if (prev_canvas_item == RID() || prev_material != mat) {
354
355 canvas_item = vs->canvas_item_create();
356 if (mat.is_valid())
357 vs->canvas_item_set_material(canvas_item, mat->get_rid());
358 vs->canvas_item_set_parent(canvas_item, get_canvas_item());
359 _update_item_material_state(canvas_item);
360 Matrix32 xform;
361 xform.set_origin(q.pos);
362 vs->canvas_item_set_transform(canvas_item, xform);
363 vs->canvas_item_set_light_mask(canvas_item, get_light_mask());
364
365 q.canvas_items.push_back(canvas_item);
366
367 if (debug_shapes) {
368
369 debug_canvas_item = vs->canvas_item_create();
370 vs->canvas_item_set_parent(debug_canvas_item, canvas_item);
371 vs->canvas_item_set_z_as_relative_to_parent(debug_canvas_item, false);
372 vs->canvas_item_set_z(debug_canvas_item, VS::CANVAS_ITEM_Z_MAX - 1);
373 q.canvas_items.push_back(debug_canvas_item);
374 prev_debug_canvas_item = debug_canvas_item;
375 }
376
377 prev_canvas_item = canvas_item;
378 prev_material = mat;
379
380 } else {
381 canvas_item = prev_canvas_item;
382 if (debug_shapes) {
383 debug_canvas_item = prev_debug_canvas_item;
384 }
385 }
386
387 Rect2 r = tile_set->tile_get_region(c.id);
388 Size2 s = tex->get_size();
389
390 if (r == Rect2())
391 s = tex->get_size();
392 else {
393 s = r.size;
394 r.pos.x += fp_adjust;
395 r.pos.y += fp_adjust;
396 r.size.x -= fp_adjust * 2.0;
397 r.size.y -= fp_adjust * 2.0;
398 }
399
400 Rect2 rect;
401 rect.pos = offset.floor();
402 rect.size = s;
403
404 if (rect.size.y > rect.size.x) {
405 if ((c.flip_h && (c.flip_v || c.transpose)) || (c.flip_v && !c.transpose))
406 tile_ofs.y += rect.size.y - rect.size.x;
407 } else if (rect.size.y < rect.size.x) {
408 if ((c.flip_v && (c.flip_h || c.transpose)) || (c.flip_h && !c.transpose))
409 tile_ofs.x += rect.size.x - rect.size.y;
410 }
411
412 /* rect.size.x+=fp_adjust;
413 rect.size.y+=fp_adjust;*/
414
415 if (c.transpose)
416 SWAP(tile_ofs.x, tile_ofs.y);
417
418 if (c.flip_h) {
419 rect.size.x = -rect.size.x;
420 tile_ofs.x = -tile_ofs.x;
421 }
422 if (c.flip_v) {
423 rect.size.y = -rect.size.y;
424 tile_ofs.y = -tile_ofs.y;
425 }
426
427 Vector2 center_ofs;
428
429 if (tile_origin == TILE_ORIGIN_TOP_LEFT) {
430 rect.pos += tile_ofs;
431
432 } else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) {
433
434 rect.pos += tile_ofs;
435
436 if (c.transpose) {
437 if (c.flip_h)
438 rect.pos.x -= cell_size.x;
439 else
440 rect.pos.x += cell_size.x;
441 } else {
442 if (c.flip_v)
443 rect.pos.y -= cell_size.y;
444 else
445 rect.pos.y += cell_size.y;
446 }
447
448 } else if (tile_origin == TILE_ORIGIN_CENTER) {
449 rect.pos += tcenter;
450
451 Vector2 center = (s / 2) - tile_ofs;
452 center_ofs = tcenter - (s / 2);
453
454 if (c.flip_h)
455 rect.pos.x -= s.x - center.x;
456 else
457 rect.pos.x -= center.x;
458
459 if (c.flip_v)
460 rect.pos.y -= s.y - center.y;
461 else
462 rect.pos.y -= center.y;
463 }
464
465 Color modulate = tile_set->tile_get_modulate(c.id);
466 if (r == Rect2()) {
467 tex->draw_rect(canvas_item, rect, false, modulate, c.transpose);
468 } else {
469 tex->draw_rect_region(canvas_item, rect, r, modulate, c.transpose);
470 }
471
472 RID body;
473 _BodyParams params = { tile_set->tile_get_one_way_collision_direction(c.id), tile_set->tile_get_one_way_collision_max_depth(c.id) };
474 Map<_BodyParams, int>::Element *B = params_bodies.find(params);
475 if (!B) {
476 if (q.bodies.size() > num_bodies_used) {
477 // recycle one already existent
478 body = q.bodies[num_bodies_used];
479 // reset it
480 ps->body_clear_shapes(body);
481 } else {
482 // create a new one
483 body = Physics2DServer::get_singleton()->body_create(use_kinematic ? Physics2DServer::BODY_MODE_KINEMATIC : Physics2DServer::BODY_MODE_STATIC);
484 Physics2DServer::get_singleton()->body_attach_object_instance_ID(body, get_instance_ID());
485 Physics2DServer::get_singleton()->body_set_layer_mask(body, collision_layer);
486 Physics2DServer::get_singleton()->body_set_collision_mask(body, collision_mask);
487 Physics2DServer::get_singleton()->body_set_param(body, Physics2DServer::BODY_PARAM_FRICTION, friction);
488 Physics2DServer::get_singleton()->body_set_param(body, Physics2DServer::BODY_PARAM_BOUNCE, bounce);
489 q.bodies.push_back(body);
490 }
491
492 // initialize to match current quadrant
493 Matrix32 xform;
494 xform.set_origin(q.pos);
495 if (is_inside_tree()) {
496 xform = get_global_transform() * xform;
497 RID space = get_world_2d()->get_space();
498 Physics2DServer::get_singleton()->body_set_space(body, space);
499 }
500 Physics2DServer::get_singleton()->body_set_state(body, Physics2DServer::BODY_STATE_TRANSFORM, xform);
501
502 // bookkeep
503 params_bodies[params] = num_bodies_used;
504 num_bodies_used++;
505 } else {
506 // take the one already set up for this tile's parameters
507 body = q.bodies[B->get()];
508 }
509
510 Vector<Ref<Shape2D> > shapes = tile_set->tile_get_shapes(c.id);
511
512 int shape_idx = ps->body_get_shape_count(body);
513 for (int i = 0; i < shapes.size(); i++) {
514
515 Ref<Shape2D> shape = shapes[i];
516 if (shape.is_valid()) {
517
518 Vector2 shape_ofs = tile_set->tile_get_shape_offset(c.id);
519 Matrix32 xform;
520 xform.set_origin(offset.floor());
521
522 _fix_cell_transform(xform, c, shape_ofs + center_ofs, s);
523
524 if (debug_canvas_item) {
525 vs->canvas_item_add_set_transform(debug_canvas_item, xform);
526 shape->draw(debug_canvas_item, debug_collision_color);
527 }
528 ps->body_add_shape(body, shape->get_rid(), xform);
529 ps->body_set_shape_metadata(body, shape_idx++, Vector2(E->key().x, E->key().y));
530 ps->body_set_one_way_collision_direction(body, params.one_way_direction);
531 ps->body_set_one_way_collision_max_depth(body, params.one_way_max_depth);
532 }
533 }
534
535 if (debug_canvas_item) {
536 vs->canvas_item_add_set_transform(debug_canvas_item, Matrix32());
537 }
538
539 if (navigation) {
540 Ref<NavigationPolygon> navpoly = tile_set->tile_get_navigation_polygon(c.id);
541 if (navpoly.is_valid()) {
542 Vector2 npoly_ofs = tile_set->tile_get_navigation_polygon_offset(c.id);
543 Matrix32 xform;
544 xform.set_origin(offset.floor() + q.pos);
545 _fix_cell_transform(xform, c, npoly_ofs + center_ofs, s);
546
547 int pid = navigation->navpoly_create(navpoly, nav_rel * xform);
548
549 Quadrant::NavPoly np;
550 np.id = pid;
551 np.xform = xform;
552 q.navpoly_ids[E->key()] = np;
553 }
554 }
555
556 Ref<OccluderPolygon2D> occluder = tile_set->tile_get_light_occluder(c.id);
557 if (occluder.is_valid()) {
558
559 Vector2 occluder_ofs = tile_set->tile_get_occluder_offset(c.id);
560 Matrix32 xform;
561 xform.set_origin(offset.floor() + q.pos);
562 _fix_cell_transform(xform, c, occluder_ofs + center_ofs, s);
563
564 RID orid = VS::get_singleton()->canvas_light_occluder_create();
565 VS::get_singleton()->canvas_light_occluder_set_transform(orid, get_global_transform() * xform);
566 VS::get_singleton()->canvas_light_occluder_set_polygon(orid, occluder->get_rid());
567 VS::get_singleton()->canvas_light_occluder_attach_to_canvas(orid, get_canvas());
568 VS::get_singleton()->canvas_light_occluder_set_light_mask(orid, occluder_light_mask);
569 Quadrant::Occluder oc;
570 oc.xform = xform;
571 oc.id = orid;
572 q.occluder_instances[E->key()] = oc;
573 }
574 }
575
576 // keep just as many bodies as needed
577 for (int i = num_bodies_used; i < q.bodies.size(); i++) {
578 ps->free(q.bodies[i]);
579 }
580 q.bodies.resize(params_bodies.size());
581
582 //OS::get_singleton()->print("body count: %d (%d)\n", q.bodies.size(), params_bodies.size());
583
584 dirty_quadrant_list.remove(dirty_quadrant_list.first());
585 quadrant_order_dirty = true;
586 }
587
588 pending_update = false;
589
590 if (quadrant_order_dirty) {
591
592 for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
593
594 Quadrant &q = E->get();
595 for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
596
597 VS::get_singleton()->canvas_item_raise(E->get());
598 }
599 }
600
601 quadrant_order_dirty = false;
602 }
603
604 for (int i = 0; i < get_child_count(); i++) {
605
606 CanvasItem *c = get_child(i)->cast_to<CanvasItem>();
607
608 if (c)
609 VS::get_singleton()->canvas_item_raise(c->get_canvas_item());
610 }
611
612 _recompute_rect_cache();
613 }
614
_recompute_rect_cache()615 void TileMap::_recompute_rect_cache() {
616
617 #ifdef DEBUG_ENABLED
618
619 if (!rect_cache_dirty)
620 return;
621
622 Rect2 r_total;
623 for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
624
625 Rect2 r;
626 r.pos = _map_to_world(E->key().x * _get_quadrant_size(), E->key().y * _get_quadrant_size());
627 r.expand_to(_map_to_world(E->key().x * _get_quadrant_size() + _get_quadrant_size(), E->key().y * _get_quadrant_size()));
628 r.expand_to(_map_to_world(E->key().x * _get_quadrant_size() + _get_quadrant_size(), E->key().y * _get_quadrant_size() + _get_quadrant_size()));
629 r.expand_to(_map_to_world(E->key().x * _get_quadrant_size(), E->key().y * _get_quadrant_size() + _get_quadrant_size()));
630 if (E == quadrant_map.front())
631 r_total = r;
632 else
633 r_total = r_total.merge(r);
634 }
635
636 if (r_total == Rect2()) {
637 rect_cache = Rect2(-10, -10, 20, 20);
638 } else {
639 rect_cache = r_total.grow(MAX(cell_size.x, cell_size.y) * _get_quadrant_size());
640 }
641
642 item_rect_changed();
643
644 rect_cache_dirty = false;
645 #endif
646 }
647
_create_quadrant(const PosKey & p_qk)648 Map<TileMap::PosKey, TileMap::Quadrant>::Element *TileMap::_create_quadrant(const PosKey &p_qk) {
649
650 Quadrant q;
651 q.pos = _map_to_world(p_qk.x * _get_quadrant_size(), p_qk.y * _get_quadrant_size());
652 q.pos += get_cell_draw_offset();
653 if (tile_origin == TILE_ORIGIN_CENTER)
654 q.pos += cell_size / 2;
655 else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT)
656 q.pos.y += cell_size.y;
657
658 // q.canvas_item = VisualServer::get_singleton()->canvas_item_create();
659
660 rect_cache_dirty = true;
661 quadrant_order_dirty = true;
662 return quadrant_map.insert(p_qk, q);
663 }
664
_erase_quadrant(Map<PosKey,Quadrant>::Element * Q)665 void TileMap::_erase_quadrant(Map<PosKey, Quadrant>::Element *Q) {
666
667 Quadrant &q = Q->get();
668 for (int i = 0; i < q.bodies.size(); i++) {
669 Physics2DServer::get_singleton()->free(q.bodies[i]);
670 }
671 q.bodies.clear();
672
673 for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
674
675 VisualServer::get_singleton()->free(E->get());
676 }
677 q.canvas_items.clear();
678 if (q.dirty_list.in_list())
679 dirty_quadrant_list.remove(&q.dirty_list);
680
681 if (navigation) {
682 for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) {
683
684 navigation->navpoly_remove(E->get().id);
685 }
686 q.navpoly_ids.clear();
687 }
688
689 for (Map<PosKey, Quadrant::Occluder>::Element *E = q.occluder_instances.front(); E; E = E->next()) {
690 VS::get_singleton()->free(E->get().id);
691 }
692 q.occluder_instances.clear();
693
694 quadrant_map.erase(Q);
695 rect_cache_dirty = true;
696 }
697
_make_quadrant_dirty(Map<PosKey,Quadrant>::Element * Q)698 void TileMap::_make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q) {
699
700 Quadrant &q = Q->get();
701 if (!q.dirty_list.in_list())
702 dirty_quadrant_list.add(&q.dirty_list);
703
704 if (pending_update)
705 return;
706 pending_update = true;
707 if (!is_inside_tree())
708 return;
709 call_deferred("_update_dirty_quadrants");
710 }
711
set_cellv(const Vector2 & p_pos,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose)712 void TileMap::set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose) {
713
714 set_cell(p_pos.x, p_pos.y, p_tile, p_flip_x, p_flip_y, p_transpose);
715 }
716
set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose)717 void TileMap::set_cell(int p_x, int p_y, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose) {
718
719 PosKey pk(p_x, p_y);
720
721 Map<PosKey, Cell>::Element *E = tile_map.find(pk);
722 if (!E && p_tile == INVALID_CELL)
723 return; //nothing to do
724
725 PosKey qk(p_x / _get_quadrant_size(), p_y / _get_quadrant_size());
726 if (p_tile == INVALID_CELL) {
727 //erase existing
728 tile_map.erase(pk);
729 Map<PosKey, Quadrant>::Element *Q = quadrant_map.find(qk);
730 ERR_FAIL_COND(!Q);
731 Quadrant &q = Q->get();
732 q.cells.erase(pk);
733 if (q.cells.size() == 0)
734 _erase_quadrant(Q);
735 else
736 _make_quadrant_dirty(Q);
737
738 return;
739 }
740
741 Map<PosKey, Quadrant>::Element *Q = quadrant_map.find(qk);
742
743 if (!E) {
744 E = tile_map.insert(pk, Cell());
745 if (!Q) {
746 Q = _create_quadrant(qk);
747 }
748 Quadrant &q = Q->get();
749 q.cells.insert(pk);
750 } else {
751 ERR_FAIL_COND(!Q); // quadrant should exist...
752
753 if (E->get().id == p_tile && E->get().flip_h == p_flip_x && E->get().flip_v == p_flip_y && E->get().transpose == p_transpose)
754 return; //nothing changed
755 }
756
757 Cell &c = E->get();
758
759 c.id = p_tile;
760 c.flip_h = p_flip_x;
761 c.flip_v = p_flip_y;
762 c.transpose = p_transpose;
763
764 _make_quadrant_dirty(Q);
765 used_size_cache_dirty = true;
766 }
767
get_cellv(const Vector2 & p_pos) const768 int TileMap::get_cellv(const Vector2 &p_pos) const {
769 return get_cell(p_pos.x, p_pos.y);
770 }
771
get_cell(int p_x,int p_y) const772 int TileMap::get_cell(int p_x, int p_y) const {
773
774 PosKey pk(p_x, p_y);
775
776 const Map<PosKey, Cell>::Element *E = tile_map.find(pk);
777
778 if (!E)
779 return INVALID_CELL;
780
781 return E->get().id;
782 }
is_cell_x_flipped(int p_x,int p_y) const783 bool TileMap::is_cell_x_flipped(int p_x, int p_y) const {
784
785 PosKey pk(p_x, p_y);
786
787 const Map<PosKey, Cell>::Element *E = tile_map.find(pk);
788
789 if (!E)
790 return false;
791
792 return E->get().flip_h;
793 }
is_cell_y_flipped(int p_x,int p_y) const794 bool TileMap::is_cell_y_flipped(int p_x, int p_y) const {
795
796 PosKey pk(p_x, p_y);
797
798 const Map<PosKey, Cell>::Element *E = tile_map.find(pk);
799
800 if (!E)
801 return false;
802
803 return E->get().flip_v;
804 }
is_cell_transposed(int p_x,int p_y) const805 bool TileMap::is_cell_transposed(int p_x, int p_y) const {
806
807 PosKey pk(p_x, p_y);
808
809 const Map<PosKey, Cell>::Element *E = tile_map.find(pk);
810
811 if (!E)
812 return false;
813
814 return E->get().transpose;
815 }
816
_recreate_quadrants()817 void TileMap::_recreate_quadrants() {
818
819 _clear_quadrants();
820
821 for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
822
823 PosKey qk(E->key().x / _get_quadrant_size(), E->key().y / _get_quadrant_size());
824
825 Map<PosKey, Quadrant>::Element *Q = quadrant_map.find(qk);
826 if (!Q) {
827 Q = _create_quadrant(qk);
828 dirty_quadrant_list.add(&Q->get().dirty_list);
829 }
830
831 Q->get().cells.insert(E->key());
832 _make_quadrant_dirty(Q);
833 }
834 }
835
_clear_quadrants()836 void TileMap::_clear_quadrants() {
837
838 while (quadrant_map.size()) {
839 _erase_quadrant(quadrant_map.front());
840 }
841 }
842
set_material(const Ref<CanvasItemMaterial> & p_material)843 void TileMap::set_material(const Ref<CanvasItemMaterial> &p_material) {
844
845 CanvasItem::set_material(p_material);
846 _update_all_items_material_state();
847 }
848
set_use_parent_material(bool p_use_parent_material)849 void TileMap::set_use_parent_material(bool p_use_parent_material) {
850
851 CanvasItem::set_use_parent_material(p_use_parent_material);
852 _update_all_items_material_state();
853 }
854
_update_all_items_material_state()855 void TileMap::_update_all_items_material_state() {
856
857 for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
858
859 Quadrant &q = E->get();
860 for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) {
861
862 _update_item_material_state(E->get());
863 }
864 }
865 }
866
_update_item_material_state(const RID & p_canvas_item)867 void TileMap::_update_item_material_state(const RID &p_canvas_item) {
868
869 VS::get_singleton()->canvas_item_set_use_parent_material(p_canvas_item, get_use_parent_material() || get_material().is_valid());
870 }
871
clear()872 void TileMap::clear() {
873
874 _clear_quadrants();
875 tile_map.clear();
876 used_size_cache_dirty = true;
877 }
878
_set_tile_data(const DVector<int> & p_data)879 void TileMap::_set_tile_data(const DVector<int> &p_data) {
880
881 int c = p_data.size();
882 DVector<int>::Read r = p_data.read();
883
884 for (int i = 0; i < c; i += 2) {
885
886 const uint8_t *ptr = (const uint8_t *)&r[i];
887 uint8_t local[8];
888 for (int j = 0; j < 8; j++)
889 local[j] = ptr[j];
890
891 #ifdef BIG_ENDIAN_ENABLED
892
893 SWAP(local[0], local[3]);
894 SWAP(local[1], local[2]);
895 SWAP(local[4], local[7]);
896 SWAP(local[5], local[6]);
897 #endif
898
899 int16_t x = decode_uint16(&local[0]);
900 int16_t y = decode_uint16(&local[2]);
901 uint32_t v = decode_uint32(&local[4]);
902 bool flip_h = v & (1 << 29);
903 bool flip_v = v & (1 << 30);
904 bool transpose = v & (1 << 31);
905 v &= (1 << 29) - 1;
906
907 // if (x<-20 || y <-20 || x>4000 || y>4000)
908 // continue;
909 set_cell(x, y, v, flip_h, flip_v, transpose);
910 }
911 }
912
_get_tile_data() const913 DVector<int> TileMap::_get_tile_data() const {
914
915 DVector<int> data;
916 data.resize(tile_map.size() * 2);
917 DVector<int>::Write w = data.write();
918
919 int idx = 0;
920 for (const Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
921
922 uint8_t *ptr = (uint8_t *)&w[idx];
923 encode_uint16(E->key().x, &ptr[0]);
924 encode_uint16(E->key().y, &ptr[2]);
925 uint32_t val = E->get().id;
926 if (E->get().flip_h)
927 val |= (1 << 29);
928 if (E->get().flip_v)
929 val |= (1 << 30);
930 if (E->get().transpose)
931 val |= (1 << 31);
932
933 encode_uint32(val, &ptr[4]);
934 idx += 2;
935 }
936
937 w = DVector<int>::Write();
938
939 return data;
940 }
941
get_item_rect() const942 Rect2 TileMap::get_item_rect() const {
943
944 const_cast<TileMap *>(this)->_update_dirty_quadrants();
945 return rect_cache;
946 }
947
set_collision_layer(uint32_t p_layer)948 void TileMap::set_collision_layer(uint32_t p_layer) {
949
950 collision_layer = p_layer;
951 for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
952
953 Quadrant &q = E->get();
954 for (int i = q.bodies.size() - 1; i >= 0; i--) {
955 Physics2DServer::get_singleton()->body_set_layer_mask(q.bodies[i], collision_layer);
956 }
957 }
958 }
959
set_collision_mask(uint32_t p_mask)960 void TileMap::set_collision_mask(uint32_t p_mask) {
961
962 collision_mask = p_mask;
963 for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
964
965 Quadrant &q = E->get();
966 for (int i = q.bodies.size() - 1; i >= 0; i--) {
967 Physics2DServer::get_singleton()->body_set_collision_mask(q.bodies[i], collision_mask);
968 }
969 }
970 }
971
set_collision_layer_bit(int p_bit,bool p_value)972 void TileMap::set_collision_layer_bit(int p_bit, bool p_value) {
973
974 uint32_t layer = get_collision_layer();
975 if (p_value)
976 layer |= 1 << p_bit;
977 else
978 layer &= ~(1 << p_bit);
979 set_collision_layer(layer);
980 }
981
set_collision_mask_bit(int p_bit,bool p_value)982 void TileMap::set_collision_mask_bit(int p_bit, bool p_value) {
983
984 uint32_t mask = get_collision_mask();
985 if (p_value)
986 mask |= 1 << p_bit;
987 else
988 mask &= ~(1 << p_bit);
989 set_collision_mask(mask);
990 }
991
get_collision_use_kinematic() const992 bool TileMap::get_collision_use_kinematic() const {
993
994 return use_kinematic;
995 }
996
set_collision_use_kinematic(bool p_use_kinematic)997 void TileMap::set_collision_use_kinematic(bool p_use_kinematic) {
998
999 _clear_quadrants();
1000 use_kinematic = p_use_kinematic;
1001 _recreate_quadrants();
1002 }
1003
set_collision_friction(float p_friction)1004 void TileMap::set_collision_friction(float p_friction) {
1005
1006 friction = p_friction;
1007 for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
1008
1009 Quadrant &q = E->get();
1010 for (int i = q.bodies.size() - 1; i >= 0; i--) {
1011 Physics2DServer::get_singleton()->body_set_param(q.bodies[i], Physics2DServer::BODY_PARAM_FRICTION, p_friction);
1012 }
1013 }
1014 }
1015
get_collision_friction() const1016 float TileMap::get_collision_friction() const {
1017
1018 return friction;
1019 }
1020
set_collision_bounce(float p_bounce)1021 void TileMap::set_collision_bounce(float p_bounce) {
1022
1023 bounce = p_bounce;
1024 for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
1025
1026 Quadrant &q = E->get();
1027 for (int i = q.bodies.size() - 1; i >= 0; i--) {
1028 Physics2DServer::get_singleton()->body_set_param(q.bodies[i], Physics2DServer::BODY_PARAM_BOUNCE, p_bounce);
1029 }
1030 }
1031 }
get_collision_bounce() const1032 float TileMap::get_collision_bounce() const {
1033
1034 return bounce;
1035 }
1036
get_collision_layer() const1037 uint32_t TileMap::get_collision_layer() const {
1038
1039 return collision_layer;
1040 }
1041
get_collision_mask() const1042 uint32_t TileMap::get_collision_mask() const {
1043
1044 return collision_mask;
1045 }
1046
get_collision_layer_bit(int p_bit) const1047 bool TileMap::get_collision_layer_bit(int p_bit) const {
1048
1049 return get_collision_layer() & (1 << p_bit);
1050 }
1051
get_collision_mask_bit(int p_bit) const1052 bool TileMap::get_collision_mask_bit(int p_bit) const {
1053
1054 return get_collision_mask() & (1 << p_bit);
1055 }
1056
set_mode(Mode p_mode)1057 void TileMap::set_mode(Mode p_mode) {
1058
1059 _clear_quadrants();
1060 mode = p_mode;
1061 _recreate_quadrants();
1062 emit_signal("settings_changed");
1063 }
1064
get_mode() const1065 TileMap::Mode TileMap::get_mode() const {
1066 return mode;
1067 }
1068
set_half_offset(HalfOffset p_half_offset)1069 void TileMap::set_half_offset(HalfOffset p_half_offset) {
1070
1071 _clear_quadrants();
1072 half_offset = p_half_offset;
1073 _recreate_quadrants();
1074 emit_signal("settings_changed");
1075 }
1076
set_tile_origin(TileOrigin p_tile_origin)1077 void TileMap::set_tile_origin(TileOrigin p_tile_origin) {
1078
1079 _clear_quadrants();
1080 tile_origin = p_tile_origin;
1081 _recreate_quadrants();
1082 emit_signal("settings_changed");
1083 }
1084
get_tile_origin() const1085 TileMap::TileOrigin TileMap::get_tile_origin() const {
1086
1087 return tile_origin;
1088 }
1089
get_cell_draw_offset() const1090 Vector2 TileMap::get_cell_draw_offset() const {
1091
1092 switch (mode) {
1093
1094 case MODE_SQUARE: {
1095
1096 return Vector2();
1097 } break;
1098 case MODE_ISOMETRIC: {
1099
1100 return Vector2(-cell_size.x * 0.5, 0);
1101
1102 } break;
1103 case MODE_CUSTOM: {
1104
1105 Vector2 min;
1106 min.x = MIN(custom_transform[0].x, min.x);
1107 min.y = MIN(custom_transform[0].y, min.y);
1108 min.x = MIN(custom_transform[1].x, min.x);
1109 min.y = MIN(custom_transform[1].y, min.y);
1110 return min;
1111 } break;
1112 }
1113
1114 return Vector2();
1115 }
1116
get_half_offset() const1117 TileMap::HalfOffset TileMap::get_half_offset() const {
1118 return half_offset;
1119 }
1120
get_cell_transform() const1121 Matrix32 TileMap::get_cell_transform() const {
1122
1123 switch (mode) {
1124
1125 case MODE_SQUARE: {
1126
1127 Matrix32 m;
1128 m[0] *= cell_size.x;
1129 m[1] *= cell_size.y;
1130 return m;
1131 } break;
1132 case MODE_ISOMETRIC: {
1133
1134 //isometric only makes sense when y is positive in both x and y vectors, otherwise
1135 //the drawing of tiles will overlap
1136 Matrix32 m;
1137 m[0] = Vector2(cell_size.x * 0.5, cell_size.y * 0.5);
1138 m[1] = Vector2(-cell_size.x * 0.5, cell_size.y * 0.5);
1139 return m;
1140
1141 } break;
1142 case MODE_CUSTOM: {
1143
1144 return custom_transform;
1145 } break;
1146 }
1147
1148 return Matrix32();
1149 }
1150
set_custom_transform(const Matrix32 & p_xform)1151 void TileMap::set_custom_transform(const Matrix32 &p_xform) {
1152
1153 _clear_quadrants();
1154 custom_transform = p_xform;
1155 _recreate_quadrants();
1156 emit_signal("settings_changed");
1157 }
1158
get_custom_transform() const1159 Matrix32 TileMap::get_custom_transform() const {
1160
1161 return custom_transform;
1162 }
1163
_map_to_world(int x,int y,bool p_ignore_ofs) const1164 Vector2 TileMap::_map_to_world(int x, int y, bool p_ignore_ofs) const {
1165
1166 Vector2 ret = get_cell_transform().xform(Vector2(x, y));
1167 if (!p_ignore_ofs) {
1168 switch (half_offset) {
1169
1170 case HALF_OFFSET_X: {
1171 if (ABS(y) & 1) {
1172
1173 ret += get_cell_transform()[0] * 0.5;
1174 }
1175 } break;
1176 case HALF_OFFSET_Y: {
1177 if (ABS(x) & 1) {
1178 ret += get_cell_transform()[1] * 0.5;
1179 }
1180 } break;
1181 default: {}
1182 }
1183 }
1184 return ret;
1185 }
map_to_world(const Vector2 & p_pos,bool p_ignore_ofs) const1186 Vector2 TileMap::map_to_world(const Vector2 &p_pos, bool p_ignore_ofs) const {
1187
1188 return _map_to_world(p_pos.x, p_pos.y, p_ignore_ofs);
1189 }
world_to_map(const Vector2 & p_pos) const1190 Vector2 TileMap::world_to_map(const Vector2 &p_pos) const {
1191
1192 Vector2 ret = get_cell_transform().affine_inverse().xform(p_pos);
1193
1194 switch (half_offset) {
1195
1196 case HALF_OFFSET_X: {
1197 if (ret.y > 0 ? int(ret.y) & 1 : (int(ret.y) - 1) & 1) {
1198 ret.x -= 0.5;
1199 }
1200 } break;
1201 case HALF_OFFSET_Y: {
1202 if (ret.x > 0 ? int(ret.x) & 1 : (int(ret.x) - 1) & 1) {
1203 ret.y -= 0.5;
1204 }
1205 } break;
1206 default: {}
1207 }
1208
1209 return ret.floor();
1210 }
1211
set_y_sort_mode(bool p_enable)1212 void TileMap::set_y_sort_mode(bool p_enable) {
1213
1214 _clear_quadrants();
1215 y_sort_mode = p_enable;
1216 VS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), y_sort_mode);
1217 _recreate_quadrants();
1218 emit_signal("settings_changed");
1219 }
1220
is_y_sort_mode_enabled() const1221 bool TileMap::is_y_sort_mode_enabled() const {
1222
1223 return y_sort_mode;
1224 }
1225
get_used_cells() const1226 Array TileMap::get_used_cells() const {
1227
1228 Array a;
1229 a.resize(tile_map.size());
1230 int i = 0;
1231 for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
1232
1233 Vector2 p(E->key().x, E->key().y);
1234 a[i++] = p;
1235 }
1236
1237 return a;
1238 }
1239
get_used_cells_by_id(int p_id) const1240 Array TileMap::get_used_cells_by_id(int p_id) const {
1241
1242 Array a;
1243 a.clear();
1244 for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
1245
1246 if (E->value().id == p_id) {
1247 Vector2 p(E->key().x, E->key().y);
1248 a.push_back(p);
1249 }
1250 }
1251
1252 return a;
1253 }
1254
get_used_rect()1255 Rect2 TileMap::get_used_rect() { // Not const because of cache
1256
1257 if (used_size_cache_dirty) {
1258 if (tile_map.size() > 0) {
1259 used_size_cache = Rect2(tile_map.front()->key().x, tile_map.front()->key().y, 0, 0);
1260
1261 for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
1262 used_size_cache.expand_to(Vector2(E->key().x, E->key().y));
1263 }
1264
1265 used_size_cache.size += Vector2(1, 1);
1266 } else {
1267 used_size_cache = Rect2();
1268 }
1269
1270 used_size_cache_dirty = false;
1271 }
1272
1273 return used_size_cache;
1274 }
1275
set_occluder_light_mask(int p_mask)1276 void TileMap::set_occluder_light_mask(int p_mask) {
1277
1278 occluder_light_mask = p_mask;
1279 for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
1280
1281 for (Map<PosKey, Quadrant::Occluder>::Element *F = E->get().occluder_instances.front(); F; F = F->next()) {
1282 VisualServer::get_singleton()->canvas_light_occluder_set_light_mask(F->get().id, occluder_light_mask);
1283 }
1284 }
1285 }
1286
get_occluder_light_mask() const1287 int TileMap::get_occluder_light_mask() const {
1288
1289 return occluder_light_mask;
1290 }
1291
set_light_mask(int p_light_mask)1292 void TileMap::set_light_mask(int p_light_mask) {
1293
1294 CanvasItem::set_light_mask(p_light_mask);
1295 for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
1296
1297 for (List<RID>::Element *F = E->get().canvas_items.front(); F; F = F->next()) {
1298 VisualServer::get_singleton()->canvas_item_set_light_mask(F->get(), get_light_mask());
1299 }
1300 }
1301 }
1302
_bind_methods()1303 void TileMap::_bind_methods() {
1304
1305 ObjectTypeDB::bind_method(_MD("set_tileset", "tileset:TileSet"), &TileMap::set_tileset);
1306 ObjectTypeDB::bind_method(_MD("get_tileset:TileSet"), &TileMap::get_tileset);
1307
1308 ObjectTypeDB::bind_method(_MD("set_mode", "mode"), &TileMap::set_mode);
1309 ObjectTypeDB::bind_method(_MD("get_mode"), &TileMap::get_mode);
1310
1311 ObjectTypeDB::bind_method(_MD("set_half_offset", "half_offset"), &TileMap::set_half_offset);
1312 ObjectTypeDB::bind_method(_MD("get_half_offset"), &TileMap::get_half_offset);
1313
1314 ObjectTypeDB::bind_method(_MD("set_custom_transform", "custom_transform"), &TileMap::set_custom_transform);
1315 ObjectTypeDB::bind_method(_MD("get_custom_transform"), &TileMap::get_custom_transform);
1316
1317 ObjectTypeDB::bind_method(_MD("set_cell_size", "size"), &TileMap::set_cell_size);
1318 ObjectTypeDB::bind_method(_MD("get_cell_size"), &TileMap::get_cell_size);
1319
1320 ObjectTypeDB::bind_method(_MD("_set_old_cell_size", "size"), &TileMap::_set_old_cell_size);
1321 ObjectTypeDB::bind_method(_MD("_get_old_cell_size"), &TileMap::_get_old_cell_size);
1322
1323 ObjectTypeDB::bind_method(_MD("set_quadrant_size", "size"), &TileMap::set_quadrant_size);
1324 ObjectTypeDB::bind_method(_MD("get_quadrant_size"), &TileMap::get_quadrant_size);
1325
1326 ObjectTypeDB::bind_method(_MD("set_tile_origin", "origin"), &TileMap::set_tile_origin);
1327 ObjectTypeDB::bind_method(_MD("get_tile_origin"), &TileMap::get_tile_origin);
1328
1329 ObjectTypeDB::bind_method(_MD("set_center_x", "enable"), &TileMap::set_center_x);
1330 ObjectTypeDB::bind_method(_MD("get_center_x"), &TileMap::get_center_x);
1331
1332 ObjectTypeDB::bind_method(_MD("set_center_y", "enable"), &TileMap::set_center_y);
1333 ObjectTypeDB::bind_method(_MD("get_center_y"), &TileMap::get_center_y);
1334
1335 ObjectTypeDB::bind_method(_MD("set_y_sort_mode", "enable"), &TileMap::set_y_sort_mode);
1336 ObjectTypeDB::bind_method(_MD("is_y_sort_mode_enabled"), &TileMap::is_y_sort_mode_enabled);
1337
1338 ObjectTypeDB::bind_method(_MD("set_collision_use_kinematic", "use_kinematic"), &TileMap::set_collision_use_kinematic);
1339 ObjectTypeDB::bind_method(_MD("get_collision_use_kinematic"), &TileMap::get_collision_use_kinematic);
1340
1341 ObjectTypeDB::bind_method(_MD("set_collision_layer", "layer"), &TileMap::set_collision_layer);
1342 ObjectTypeDB::bind_method(_MD("get_collision_layer"), &TileMap::get_collision_layer);
1343
1344 ObjectTypeDB::bind_method(_MD("set_collision_mask", "mask"), &TileMap::set_collision_mask);
1345 ObjectTypeDB::bind_method(_MD("get_collision_mask"), &TileMap::get_collision_mask);
1346
1347 ObjectTypeDB::bind_method(_MD("set_collision_layer_bit", "bit", "value"), &TileMap::set_collision_layer_bit);
1348 ObjectTypeDB::bind_method(_MD("get_collision_layer_bit", "bit"), &TileMap::get_collision_layer_bit);
1349
1350 ObjectTypeDB::bind_method(_MD("set_collision_mask_bit", "bit", "value"), &TileMap::set_collision_mask_bit);
1351 ObjectTypeDB::bind_method(_MD("get_collision_mask_bit", "bit"), &TileMap::get_collision_mask_bit);
1352
1353 ObjectTypeDB::bind_method(_MD("set_collision_friction", "value"), &TileMap::set_collision_friction);
1354 ObjectTypeDB::bind_method(_MD("get_collision_friction"), &TileMap::get_collision_friction);
1355
1356 ObjectTypeDB::bind_method(_MD("set_collision_bounce", "value"), &TileMap::set_collision_bounce);
1357 ObjectTypeDB::bind_method(_MD("get_collision_bounce"), &TileMap::get_collision_bounce);
1358
1359 ObjectTypeDB::bind_method(_MD("set_occluder_light_mask", "mask"), &TileMap::set_occluder_light_mask);
1360 ObjectTypeDB::bind_method(_MD("get_occluder_light_mask"), &TileMap::get_occluder_light_mask);
1361
1362 ObjectTypeDB::bind_method(_MD("set_cell", "x", "y", "tile", "flip_x", "flip_y", "transpose"), &TileMap::set_cell, DEFVAL(false), DEFVAL(false), DEFVAL(false));
1363 ObjectTypeDB::bind_method(_MD("set_cellv", "pos", "tile", "flip_x", "flip_y", "transpose"), &TileMap::set_cellv, DEFVAL(false), DEFVAL(false), DEFVAL(false));
1364 ObjectTypeDB::bind_method(_MD("get_cell", "x", "y"), &TileMap::get_cell);
1365 ObjectTypeDB::bind_method(_MD("get_cellv", "pos"), &TileMap::get_cellv);
1366 ObjectTypeDB::bind_method(_MD("is_cell_x_flipped", "x", "y"), &TileMap::is_cell_x_flipped);
1367 ObjectTypeDB::bind_method(_MD("is_cell_y_flipped", "x", "y"), &TileMap::is_cell_y_flipped);
1368 ObjectTypeDB::bind_method(_MD("is_cell_transposed", "x", "y"), &TileMap::is_cell_transposed);
1369
1370 ObjectTypeDB::bind_method(_MD("clear"), &TileMap::clear);
1371
1372 ObjectTypeDB::bind_method(_MD("get_used_cells"), &TileMap::get_used_cells);
1373 ObjectTypeDB::bind_method(_MD("get_used_cells_by_id", "id"), &TileMap::get_used_cells_by_id);
1374 ObjectTypeDB::bind_method(_MD("get_used_rect"), &TileMap::get_used_rect);
1375
1376 ObjectTypeDB::bind_method(_MD("map_to_world", "mappos", "ignore_half_ofs"), &TileMap::map_to_world, DEFVAL(false));
1377 ObjectTypeDB::bind_method(_MD("world_to_map", "worldpos"), &TileMap::world_to_map);
1378
1379 ObjectTypeDB::bind_method(_MD("_clear_quadrants"), &TileMap::_clear_quadrants);
1380 ObjectTypeDB::bind_method(_MD("_recreate_quadrants"), &TileMap::_recreate_quadrants);
1381 ObjectTypeDB::bind_method(_MD("_update_dirty_quadrants"), &TileMap::_update_dirty_quadrants);
1382
1383 ObjectTypeDB::bind_method(_MD("_set_tile_data"), &TileMap::_set_tile_data);
1384 ObjectTypeDB::bind_method(_MD("_get_tile_data"), &TileMap::_get_tile_data);
1385
1386 ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Square,Isometric,Custom"), _SCS("set_mode"), _SCS("get_mode"));
1387 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), _SCS("set_tileset"), _SCS("get_tileset"));
1388 ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_size", PROPERTY_HINT_RANGE, "1,8192,1", 0), _SCS("_set_old_cell_size"), _SCS("_get_old_cell_size"));
1389 ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cell/size", PROPERTY_HINT_RANGE, "1,8192,1"), _SCS("set_cell_size"), _SCS("get_cell_size"));
1390 ADD_PROPERTY(PropertyInfo(Variant::INT, "cell/quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), _SCS("set_quadrant_size"), _SCS("get_quadrant_size"));
1391 ADD_PROPERTY(PropertyInfo(Variant::MATRIX32, "cell/custom_transform"), _SCS("set_custom_transform"), _SCS("get_custom_transform"));
1392 ADD_PROPERTY(PropertyInfo(Variant::INT, "cell/half_offset", PROPERTY_HINT_ENUM, "Offset X,Offset Y,Disabled"), _SCS("set_half_offset"), _SCS("get_half_offset"));
1393 ADD_PROPERTY(PropertyInfo(Variant::INT, "cell/tile_origin", PROPERTY_HINT_ENUM, "Top Left,Center,Bottom Left"), _SCS("set_tile_origin"), _SCS("get_tile_origin"));
1394 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell/y_sort"), _SCS("set_y_sort_mode"), _SCS("is_y_sort_mode_enabled"));
1395 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision/use_kinematic", PROPERTY_HINT_NONE, ""), _SCS("set_collision_use_kinematic"), _SCS("get_collision_use_kinematic"));
1396 ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/friction", PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_collision_friction"), _SCS("get_collision_friction"));
1397 ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_collision_bounce"), _SCS("get_collision_bounce"));
1398 ADD_PROPERTY(PropertyInfo(Variant::INT, "collision/layers", PROPERTY_HINT_ALL_FLAGS), _SCS("set_collision_layer"), _SCS("get_collision_layer"));
1399 ADD_PROPERTY(PropertyInfo(Variant::INT, "collision/mask", PROPERTY_HINT_ALL_FLAGS), _SCS("set_collision_mask"), _SCS("get_collision_mask"));
1400 ADD_PROPERTY(PropertyInfo(Variant::INT, "occluder/light_mask", PROPERTY_HINT_ALL_FLAGS), _SCS("set_occluder_light_mask"), _SCS("get_occluder_light_mask"));
1401
1402 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), _SCS("_set_tile_data"), _SCS("_get_tile_data"));
1403
1404 ADD_SIGNAL(MethodInfo("settings_changed"));
1405
1406 BIND_CONSTANT(INVALID_CELL);
1407 BIND_CONSTANT(MODE_SQUARE);
1408 BIND_CONSTANT(MODE_ISOMETRIC);
1409 BIND_CONSTANT(MODE_CUSTOM);
1410 BIND_CONSTANT(HALF_OFFSET_X);
1411 BIND_CONSTANT(HALF_OFFSET_Y);
1412 BIND_CONSTANT(HALF_OFFSET_DISABLED);
1413 BIND_CONSTANT(TILE_ORIGIN_TOP_LEFT);
1414 BIND_CONSTANT(TILE_ORIGIN_CENTER);
1415 BIND_CONSTANT(TILE_ORIGIN_BOTTOM_LEFT);
1416 }
1417
TileMap()1418 TileMap::TileMap() {
1419
1420 rect_cache_dirty = true;
1421 used_size_cache_dirty = true;
1422 pending_update = false;
1423 quadrant_order_dirty = false;
1424 quadrant_size = 16;
1425 cell_size = Size2(64, 64);
1426 center_x = false;
1427 center_y = false;
1428 collision_layer = 1;
1429 collision_mask = 1;
1430 friction = 1;
1431 bounce = 0;
1432 mode = MODE_SQUARE;
1433 half_offset = HALF_OFFSET_DISABLED;
1434 use_kinematic = false;
1435 navigation = NULL;
1436 y_sort_mode = false;
1437 occluder_light_mask = 1;
1438
1439 fp_adjust = 0.00001;
1440 tile_origin = TILE_ORIGIN_TOP_LEFT;
1441 }
1442
~TileMap()1443 TileMap::~TileMap() {
1444
1445 clear();
1446 }
1447