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.
Related
I am making a Farming game in Unity and I tried to implement an EXP System. I can not implement a function where you can plant a crop from an X player level.
This Code manages the whole farm
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FarmManager : MonoBehaviour
{
[Header("Money Settings")]
public PlantItem selectPlant;
public bool isPlanting = false;
public int money = 100;
public Text moneyTxt;
[Header("Button Color Settings")]
public Color buyColor = Color.green;
public Color cancelColor = Color.red;
public Color lockedColor = Color.grey;
[Header("Button Audio Settings")]
public AudioSource clickSound;
[Header("Cursor Settings")]
public Texture2D cursorArrow;
public Texture2D cursorPickaxe;
[Header("XP Settings")]
public int maxExp;
public float updatedExp;
public float plusXp;
public Image ExpBar;
public float expIncreasedPerSecond;
public int playerLevel;
public Text levelText;
public Text xpLevel;
// Start is called before the first frame update
void Start()
{
Cursor.SetCursor(cursorArrow, Vector2.zero, CursorMode.ForceSoftware);
moneyTxt.text = "$"+money;
playerLevel =1;
expIncreasedPerSecond =5f;
maxExp = 25;
updatedExp = 0;
plusXp = 0;
}
void Update () {
//updatedExp += expIncreasedPerSecond * Time.deltaTime;
ExpBar.fillAmount = updatedExp / maxExp;
levelText.text = playerLevel + "";
xpLevel.text = updatedExp + "/" + maxExp;
if (updatedExp >= maxExp)
{
plusXp = updatedExp-maxExp;
playerLevel++;
updatedExp=0+plusXp;
maxExp+=maxExp;
}
}
public void SelectPlant(PlantItem newPlant)
{
if(selectPlant == newPlant)
{
Debug.Log("Deselected" + selectPlant.plant.plantName);
selectPlant.btnImage.color = buyColor;
selectPlant.btnTxt.text = "Buy";
selectPlant = null;
isPlanting = false;
clickSound.Play();
}
else
{
if(selectPlant!=null)
{
selectPlant.btnImage.color = buyColor;
selectPlant.btnTxt.text = "Buy";
}
selectPlant = newPlant;
selectPlant.btnImage.color = cancelColor;
selectPlant.btnTxt.text = "Cancel";
Debug.Log("Selected" + selectPlant.plant.plantName);
isPlanting = true;
clickSound.Play();
}
}
public void Transaction(int value)
{
money+=value;
moneyTxt.text = "$"+money;
}
public void GiveXP (float value)
{
updatedExp += value;
}
}
And this is the code where I import the information from
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "New Plant", menuName ="Plant")]
public class PlantObject : ScriptableObject
{
[Header("Plant settings")]
public string plantName;
public Sprite[] plantStages;
public float timeBtwStages;
[Header("Money Settings")]
public int buyPrice;
public int sellPrice;
[Header("XP Settings")]
public int xpAmount;
public int levelNeeded;
[Header("Plant Icon")]
public Sprite icon;
}
I tried doing it this way, but it would not fix my issue and would not disable the crop until the needed level was reached and it gave me a ton of errors.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FarmManager : MonoBehaviour
{
[Header("Money Settings")]
public PlantItem selectPlant;
public bool isPlanting = false;
public int money = 100;
public Text moneyTxt;
[Header("Button Color Settings")]
public Color buyColor = Color.green;
public Color cancelColor = Color.red;
public Color lockedColor = Color.grey;
[Header("Button Audio Settings")]
public AudioSource clickSound;
[Header("Cursor Settings")]
public Texture2D cursorArrow;
public Texture2D cursorPickaxe;
[Header("XP Settings")]
public int maxExp;
public float updatedExp;
public float plusXp;
public Image ExpBar;
public float expIncreasedPerSecond;
public int playerLevel;
public Text levelText;
public Text xpLevel;
// Start is called before the first frame update
void Start()
{
Cursor.SetCursor(cursorArrow, Vector2.zero, CursorMode.ForceSoftware);
moneyTxt.text = "$"+money;
playerLevel =1;
expIncreasedPerSecond =5f;
maxExp = 25;
updatedExp = 0;
plusXp = 0;
}
void Update () {
//updatedExp += expIncreasedPerSecond * Time.deltaTime;
ExpBar.fillAmount = updatedExp / maxExp;
levelText.text = playerLevel + "";
xpLevel.text = updatedExp + "/" + maxExp;
if (updatedExp >= maxExp)
{
plusXp = updatedExp-maxExp;
playerLevel++;
updatedExp=0+plusXp;
maxExp+=maxExp;
}
}
public void SelectPlant(PlantItem newPlant)
{
if(selectPlant == newPlant)
{
Debug.Log("Deselected" + selectPlant.plant.plantName);
selectPlant.btnImage.color = buyColor;
selectPlant.btnTxt.text = "Buy";
selectPlant = null;
isPlanting = false;
clickSound.Play();
}
else
{
if(selectPlant!=null)
{
selectPlant.btnImage.color = buyColor;
selectPlant.btnTxt.text = "Buy";
}
selectPlant = newPlant;
selectPlant.btnImage.color = cancelColor;
selectPlant.btnTxt.text = "Cancel";
Debug.Log("Selected" + selectPlant.plant.plantName);
isPlanting = true;
clickSound.Play();
}
if (selectPlant.plant.levelNeeded > playerLevel)
{
selectPlant.btnImage.color = lockedColor;
}
}
public void Transaction(int value)
{
money+=value;
moneyTxt.text = "$"+money;
}
public void GiveXP (float value)
{
updatedExp += value;
}
}
I have been stuck on this for weeks now any ideas?
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.
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;
}
}
}
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(); }
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!