Carriable/PelletGun.cs
using System;
using Clover.Objects;
namespace Clover.Carriable;
[Category( "Clover/Carriable" )]
public class PelletGun : BaseCarriable
{
[Property] public float FireRate { get; set; } = 3f;
[Property] public float PelletSpeed { get; set; } = 10f;
[Property] public GameObject PelletScene { get; set; }
[Property] public GameObject PelletGunFpsScene { get; set; }
[Property] public SoundEvent FireSound { get; set; }
private float _fireTimer;
private bool _isAiming;
private bool _isWaitingForHit;
private bool _isLookingAtWhenShot;
private Angles _aimDirection;
/// <summary>
/// A scene that contains a camera and a gun model. When aiming, this scene is instantiated and the player model is hidden.
/// The entire thing rotates to aim.
/// </summary>
private GameObject _pelletGunFpsNode;
public override void OnUseDown()
{
if ( _isWaitingForHit ) return;
base.OnUseDown();
StartAiming();
}
public override void OnUseUp()
{
if ( _isWaitingForHit ) return;
base.OnUseUp();
Fire();
// StopAiming();
}
public override void OnUnequip()
{
base.OnUnequip();
StopAiming();
}
public override string GetUseName()
{
return "Fire";
}
private void StartAiming()
{
_isAiming = true;
_pelletGunFpsNode = PelletGunFpsScene.Clone();
_pelletGunFpsNode.WorldPosition = Player.WorldPosition + Vector3.Up * 32f;
_pelletGunFpsNode.WorldRotation = Rotation.FromYaw( Player.PlayerController.Yaw );
// TODO: Hide the player model
Player.SetVisible( false );
Mouse.Visibility = MouseVisibility.Hidden;
// Hide the player model
// PlayerModel.Visible = false;
}
private void StopAiming()
{
_isAiming = false;
Player.PlayerController.Yaw = _pelletGunFpsNode.WorldRotation.Yaw();
_pelletGunFpsNode.Destroy();
// TODO: Show the player model
Player.SetVisible( true );
Mouse.Visibility = MouseVisibility.Auto;
}
public override bool ShouldDisableMovement()
{
return base.ShouldDisableMovement() || _isAiming;
}
private void Fire()
{
if ( !_pelletGunFpsNode.IsValid() ) return;
var startPos = _pelletGunFpsNode.WorldPosition + _pelletGunFpsNode.WorldRotation.Forward * 16f;
var pelletObject = PelletScene.Clone( startPos );
var pellet = pelletObject.GetComponent<Pellet>();
pellet.StartPosition = startPos;
pellet.PelletGun = this;
pellet.Speed = PelletSpeed;
// var pelletDirection = _pelletGunFpsNode.Transform.Basis.Z;
pelletObject.WorldPosition = startPos;
pelletObject.WorldRotation = _pelletGunFpsNode.WorldRotation;
// pelletGunFpsNode.GetNode<Control>( "Crosshair" ).Visible = false;
pellet.OnTimeout += () =>
{
_isWaitingForHit = false;
StopAiming();
};
pellet.OnHit += OnPelletHit;
_fireTimer = 0;
_isWaitingForHit = true;
// GetNode<AudioStreamPlayer3D>( "Fire" ).Play();
SoundEx.Play( FireSound, _pelletGunFpsNode.WorldPosition );
// _pelletGunFpsNode.GetNode<AnimationPlayer>( "AnimationPlayer" ).Play( "fire" );*/
}
private void OnPelletHit( GameObject target, PelletGun gun )
{
_isWaitingForHit = false;
_isLookingAtWhenShot = false;
StopAiming();
}
protected override void OnUpdate()
{
if ( !_isAiming ) return;
if ( !_isWaitingForHit && !_isLookingAtWhenShot )
{
var input = Input.AnalogLook;
// _aimDirection += input.WithRoll( 0f );
var angles = _aimDirection;
angles += input;
angles.pitch = Math.Clamp( angles.pitch, -89, 89 );
angles.roll = 0;
_aimDirection = angles;
}
if ( Input.Pressed( "attack2" ) )
{
StopAiming();
}
_pelletGunFpsNode.WorldRotation = _aimDirection;
}
}