Sorry it looks like I also need help pasting code the right way. I copied from godot's editor, clicked on "insert code" button here and pasted the code but it lost the identation for some reason.
Trying to detect if the user clicked on a drawing but failing miserably.
- Edited
Place ~~~ on a line before and after the code to display it properly here. That's more reliable than using the insert-code widget.
DaveTheCoder three of them or just one?
- Edited
Three.
Then shalt thou count to three, no more no less. Three shalt be the number thou shalt count, and the number of the counting shalt be three. Four shalt thou not count, neither count thou two, excepting that thou then proceed to three.
- Edited
- Best Answerset by Denxel
How about something like this:
extends AnimatedSprite
const HIT_ALPHA_THRESHOLD = .1
func mouse_hit():
# get mouse local position (in sprite's local space)
var pos = get_local_mouse_position()
# get current frame texture and its size
var texture = frames.get_frame(animation, frame)
var size = texture.get_size()
# adjust local position if sprite is centered or flipped
if centered:
pos = pos + size*.5
if flip_v:
pos.y = size.y - pos.y
if flip_h:
pos.x = size.x - pos.x
# check if mouse position is out of sprite's texture bounds
if pos.x < 0 or pos.x >= size.x or pos.y < 0 or pos.y >= size.y:
return false
# read the pixel under mouse from image data
var img = texture.get_data()
img.lock()
var alpha = img.get_pixel(pos.x, pos.y).a
img.unlock()
# check if pixel is opaque
return alpha > HIT_ALPHA_THRESHOLD
func _process(delta):
if mouse_hit():
print("hit")
else:
print("miss")
There's no reason to check pixel positions manually. Place an Area2D in the node and just check for collision with that.
cybereality Sadly I need precision, the drawing I want to detect is too complex, changes each frame and has many different animations, so if I'm able to get the pixel detection working, it would be nice.
xyz
Alright that's it! Honor! Honor on your whole family. Make a note of this. Honor on you, honor on your cow...
It worked flawlesly and I'm loving it. Now even if add a new enemy, a new animation, flip it, scale it, lick it, put it on fire and throw it out of the window, it's still being detected. Thank you.
- Edited
Denxel With great power comes great responsibility, so use this wisely
But seriously, what @cybereality said; it's better to use colliders in most cases. For the player, pixel perfect collisions often feel too strict and possibly annoying. Well placed colliders with some margin for mistakes make interactions more forgiving.
If you simply must go pixel perfect... well then, my cows shall take note of honors bestowed upon them
- Edited
xyz Hi again! Your solution worked perfectly. But now I'm porting this little game to Godot 4 and I'm getting an error that I can't solve. So far I solved everything until this part:
# read the pixel under mouse from image data
var img = texture.get_data() ------> **error: Invalid get index 'get_data' (on base: 'CompressedTexture2D').**
img.lock()
var alpha = img.get_pixel(pos.x, pos.y).a
img.unlock()
The object was previously StreamTexture running your code on Godot 3.5, but now it is CompressedTexture2D on Godot 4, and that seems to cause the error. I should mention that I had to fix the part that gets the texture because it gives an error in Godot 4:
I had to change this:
# get current frame texture and its size
var texture = frames.get_frame(animation, frame)
For this:
var texture = sprite_frames.get_frame_texture(animation, frame)
Denxel okay I solved it! In case someone ends here looking for the solution, what I did was changing this lines:
var img = texture.get_data()
img.lock()
var alpha = img.get_pixel(pos.x, pos.y).a
img.unlock()
for this:
var img = texture.get_image()
var alpha = img.get_pixel(pos.x, pos.y).a
So basically removing the lock and unlock (not needed in G4) and geting the image through get_image() instead of get_data().