@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()