Passion for Videogames
I love the fact that games connect with people, and I am always excited to work on new projects to achieve that goal, whether it be in programming or design.
Connecting Unreal and Unity
01/2025 - 04/2025
Unity, Unreal, C#
A student project prototype of a capture-the-flag game, where Unreal and Unity clients connect through a server using sockets.
It is a capture-the-flag game where sockets were used to connect clients built in both Unreal and Unity engines, transmitting information to a C# server, which then updates all connected clients.
When a client connects, the server stores it in a dictionary. The server then waits for new packets, filters them using a switch with enums, and sends the changes to all other clients.
switch (packetType)
{
case PacketType.WELCOME:
//This will show the senders/clients IP Address and Port Number
Console.WriteLine("Message received from " + stringSplit[1] + " ip:" + remote.ToString());
string hi = ((int)PacketType.WELCOME) + ";Yep, you just connected!";
data = Encoding.ASCII.GetBytes(hi);
// First parameter is the data, 2nd is packet size, 3rd is any flags we want,
// and 4th is destination client (which was saved when ReceiveFrom() is called)
newsock.SendTo(data, data.Length, SocketFlags.None, remote);
IPEndPoint ePoint = (IPEndPoint)remote;
isNewClient(ePoint);
break;
case PacketType.UID:
// Asign unique ID to clients
break;
case PacketType.UPDATE:
// Update all the transforms
// After the switch all transforms are sent to the clients
break;
case PacketType.HIT:
{
// Hit event Handle
}
case PacketType.FLAG:
{
int client_uniqueid = int.Parse(stringSplit[1]);
int flagEvent = int.Parse(stringSplit[2]); // PickUp, Drop, Return
int team = int.Parse(stringSplit[3]);
byte[] packetdata = new byte[4096];
string data_HIT_send = ((int)PacketType.FLAG) + ";" + client_uniqueid + ";" + flagEvent + ";" + team;
packetdata = Encoding.ASCII.GetBytes(data_HIT_send);
SendDataToClients(packetdata);
break;
}
}
Packet sending on the client side works as follows: when a client performs an action, it sends a packet to the server indicating which event has occurred.
// Only players can enter OnTrigger
private void OnTriggerEnter(Collider other)
{
NetworkGameObject player = other.GetComponent();
if (!player)
return;
if (!FlagInPosition() || !player.isLocallyOwned)
return;
if (player.GetTeam() != zone_flag_.GetTeam())
{
PickFlag(player);
}
else
{
if (player.own_flag_.activeSelf)
ReturnFlag(player);
}
}
public void PickFlag(NetworkGameObject nt)
{
nt.PickFlag(zone_flag_.GetTeam());
zone_flag_.gameObject.SetActive(false);
// Send a network message to notify all players about the flag pickup
string flagMessage = (int)PacketType.FLAG + ";" + nt.uniqueNetworkID + ";" + (int)FlagEvent.PICKUP + ";" + (int)zone_flag_.GetTeam();
byte[] hitPacket = Encoding.ASCII.GetBytes(flagMessage);
NetworkManager.udpClient.Send(hitPacket, hitPacket.Length);
}
When the client's network manager receives the event, it will be filtered using a switch with enums, and it will call the components that have been affected.
// Network Manager class
switch (packetInt)
{
case EPacketType::WELCOME:
UE_LOG(LogTemp, Warning, TEXT("Mesage: %s"), *newString);
break;
case EPacketType::UID:
{
// Assign unique IDs to network objects
int32 local_ID = FCString::Atoi(*stringSplit[1]);
int32 global_ID = FCString::Atoi(*stringSplit[2]);
ETeam team = (ETeam)FCString::Atoi(*stringSplit[3]);
AssignUIDS(local_ID, global_ID, team);
break;
}
case EPacketType::UPDATE:
{
// Handle position and state updates for networked objects
}
case EPacketType::HIT:
{
// Handle damage events
}
// Handle Flag events
case EPacketType::FLAG:
{
int32 globalID = FCString::Atoi(*stringSplit[1]);
EFlagEvent flagEvent = (EFlagEvent)FCString::Atoi(*stringSplit[2]);
ETeam team = (ETeam)FCString::Atoi(*stringSplit[3]);
UNetworkObject* flag_player = GetNetworkObject(globalID);
flag_manager_->FlagEvents(flag_player, flagEvent, team);
break;
}
// Flag Manager class
void AFlagManager::FlagEvents(UNetworkObject* flagPlayer, EFlagEvent eventFlag, ETeam team) {
int32 t = (int32)team;
switch (eventFlag)
{
case EFlagEvent::PICKUP:
flag_zone_[t]->Activate(false);
flagPlayer->PickUpFlag();
break;
case EFlagEvent::DROP:
flag_zone_[t]->Activate(true);
flagPlayer->ReturnFlag();
break;
case EFlagEvent::RETURN:
flag_zone_[t]->Activate(true);
flagPlayer->ReturnFlag();
points_->Score(flagPlayer->team_);
break;
}
}