Files
MovementTests/systems/weapon/WeaponSystem.cs
Minimata 916a6e7153
All checks were successful
Create tag and build when new code gets to main / BumpTag (push) Successful in 33s
Create tag and build when new code gets to main / Test (push) Successful in 6m19s
Create tag and build when new code gets to main / Export (push) Successful in 7m39s
some editor icons and a base level scene
2026-01-27 10:35:35 +01:00

197 lines
6.0 KiB
C#

using System;
using Godot;
using GodotStateCharts;
using Movementtests.interfaces;
using Movementtests.systems.damage;
namespace Movementtests.systems;
[GlobalClass, Icon("res://assets/ui/IconGodotNode/node_3D/icon_sword.png")]
public partial class WeaponSystem : RigidBody3D, IDamageDealer
{
[Signal]
public delegate void WeaponThrownEventHandler();
[Signal]
public delegate void WeaponRetrievedEventHandler();
[Export]
public RDamage RDamage { get; set; }
[Export(PropertyHint.Range, "0,100,1,or_greater")]
public float ThrowForce { get; set; } = 1f;
[Export(PropertyHint.Range, "0,0.2,0.01,or_greater")]
public float StraightThrowDuration { get; set; } = 0.1f;
private StateChart _weaponState;
public StateChartState InHandState;
public StateChartState FlyingState;
public StateChartState PlantedState;
private ShapeCast3D _dashCast3D;
private TweenQueueSystem _tweenQueueSystem;
private Transform3D _startTransform;
private Vector3 _startMeshRotation;
private Vector3 _throwDirection;
public Vector3 PlantLocation { get; set; }
public Vector3 PlantNormal { get; set; }
public Node PlantObject { get; set; }
public MeshInstance3D WeaponLocationIndicator { get; set; }
public StandardMaterial3D WeaponLocationIndicatorMaterial { get; set; }
public MeshInstance3D WeaponMesh { get; set; }
public void Init()
{
_weaponState = StateChart.Of(GetNode("StateChart"));
InHandState = StateChartState.Of(GetNode("StateChart/Root/InHand"));
FlyingState = StateChartState.Of(GetNode("StateChart/Root/Flying"));
PlantedState = StateChartState.Of(GetNode("StateChart/Root/Planted"));
WeaponLocationIndicator = GetNode<MeshInstance3D>("WeaponLocationIndicator");
WeaponLocationIndicator.Visible = false;
WeaponLocationIndicatorMaterial = WeaponLocationIndicator.GetActiveMaterial(0) as StandardMaterial3D;
WeaponMesh = GetNode<MeshInstance3D>("Weapon");
_startMeshRotation = WeaponMesh.Rotation;
_tweenQueueSystem = GetNode<TweenQueueSystem>("TweenQueueSystem");
_tweenQueueSystem.Init(this);
_startTransform = Transform;
Freeze = true;
Visible = false;
BodyEntered += OnThrownWeaponReachesGround;
InHandState.StateExited += WeaponLeft;
InHandState.StateEntered += WeaponBack;
}
public void WeaponLeft()
{
Visible = true;
// WeaponLocationIndicator.Visible = true;
EmitSignalWeaponThrown();
}
public void WeaponBack()
{
Visible = false;
// WeaponLocationIndicator.Visible = false;
EmitSignalWeaponRetrieved();
}
public void PlaceWeaponForTutorial(Vector3 location)
{
_weaponState.SendEvent("plant");
Freeze = true;
GlobalPosition = location;
PlantLocation = location;
}
public void ThrowWeapon(Vector3 end, bool hasHit, Vector3 collisionLocation, Vector3 collisionNormal, Node collidedObject)
{
_weaponState.SendEvent("throw");
// WeaponLocationIndicatorMaterial.StencilColor = new Color(1f, 1f, 1f);
_throwDirection = (end - GlobalPosition).Normalized();
PlantLocation = collisionLocation;
PlantNormal = collisionNormal;
LookAt(end);
var tween = _tweenQueueSystem.TweenToLocation(new TweenQueueSystem.TweenInputs(end, StraightThrowDuration));
if (hasHit)
{
PlantObject = collidedObject;
tween.Finished += PlantWeaponInWall;
}
else
tween.Finished += ThrowWeaponOnCurve;
}
public void PlantInEnemy(Node3D enemy)
{
GetTree().GetRoot().CallDeferred(Node.MethodName.RemoveChild, this);
enemy.CallDeferred(Node.MethodName.AddChild, this);
if (enemy is IDamageable damageable)
{
damageable.TakeDamage(new DamageRecord(GlobalPosition, RDamage));
}
}
public void RethrowWeapon()
{
_weaponState.SendEvent("throw");
_throwDirection = Vector3.Up;
ThrowWeaponOnCurve();
}
public void ThrowWeaponOnCurve()
{
Freeze = false;
ApplyImpulse(_throwDirection * ThrowForce);
}
public void PlantWeaponInWall()
{
_weaponState.SendEvent("plant");
Freeze = true;
WeaponMesh.Rotation = _startMeshRotation;
// WeaponLocationIndicatorMaterial.StencilColor = new Color(1f, 0.2f, 0.2f);
if (PlantObject is Node3D node)
{
PlantInEnemy(node);
}
CallDeferred(Node3D.MethodName.SetGlobalPosition, PlantLocation);
CallDeferred(Node3D.MethodName.LookAt, GlobalTransform.Origin + PlantNormal, Vector3.Up, true);
}
public void OnThrownWeaponReachesGround(Node other)
{
PlantObject = other;
PlantWeaponInWall();
}
public void ResetWeapon()
{
_weaponState.SendEvent("recover");
Transform = _startTransform;
Freeze = true;
Visible = false;
}
public override void _IntegrateForces(PhysicsDirectBodyState3D state)
{
base._IntegrateForces(state);
if (!Freeze && state.GetContactCount() > 0)
{
PlantLocation = state.GetContactLocalPosition(0);
PlantNormal = state.GetContactLocalNormal(0);
}
}
public override void _Process(double delta)
{
if (!FlyingState.Active) return;
WeaponMesh.Rotation = new Vector3(WeaponMesh.Rotation.X, WeaponMesh.Rotation.Y + (float) delta * 100, WeaponMesh.Rotation.Z);
//LookAt(GlobalTransform.Origin + LinearVelocity.Normalized(), Vector3.Up, false);
}
public bool IsPlantedUnderPlatform()
{
return PlantedState.Active && GlobalRotation.X > 1 && Math.Abs(GlobalRotation.Y) > 1;
}
public bool IsPlantedInWall()
{
return PlantedState.Active && Math.Abs(GlobalRotation.X) + Math.Abs(GlobalRotation.Z) < 0.3;
}
}