Adding a New NetworkEntity
This time we’ll make a simple little AI guy to run around. For anything you want replicated across the network, it must have a component extending the NetworkEntity class. This might be enemies, items, boxes, bullets, explosions, a door etc. If you need to make a player, that needs to extend the PlayerNetworkEntity class and is covered in the previous guide.
build new gameobject
Open Scenes→TestingGround or make a new Scene in Unity. We’re not worried about the Scene so much, its just a spot to drag things into.
Next go to 2d assets and find a sprite to drag into the editor. For example expand ghost sprite and drag ghost_0 into the Scene somewhere

You can use your own assets, these ones have just be added to the sample project already and have been sliced already. Anyway, this creates a GameObject with a SpriteRenderer component. Lets rename this GameObject to something else like TestEntity

There are some ordering settings setup in Unity for this type of game, but to make sure this character is ordered above the background we should set Order In Layer on the Sprite Renderer to something higher then 0. How about 5

Currently the game sorts things on the y axis, things further down the screen are put closer to the camera to give the fake 3d illusion lots of 2d games use. If you want to change that though or want to know how I set it up, go to Project Settings→Graphics→Transparency Sort Mode and tweak those. Here’s what I have there for the sample project

IF you did the Player Prefab tutorial this probably feels like Deja Vu. That’s because I copied some of the text from there, but stuff will be different further down
Add Components we need
Ok, its a good start but no where near done. Lets add a couple of basic components. Go to Assets→Scripts→Cyborg Netcode→Components and drag PhysicsComponent and AnimationComponent onto your TestEntity gameObject

Setting up Physics Component
We can set a few values in here soon, but before we do, we’ll need a collision box of sorts so our entity knows how to bump into things in the world. Go to Assets→Scripts→Cyborg Netcode→Math and Shaps and drag ObjectRect onto TestEntity.

Set some values so that it fits over the character nicely. I use these and made the box red so I could see it easier:

Then drag that ObjectRect into the CollisionBox section of the PhysicsComponent

Might as well change these too

Setting up Animation Component
Set Animation Set Name to something, I went with Base, and set the Sprite Renderer to the one attached to TestEntity(either click the dot-circle thing and find TestEntity or drag TestEntity’s SpriteRenderer into this slot):

We’ll setup more for here later as we’ll have to choose whether to use Unity’s animation system or the one I built for this project.
Add New Class and fill it in
Ok, now its time for some fun. Lets build the thing where our logic is going to go, we’re going to extend the NetworkEntity class! To do that click the Add Component button at the bottom of our TestEntity’s inspector info

Choose New Script and this window should pop up, fill in TestEntity as the script name and hit Create and Add button

It will have added the script as a component to your TestEntity game object. Not super exciting yet, so open up the TestEntity script in Visual Studio or whatever you use on your end. Once its open, it should look similar to this

Boring! Lets set this thing up. Lets add some new library references at the top and then make this class extend(inherit from) NetworkEntity. You’ll probably get a red wiggly line, ignore that for now

If you are using Visual Studio and hover over TestPlayer with the red line, it will suggest implementing a few abstract methods inherited from PlayerNetworkEntity

If you can, do that option, if not, type this out. Oh and remove the exception stuff from within them.

The PhysicsComponent needs to know about the NetworkEntities transform to update things correctly, so this next step is just a little house keeping
void Start()
{
physicsComponent.Init(sTransform);
}
Great, now the fun can really get started. This character is going to be simple, it picks a random direction to walk and moves that until a timer ticks down and then it picks another random direction to walk in. It has a physics component, so it will bump into walls fine. If you want to detect is a wall is ahead, check out the Glob class as it checks one of the 4 directions it can move and stops rather then keeps running before it bumps into them.
Lets create an attribute to help control this things movespeed
public class TestEntity : NetworkEntity
{
public sfloat moveSpeed = (sfloat)0.24f;
public sfloat walkDirectionTimer = sfloat.Zero;
//...
Let’s make sure we update the physicsComponent each frame, but only if we’re not doing a rollback.
public override void UpdateEntity()
{
if (NetworkEntityManager.IsRollbacking())
{
return;
}
physicsComponent.UpdateComponent();
}
Create a new method called Think() which will take care of the basic brain behind this character.
void Think()
{
}
So with player objects, if a we are controlling one as a client, we want to also do some of that logic on client side. However when it comes to AI control characters or other things in the world, say items and explosions, then we want the server to do the decision making. The thinking is done on the server side and the movement done there, then that movement is replicated to the clients.
So for our character thinking on the server side, we’ll tick down the timer and when that is less than or equal to zero, pick 1 of 4 random directions to move in. We also reset the timer so it can happen again
void Think()
{
//stuff player doesn't control directly, should be done on the server side
if (NetworkManager.GetConnectionType() == ConnectionType.server)
{
walkDirectionTimer -= Time.fixedDeltaTime;
if(walkDirectionTimer <= 0)
{
//reset timer - value betwee 200milliseconds - 3 seconds
walkDirectionTimer = Random.Range(0.2f, 3f);
//pick a random direction (4 way direction that is)
int d = Random.Range(0, 4);
physicsComponent.instantVelocity = new SVector();
if (d == 0)
{
physicsComponent.instantVelocity.y = -moveSpeed;
}
else if (d == 1)
{
physicsComponent.instantVelocity.x = moveSpeed;
}
else if (d == 2)
{
physicsComponent.instantVelocity.y = moveSpeed;
}
else
{
physicsComponent.instantVelocity.x = -moveSpeed;
}
}
}
}
Now add this Think method call to your UpdateEntity method
public override void UpdateEntity()
{
if (NetworkEntityManager.IsRollbacking())
{
return;
}
Think();
physicsComponent.UpdateComponent();
}
We also need to make sure this class sends the correct data across the network and can read it. Thankfully its quite short for this one, fill these in
public override void WriteToPacket(NetDataWriter writer)
{
base.WriteToPacket(writer);
//physics
physicsComponent.WriteToPacket(writer);
}
public override void ReadFromPacket(NetDataReader reader)
{
base.ReadFromPacket(reader);
//physics
physicsComponent.ReadFromPacket(reader);
}
One more thing, if we only wanted to spawn this network entity later from code we would be done, but if you want them to be placed in the scene directly so when the game scene starts they are there, then we need a little bit more code.
private void Update()
{
if (entityID == UNASSIGNED_ENTITY_ID && NetworkEntityManager.networkEntityManager != null)
{
//will only do anything if we have an unassigned entity id
NetworkEntityManager.networkEntityManager.RegisterNetworkEntity(this);
}
}
Using the Unity Update might be overkill, perhaps FixedUpdate is better. Anyway, per update it checks if this entity is not registered yet and if there is a NetworkEntityManager setup. If so, it calls the RegisterNetworkEntity method which should add it to the system where network entities are updated and their data saved and sent across to clients. If this ran client side, they get an ID but when the next packet from the server comes, they should be replaced with the one from the server.
I think we’re done, save and lets go back to Unity.
In Unity it should recompile and hopefully get no errors, if you do they will be in the console output and you can double check everything above again to see what happened.
If it did work, we the TestNetworkEntity component should be ready to fill in, first up give it a reference to our PhysicsComponent

We need to set the Type on this network entity, so we need to make one. Go to Assets→Prefabs→NetworkEntities and right click in that folder, choose Create→CyborgNetcode→NetworkEntityType

Call it TestEntity and fill in the details

The Type ID must be unique, so it can be any number if you like. I went with 6 because its my 6th one of these NetworkWorkEntity type files.
Once you’ve done that, drag this into the Type slot

Create Prefab
That will do for now, lets make TestEntity a prefab now by dragging them into the Assets→Prefabs→NetworkEntities folder

So that our servers and clients know how to make this entity when needed we need to register them in the NetworkEntityPrefabs file. So click on that file and then drag TestEntity into it

Lets test them out!
Go to Scenes→GameScene and then drag our TestEntity(Prefabs→NetworkEntities folder) into the scene somewhere easy to find, say around the center. Save and we’re ready to test!
TEST
The full guides to testing are here but lets just do a basic test. Open Scenes→Join and hit play. The quickest way to see that it kinda works is running a server, so choose Host Game

And then check can server be a player too and click Host Private Game because we don’t want to list this as a joinable game anywhere.

If everything worked ok, you should see your little guy running around. The first numbers I gave you are a bit fast and need tweaking, but they are in and networked ready.

If you have errors, go back through the previous steps. This doesn’t actually check any networked play though. For that we need a Client and a Server running. Follow this guide to test that: Testing Client and Server Locally. If the client also works, then well done! If not, its probably the Read/Write packet stuff from above.
That’s enough for now!
From here, its probably a good time to jump into another one of the guides or experiment for a bit. Maybe try to get this character animated from one of the animation guides