My awake function is not initializing, so a NullReferenceException is coming up - c#

I was working on a xml saving system for my game but whenever I instantiate my prefab all of my public transforms, animators etc have gone null. I found this out by going into debug mode and looking into my player script. in my create actor function in my Game controller script I have created a player movement state machine script from a video series I watched. Inside it has all of the states, animations etc.
Here is my Player script code:
using UnityEngine;
using Cinemachine;
namespace GenshinImpactMovementSystem
{
[RequireComponent(typeof(PlayerInput))]
[RequireComponent(typeof(PlayerResizableCapsuleCollider))]
public class Player : MonoBehaviour
{
[field: Header("References")]
[field: SerializeField] public PlayerSO Data { get; private set; }
[field: Header("Collisions")]
[field: SerializeField] public PlayerLayerData LayerData { get; private set; }
[field: Header("Camera")]
[field: SerializeField] public PlayerCameraRecenteringUtility CameraRecenteringUtility { get; set; }
[field: Header("Animations")]
[field: SerializeField] public PlayerAnimationData AnimationData { get; private set; }
public Rigidbody Rigidbody { get; private set; }
public Animator Animator { get; private set; }
public PlayerInput Input { get; private set; }
public PlayerResizableCapsuleCollider ResizableCapsuleCollider { get; private set; }
public Transform MainCameraTransform { get; private set; }
public PlayerMovementStateMachine movementStateMachine;
public IKController IKController;
public Transform cameraPointLookAt;
public CinemachineVirtualCamera cam;
private void Awake()
{
CameraRecenteringUtility.Initialize();
AnimationData.Initialize();
Rigidbody = GetComponent<Rigidbody>();
Animator = GetComponentInChildren<Animator>();
Input = GetComponent<PlayerInput>();
ResizableCapsuleCollider = GetComponent<PlayerResizableCapsuleCollider>();
MainCameraTransform = Camera.main.transform;
movementStateMachine = new PlayerMovementStateMachine(this);
}
private void Start()
{
movementStateMachine.ChangeState(movementStateMachine.IdlingState);
}
private void Update()
{
movementStateMachine.HandleInput();
movementStateMachine.Update();
}
private void FixedUpdate()
{
movementStateMachine.PhysicsUpdate();
}
private void OnTriggerEnter(Collider collider)
{
movementStateMachine.OnTriggerEnter(collider);
}
private void OnTriggerExit(Collider collider)
{
movementStateMachine.OnTriggerExit(collider);
}
public void OnMovementStateAnimationEnterEvent()
{
movementStateMachine.OnAnimationEnterEvent();
}
public void OnMovementStateAnimationExitEvent()
{
movementStateMachine.OnAnimationExitEvent();
}
public void OnMovementStateAnimationTransitionEvent()
{
movementStateMachine.OnAnimationTransitionEvent();
}
}
}
Here is my Game Controller code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Cinemachine;
using TMPro;
namespace GenshinImpactMovementSystem
{
public class GameController : MonoBehaviour
{
public Button saveButton;
public Button loadButton;
public CinemachineVirtualCamera camera;
public const string playerPath = "Prefabs/Player";
private static string dataPath = string.Empty;
void Awake()
{
if (Application.platform == RuntimePlatform.IPhonePlayer)
{
dataPath = System.IO.Path.Combine(Application.persistentDataPath, "Resources/actors.xml");
}
else
{
dataPath = System.IO.Path.Combine(Application.dataPath, "Resources/actors.xml");
}
}
void Start()
{
CreateActor(playerPath, new Vector3(0, 0, 0), Quaternion.identity);
}
public static Actor CreateActor(string path, Vector3 position, Quaternion rotation)
{
GameObject prefab = Resources.Load<GameObject>(path);
GameObject go = GameObject.Instantiate(prefab, position, rotation) as GameObject;
Player playerScript = go.GetComponent<Player>();
Transform cameraLookAt = playerScript.cameraPointLookAt;
CinemachineVirtualCamera cam = FindObjectOfType<CinemachineVirtualCamera>();
cam.Follow = cameraLookAt;
cam.LookAt = cameraLookAt;
playerScript.CameraRecenteringUtility.VirtualCamera = cam;
Actor actor = go.GetComponent<Actor>() ?? go.AddComponent<Actor>();
return actor;
}
public static Actor CreateActor(ActorData data, string path, Vector3 position, Quaternion rotation)
{
GameObject prefab = Resources.Load<GameObject>(path);
GameObject go = GameObject.Instantiate(prefab, position, rotation);
Actor actor = go.GetComponent<Actor>() ?? go.AddComponent<Actor>();
actor.data = data;
return actor;
}
void OnEnable()
{
saveButton.onClick.AddListener(delegate {SaveData.Save(dataPath, SaveData.actorContainer);});
loadButton.onClick.AddListener(delegate {SaveData.Load(dataPath);});
}
void OnDisable()
{
saveButton.onClick.RemoveListener(delegate {SaveData.Save(dataPath, SaveData.actorContainer);});
loadButton.onClick.RemoveListener(delegate {SaveData.Load(dataPath);});
}
}
}
I thought I would show you the player camera recentering utility script because there is an error there also:
using Cinemachine;
using System;
using UnityEngine;
namespace GenshinImpactMovementSystem
{
[Serializable]
public class PlayerCameraRecenteringUtility
{
[field: SerializeField] public CinemachineVirtualCamera VirtualCamera { get; set; }
[field: SerializeField] public float DefaultHorizontalWaitTime { get; private set; } = 0f;
[field: SerializeField] public float DefaultHorizontalRecenteringTime { get; private set; } = 4f;
private CinemachinePOV cinemachinePOV;
public void Initialize()
{
cinemachinePOV = VirtualCamera.GetCinemachineComponent<CinemachinePOV>();
}
public void EnableRecentering(float waitTime = -1f, float recenteringTime = -1f, float baseMovementSpeed = 1f, float movementSpeed = 1f)
{
cinemachinePOV.m_HorizontalRecentering.m_enabled = true;
cinemachinePOV.m_HorizontalRecentering.CancelRecentering();
if (waitTime == -1f)
{
waitTime = DefaultHorizontalWaitTime;
}
if (recenteringTime == -1f)
{
recenteringTime = DefaultHorizontalRecenteringTime;
}
recenteringTime = recenteringTime * baseMovementSpeed / movementSpeed;
cinemachinePOV.m_HorizontalRecentering.m_WaitTime = waitTime;
cinemachinePOV.m_HorizontalRecentering.m_RecenteringTime = recenteringTime;
}
public void DisableRecentering()
{
cinemachinePOV.m_HorizontalRecentering.m_enabled = false;
}
}
}

Related

After implemented state machine for my player, i can't use variables of the state manager inside state scripts

As the title says, I've refactored my player controller and I've implemented a hierarchical state machine.
I want to maintain some variables inside the state manager because they are re-used a lot in my code (e.g. player direction based on input). The problem is: when I'm trying to use the variables, stored in the state manager, inside each different state script, after hitting play they update themselves only in the state manager, instead, the references are equal to their default values.
Below there is an example of some logic behind my implementation (To let them readable, I'm not copying all of their variables and methods), if needed I'll append a link with all the files
Player base state. This defines common logic between states
public abstract class PlayerBaseState
{
protected PlayerStateMachine _context;
protected PlayerStateFactory _factory;
protected PlayerBaseState _currentSuperState;
protected PlayerBaseState _currentSubState;
public PlayerBaseState(PlayerStateMachine context, PlayerStateFactory factory)
{
_context = context;
_factory = factory;
}
public abstract void EnterState();
public abstract void UpdateState();
public abstract void ExitState();
public abstract void CheckSwitchStates();
public abstract void InitialSubState();
public void UpdateStates()
{
UpdateState();
if (_currentSubState != null)
_currentSubState.UpdateStates();
}
protected void SetSuperState(PlayerBaseState newSuperState)
{
_currentSuperState = newSuperState;
}
protected void SetSubState(PlayerBaseState newSubState)
{
_currentSubState = newSubState;
newSubState.SetSuperState(this);
}
protected void SwitchStates(PlayerBaseState newState)
{
ExitState();
newState.EnterState();
_context.currentState = newState;
}
}
Player grounding state
public class PlayerGroundingState : PlayerBaseState
{
public PlayerGroundingState(PlayerStateMachine context, PlayerStateFactory factory)
: base(context, factory)
{
InitialSubState();
}
public override void EnterState()
{
_context.rb.drag = _context.groundDrag;
}
public override void UpdateState()
{
Debug.Log("Ground state: " + _context.direction);
GroundMovement();
CheckSwitchStates();
}
/// <summary>
/// Move the player to the horizontal plane
/// </summary>
private void GroundMovement()
{
if (_context.direction != Vector3.zero)
{
_context.rb.AddForce(_context.direction * _context.walkingSpeed * _context.movementMultiplier, ForceMode.Acceleration);
}
}
}
Player state manager
using System.Collections;
using Unity.VisualScripting;
using UnityEngine;
public class PlayerStateMachine : MonoBehaviour
{
/// <summary>
/// State field
/// </summary>
public PlayerBaseState currentState;
public PlayerBaseState subCurrentState { get; set; }
public PlayerStateFactory playerStateFactory { get; set; }
[Header("References")]
[SerializeField] public Rigidbody rb;
[SerializeField] public Transform groundCheck;
[SerializeField] public PlayerAnimator playerAnimator;
[Header("Ground check fields")]
public float groundCheckRadius;
public LayerMask groundMask;
[Header("Walk fields")]
public float walkingSpeed;
[Header("Dash fields")]
public float dashForce;
public float dashCooldown;
[Tooltip("Moltiplicatore per velocità di movimento")]
public float movementMultiplier;
public float airMultiplier = .5f;
[Tooltip("Drag attributes for different situations")]
public float groundDrag, airDrag;
[Header("Multiple jumps variables")]
public float jumpForce;
public int jumpCounter;
public int maxJumpCounter { get; set; }
public string jumpButton = "Jump";
private float _horizontal;
private float _vertical;
private Vector3 _direction;
private bool _canDash;
private bool _freeze;
private bool _isGrounded;
public float horizontal { get { return _horizontal; } set { _horizontal = value; } }
public float vertical { get { return _vertical; } set { _vertical= value; } }
public Vector3 direction { get { return _direction; } set { _direction = value; } }
public bool canDash { get { return _canDash; } set { _canDash = value; } }
public bool freeze { get { return _freeze; } set { _freeze = value; } }
public bool isGrounded { get { return _isGrounded; } set { _isGrounded = value; } }
private void Awake()
{
rb = GetComponent<Rigidbody>();
rb.freezeRotation = true;
playerAnimator = GetComponent<PlayerAnimator>();
}
private void Start()
{
playerStateFactory = new PlayerStateFactory(this);
currentState = playerStateFactory.Grounded();
currentState.EnterState();
Debug.Log(currentState.ToString());
}
private void Update()
{
currentState.UpdateStates();
//Controlla se il player è a terra
_isGrounded = IsGrounded();
//Ricava il vettore di movimento
GetDirectionVector();
DashHandler(); //Permette di fare dash in ogni statox
Debug.Log(direction + "; " + isGrounded);
}
public void GetDirectionVector()
{
_horizontal = Input.GetAxisRaw("Horizontal");
_vertical = Input.GetAxisRaw("Vertical");
_direction = transform.forward * _vertical + transform.right * _horizontal;
}
public bool IsGrounded() => Physics.CheckSphere(groundCheck.position, groundCheckRadius, groundMask);
}
For context, PlayerStateFactory instantiates every player state based on player conditions
public class PlayerStateFactory
{
PlayerStateMachine _context;
public PlayerStateFactory(PlayerStateMachine context)
{
_context = context;
}
public PlayerBaseState Idle()
{
return new PlayerIdleState(_context, this);
}
public PlayerBaseState Walking()
{
return new PlayerWalkingState(_context, this);
}
public PlayerBaseState Jumping()
{
return new PlayerJumpState(_context, this);
}
public PlayerBaseState Grounded()
{
return new PlayerGroundingState(_context, this);
}
public PlayerBaseState InAir()
{
return new PlayerInAirState(_context, this);
}
}
SOLVED
I don't know that i need to write
using UnityEngine
inside all the class of unity.

After loading from json file, all scriptableobjects in main scriptableobject are none

I have an scriptable object script for my inventory, which saves some goods there. Goods are scriptable objects too and they are not changing.
Inventory script:
public class InventoryList : ScriptableObject
{
public List<KeyObject> keys;
public List<HealthPotion> healingGoods;
public List<ScrollObject> scrolls;
private string path {
get { return Application.persistentDataPath + #"/Inventory.IO"; }
}
public void Save() {
string json = JsonUtility.ToJson(this);
File.WriteAllText(path, json);
}
public void Load() {
string json = File.ReadAllText(path);
JsonUtility.FromJsonOverwrite(json, this);
}
}
Healing potion script:
public class HealthPotion : ScriptableObject, IItemsCollect
{
[SerializeField] private InventoryList InventoryList;
[SerializeField] private Sprite Sprite;
[SerializeField] private string Description;
[SerializeField] private int Cost = 200;
private bool willdestroy { get; set; }
bool IItemsCollect.DestroyOnUse => willdestroy;
string IItemsCollect.Description => Description;
int IItemsCollect.Cost => Cost;
Sprite IItemsCollect.Sprite => Sprite;
public void AddToInventoryList() {
InventoryList.healingGoods.Add(this);
InventoryList.Save();
}
public void Use(SpiritController spiritController, ControllerCanvas controllerCanvas) {
willdestroy = spiritController.HealthAdd();
if (willdestroy) {
InventoryList.healingGoods.Remove(this);
InventoryList.Save();
}
}
}
Key script:
public class KeyObject : ScriptableObject, IItemsCollect
{
[SerializeField] private InventoryList InventoryList;
[SerializeField] private Sprite Sprite;
[SerializeField] private string Description;
[SerializeField] private int Cost = 400;
public string KeyCode;
bool IItemsCollect.DestroyOnUse => false;
string IItemsCollect.Description => Description;
int IItemsCollect.Cost => Cost;
Sprite IItemsCollect.Sprite => Sprite;
public void AddToInventoryList() {
if (!InventoryList.keys.Contains(this)) {
InventoryList.keys.Add(this);
InventoryList.Save();
}
}
public void Use(SpiritController spiritController, ControllerCanvas controllerCanvas) {
return;
}
}
Scroll script:
public class ScrollObject : ScriptableObject, IItemsCollect
{
[SerializeField] private InventoryList InventoryList;
[SerializeField] private Sprite Sprite;
[SerializeField] private string Description;
[SerializeField] private int Cost = 400;
public string Text;
public Sprite SpriteForScroll;
bool IItemsCollect.DestroyOnUse => false;
string IItemsCollect.Description => Description;
int IItemsCollect.Cost => Cost;
Sprite IItemsCollect.Sprite => Sprite;
public void AddToInventoryList() {
if (!InventoryList.scrolls.Contains(this)) {
InventoryList.scrolls.Add(this);
InventoryList.Save();
}
}
public void Use(SpiritController spiritController, ControllerCanvas controllerCanvas) {
if (SpriteForScroll != null) controllerCanvas.ShowScrollAndImage(SpriteForScroll);
else controllerCanvas.ShowScrollAndText(Text);
}
}
After the save I have this:
But if I restart Unity and reload the inventory scriptableobject, I will have this:
Am I save something wrong? My version of unity is 2020.2.2f.

Dialogue does not begin with the first sentence and it starts before I press key to begin dialogue in Unity

I am working on a dialogue and questing system for a 2d game I am working on. I am attempting to have multiple NPCs that will give different quests with different dialogue that is unique to each quest. I attempt to trigger my dialogue whenever a player presses the E key. Currently my game displays the dialogue whenever the player becomes in contact with the NPCs collider. The dialogue also begins with the second sentence of the dialogue array. Additionally, once the player has interacted with multiple npcs, the dialogue for all npc becomes the dialogue of the last npc that was interacted with.
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
public class QuestGiver : NPC
{
public bool AssignedQuest { get; set; }
public bool Helped { get; set; }
[SerializeField]
private GameObject quests;
[SerializeField]
private string questType;
private Quest Quest { get; set; }
public CharacterController2D player;
public GameObject questWindow;
public Text titleText;
public Text descriptionText;
public Text expRewardText;
public Text currencyRewardText;
private void Start()
{
}
public override void Interact()
{
if (!AssignedQuest && !Helped)
{
DialogueManager.Instance.AddNewDialogue(dialogue, name);
AssignQuest();
}
else if (AssignedQuest && !Helped)
{
CheckQuest();
}
else
{
DialogueManager.Instance.AddNewDialogue(Quest.completedDialogue, name);
}
}
void AssignQuest()
{
AssignedQuest = true;
Quest = (Quest)quests.AddComponent(Type.GetType(questType));
}
void CheckQuest()
{
if (Quest.Completed)
{
Quest.GiveReward();
Helped = true;
AssignedQuest = false;
DialogueManager.Instance.AddNewDialogue(Quest.rewardDialogue, name);
Destroy(quests.GetComponent(Type.GetType(questType)));
}
else
{
DialogueManager.Instance.AddNewDialogue(Quest.inProgressDialogue, name);
}
}
public void OpenQuestWindow()
{
questWindow.SetActive(true);
titleText.text = Quest.QuestName;
descriptionText.text = Quest.Description;
expRewardText.text = Quest.ExpRewards.ToString();
currencyRewardText.text = Quest.CurrencyReward.ToString();
}
public void AcceptQuest()
{
questWindow.SetActive(false);
Quest.Completed = false;
player.questsList.Add(Quest);
}
}
This is the Quest script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
[System.Serializable]
public class Quest : MonoBehaviour
{
public List<QuestGoal> Goals { get; set; } = new List<QuestGoal>();
public string[] inProgressDialogue, rewardDialogue, completedDialogue;
public string QuestName { get; set; }
public string Description { get; set; }
public int ExpRewards { get; set; }
public int CurrencyReward { get; set; }
public Item ItemReward { get; set; }
public bool Completed { get; set; }
public void CheckGoals()
{
Completed = Goals.All(q => q.Completed);
if (Completed) GiveReward();
}
public void GiveReward()
{
if (ItemReward != null)
Inventory.inventory.Add(ItemReward);
}
This is the NPC:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NPC : Interactable
{
public string[] dialogue;
public string name;
public override void Interact()
{
base.Interact();
DialogueManager.Instance.AddNewDialogue(dialogue, name);
Debug.Log("Interacting with " + name);
}
public void TriggerDialogue()
{
FindObjectOfType<DialogueManager>().AddNewDialogue(dialogue, name);
}
}
This is my dialogue script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
public class DialogueManager : MonoBehaviour
{
#region
public static DialogueManager Instance { get; set; }
public GameObject dialoguePanel;
private void Awake()
{
dialoguePanel.SetActive(false);
if (Instance != null && Instance != this)
{
Debug.Log(Instance);
Destroy(Instance);
}
else
{
Instance = this;
}
}
#endregion
public Text nameText, dialogueText;
public Button continueButton;
public Animator animator;
public string npcName;
int dialogueIndex;
public List<string> dialogueLines = new List<string>();
void Start()
{
}
public void AddNewDialogue(string[] lines, string npcName)
{
dialogueIndex = 0;
dialogueLines = new List<string>();
foreach (string line in lines)
{
dialogueLines.Add(line);
}
this.npcName = npcName;
Debug.Log(dialogueLines.Count);
Debug.Log(npcName);
CreateDialogue();
}
public void CreateDialogue()
{
nameText.text = npcName;
dialogueText.text = dialogueLines[dialogueIndex];
dialoguePanel.SetActive(true);
animator.SetBool("IsOpen", true);
ContinueDialogue();
}
public void ContinueDialogue()
{
if (dialogueIndex < dialogueLines.Count - 1)
{
dialogueIndex++;
dialogueText.text = dialogueLines[dialogueIndex];
}
else
{
EndDialogue();
}
StopAllCoroutines();
StartCoroutine(TypeSentence(dialogueText.text));
}
IEnumerator TypeSentence (string sentence)
{
dialogueText.text = "";
foreach (char letter in sentence.ToCharArray())
{
dialogueText.text += letter;
yield return null;
}
}
void EndDialogue()
{
animator.SetBool("IsOpen", false);
Debug.Log("End of conversation");
}
}
This is part of the Player controller:
using UnityEngine;
using UnityEngine.Events;
using Spine.Unity;
using UnityEngine.EventSystems;
using System.Collections.Generic;
public class CharacterController2D : MonoBehaviour
{
private GameObject triggeringNpc;
public GameObject npcText;
public List<Quest> questsList = new List<Quest>();
private bool triggering;
private void OnTriggerEnter2D(Collider2D other)
{
Interactable interactable = other.gameObject.GetComponent<Interactable>();
if (interactable != null)
{
interactable.Interact();
}
if (other.tag == "NPC")
{
triggering = true;
triggeringNpc = other.gameObject;
}
if (other.tag == "QuestGiver")
{
triggering = true;
triggeringNpc = other.gameObject;
}
}
private void OnTriggerExit2D(Collider2D other)
{
if (other.tag == "NPC")
{
triggering = false;
triggeringNpc = null;
}
if (other.tag == "QuestGiver")
{
triggering = false;
triggeringNpc = null;
}
}
private void Update()
{
if (triggering)
{
npcText.SetActive(true);
if (Input.GetKeyDown(KeyCode.E))
{
FindObjectOfType<QuestGiver>().TriggerDialogue();
}
}
else
{
npcText.SetActive(false);
}
}
}
Thank you in advance, sorry for the long post.
Dialogue starting on the second line:
In the CreateDialogue() method, at the end you are calling ContinueDialogue(). So you create dialogue and then immediately tell it to go to the next line. I think instead you might want to be calling StartCoroutine(TypeSentence(dialogueText.text)) at the end of CreateDialogue().
Interaction issues:
You're calling Interact() at the beginning of OnTriggerEnter2D by doing interactable.Interact(). Here, erase all the code inside your OnTriggerEnter2D method and replace it with this.
if (other.tag == "NPC" || other.tag == "QuestGiver") {
triggering = true;
triggeringNpc = other.gameObject;
} else if (interactable != null) { interactable.Interact(); }

Unity2D. Method "OnTriggerEnter2D" does not work on prefabs

I have one problem, I am not running the "OnTriggerEnter2D" method on the prefab.
I took the object, threw a script on it, added the right components and made it prefab.
I have a hero when he attacks a collider appears which is a trigger.
If this collider is a player's sword then the enemy receives damage.
A regular object (not a prefab) gets damaged, but if I do this object a prefab and drag it onto the stage then the "OnTriggerEnter2D" method does not work.
Here's the enemy script. I also poured my project on the Github, for a better understanding. I will be very grateful for the help, because I could not understand the reason. My project -
https://github.com/OleksandrKupchuk/SimpleGame
//Enemy Archer
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyArcher : EnemyBase
{
[SerializeField] GameObject arrowPrefab;
[SerializeField] Transform startPositionArrow;
public override void Start()
{
base.Start();
ChangeStateEnemy(new IdleState());
}
public new void Update()
{
//ChangeState(currentState);
StateEnemy();
}
private void StateEnemy()
{
currentState.Execute();
}
public override void Attack()
{
timeAttack += Time.deltaTime;
enemyAnimator.SetFloat("animatorEnemyRun", 0);
if (timeAttack >= delayAttack)
{
CanAttack = true;
timeAttack = 0;
}
if (CanAttack)
{
enemyAnimator.SetTrigger("animatorEnemyAttack");
CanAttack = false;
}
}
public void FireArrow()
{
if (facingRight)
{
enemyAnimator.SetTrigger("animatorEnemyAttack");
GameObject arrow = Instantiate(arrowPrefab, startPositionArrow.position, Quaternion.identity);
arrow.GetComponent<EnemyArrowMove>().ArrowInitialization(Vector2.right);
}
else
{
GameObject arrow = Instantiate(arrowPrefab, startPositionArrow.position, Quaternion.Euler(new Vector3(0f, 180f, 0f)));
arrow.GetComponent<EnemyArrowMove>().ArrowInitialization(Vector2.left);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.CompareTag("PlayerSword"))
{
Debug.Log("Take");
TakeDamage();
EnemyTarget = collision.gameObject;
}
}
}
//////
//Enemy Base
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(BoxCollider2D))]
[RequireComponent(typeof(CircleCollider2D))]
public class EnemyBase : CharacterBase
{
public IStateEnemy currentState;
protected float timeAttack;
[SerializeField] protected float delayAttack;
public bool CanAttack { get; set; }
protected float dirPlayer;
public GameObject EnemyTarget { get; set; }
[SerializeField] protected float enemyRangeAttack;
[SerializeField] int experienceForTheEnemy;
public bool EnemyRangeAttack
{
get
{
if (EnemyTarget != null)
{
if (Vector2.Distance(EnemyTarget.transform.position, transform.position) <= enemyRangeAttack)
{
return true;
}
}
return false;
}
}
public bool EnemyOutsideEdge
{
get
{
if(transform.position.x >= rightEdge.position.x || transform.position.x <= leftEdge.position.x)
{
return true;
}
return false;
}
}
//edges for enemy
[SerializeField] protected Transform leftEdge;
[SerializeField] protected Transform rightEdge;
public bool EnemyDie
{
get
{
if(health <= 0)
{
return true;
}
return false;
}
}
[SerializeField] EdgeCollider2D enemySword;
[SerializeField] private Rigidbody2D enemyRigidbody;
public Rigidbody2D EnemyRigidbody { get => enemyRigidbody; set => enemyRigidbody = value; }
public Animator enemyAnimator;
[SerializeField] int takeDamage;
public bool EnemyAttack { get; set; }
public bool EnemyHit { get; set; }
protected float directionEnemy;
public override void Start()
{
base.Start();
enemyAnimator = GetComponent<Animator>();
}
public void Update()
{
}
public void TakeDamage()
{
if (!EnemyDie)
{
enemyAnimator.SetTrigger("animatorEnemyHit");
health -= takeDamage;
if (health <= 0)
{
enemyAnimator.SetTrigger("animatorEnemyDie");
Destroy(gameObject, 1.5f);
Player.PlayerInstance.AddIndicatorForPlayer(experienceForTheEnemy);
}
}
}
public void EnemySwordEnabled()
{
enemySword.enabled = true;
}
public void EnemySwordDisabled()
{
enemySword.enabled = false;
}
public void Flip()
{
//Debug.Log("Flip");
facingRight = !facingRight;
transform.localScale = new Vector2(transform.localScale.x * -1, transform.localScale.y);
//transform.Rotate(0f, 180f, 0f);
}
public void Walk()
{
if (!EnemyAttack && !EnemyDie && !EnemyHit)
{
if ((ChangeSide().x > 0 && transform.position.x < rightEdge.position.x) || (ChangeSide().x < 0 && transform.position.x > leftEdge.position.x))
{
enemyAnimator.SetFloat("animatorEnemyRun", 1);
transform.Translate(ChangeSide() * speed * Time.deltaTime);
}
}
}
public Vector2 ChangeSide()
{
if (facingRight)
{
return Vector2.right;
}
return Vector2.left;
}
public void ChangeDirection()
{
if (transform.position.x >= rightEdge.position.x || transform.position.x <= leftEdge.position.x)
{
Flip();
}
}
public void EnemyLookTarget()
{
if (!EnemyDie && EnemyTarget != null)
{
directionEnemy = EnemyTarget.transform.position.x - transform.position.x;
if (directionEnemy < 0 && facingRight || directionEnemy > 0 && !facingRight)
{
Flip();
}
}
}
public virtual void Attack()
{
timeAttack += Time.deltaTime;
//enemyAnimator.SetFloat("animatorEnemyRun", 0);
if (timeAttack >= delayAttack)
{
CanAttack = true;
timeAttack = 0;
}
if (CanAttack)
{
enemyAnimator.SetTrigger("animatorEnemyAttack");
CanAttack = false;
}
}
public void ChangeStateEnemy(IStateEnemy newState)
{
currentState = newState;
currentState.Enter(this);
}
}

Add custom object to the script

I just cant manage to add a public object to the dcript i have.
There is code:
public class Player : MonoBehaviour {
public string charName = "";
public int currentLevel = 0;
public int experiense = 0;
public int strength = 1;
public int agility = 1;
public int maxHealth = 30;
public float currentHealth = 30;
public int maxActionPoints = 5;
public int currentLevelPoints = 10;}
there is another script where i want to add a public property with this class
public class CharManager : MonoBehaviour {
public GameObject currentCharacter;
public GameObject charMenu;
public Player currentPlayerStats;
public void changeCharacter(GameObject character)
{
if (currentCharacter){
saveCharacter ();
}
currentCharacter = character;
loadSavedInfo ();
}
void loadSavedInfo()
{
string playerJson = "";
if (currentCharacter.tag== "Man")
{
if (File.Exists(Application.persistentDataPath +"/Char1.json"))
{
playerJson = File.ReadAllText(Application.persistentDataPath +"/Char1.json");
}
}
else
{
if (File.Exists(Application.persistentDataPath +"/Char2.json"))
{
playerJson = File.ReadAllText(Application.persistentDataPath +"/Char2.json");
}
}
if (playerJson != string.Empty)
{
Player thePlayer = JsonConvert.DeserializeObject<Player>(playerJson);
currentPlayerStats = thePlayer;
}
else
{
currentPlayerStats = gameObject.AddComponent<Player>() as Player;
}
}
This code add NEW player component and currentPlayerStats have class CharManager... what am i doing wrong?
Any help is very appreciated!
gameObject.AddComponent() adds a MonoBehaviour derived component to the game object. Player does not derive from MonoBehaviour thus it cannot be added
Looks like Player is just a regular class, so you can just create an object of that class
Player currentPlayerStats = new Player();
I figured it out.
Player class must be non MonoBehaviour class. A class where i have to access the player class should have a public property:
public Player thePlayer;
not
public GameObject thePlayer;
Thanks everyone!

Categories