134 lines
3.9 KiB
GDScript
134 lines
3.9 KiB
GDScript
@tool
|
|
class_name GrassMultiMesh extends MultiMeshInstance2D
|
|
|
|
@export_group("Visuals")
|
|
@export var texture_sheet : Texture2D
|
|
@export var blade_size : Vector2 = Vector2(16, 16)
|
|
@export var texture_sheet_size : Vector2 = Vector2(64, 16)
|
|
@export var grass_tint : Color
|
|
|
|
@export_group("Editor")
|
|
@export var editing : bool = false
|
|
@export var brush_radius : float = 50.0
|
|
@export var brush_density : int = 5
|
|
|
|
@export var grass_data : Array[Dictionary] = []
|
|
|
|
enum GrassState {NORMAL = 0, CUT = 1}
|
|
|
|
func _ready() -> void:
|
|
if not multimesh:
|
|
multimesh = MultiMesh.new()
|
|
multimesh.transform_format = MultiMesh.TRANSFORM_2D
|
|
multimesh.use_colors = true
|
|
multimesh.use_custom_data = true
|
|
|
|
multimesh.mesh = _create_mesh_rect()
|
|
|
|
if material is ShaderMaterial:
|
|
material.set_shader_parameter("frame_size", blade_size)
|
|
material.set_shader_parameter("sheet_size", texture_sheet_size)
|
|
|
|
_rebuild_multimesh()
|
|
|
|
func _process(_delta):
|
|
# move_grass_away(%Player.global_position, 25)
|
|
if editing and Engine.is_editor_hint():
|
|
if Input.is_key_pressed(KEY_K):
|
|
_brush_paint()
|
|
if Input.is_key_pressed(KEY_E):
|
|
_brush_erase()
|
|
queue_redraw()
|
|
|
|
func cut_grass_at(pos: Vector2, radius: float):
|
|
_interact_with_grass(pos, radius, GrassState.CUT)
|
|
|
|
func move_grass_away(pos: Vector2, radius: float):
|
|
var half = radius / 2
|
|
var local_target = to_local(pos)
|
|
for i in range(multimesh.instance_count):
|
|
var t = multimesh.get_instance_transform_2d(i)
|
|
var dist = t.origin.distance_squared_to(local_target)
|
|
if dist < half * half:
|
|
var custom_data = multimesh.get_instance_custom_data(i)
|
|
|
|
custom_data.r = (t.origin.x - local_target.x) * 2
|
|
|
|
multimesh.set_instance_custom_data(i, custom_data)
|
|
elif dist < radius * radius:
|
|
var custom_data = multimesh.get_instance_custom_data(i)
|
|
|
|
custom_data.r = grass_data[i]["rot"]
|
|
|
|
multimesh.set_instance_custom_data(i, custom_data)
|
|
|
|
func _interact_with_grass(global_target_pos: Vector2, radius: float, new_state: int):
|
|
var local_target = to_local(global_target_pos)
|
|
for i in range(multimesh.instance_count):
|
|
var t = multimesh.get_instance_transform_2d(i)
|
|
|
|
if t.origin.distance_squared_to(local_target) < radius * radius:
|
|
var custom_data = multimesh.get_instance_custom_data(i)
|
|
|
|
if int(custom_data.b) == new_state:
|
|
continue
|
|
|
|
custom_data.b = float(new_state)
|
|
|
|
multimesh.set_instance_custom_data(i, custom_data)
|
|
grass_data[i]["state"] = new_state
|
|
|
|
func _create_mesh_rect() -> QuadMesh:
|
|
var mesh = QuadMesh.new()
|
|
mesh.size = blade_size
|
|
return mesh
|
|
|
|
func _rebuild_multimesh() -> void:
|
|
multimesh.instance_count = grass_data.size()
|
|
var pivot_offset = Vector2(0, -blade_size.y / 2.0)
|
|
|
|
for i in range(grass_data.size()):
|
|
var d = grass_data[i]
|
|
var xform = Transform2D().translated(d.pos).rotated(d.get("rot", 0.0)).translated(pivot_offset)
|
|
|
|
multimesh.set_instance_transform_2d(i, xform)
|
|
multimesh.set_instance_color(i, grass_tint)
|
|
|
|
var custom = Color(
|
|
randf(),
|
|
float(d.get("tex_idx", 0)),
|
|
float(d.get("state", 0)),
|
|
0.0
|
|
)
|
|
multimesh.set_instance_custom_data(i, custom)
|
|
|
|
func _brush_paint() -> void:
|
|
var s = Time.get_ticks_msec()
|
|
print(s)
|
|
seed(s)
|
|
var mouse_pos = get_local_mouse_position()
|
|
for i in range(brush_density):
|
|
var angle = randf() * TAU
|
|
var rad = sqrt(randf()) * brush_radius
|
|
var pos = mouse_pos + Vector2(cos(angle), sin(angle)) * rad
|
|
|
|
var new_blade = {
|
|
"pos": pos,
|
|
"tex_idx": int((randf() ** (1.0/3.0)) * 8),
|
|
"state": GrassState.NORMAL,
|
|
"rot": randf_range(-0.1, 0.1)
|
|
}
|
|
grass_data.append(new_blade)
|
|
|
|
_rebuild_multimesh()
|
|
|
|
func _brush_erase() -> void:
|
|
var mouse_pos = get_local_mouse_position()
|
|
for i in range(grass_data.size() - 1, -1, -1):
|
|
if grass_data[i].pos.distance_to(mouse_pos) < brush_radius:
|
|
grass_data.remove_at(i)
|
|
_rebuild_multimesh()
|
|
|
|
func _draw() -> void:
|
|
if editing and Engine.is_editor_hint():
|
|
draw_arc(get_local_mouse_position(), brush_radius, 0, TAU, 32, Color.YELLOW, 2.0)
|