xiandie/scene/entity/ux/刮刮乐mask.gd

97 lines
2.5 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@tool
extends TextureRect
signal shaven(progress: float)
@export var area_size := Vector2(40, 20):
set(val):
area_size = val
custom_minimum_size = val
if is_node_ready():
_init_bit_mask()
@export var debug_reload := false:
set(val):
debug_reload = false
if is_node_ready():
_init_bit_mask()
# points inside radius 5 circle
var brush_points := generate_brush_points(5)
var bit_mask: BitMap
func _ready() -> void:
# init bit mask
_init_bit_mask()
# a solid circle brush, center = (0, 0)
func generate_brush_points(radius: int) -> PackedVector2Array:
var points := PackedVector2Array()
# Check each pixel in square area
for x in range(-radius, radius + 1):
for y in range(-radius, radius + 1):
# If point is within circle radius
if x * x + y * y <= radius * radius:
points.append(Vector2(x, y))
return points
func _init_bit_mask() -> void:
if not bit_mask:
bit_mask = BitMap.new()
bit_mask.create(area_size)
texture = ImageTexture.create_from_image(bit_mask.convert_to_image())
func _shave(mouse_pos: Vector2) -> void:
if not mouse_pressing:
return
var updated = false
for point in brush_points:
var pos = mouse_pos + point
if pos.x < 0 or pos.x >= area_size.x or pos.y < 0 or pos.y >= area_size.y:
continue
bit_mask.set_bitv(pos, true)
updated = true
texture.update(bit_mask.convert_to_image())
if updated:
_send_signal()
func _send_signal() -> void:
var total = area_size.x * area_size.y
var true_bit_count = bit_mask.get_true_bit_count()
var progress = float(true_bit_count) / float(total)
shaven.emit(progress)
var mouse_pressing = false
# 可以刮出区域
func _gui_input(event: InputEvent) -> void:
# 通过鼠标点击拖动刮开区域set_bit 一个 brush_size 的圆形区域为 true
# 每次更新后bit_mask 会更新到 texture 上
# 通过 shaven 信号,通知外部,刮开了多少区域
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
# 先设置 mouse_pressing 为 true
mouse_pressing = true
# 刮开区域
_shave(event.position)
accept_event()
elif event.button_index == MOUSE_BUTTON_LEFT and not event.pressed:
mouse_pressing = false
accept_event()
elif event is InputEventMouseMotion and mouse_pressing:
_shave(event.position)
accept_event()
# elif event is InputEventScreenTouch:
# if event.pressed:
# mouse_pressing = true
# _shave(event.position)
# accept_event()
# elif not event.pressed:
# mouse_pressing = false
# accept_event()