EDIT: By setting spline quality to medium in the spriteshapecontroller inspector, it seems to work… But i still have to go to the scene window to show the mesh the first time. However the collider is there and my character is floating in thin air…
Hi there,
I have beed trying to use the Sprite shape package to make some kind of platformer like the sort of Alto. My idea was to build a few sprite shape controllers ahead of time and repurpose these as needed. So here is what I did:
- at startup I instanciate 3-4 game objects with sprite shapes and colliders attached (one edge collider for the geometry and one box trigger collider for other purposes). I then modify the shapes as needed to fit my needs.
- When the object becomes invisible, it is ‘repurposed’, i.e. I modify the spline in order to continue the path at the end of the currently generated path.
Basically, I see the first repurposing instance for each object in the logs, but when I reach the end of the path, the path is empty. However the colliders are there, cause my object goes on. By going to the scene window and dezooming, I see the objects pop up on the screen and in my game window… I even tried to delete the objects and recreate them instead and I had no luck there… Here is a link to a gif showing the problem I hope :
http://i.imgur.com/GB6nfx6.gifv
And here is the code I use:
Class that creates the objects and modify the spline
public class WorldBuilding : MonoBehaviour
{
public static WorldBuilding instance = null;
public SpriteShapeController prefab;
[Header("World generic data")]
public float m_fSectionSize = 10f;
public float m_fSectionHeight = 100f;
[Range(3,10)]
public int m_iNumberOfPreloadedSections = 3;
SpriteShapeController[] controllers;
int nextSection;
Queue<int> repurposeList = new Queue<int>();
// Use this for initialization
void Start ()
{
if(instance ==null)
{
instance = this;
}
else
{
DestroyImmediate(gameObject);
return;
}
nextSection = m_iNumberOfPreloadedSections;
CreateShapes();
}
void CreateShapes()
{
controllers = new SpriteShapeController[m_iNumberOfPreloadedSections];
for (int i = 0; i < m_iNumberOfPreloadedSections; ++i)
{
CreateShape(i, i, i == 0);
}
}
void CreateShape(int idx, int sectionNumber, bool isFirst = false)
{
controllers[idx] = GameObject.Instantiate<SpriteShapeController>(prefab, transform);
controllers[idx].splineDetail = 32;
MakePath(idx, sectionNumber, isFirst);
}
void MakePath(int idx, int sectionNumber, bool first = false)
{
Spline s = controllers[idx].spline;
s.Clear();
float startPos = sectionNumber * m_fSectionSize;
float endPos = (sectionNumber + 1) * m_fSectionSize;
int offset = 0;
s.InsertPointAt(offset++, new Vector3(endPos, -m_fSectionHeight, 0));
s.InsertPointAt(offset++, new Vector3(startPos, -m_fSectionHeight, 0));
s.InsertPointAt(offset++, new Vector3(startPos, 0, 0));
if (!first)
{
s.SetTangentMode(offset - 1, ShapeTangentMode.Continuous);
s.SetLeftTangent(offset - 1, new Vector3(-1, 0, 0));
s.SetRightTangent(offset - 1, new Vector3(1, 0, 0));
}
s.InsertPointAt(offset++, new Vector3(0.5f * (startPos + endPos), 2f, 0));
s.SetTangentMode(offset - 1, ShapeTangentMode.Continuous);
s.SetLeftTangent(offset - 1, new Vector3(-1, 0, 0));
s.SetRightTangent(offset - 1, new Vector3(1, 0, 0));
s.InsertPointAt(offset++, new Vector3(endPos, 0, 0));
s.SetTangentMode(offset - 1, ShapeTangentMode.Continuous);
s.SetLeftTangent(offset - 1, new Vector3(-1, 0, 0));
s.SetRightTangent(offset - 1, new Vector3(1, 0, 0));
//controllers[idx].BakeMesh(); // Gives an error on splinedetails which sould be between 4 and 32. Setting it right before this call does not change the problem.
//controllers[idx].spriteShapeRenderer.bounds.SetMinMax(new Vector3(startPos, -m_fSectionHeight, 0), new Vector3(endPos, m_fSectionHeight, 0));
controllers[idx].BakeCollider();
BoxCollider2D box = controllers[idx].GetComponent<BoxCollider2D>();
box.size = new Vector2(m_fSectionSize, m_fSectionHeight * 2);
box.offset = new Vector2(0.5f * (startPos + endPos), 0);
WorldSection section = controllers[idx].GetComponent<WorldSection>();
section.Index = idx;
section.WasInside = false;
controllers[idx].gameObject.SetActive(true);
}
public void Repurpose(int idx)
{
Debug.Log("Repurposing " + idx);
repurposeList.Enqueue(idx);
}
// Update is called once per frame
void Update ()
{
RebuildPathAhead();
}
void RebuildPathAhead()
{
while(repurposeList.Count > 0)
{
int idx = repurposeList.Dequeue();
Debug.Log("Rebuild " + idx);
DestroyImmediate(controllers[idx].gameObject);
CreateShape(idx, nextSection++);
//MakePath(idx, nextSection++, false);
}
}
}
Class that handles the becameinvisible part and is attached to the object that has the sprite shape controller component attached to it:
public class WorldSection : MonoBehaviour
{
int index;
public int Index
{
get { return index; }
set { index = value; }
}
bool wasInside = false;
public bool WasInside
{
get { return wasInside; }
set { wasInside = value; }
}
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
private void OnTriggerStay2D(Collider2D collision)
{
//Debug.Log("Inside section");
wasInside = true;
}
public void OnBecameInvisible()
{
Debug.Log("BecameInvisible");
if (!wasInside) return;
WorldBuilding.instance?.Repurpose(index);
gameObject.SetActive(false);
}
}
Thanks for any help that you could give and ask me if you need more infos!.