How to make a texture erase effect (image)?

Godot Version



There are 2 images A and B. Image A is the front, B is the background. We need to make the effect of erasing image A to see the background. The project is being developed for mobile devices so the use of shaders should be avoided.

I managed to partially replicate this effect, but it is done in a very strange way.

In the CanvasItem class there is a method Clip Children. If we move the background (image B) forward and set it as a Line2D child node with the ClipChildren parameter enabled, we will get almost what we need.

Project structure

Further drawing Line2D line you display images B. But this is a very strange and impractical solution, because in fact you do not erase images A, but adjust images B on top of A and cut along the Line2D contour. Is there any way to do it simpler and more correct? Help please .

This actually is the best way of doing that, so maybe try simplifying your code.

If you -truly- want to erase the image, and I mean pixel by pixel, here is a solution I created years ago to render actual holes in a texture. Calling this repeatedly on mouse position would create a line, it cant be too thick though, for performance reasons:

extends Node2D

var planet_image
var planet_texture

# interactions
var hardness = 10 # planet hardness, changes hole radius
func laser_impact(point, blast, damage, res_yield): calc_radius(point, int(blast/(hardness/4))+2)
func bullet_impact(point, damage, res_yield): calc_radius(point, 7)
func rocket_impact(point, blast, damage, res_yield): calc_radius(point, int(blast/(hardness/5))*5+7)

func render_specific(texturefile):
	for b in $bullets.get_children(): b.flying = false
	planet_image =
	planet_image = texturefile

func instance_new_planet():
	planet_image =
#	planet_image = $images.get_node(pl.planet).texture.get_data() # the "$images.get_node(pl.planet) just gets the right planet for the texture

func render_planet():
	for b in $bullets.get_children(): b.flying = false
	planet_texture =
	$Sprite.texture = planet_texture

func calc_radius(point, r): # hitpoint position ON THE SPRITE starting from left upper corner as (0,0)
	finish_calc_circle(run_circle(r, point))

func run_circle(r, point):
	# complicated math to get every single pixel in the circle
	var out = []
	var t1 = r / 16
	var x = r
	var y = 0
	while x >= y:
		out += get_related_pixels(x, y, point)
		y = y + 1
		t1 = t1 + y
		var t2 = t1 - x
		if t2 >= 0:
			t1 = t2
			x = x - 1
	return out

var related_out = []
func get_related_pixels(x, y, point):
	related_out = []
	for ix in range(-x, x): add_pixel(Vector2(ix, y)+point)
	for ix in range(-x, x): add_pixel(Vector2(ix, -y)+point)
	for ix in range(-x, x): add_pixel(Vector2(y, ix)+point)
	for ix in range(-x, x): add_pixel(Vector2(-y, ix)+point)
	return related_out

func add_pixel(vec):
	if related_out.has(vec): return
	if get_pix(vec).a > 0: related_out.append(vec)
func get_pix(vec):
	if planet_image and vec.x > 0 and vec.x < 1080 and vec.y > 0 and vec.y < 1080: return planet_image.get_pixelv(vec)
	return Color(0, 0, 0, 0)

func finish_calc_circle(out):
	var ressources_mined = 0
	removed_pixels = []
	for v in out: remove_pixel(v)
	planet_texture.create_from_image(planet_image) # updates the texture to be with the hole
#	if invisible(): go_to_next_planet() # checks if 99.9% of the image is gone, starting with the middle and going out logarithmically to save performance

var removed_pixels = []
func remove_pixel(pos):
	if pos in removed_pixels: return
	# sets pixel to invisible
	planet_image.set_pixelv(pos, Color(0, 0, 0, 0))

# invisible calculations, complicated
const x_start_array = [540,480,360,600,360,360,720,240,240,240,840,60,240,240,840,60,840,60,0,0,60,1020]
const x_stop_array = [541,600,480,720,720,720,840,360,840,840,1020,240,840,840,1020,240,1020,240,1020,60,1080,1080]
const y_start_array = [540,480,480,480,360,600,360,360,240,720,240,240,840,60,840,840,60,60,0,60,1020,0]
const y_stop_array = [600,600,600,600,480,720,720,720,360,840,840,840,1020,240,1020,1020,240,240,60,1080,1080,1020]
func invisible():
	var runs = 0
	var total_alpha = 0
	while runs < x_start_array.size():
		var alphas = get_pixel_alpha(x_start_array[runs], x_stop_array[runs], y_start_array[runs], y_stop_array[runs])
		if alphas/(((x_stop_array[runs]-x_start_array[runs])*(y_stop_array[runs]-y_start_array[runs]))) > 0.2/(runs*15+1): return false
		total_alpha += alphas
		runs += 1
	if total_alpha/1166400 > 0.0005: return false
	else: return true
func get_pixel_alpha(x_start, x_stop, y_start, y_stop):
	var total_alpha = 0
	for x in range(x_start, x_stop):
		for y in range(y_start, y_stop):
			total_alpha += get_pix(Vector2(x, y)).a
	return total_alpha

func _notification(what: int) -> void: if what == NOTIFICATION_WM_QUIT_REQUEST: data.save_planet(planet_image)

Sorry if the comments arent that good, its just a copypaste from my project