OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / creature_test.gd

166 lines · gd ref:
extends Node3D
## Minimal creature test — flat plane, single creature, flymode camera.
##
## Controls:
##   [1] Spawn GroundCrawler  [2] Spawn FlyingSerpent
##   [3] Kill all creatures   [4] Toggle pause creature AI
##   [+/-] Scale creature     [F12] Screenshot
##   WASD: fly camera   Mouse: look   Scroll: speed

@onready var stats_label: Label = $CanvasLayer/StatsLabel
@onready var camera: Camera3D = $Camera3D

var _rng := RandomNumberGenerator.new()
var _creature: Node3D = null
var _creatures_paused: bool = false

# Fly camera
var _fly_speed: float = 10.0
var _mouse_sens: float = 0.003
var _cam_yaw: float = 0.0
var _cam_pitch: float = -0.3


func _ready() -> void:
	_rng.randomize()
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
	camera.global_position = Vector3(0, 3, 8)


func _process(delta: float) -> void:
	_fly_camera(delta)
	_update_hud()


func _fly_camera(delta: float) -> void:
	var input := Vector3.ZERO
	if Input.is_key_pressed(KEY_W):
		input.z -= 1.0
	if Input.is_key_pressed(KEY_S):
		input.z += 1.0
	if Input.is_key_pressed(KEY_A):
		input.x -= 1.0
	if Input.is_key_pressed(KEY_D):
		input.x += 1.0
	if Input.is_key_pressed(KEY_E) or Input.is_key_pressed(KEY_SPACE):
		input.y += 1.0
	if Input.is_key_pressed(KEY_Q) or Input.is_key_pressed(KEY_CTRL):
		input.y -= 1.0

	var speed := _fly_speed
	if Input.is_key_pressed(KEY_SHIFT):
		speed *= 3.0

	if input.length_squared() > 0.0:
		input = input.normalized()
		camera.global_position += camera.global_transform.basis * input * speed * delta


func _update_hud() -> void:
	if not stats_label:
		return

	var info: String = "No creature"
	if _creature and is_instance_valid(_creature):
		var pos: Vector3 = _creature.global_position
		if _creature is GroundCrawler:
			info = "GroundCrawler (segs=%d legs=%d scale=%.2f)" % [_creature.segment_count, _creature.segment_count * 2, _creature.creature_scale]
		elif _creature is FlyingSerpent:
			info = "FlyingSerpent (segs=%d scale=%.2f)" % [_creature.segment_count, _creature.creature_scale]
		elif _creature is Hopper:
			info = "Hopper (segs=%d scale=%.2f)" % [_creature.segment_count, _creature.creature_scale]
		info += "\nPos: (%.1f, %.1f, %.1f)" % [pos.x, pos.y, pos.z]
	else:
		_creature = null

	var pause_str: String = " [AI PAUSED]" if _creatures_paused else ""
	stats_label.text = "FPS: %d%s\n%s\n\n[1] Crawler  [2] Serpent  [3] Hopper\n[4] Kill all  [5] Pause AI  [+/-] Scale\nWASD: fly  EQ: up/down  Scroll: speed" % [
		Engine.get_frames_per_second(), pause_str, info]


func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
		_cam_yaw -= event.relative.x * _mouse_sens
		_cam_pitch = clampf(_cam_pitch - event.relative.y * _mouse_sens, -PI * 0.49, PI * 0.49)
		camera.rotation = Vector3(_cam_pitch, _cam_yaw, 0)

	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_WHEEL_UP and event.pressed:
			_fly_speed = minf(100.0, _fly_speed * 1.2)
		elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN and event.pressed:
			_fly_speed = maxf(1.0, _fly_speed / 1.2)

	if event.is_action_pressed("ui_cancel"):
		if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
			Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
		else:
			Input.mouse_mode = Input.MOUSE_MODE_CAPTURED

	if not event is InputEventKey or not event.pressed:
		return

	match event.keycode:
		KEY_1:
			_spawn_type("crawler")
		KEY_2:
			_spawn_type("serpent")
		KEY_3:
			_spawn_type("hopper")
		KEY_4:
			_kill_all()
		KEY_5:
			_creatures_paused = !_creatures_paused
			for child in get_children():
				if child is GroundCrawler or child is FlyingSerpent or child is Hopper:
					child.set_process(!_creatures_paused)
					child.set_physics_process(!_creatures_paused)
		KEY_EQUAL:
			_rescale(1.2)
		KEY_MINUS:
			_rescale(1.0 / 1.2)
		KEY_F12:
			var img: Image = get_viewport().get_texture().get_image()
			var ts: String = Time.get_datetime_string_from_system().replace(":", "-")
			var path: String = "/home/fleeky/Desktop/hyper-tps/creature_%s.png" % ts
			img.save_png(path)
			print("Screenshot saved: %s" % path)


func _spawn_type(type: String) -> void:
	_kill_all()
	match type:
		"crawler":
			_creature = GroundCrawler.new()
			_creature.name = "TestCrawler"
			add_child(_creature)
			_creature.global_position = Vector3(0, 0.5, 0)
			_creature.initialize(_rng)
			print("Spawned GroundCrawler (segs=%d)" % _creature.segment_count)
		"serpent":
			_creature = FlyingSerpent.new()
			_creature.name = "TestSerpent"
			add_child(_creature)
			_creature.global_position = Vector3(0, 5.0, 0)
			_creature.initialize(_rng)
			print("Spawned FlyingSerpent (segments=%d)" % _creature.segment_count)
		"hopper":
			_creature = Hopper.new()
			_creature.name = "TestHopper"
			add_child(_creature)
			_creature.global_position = Vector3(0, 0.1, 0)
			_creature.initialize(_rng)
			print("Spawned Hopper (segments=%d)" % _creature.segment_count)


func _kill_all() -> void:
	for child in get_children():
		if child is GroundCrawler or child is FlyingSerpent or child is Hopper:
			child.queue_free()
	_creature = null


func _rescale(factor: float) -> void:
	if _creature and is_instance_valid(_creature):
		_creature.scale *= factor
		print("Scale: %.2f" % _creature.scale.x)