feat: more combat tweaks

shuriken can now be thrown
jumping animtions
jumping animations timing
state machine changes
start of online integration
This commit is contained in:
Chris
2026-01-15 14:42:25 -05:00
parent a06784f7b6
commit 25b7fae339
45 changed files with 28662 additions and 250 deletions

View File

@@ -1,14 +1,13 @@
using System;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using Unity.Netcode;
using Unity.Netcode.Components;
using Reset.Units;
using UnityEngine;
namespace Reset.Core {
[Category("Reset")]
[Description("Sends an animation trigger with network sync to networked objects")]
public class SendAnimationTrigger : ActionTask<NetworkAnimator>{
public class SendAnimationTrigger : ActionTask<UnitAnimation>{
public BBParameter<string> trigger;
//Use for initialization. This is called only once in the lifetime of the task.
@@ -21,11 +20,8 @@ namespace Reset.Core {
//Call EndAction() to mark the action as finished, either in success or failure.
//EndAction can be called from anywhere.
protected override void OnExecute(){
try {
agent.SetTrigger(trigger.value);
} catch (Exception e) {
Debug.LogError($"Did not set Network Animator trigger <i>{trigger.name}</i> on <b>{(agent == null ? null : agent.name)}</b>: {e.Message}");
}
agent.SendAnimationTrigger(trigger.value);
EndAction(true);
}

View File

@@ -270,7 +270,7 @@ namespace Reset.Units{
// Catch exception from nothing being found
if (!closestTarget) {
Debug.LogWarning("Lock-on attempted, but no lock on target was found viable.");
Debug.LogWarning($"Lock-on attempted, but no lock on target was found viable. Searched {acceptedTargets.Count} targets.");
return;
}

View File

@@ -1,9 +1,10 @@
using System.Collections.Generic;
using Sirenix.OdinInspector;
using Unity.Netcode;
using UnityEngine;
namespace Reset.Items{
public abstract class Item : ScriptableObject{
public abstract class Item : SerializedScriptableObject{
public string itemName;
public float permanency;

View File

@@ -1,8 +1,11 @@
using System;
using Drawing;
using NodeCanvas.StateMachines;
using NodeCanvas.Framework;
using Reset.Core;
using Reset.Units;
using Sirenix.OdinInspector;
using Sirenix.Serialization;
using Unity.Netcode;
using UnityEngine;
namespace Reset.Items{
@@ -18,6 +21,8 @@ namespace Reset.Items{
public string actorScriptName;
[OdinSerialize, ShowInInspector] public Type actorScript;
public void AddActorScript(){
// Type actorScript = Type.GetType("ShurikenActor");
//
@@ -26,10 +31,17 @@ namespace Reset.Items{
// return;
// }
WeaponActor weaponActor = PlayerManager.Player.AddComponent<ShurikenActor>() as WeaponActor;
weaponActor.relatedObject = PlayerManager.Player.GetComponent<PlayerInventory>().GetCurrentWeaponItem();
weaponActor.relatedWeapon = this;
try {
if (actorScript != null) {
WeaponActor weaponActor = PlayerManager.Player.AddComponent(actorScript) as WeaponActor;
weaponActor.relatedObject = PlayerManager.Player.GetComponent<PlayerCombat>().GetCurrentWeaponItem();
weaponActor.relatedWeapon = this;
weaponActor.relatedGraph = PlayerManager.Player.GetComponent<GraphOwner>();
}
} catch (Exception e) {
Debug.LogException(e);
}
}
public override void DrawItemInfo(Vector3 position){
@@ -37,9 +49,10 @@ namespace Reset.Items{
Draw.ingame.Label2D(position + Vector3.up * 1.35f, "Speed goes here");
}
public GameObject PlaceInHand(){
return GameObject.Instantiate(weaponModel);
public GameObject InstantiateItemObject(){
return GameObject.Instantiate(weaponModel);
}
}
}

View File

@@ -1,18 +1,44 @@
using System;
using System.Collections.Generic;
using NodeCanvas.Framework;
using UnityEngine;
using UnityEngine.UI;
namespace Reset.Items{
public abstract class WeaponActor : MonoBehaviour{
public Dictionary<string, Action> weaponEvents = new Dictionary<string, Action>();
public Dictionary<string, object> weaponVariables = new Dictionary<string, object>();
public Weapon relatedWeapon;
public GraphOwner relatedGraph;
public GameObject relatedObject;
// Recieve Weapon Catch signal from Animation
public void WeaponCatch(){
relatedGraph.SendEvent("Weapon Catch");
}
// Recieve Weapon Release signal from Animation
public void WeaponRelease(){
relatedGraph.SendEvent("Weapon Release");
}
public void RegisterWeaponEvent(string calledName, Action action){
weaponEvents.Add(calledName, action);
}
public void RegisterWeaponVariable(string variable, object value){
if (weaponVariables.ContainsKey(variable)) {
weaponVariables[variable] = value;
} else {
weaponVariables.Add(variable, value);
}
}
public object ReadWeaponVariable<T>(string variable) where T : class{
return (T)weaponVariables[variable];
}
public void DoWeaponEvent(string eventName){
if (weaponEvents.ContainsKey(eventName)) {
weaponEvents[eventName].Invoke();

View File

@@ -1,17 +1,115 @@

using System;
using System.Collections.Generic;
using System.Numerics;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Services.Relay.Models;
using UnityEngine;
using Quaternion = UnityEngine.Quaternion;
using Vector3 = UnityEngine.Vector3;
namespace Reset.Items{
public class ShurikenActor : WeaponActor{
public GameObject bladeRing;
void Start(){
Debug.Log(GetType());
bladeRing = relatedObject.transform.GetChild(0).gameObject;
public Transform target;
private Vector3 targetPosition;
private Transform originalParent;
private Quaternion originalRotation;
private Vector3 originalPosition;
private Vector3 originalWorldPosition;
private float rotateSpeed;
private float rotateSpeedTarget;
private float rotationAcceleration;
void Awake(){
// Register Weapon Events
weaponEvents.Add("Set Target", SetTarget);
weaponEvents.Add("Fly To Target", FlyToTarget);
weaponEvents.Add("Fly To Hand", FlyToHand);
weaponEvents.Add("Return To Hand", ReturnToHand);
}
void SetTarget(){
Debug.Log($"{weaponVariables["target"]}, {weaponVariables["target"] as GameObject}");
target = (Transform)weaponVariables["target"];
}
void FlyToTarget(){
rotateSpeedTarget = 1200f;
rotationAcceleration = 200f;
RegisterWeaponVariable("state", "Flying To Target");
originalParent = relatedObject.transform.parent;
originalPosition = relatedObject.transform.localPosition;
originalRotation = relatedObject.transform.localRotation;
originalWorldPosition = relatedObject.transform.position;
relatedObject.transform.SetParent(null, true);
}
void FlyToHand(){
rotateSpeed = 3000f;
rotateSpeedTarget = 50f;
rotationAcceleration = 2f;
RegisterWeaponVariable("state", new string("Flying To Hand"));
}
void ReturnToHand(){
rotateSpeedTarget = 250f;
rotationAcceleration = 1f;
RegisterWeaponVariable("state", new string("Back In Hand"));
relatedObject.transform.SetParent(originalParent);
relatedObject.transform.localPosition = originalPosition;
relatedObject.transform.localRotation = originalRotation;
}
void Start(){
// Save refernce to the blade outer ring
bladeRing = relatedObject.transform.GetChild(0).gameObject;
}
void Update(){
bladeRing.transform.Rotate(Vector3.up * (180f * Time.deltaTime));
if (target) {
targetPosition = target.transform.position;
} else {
targetPosition = Vector3.forward * 5f;
}
RegisterWeaponVariable("position", transform.position);
rotateSpeed = Mathf.Lerp(rotateSpeed, rotateSpeedTarget, rotationAcceleration * Time.deltaTime);
bladeRing.transform.Rotate(Vector3.up * (rotateSpeed * Time.deltaTime));
Debug.Log((string)ReadWeaponVariable<string>("state"));
// Fly to the target
if ((string)ReadWeaponVariable<string>("state") == "Flying To Target") {
relatedObject.transform.position = Vector3.Lerp(relatedObject.transform.position, targetPosition, 5f * Time.deltaTime);
// When there, set next stage
if (Vector3.Distance(relatedObject.transform.position, targetPosition) < .5f) {
rotationAcceleration = 50f;
rotateSpeedTarget = 1200f;
RegisterWeaponVariable("state", new string("At Target"));
}
}
// Fly to the hand
if ((string)ReadWeaponVariable<string>("state") as string == "Flying To Hand") {
relatedObject.transform.position = Vector3.Lerp(relatedObject.transform.position, originalParent.transform.position, 5f * Time.deltaTime);
// When there, set as finished
if (Vector3.Distance(relatedObject.transform.position, originalParent.transform.position) < .5f) {
RegisterWeaponVariable("state", new string("At Hand"));
}
}
}
}
}

View File

@@ -1,7 +1,9 @@
using System;
using Reset.Units;
using UnityEngine;
using UnityEngine.InputSystem;
using Unity.Cinemachine;
using Unity.Services.Matchmaker.Models;
// This class receives input from a PlayerInput component and disptaches it
// to the appropriate Cinemachine InputAxis. The playerInput component should
@@ -32,7 +34,7 @@ class CustomInputHandler : InputAxisControllerBase<CustomInputHandler.Reader>
// We process user input on the Update clock
void Update()
{
if (Application.isPlaying){
if (Application.isPlaying && PlayerManager.Player){
UpdateControllers();
Controllers[0].Input.ProcessInput(PlayerInput);
Controllers[1].Input.ProcessInput(PlayerInput);

View File

@@ -26,6 +26,11 @@ public class EnvironmentObserver{
BoxCast,
SphereCast
}
public enum CastOrigin{
Owner,
Location
}
[PropertySpace(0, 5), LabelWidth(60)]
public string label;
@@ -40,6 +45,8 @@ public class EnvironmentObserver{
[HideInInspector]
public bool active;
public CastOrigin castOrigin;
// Parameters for Cast cast types
[FoldoutGroup("Settings")] [HideIf("@castType == CastType.BoxOverlap || castType == CastType.SphereOverlap")]
public float length;

View File

@@ -0,0 +1,60 @@
using System.Runtime.InteropServices.WindowsRuntime;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using UnityEngine;
namespace Reset.Items{
[Category("Reset/Combat")]
[Description("Check if the provided value matches the weapon actor's variable")]
public class CheckWeaponActorVariable<T> : ConditionTask<Transform> where T : class{
public BBParameter<string> variable;
public BBParameter<T> value;
WeaponActor actor;
protected override string info{
get{ return $"weapon actor variable <b>{variable.value}</b> is <b><i>{value.value}</b></i>"; }
}
//Use for initialization. This is called only once in the lifetime of the task.
//Return null if init was successfull. Return an error string otherwise
protected override string OnInit(){
return null;
}
//Called whenever the condition gets enabled.
protected override void OnEnable(){
actor = agent.GetComponent<WeaponActor>();
}
//Called whenever the condition gets disabled.
protected override void OnDisable(){
}
//Called once per frame while the condition is active.
//Return whether the condition is success or failure.
protected override bool OnCheck(){
if (!actor) {
Debug.LogError(
$"No weapon actor variable found on this player. Cannot check for value of {variable.value}.",
agent);
return false;
}
if (actor.weaponVariables.ContainsKey(variable.value)) {
T valueAsType = value.value;
Debug.Log((T)actor.weaponVariables[variable.value]);
Debug.Log(valueAsType);
return ((T)actor.weaponVariables[variable.value]).Equals(valueAsType);
} else {
Debug.LogError($"No variable found by name {variable.value} on the weapon actor", agent);
return false;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 33a915cdda8127941aa56ed4e845d813

View File

@@ -0,0 +1,57 @@
using System;
using System.Runtime.CompilerServices;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using UnityEngine;
namespace Reset.Units {
[Category("Reset")]
[Description("Get the current target and save it to a graph variable")]
public class GetCurrentTarget : ActionTask<LockOnManager>{
public BBParameter<Transform> target;
//Use for initialization. This is called only once in the lifetime of the task.
//Return null if init was successfull. Return an error string otherwise
protected override string OnInit() {
return null;
}
//This is called once each time the task is enabled.
//Call EndAction() to mark the action as finished, either in success or failure.
//EndAction can be called from anywhere.
protected override void OnExecute(){
if (agent.mainTarget == null) {
Debug.LogWarning("There is no LockOnTarget to save as current target");
EndAction(true);
return;
}
try {
target.value = agent.mainTarget.gameObject.transform;
} catch (Exception e) {
Debug.LogError($"Failed to save the current LockOnTarget target: {e.Message}");
EndAction(false);
return;
}
EndAction(true);
}
//Called once per frame while the action is active.
protected override void OnUpdate() {
}
//Called when the task is disabled.
protected override void OnStop() {
}
//Called when the task is paused.
protected override void OnPause() {
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 13713276d513eea4186f28ea39cbf302

View File

@@ -0,0 +1,50 @@
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using UnityEngine;
namespace Reset.Items {
[Category("Reset/Combat")]
[Description("Retrieve the valule of a weapon actor variable")]
public class GetWeaponActorVariable<T> : ActionTask<Transform>{
public BBParameter<string> variable;
public BBParameter<T> saveValueTo;
//Use for initialization. This is called only once in the lifetime of the task.
//Return null if init was successfull. Return an error string otherwise
protected override string OnInit() {
return null;
}
//This is called once each time the task is enabled.
//Call EndAction() to mark the action as finished, either in success or failure.
//EndAction can be called from anywhere.
protected override void OnExecute() {
WeaponActor actor = agent.GetComponent<WeaponActor>();
if (!actor) {
Debug.LogError($"No weapon actor variable found on this player. Cannot check for value of {variable.value}.", agent);
EndAction(false);
}
saveValueTo.value = (T)actor.weaponVariables[variable.value];
EndAction(true);
}
//Called once per frame while the action is active.
protected override void OnUpdate() {
}
//Called when the task is disabled.
protected override void OnStop() {
}
//Called when the task is paused.
protected override void OnPause() {
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f379bc09216af524290d9b72067031d5

View File

@@ -0,0 +1,56 @@
using System;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using Reset.Items;
using UnityEngine;
namespace Reset.Items {
[Category("Reset/Combat")]
[Description("Sends a named event as a string to the current weapon's WeaponActor.")]
public class SendWeaponActorEvent : ActionTask<Transform>{
public BBParameter<string> weaponEvent;
protected override string info{
get{ return $"Send weapon event <b>{weaponEvent.value}</b>"; }
}
//Use for initialization. This is called only once in the lifetime of the task.
//Return null if init was successfull. Return an error string otherwise
protected override string OnInit() {
return null;
}
//This is called once each time the task is enabled.
//Call EndAction() to mark the action as finished, either in success or failure.
//EndAction can be called from anywhere.
protected override void OnExecute(){
WeaponActor actor = agent.GetComponent<WeaponActor>();
if (actor == null) {
Debug.LogError("No WeaponActor was found on this player.");
EndAction(false);
}
actor.DoWeaponEvent(weaponEvent.value);
EndAction(true);
}
//Called once per frame while the action is active.
protected override void OnUpdate() {
}
//Called when the task is disabled.
protected override void OnStop() {
}
//Called when the task is paused.
protected override void OnPause() {
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 567e649f23e3ba44ea1339e928d17b83

View File

@@ -0,0 +1,61 @@
using System;
using NodeCanvas.Framework;
using ParadoxNotion.Design;
using UnityEngine;
namespace Reset.Items {
[Category("Reset/Combat")]
[Description("Set an existing or new weapon actor variable to the defined value.")]
public class SetWeaponActorVariable : ActionTask<Transform>{
public BBParameter<string> variable;
public BBParameter<object> value;
protected override string info{
get{ return $"Set weapon variable <b>{variable.value}</b> == <i>{value.name}</i>"; }
}
//Use for initialization. This is called only once in the lifetime of the task.
//Return null if init was successfull. Return an error string otherwise
protected override string OnInit() {
return null;
}
//This is called once each time the task is enabled.
//Call EndAction() to mark the action as finished, either in success or failure.
//EndAction can be called from anywhere.
protected override void OnExecute() {
WeaponActor actor = agent.GetComponent<WeaponActor>();
if (actor == null) {
Debug.LogError("No WeaponActor was found on this player.");
EndAction(false);
}
try {
actor.RegisterWeaponVariable(variable.value, value.value);
} catch (Exception e) {
Debug.LogError($"Failed to set weapon variable '{variable.value}': {e.Message} ");
EndAction(false);
}
EndAction(true);
}
//Called once per frame while the action is active.
protected override void OnUpdate() {
}
//Called when the task is disabled.
protected override void OnStop() {
}
//Called when the task is paused.
protected override void OnPause() {
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ff6862d725648584c89631637986f89c

View File

@@ -1,7 +1,75 @@
using Reset.Core;
using Reset.Items;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Profiling;
namespace Reset.Units{
public class PlayerCombat : UnitCombat{
public CombatType currentCombatType;
private IEquipable currentWeapon;
private GameObject currentWeaponItem;
public void OnDrawWeapon(){
if (Unit.UnitIsNetworked()) {
CreatePlayerWeaponRpc();
} else {
CreatePlayerWeapon();
}
}
[Rpc(SendTo.Everyone)]
public void CreatePlayerWeaponRpc(){
CreatePlayerWeapon();
}
public void CreatePlayerWeapon(){
// Remove a current weapon
DisposeCurrentWeapon();
// Reference inventory and inventory
PlayerInventory playerInventory = Unit.Inventory as PlayerInventory;
PlayerAnimation playerAnimation = Unit.Animation as PlayerAnimation;
// Add weapon to status and hand
currentWeapon = playerInventory.meleeWeapon;
currentWeaponItem = playerInventory.meleeWeapon.InstantiateItemObject();
// Move item to hand
currentWeaponItem.transform.SetParent(playerAnimation.rightHand);
currentWeaponItem.transform.localPosition = playerInventory.meleeWeapon.handPositionOffset;
currentWeaponItem.transform.rotation = playerAnimation.rightHand.rotation * Quaternion.Euler(playerInventory.meleeWeapon.handRotationOffset);
// Add related weapon's actor script
(currentWeapon as Weapon).AddActorScript();
}
public GameObject GetCurrentWeaponItem(){
return currentWeaponItem;
}
public void OnHolsterWeapon(){
DisposeCurrentWeapon();
}
public void DisposeCurrentWeapon(){
// Return if no weapon active
if (currentWeapon == null) {
return;
}
// Destroy physical mesh
Destroy(currentWeaponItem);
// Destroy weapon actor
if ((GetComponent<WeaponActor>()) != null) {
Destroy(GetComponent<WeaponActor>());
}
// Remove references
currentWeaponItem = null;
currentWeapon = null;
}
}
}

View File

@@ -1,10 +1,9 @@
using System.Collections.Generic;
using NodeCanvas.Tasks.Actions;
using Reset.Items;
using UnityEngine;
namespace Reset.Units{
public class PlayerInventory : UnitComponent, IInventory {
public class PlayerInventory : UnitComponent, IInventory{
public Weapon rangedWeapon;
public Weapon meleeWeapon;
@@ -14,49 +13,7 @@ namespace Reset.Units{
public Ability toolAbility1;
public Ability toolAbility2;
public List<Item> storedItems { get; set; }
private IEquipable currentWeapon;
private GameObject currentWeaponItem;
public void OnDrawWeapon(){
// Remove a current weapon
if (currentWeapon != null) {
Destroy(currentWeaponItem);
currentWeaponItem = null;
}
// Add weapon to status and hand
currentWeapon = meleeWeapon;
currentWeaponItem = meleeWeapon.PlaceInHand();
// Move item to hand
currentWeaponItem.transform.SetParent((Unit.Animation as PlayerAnimation).rightHand);
currentWeaponItem.transform.localPosition = meleeWeapon.handPositionOffset;
currentWeaponItem.transform.rotation = (Unit.Animation as PlayerAnimation).rightHand.rotation * Quaternion.Euler(meleeWeapon.handRotationOffset);
Debug.Log(currentWeapon);
//
(currentWeapon as Weapon).AddActorScript();
//
// Unit.Graph.SendEvent("Draw Weapon");
}
public GameObject GetCurrentWeaponItem(){
return currentWeaponItem;
}
public void OnHolsterWeapon(){
Destroy(currentWeaponItem);
currentWeaponItem = null;
currentWeapon = null;
Debug.Log(currentWeapon);
//
// Unit.Graph.SendEvent("Holster Weapon");
}
public List<Item> storedItems{ get; set; }
public void EquipToCharacter(Item item){
if (item is not IEquipable) {
@@ -73,11 +30,5 @@ namespace Reset.Units{
}
}
// Update is called once per frame
void Update(){
}
}
}

View File

@@ -33,13 +33,20 @@ namespace Reset.Units{
}
private UnitAnimation _animation;
internal UnitAnimation Animation{
get {
if (_animation == null) { _animation = GetComponent<UnitAnimation>(); }
return _animation;
}
}
private IInventory _inventory;
internal IInventory Inventory{
get {
if (_inventory == null) { _inventory = GetComponent<IInventory>(); }
return _inventory;
}
}
// Debug and Gizmos
public NetworkVariable<FixedString64Bytes> graphStateAsString;

View File

@@ -1,4 +1,5 @@
using System;
using Unity.Netcode.Components;
using UnityEngine;
using UnityEngine.Rendering;
@@ -18,6 +19,8 @@ namespace Reset.Units{
// Temporary
private float inputMagnitude;
private NetworkAnimator netAnimator;
void Update(){
// Temporary
@@ -34,8 +37,19 @@ namespace Reset.Units{
modelAnimator.SetFloat("Gravity", Unit.Movement.resolvedMovement.gravity);
modelAnimator.SetBool("Grounded", Physics.Raycast(transform.position, Vector3.down, .2f));
Debug.Log(Unit.Movement.GetGrounded());
}
public void SendAnimationTrigger(string trigger){
if (Unit.UnitIsNetworked()) {
try {
netAnimator.SetTrigger(trigger);
} catch (Exception e){
Debug.LogError($"Failed to send network animation trigger: {e.Message}");
}
} else {
modelAnimator.SetTrigger(trigger);
}
}
private void LateUpdate(){

View File

@@ -54,7 +54,9 @@ namespace Reset.Units{
DoMovement(resolvedMovement.moveDirection.World, resolvedMovement.gravity, resolvedMovement.moveSpeed, data.gravityScale.Value);
// Apply movespeed to the Animator
Unit.Animation.moveSpeed = resolvedMovement.moveSpeed * resolvedMovement.moveDirection.Local.magnitude / data.moveSpeed.currentValue;
if (transform.gameObject == PlayerManager.Player){ // temp
Unit.Animation.moveSpeed = resolvedMovement.moveSpeed * resolvedMovement.moveDirection.Local.magnitude / data.moveSpeed.currentValue;
}
DebugOverlayDrawer.ChangeValue("Movement", "Move Direction (Local)", resolvedMovement.moveDirection.Local);
DebugOverlayDrawer.ChangeValue("Movement", "Move Direction (World)", resolvedMovement.moveDirection.World);