I have a node that takes in an SO to extends/change is functionality. The idea is to generate my word from these nodes and alter what they are by plugging in different SO. Could be a navigation node to a prop that pools prefab objects. My question is when I generate all these nodes will the SO properties act like a static variable, will changing a SO property result in changing it for all the nodes?. Also im not clear how to set this up and access it. My failed attempt below
using UnityEngine;
using System.Collections;
[System.Serializable]
public class Node {
public Vector3 worldPosition; // World pos
public int gridX; // Grid X pos
public int gridY; // Grid Y pos
[SerializeField]public NodeAttrs[] nodeAttrs; // Takes an SO to extend functionality
// Constructor
public Node( Vector3 _worldPos, int _gridX, int _gridY) {
worldPosition = _worldPos;
gridX = _gridX;
gridY = _gridY;
}
}
My SO trying to extend base node
[CreateAssetMenu(menuName="ScriptableObject Assets/NodeAttributes/NodeAttrAStar")]
public class NodeAttrAStar : NodeAttrs {
[SerializeField]private int _obstaclePenalty;
public int obstaclePenalty{
get {return _obstaclePenalty; }
set {_obstaclePenalty = value; }
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class NodeAttrs : ScriptableObject {
}
Maybe add in the NodeAttrs[ ] in as a param for the constructor, and the in your grid when you are populating it with nodes just create your so and pass it to the constructor for the node.
When I create my Grid of nodes I have no reference to the SOs. I need to somehow create an instance of the SO for each node. Im not sure how to access the obstaclePenalty property per node. Getting the non SO attributes seem simple
foreach (Node n in grid) {
Debug.Log (n.gridX +" "+n.gridY);
}
Here is the create grid
void CreateGrid() {
grid = new Node[gridSizeX, gridSizeY];
Vector3 worldBottomLeft = transform.position - Vector3.right * gridWorldSize.x / 2 - Vector3.forward * gridWorldSize.y / 2;
for (int x = 0; x < gridSizeX; x++) {
for (int y = 0; y < gridSizeY; y++) {
Vector3 worldPoint = worldBottomLeft + Vector3.right * (x * nodeDiameter + nodeRadius) + Vector3.forward * (y * nodeDiameter + nodeRadius);
grid [x, y] = new Node (worldPoint, x, y);
}
}
}
Thanks Jister this seems to work. One more question. Is it possible to instance all the SO in the constructor by looping over the different SO connected to [SerializeField]public NodeAttrs[ ] nodeAttrs; and not passing an argument
How do I find the SO name to instance or can I just somehow instance the whole list of SO
but it’s not very optimal.
maybe it would be better to use some kind of Factory Method
public class AttrsFactory
{
public static Attrs Create(AttrsType a)
{
return (Attrs)ScriptableObject.CreateInstance(a.ToString());
}
}
with the code above you would use an enum with all the types of Attrs listed. this way you could iterate over the enum and create all the Attrs types you need.
Thanks for the help on this, I took a step back a thought what if I have one SO per type of node and attrs as MonoBehaviour. Problem now is why cant I drag in my NodeAttributeBase to NodeBase::nodeAttributeBase in the editor ?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName="ScriptableObject Assets/Test/NodeBase")]
public class NodeBase : ScriptableObject {
[SerializeField]private NodeAttributeBase[] _nodeAttributes;
public NodeAttributeBase[] nodeAttributeBase{get {return _nodeAttributes;}}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class NodeAttributeBase: MonoBehaviour {
public Vector3 worldPosition;
public int gridX;
public int gridY;
}
maybe tell us what the end goals is, so we can think along
so i get you want a grid of node and the node’s can hold a SO for functionality.
first of why a SO?
then you wanted a list of SO’s per node. Why? to choose between the SO functionalities? So If you change to one SO/Node, which node has what SO? and why?
if all these things are clear, I bet there’s an easy way to do it
OK let me try to explain what im trying to achieve. Here is my dream workflow.
1)I create an empty base node from my node menu as a SO.
2)I create attributes that I want to connect to the empty base node from my nodeAttributs menu as SO. eg prefab name or Astar variables or pool functionality.
3)I connect my SO attributes to my base node in the Unity editor designing my Node.
4)I connect my SO node to my grid script that instance the node to my game world.
I dont have to use SO I just lack knowledge as to what the best approach is.This is the dream but struggling to get there
A ScriptableObject is basically for anything that you need to serialize and save to disk. Keeping them or dropping them is a question of whether you need that functionality or not.
What’s the difference between a node and the attributes that you want to put on them? Why isn’t it possible just to code the node with those attributes to begin with?
Ok reading this, I’m thinking you are making a custom editor with nodes your can drag and drop and connect?
something like:
if so you need the SO’s if not you don’t need them.
The nodes represent anything in my game and depending on the attributes plugged in it behave differently eg I have a grid of nodes, when i attach my prefab attribute and pool attribute they form my game terrain. When i attach my astart attribute the node is use for navigation ect.
i think i would just use an Interface IAttributable or an Abstract class Attribute or even just a Base class with a virtual void Execute() orso…
if your not making something like i showed above, there is no need for a SO in your case i think.