Irregular texture rects?

Godot 4.4

Is there a way for a TextureRect to take up an irregular area?

I am attempting to make clickable objects that visually overlap with one another. I initially tried to use Area2Ds and collision shapes, however, if one area is clicked, the area behind it is also clicked. Control nodes and TextureRects seem like better options for layering, but are inconvenient for irregularly-shaped objects. Is there a way to create an irregularly-shaped TextureRect?

You can override _has_point and check for areas that should be ignored, you can then check the opacity of the texture (if it supports it)

Would I override functions in a “_ready” function?

This isn’t functional code, but I feel like I’m getting at the right idea:

func _ready() -> void:
	$Pipe.has_point(point)
		var point = $Pipe.texture.opacity

I’m not sure how the opacity variable is stored. The texture is a transparent PNG, so checking the opacity should work out.

No you override it like you override _ready, but in the texture rect, in a new script for it

Something more similar to this?

extends TextureRect

func _has_point(point: Vector2) -> bool:
	Vector2 = texture.has_alpha()
1 Like

It would be return has_alpha but yes, you can check using different methods on Image from texture.get_image

This gives me an “Invalid access to property or key ‘has_alpha’ on a base object of type ‘image’.” error, so I don’t think I’m calling the alpha correctly

extends TextureRect

func _has_point(point: Vector2) -> bool:
	return texture.get_image().has_alpha

You should probably use texture..get_image().get_pixelv(point).a > 0.0 or some similar threshold, you’re not calling a method here

Should I use an “if” statement to check for the alpha?

extends TextureRect

func _has_point(point: Vector2) -> bool:
	if texture.has_alpha() == true:
		return texture.get_image().get_pixelv(point).a > 0.0

Sounds good, I’d also check that texture.get_image() is valid with an if statement too

I have a “Not all code paths return a value” error at the func line of my current code

Yes, add a return false at the end

The code doesn’t trigger errors anymore, but now the object attached doesn’t react to anything.

extends TextureRect

func _has_point(point: Vector2) -> bool:
	if texture.has_alpha() == true:
		return texture.get_image().get_pixelv(point).a > 0.0
	return false

I tried keeping the original code in the control node:

extends Control

var pipe_base = preload("res://sprites/placeholder_sprites/pipe.png")
var pipe_outline = preload("res://sprites/placeholder_sprites/outlined/pipe_outline.png")

func _on_pipe_mouse_entered() -> void:
	$Pipe.texture = pipe_outline

func _on_pipe_mouse_exited() -> void:
	$Pipe.texture = pipe_base

func _on_pipe_gui_input(event: InputEvent) -> void:
	if event.is_action_pressed("click"):
		if Global.UMBRELLA == true:
			print("The umbrella shields the door. The door is safeguarded")
			$"../UmbrellaOpen".visible = true
			Global.SAFEGUARDED = true
		else:
			print("The pipe is unsecure")

and adding it to the TextureRect node:

extends TextureRect

func _has_point(point: Vector2) -> bool:
	if texture.has_alpha() == true:
		return texture.get_image().get_pixelv(point).a > 0.0
	return false

var pipe_base = preload("res://sprites/placeholder_sprites/pipe.png")
var pipe_outline = preload("res://sprites/placeholder_sprites/outlined/pipe_outline.png")

func _on_mouse_entered() -> void:
	$Pipe.texture = pipe_outline

func _on_mouse_exited() -> void:
	$Pipe.texture = pipe_base


func _on_gui_input(event: InputEvent) -> void:
	if event.is_action_pressed("click"):
		if Global.UMBRELLA == true:
			print("The umbrella shields the door. The door is safeguarded")
			$"../UmbrellaOpen".visible = true
			Global.SAFEGUARDED = true
		else:
			print("The pipe is unsecure")

Then the texture probably doesn’t support alpha, or doesn’t support reading the alpha, so you’d need to solve it by some other way, can’t really help further with that

You could try removing the has_alpha check as it might give false results, and see if that helps