crowd markers, unsheathed sword correct
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
@tool
|
||||
extends Node3D
|
||||
class_name CrowdMarker
|
||||
## A designer-placed spot for one billboard spectator. Drop these into a level in the
|
||||
## editor; crowd_billboards.gd harvests every marker (via the &"crowd_marker" group) into
|
||||
## its MultiMesh at runtime, using each marker's global position and chosen facing.
|
||||
##
|
||||
## The marker draws a lightweight preview (a slab standing in for the sprite + a forward
|
||||
## arrow) so its position and orientation are visible in the viewport. That preview is
|
||||
## editor-only and never serialised into the scene, so it costs nothing at runtime.
|
||||
|
||||
## The six selectable facings, one every 60° about the Y axis. DEG_0 faces the quad's
|
||||
## front (+Z) along world +Z; increasing values rotate clockwise looking down.
|
||||
enum Orientation {
|
||||
DEG_0,
|
||||
DEG_60,
|
||||
DEG_120,
|
||||
DEG_180,
|
||||
DEG_240,
|
||||
DEG_300,
|
||||
}
|
||||
|
||||
const ORIENTATION_STEPS := 6
|
||||
## Metres — matches crowd_billboards.figure_height so the editor preview reads true to scale.
|
||||
const PREVIEW_HEIGHT := 2.0
|
||||
|
||||
@export var orientation := Orientation.DEG_0:
|
||||
set(value):
|
||||
orientation = value
|
||||
_apply_orientation()
|
||||
|
||||
var _preview: Node3D
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
add_to_group(&"crowd_marker")
|
||||
if Engine.is_editor_hint():
|
||||
_build_preview()
|
||||
_apply_orientation()
|
||||
|
||||
|
||||
# Facing about Y for the current orientation: 0, 60, 120 … degrees as radians.
|
||||
func facing_yaw() -> float:
|
||||
return float(orientation) * (TAU / float(ORIENTATION_STEPS))
|
||||
|
||||
|
||||
# Unit forward the spectator's front (+Z) points along, on the horizontal plane.
|
||||
func facing_dir() -> Vector3:
|
||||
var a := facing_yaw()
|
||||
return Vector3(sin(a), 0.0, cos(a))
|
||||
|
||||
|
||||
func _apply_orientation() -> void:
|
||||
if _preview != null:
|
||||
_preview.rotation = Vector3(0.0, facing_yaw(), 0.0)
|
||||
|
||||
|
||||
# Editor-only preview. Children are added without an owner so they are excluded from the
|
||||
# saved .tscn (Godot only serialises nodes owned by the scene root).
|
||||
func _build_preview() -> void:
|
||||
_preview = Node3D.new()
|
||||
add_child(_preview)
|
||||
|
||||
var aspect := 0.5
|
||||
var slab := MeshInstance3D.new()
|
||||
var quad := QuadMesh.new()
|
||||
quad.size = Vector2(PREVIEW_HEIGHT * aspect, PREVIEW_HEIGHT)
|
||||
quad.center_offset = Vector3(0.0, PREVIEW_HEIGHT * 0.5, 0.0) # stand on the marker
|
||||
slab.mesh = quad
|
||||
slab.material_override = _preview_material(Color(0.3, 0.7, 1.0, 0.35))
|
||||
_preview.add_child(slab)
|
||||
|
||||
var arrow := MeshInstance3D.new()
|
||||
var shaft := BoxMesh.new()
|
||||
shaft.size = Vector3(0.08, 0.08, PREVIEW_HEIGHT * 0.5)
|
||||
arrow.mesh = shaft
|
||||
# Push the shaft out along +Z (the facing) and up to chest height.
|
||||
arrow.position = Vector3(0.0, PREVIEW_HEIGHT * 0.5, PREVIEW_HEIGHT * 0.25)
|
||||
arrow.material_override = _preview_material(Color(1.0, 0.85, 0.2, 0.9))
|
||||
_preview.add_child(arrow)
|
||||
|
||||
|
||||
func _preview_material(col: Color) -> StandardMaterial3D:
|
||||
var mat := StandardMaterial3D.new()
|
||||
mat.albedo_color = col
|
||||
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||
mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||
mat.cull_mode = BaseMaterial3D.CULL_DISABLED
|
||||
return mat
|
||||
Reference in New Issue
Block a user