I’m making a 2D game where I have enemies coming in from left to right. The enemies are made up of a sprite sheet that I have put into their own sorting layer. The problem I am having is that I spawn the enemies at different positions along the Y axis. Doing this means that the enemies will overlap each other as they are quite large. However once spawned they are blending together based on the sorting layer order index of each body part. I’m trying to find a method of stopping this from happening. I’ve come up with an idea that each time a new enemy is spawned, the Z position of the object is relevant to the Y position. However I have no idea of how to implement this or if it is even the right way to go about it. Any help is greatly appreciated.
One more question I have is, Is it bad practice to have OnTrigger methods on both objects colliding. I ask as I have a hitmark prefab I instantiate via the projectile script and a damage function on the other object.
No I understand why I need the sorting layer. I was just referencing that to explain what is happening when the instances of my prefab enemy overlap each other. Individually the sprites are perfect, except when they collide with each other, as they almost blend together.
i want the enemy at the bottom of the screen to be in front of the middle enemy and the middle In front of the top. Does that make sense?
I think you mean the Y axis then. But I’m still not quite sure how your prefabs are setup. Are your enemy prefabs comprised of more than 1 sprite? e.g. does each enemy have multiple parts that are placed at unique sorting order numbers?
Are your enemies capable of going up/down or do they only move left/right?
Yes you are right, I mean the Y axis. I feel a right idiot haha. I have edited the question.
Yes the enemy prefabs are made up of multiple sprites to which I have animations attached to the character rig. Yes each body part I have assigned a different sorting order number.
The enemies move along the x Axis only, from left to right.
The enemies at the bottom point I want to be spawned on top of the ones above/behind. I’ve attached a pic demonstrating
what I mean. The only solution I can think of is to adjust the z axis of every sprite depending on where it sits in the Y axis, but don’t know where to start with this. Thanks again
This is where I think sorting order falls short. What you can do is:
a) have multiple sorting layers and have each enemy in different one depending on y position. It can be very limiting though. You can also add or substract from the sorting order based on y position, so enemies in the same sorting layer have different order.
b) use z-ordering:
[SerializeField]
float zOffset = 0;//positive numbers are farther from camera
void Update(){
transform.position = new Vector3(transform.position.x, transform.position.y, transform.position.y/100 + zOffset);
}
this puts objects farther away from the camera the higher y coordinate they have. Keep in mind that you can’t use sorting order with this, but you can set an offset for each body part to emulate it.
Thanks for your input Pagi, I’ve tried the above by instantiating the enemy prefabs with that conditional Z position, but no joy, the objects still blend. I understand what you mean now by the sorting layers won’t work it, as the sorting layers are taking priority over the Z positins. I’m debating whether to just scrap using the sorting layers and have the sprites positioned in different Z positions within a parent character rig Gameobject.
Aerin41, I am indeed using an orthographic camera. I’ll try what i’ve said above and get back to the thread with what works and doesn’t. I’ve seen lots of game do this and never thought of this being a problem that I would have the most trouble with, but there ya go XD
I’m very new to Unity and coding so please point out whether the code is a terrible way of doing things or not.
I’ve somewhat fixed the problem. I kept the sorting layers as is, and did what Pagi suggested and created other layers. Using a for loop and using the GetComponentsInChild, I’ve come up with the solution below. It only works now as the sorting layers don’t blend at the top of each enemy prefab.
for (int i = 0; i < sprites.Length; i++) {
if (transform.position.y >= -1.5) {
sprites [i].sortingLayerName = "EnemyLayer";
} else if (transform.position.y >= -2.5 && transform.position.y < -1.5) {
sprites [i].sortingLayerName = "EnemyLayer2";
} else if (transform.position.y >= -3.5 && transform.position.y < -2.5) {
sprites [i].sortingLayerName = "EnemyLayer3";
} else if (transform.position.y >= -4.5 && transform.position.y < -3.5) {
sprites [i].sortingLayerName = "EnemyLayer4";
}
That is the code I’ve applied to my enemy Script. Would this be a little too demanding in terms of computing power for a mobile? I’m basically cycling through all child objects of my enemy, then multiple checks in the IF statements, and I’m spawning these enemies relatively quickly. This is on top of everything else I have running in the script, ie, collision detections and animations.
The reason I ask is this seems a lot of checks for one very basic enemy
Well if you have only 3 potential spawn points then you could just assign a sorting layer to each spawn point essentially. However, if it’s possible for an enemy to spawn anywhere along the Y axis it’s a lot more complicated.
You could try and get everything properly setup in the enemy prefab without using Order in Layer. Then when the enemy is spawned you could set the order in layer through code.
using UnityEngine;
using System.Collections.Generic;
public class EnemyScript : MonoBehaviour
{
// Might be better to make this public and set the references in the inspector
// That way each enemy doesn't have to get all their renderers when they spawn
private List<SpriteRenderer> _allRenderers = new List<SpriteRenderer>();
// Use this for initialization
void Start ()
{
_allRenderers.Add(this.GetComponent<SpriteRenderer>());
_allRenderers.AddRange(this.GetComponentsInChildren<SpriteRenderer>());
foreach(SpriteRenderer renderer in _allRenderers)
{
renderer.sortingOrder = (int) this.gameObject.transform.position.y;
}
}
}
Edit: Just saw your recent post. Give me a sec.
Edit2: Yeah what you posted will work. There’s nothing strictly wrong with it. You could put the sprites.Length in a local variable so it’s not checking the length every loop iteration. Same thing with the transform.position, save it as a Vector3 local variable so in the worst case it doesn’t have to go down an extra level each check.