Skip to content

Instantly share code, notes, and snippets.

@Technohacker
Last active March 13, 2021 18:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Technohacker/9c1e28c8fec5ce6e85fc8c43f3346225 to your computer and use it in GitHub Desktop.
Save Technohacker/9c1e28c8fec5ce6e85fc8c43f3346225 to your computer and use it in GitHub Desktop.
A script that removes borders when two autotiles mesh together
# The MIT License
#
# Copyright (c) 2021 Kevin Kuriakose (Technohacker)
#
# Permission is hereby granted, free of charge,
# to any person obtaining a copy of this software and
# associated documentation files (the "Software"), to
# deal in the Software without restriction, including
# without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom
# the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
extends TileMap
var state = null
#func _input(event: InputEvent) -> void:
# if event.is_action_pressed("ui_down", true):
# if state != null:
# state = state.resume()
# else:
# state = step()
func _ready() -> void:
var start = OS.get_system_time_msecs()
state = step()
while state != null:
state = state.resume()
print(OS.get_system_time_msecs() - start)
func step():
# Keep track of cumulative bitmask application so we don't lose intermediate bitmasks
# by invalid autotile configurations
var changed_bitmasks = {}
# Loop through the tilemap
for x in 32:
var last_tile = get_cell(x, 0);
var tile_exteriors_stack = [];
for y in 32:
var current_cell = get_cell(x, y)
var cell_coords = Vector2(x, y)
if current_cell != INVALID_CELL && current_cell != last_tile:
if tile_exteriors_stack.back() == current_cell:
# Returning to exterior. Adjust tiles around the last interior tile and pop this exterior
cell_coords.y -= 1;
while !tile_exteriors_stack.empty() && tile_exteriors_stack.pop_back() != current_cell:
pass
else:
# New layer created. Adjust tiles around the new tile
tile_exteriors_stack.push_back(last_tile)
# Get all necessary bitflips
if current_cell != last_tile || tile_exteriors_stack.size() > 0:
var bitflips = adjust_around_cell(cell_coords)
for row in bitflips.size():
for col in bitflips[row].size():
# convert from 0..2 to -1..1
var direction = Vector2(col - 1, row - 1)
var border_pos = cell_coords + direction
var border_cell = get_cell(border_pos.x, border_pos.y)
var border_autocoord = get_cell_autotile_coord(border_pos.x, border_pos.y)
# Store the initial bitmask
if !changed_bitmasks.has(border_pos):
changed_bitmasks[border_pos] = tile_set.autotile_get_bitmask(border_cell, border_autocoord)
# print("Before\tAfter")
# var before = bitmask_to_ascii(changed_bitmasks[border_pos])
# Apply the bitmask
changed_bitmasks[border_pos] |= bitflips[row][col]
# var after = bitmask_to_ascii(changed_bitmasks[border_pos])
# for i in 3:
# print(before[i] + "\t\t" + after[i])
# Search for the corresponding autotile sub-tile
var subtile_range = tile_set.tile_get_region(border_cell).size / tile_set.autotile_get_size(border_cell)
yield(move_debug_icon(border_pos), "completed");
for x_sub in subtile_range.x:
for y_sub in subtile_range.y:
if tile_set.autotile_get_bitmask(border_cell, Vector2(x_sub, y_sub)) == changed_bitmasks[border_pos]:
# Set it
set_cell(border_pos.x, border_pos.y, border_cell, false, false, false, Vector2(x_sub, y_sub))
break
last_tile = current_cell
func move_debug_icon(pos):
$icon.position = map_to_world(pos)
yield()
func bitmask_to_ascii(bitmask):
var map = []
for c in 3:
var row = ""
for r in 3:
var mask = 1 << (3 * c + r)
if bitmask & mask == 0:
row += "."
else:
row += "#"
map.append(row)
return map
func adjust_around_cell(cell_position: Vector2) -> Array:
# Get the current cell
var cell = get_cell(cell_position.x, cell_position.y)
# Get the bitmask
var autocoord = get_cell_autotile_coord(cell_position.x, cell_position.y)
var cell_bitmask = tile_set.autotile_get_bitmask(cell, autocoord)
var bitflips = []
# Loop through the bits of the bitmask and find out which ones are zero
for row in 3:
var cols = []
for col in 3:
var mask = 1 << (3 * row + col)
var toggle_mask = 0
if cell_bitmask & mask == 0:
# Add the required bitflips. Generally it's the opposite edge/corner that's flipped
match mask:
TileSet.BIND_TOPLEFT:
toggle_mask = TileSet.BIND_BOTTOMRIGHT
TileSet.BIND_TOP:
toggle_mask = TileSet.BIND_BOTTOMRIGHT | TileSet.BIND_BOTTOM | TileSet.BIND_BOTTOMLEFT
TileSet.BIND_TOPRIGHT:
toggle_mask = TileSet.BIND_BOTTOMLEFT
TileSet.BIND_LEFT:
toggle_mask = TileSet.BIND_TOPRIGHT | TileSet.BIND_RIGHT | TileSet.BIND_BOTTOMRIGHT
# No center
TileSet.BIND_RIGHT:
toggle_mask = TileSet.BIND_TOPLEFT | TileSet.BIND_LEFT | TileSet.BIND_BOTTOMLEFT
TileSet.BIND_BOTTOMLEFT:
toggle_mask = TileSet.BIND_TOPRIGHT
TileSet.BIND_BOTTOM:
toggle_mask = TileSet.BIND_TOPRIGHT | TileSet.BIND_TOP | TileSet.BIND_TOPLEFT
TileSet.BIND_BOTTOMRIGHT:
toggle_mask = TileSet.BIND_TOPLEFT
cols.append(toggle_mask)
bitflips.append(cols)
return bitflips
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment