I am using Pure ECS (so no GO in hierarchy) and am able to get an AI Script to work on my recast graph. The only issue I am having now is the NavMeshCut. I cant seem to strip it away from its base monobehavior (mainly because it needs a transform to act on I think). Has any one got the NavMeshCut to work without being attached to a GO or have any other suggestions?
So for more details, I have a NavMeshCut on my prefab and have it injected onto my Entity. But it wont function correctly and I cant subclass it to get it to work. It has internal marked methods that block me from overriding some methods using the transform (that for me is null). I am using the latest version “Version 4.3.35”. Thanks.
No problem, in the end I just went back to Hybrid, using something like: conversionSystem.AddHybridComponent(seeker).
That seems to be a good compromise between GO and ECS. Its just unrealistic for us to go to pure ECS right now, the work vs the reward is NOT there for our situation.
I too gave up on trying to do navmesh cutting without game objects. It’s lame having game objects just sitting around for no reason other than cutting a navmesh, but I couldn’t find any way around it. I ended up switching to the Agents Navigation package (which is built specifically for ECS) instead of A* Pathfinding Project, but it also has the same problem with navmesh cutting requiring game objects.
If your looking for something closer to pure ECS I made this authoring component that handles a NavmeshCut Gameobject for an Entity prefab. You can just add the authoring then create and assign a NavmeshCut child on your Entity prefab.
using Pathfinding;
using Unity.Collections;
using Unity.Entities;
using Unity.Transforms;
using UnityEngine;
//Entities need gameobjects with a NavmeshCut to modify the navmesh
public class NavmeshCutAuthoring : MonoBehaviour
{
public NavmeshCut navmeshCut;
public class Baker : Baker<NavmeshCutAuthoring>
{
public override void Bake(NavmeshCutAuthoring authoring)
{
Entity entity = GetEntity(TransformUsageFlags.Dynamic);
AddComponentObject(entity, new NavmeshCutter { NavmeshCutGO = authoring.navmeshCut.gameObject });
}
}
}
public class NavmeshCutter : IComponentData
{
public GameObject NavmeshCutGO;
}
public class NavmeshCutterCleanup : ICleanupComponentData
{
public GameObject NavmeshCutGO;
}
public partial struct NavmeshCutterSystem : ISystem
{
void OnUpdate(ref SystemState state)
{
var world = World.DefaultGameObjectInjectionWorld;
var ecb = new EntityCommandBuffer(Allocator.Temp);
//Create a gameobject navmesh cutter for those without cleanups
foreach (var (navmeshCutter, localTransform, entity) in SystemAPI.Query<NavmeshCutter, LocalTransform>().WithNone<NavmeshCutterCleanup>().WithEntityAccess())
{
var instance = GameObject.Instantiate(navmeshCutter.NavmeshCutGO, localTransform.Position, localTransform.Rotation);
ecb.AddComponent(entity, new NavmeshCutterCleanup { NavmeshCutGO = instance });
}
//Any cleanups that no longer have NavmeshCutter have been destroyed, the navmeshcutter gameobjects needs to be destroyed and cleaned up
foreach (var (navmeshCutContainer, entity) in SystemAPI.Query<NavmeshCutterCleanup>().WithNone<NavmeshCutter>().WithEntityAccess())
{
GameObject.Destroy(navmeshCutContainer.NavmeshCutGO);
ecb.RemoveComponent(entity, new ComponentTypeSet(typeof(NavmeshCutterCleanup)));
}
ecb.Playback(world.EntityManager);
ecb.Dispose();
}
}
Fixed a bug in the NavmeshCutterSystem. It was creating some duplicates depending on the initial state of a subscene containing these cutters. Not exactly sure why but this seems to at least clean them up.
[UpdateInGroup(typeof(TransformSystemGroup))]
public partial struct NavmeshCutterSystem : ISystem
{
void OnUpdate(ref SystemState state)
{
var world = World.DefaultGameObjectInjectionWorld;
var ecb = new EntityCommandBuffer(Allocator.Temp);
//Create a gameobject navmesh cutter for those without cleanups
foreach (var (navmeshCutter, localTransform, entity) in SystemAPI.Query<NavmeshCutter, LocalTransform>().WithNone<NavmeshCutterCleanup>().WithEntityAccess())
{
GameObject instance = GameObject.Instantiate(navmeshCutter.NavmeshCutGO, localTransform.Position, localTransform.Rotation);
//Sometimes duplicates are created at world center if the subscene is disabled in the hierarchy
if (!navmeshCutter.NavmeshCutGO.scene.isSubScene)
{
GameObject.Destroy(navmeshCutter.NavmeshCutGO);
}
ecb.AddComponent(entity, new NavmeshCutterCleanup { NavmeshCutGO = instance });
}
//Any cleanups that no longer have NavmeshCutter have been destroyed, the navmeshcutter gameobjects needs to be destroyed and cleaned up
foreach (var (navmeshCutContainer, entity) in SystemAPI.Query<NavmeshCutterCleanup>().WithNone<NavmeshCutter>().WithEntityAccess())
{
GameObject.Destroy(navmeshCutContainer.NavmeshCutGO);
ecb.RemoveComponent(entity, new ComponentTypeSet(typeof(NavmeshCutterCleanup)));
}
ecb.Playback(world.EntityManager);
ecb.Dispose();
}
}