该项目的目的是同时测试和演示来自 Unity DOTS 技术堆栈的多个新包。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

198 行
8.0 KiB

using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
using Unity.Entities;
using Unity.Sample.Core;
// Simple, team based deathmatch mode
public class GameModeDeathmatch : IGameMode
{
[ConfigVar(Name = "game.dm.minplayers", DefaultValue = "1", Description = "Minimum players before match starts")]
public static ConfigVar minPlayers;
[ConfigVar(Name = "game.dm.prematchtime", DefaultValue = "0", Description = "Time before match starts")]
public static ConfigVar preMatchTime;
[ConfigVar(Name = "game.dm.postmatchtime", DefaultValue = "10", Description = "Time after match ends before new will begin")]
public static ConfigVar postMatchTime;
[ConfigVar(Name = "game.dm.roundlength", DefaultValue = "1800", Description = "Deathmatch round length (seconds)")]
public static ConfigVar roundLength;
public void Initialize(World world, GameModeSystemServer gameModeSystemServer)
{
m_world = world;
m_GameModeSystemServer = gameModeSystemServer;
// Create teams
m_GameModeSystemServer.CreateTeam("Team 1");
m_GameModeSystemServer.CreateTeam("Team 2");
Console.Write("Deathmatch game mode initialized");
}
public void Restart()
{
foreach (var t in m_GameModeSystemServer.teams)
t.score = 0;
m_Phase = Phase.Countdown;
m_GameModeSystemServer.StartGameTimer(preMatchTime, "PreMatch");
}
public void Shutdown()
{
}
char[] _msgBuf = new char[256];
public void Update()
{
var players = m_GameModeSystemServer.playersComponentGroup.ToComponentDataArray<Player.State>(Allocator.TempJob);
switch (m_Phase)
{
case Phase.Countdown:
if (m_GameModeSystemServer.GetGameTimer() == 0)
{
if (players.Length < minPlayers.IntValue)
{
m_GameModeSystemServer.chatSystem.SendChatAnnouncement("Waiting for more players.");
m_GameModeSystemServer.StartGameTimer(preMatchTime, "PreMatch");
}
else
{
m_GameModeSystemServer.StartGameTimer(roundLength, "");
m_Phase = Phase.Active;
m_GameModeSystemServer.chatSystem.SendChatAnnouncement("Match started!");
}
}
break;
case Phase.Active:
if (m_GameModeSystemServer.GetGameTimer() == 0)
{
// Find winner team
var winTeam = -1;
var teams = m_GameModeSystemServer.teams;
// TODO (petera) Get rid of teams list and hardcode for teamsize 2 as all ui etc assumes it anyways.
if (teams.Count == 2)
{
winTeam = teams[0].score > teams[1].score ? 0 : teams[0].score < teams[1].score ? 1 : -1;
}
// TODO : For now we just kill all players when we restart
// but we should change it to something less dramatic like taking
// control away from the player or something
for (int i = 0, c = players.Length; i < c; i++)
{
var playerState = players[i];
if (playerState.controlledEntity != Entity.Null)
{
var healthState = m_world.EntityManager
.GetComponentData<HealthStateData>(playerState.controlledEntity);
healthState.health = 0.0f;
healthState.deathTick = -1;
m_world.EntityManager
.SetComponentData(playerState.controlledEntity, healthState);
}
playerState.displayGameResult = true;
if (winTeam == -1)
playerState.gameResult = new NativeString64("TIE");
else
playerState.gameResult = new NativeString64((playerState.teamIndex == winTeam) ? "VICTORY" : "DEFEAT");
playerState.displayCountDown = false;
playerState.displayScoreBoard = false;
playerState.displayGoal = false;
}
m_Phase = Phase.Ended;
m_GameModeSystemServer.SetRespawnEnabled(false);
m_GameModeSystemServer.StartGameTimer(postMatchTime, "PostMatch");
var l = 0;
if (winTeam > -1)
l = StringFormatter.Write(ref _msgBuf, 0, "Match over. {0} wins!", m_GameModeSystemServer.teams[winTeam].name);
else
l = StringFormatter.Write(ref _msgBuf, 0, "Match over. Its a tie!");
m_GameModeSystemServer.chatSystem.SendChatAnnouncement(new CharBufView(_msgBuf, l));
}
break;
case Phase.Ended:
if (m_GameModeSystemServer.GetGameTimer() == 0)
{
for (int i = 0, c = players.Length; i < c; i++)
{
var playerState = players[i];
playerState.displayGameResult = false;
}
m_GameModeSystemServer.Restart();
}
break;
}
for (int i = 0; i < players.Length; i++)
{
var player = players[i];
if (player.controlledEntity == Entity.Null)
continue;
var charPredictedState = m_world.EntityManager.GetComponentData<Character.PredictedData>(player.controlledEntity);
var position = charPredictedState.position;
player.enableCharacterSwitch = false;
foreach (var b in m_GameModeSystemServer.teamBases)
{
if (b.teamIndex == player.teamIndex)
{
var inside = (b.boxCollider.transform.InverseTransformPoint(position) - b.boxCollider.center);
if (Mathf.Abs(inside.x) < b.boxCollider.size.x * 0.5f && Mathf.Abs(inside.y) < b.boxCollider.size.y * 0.5f && Mathf.Abs(inside.z) < b.boxCollider.size.z * 0.5f)
{
player.enableCharacterSwitch = true;
break;
}
}
}
}
players.Dispose();
var gameModeState = m_world.EntityManager.GetComponentData<GameModeData>(m_GameModeSystemServer.gameModeEntity);
// Push scores to gameMode that is synchronized to client
gameModeState.teamScore0 = m_GameModeSystemServer.teams[0].score;
gameModeState.teamScore1 = m_GameModeSystemServer.teams[1].score;
m_world.EntityManager.SetComponentData(m_GameModeSystemServer.gameModeEntity, gameModeState);
}
public void OnPlayerJoin(ref Player.State playerState)
{
playerState.score = 0;
m_GameModeSystemServer.AssignTeam(ref playerState);
}
public void OnPlayerKilled(ref Player.State victim, ref Player.State killer)
{
if (killer.teamIndex != victim.teamIndex)
{
killer.score++;
m_GameModeSystemServer.teams[killer.teamIndex].score++;
}
else if (victim.playerId == killer.playerId)
{
victim.score--;
m_GameModeSystemServer.teams[victim.teamIndex].score--;
}
}
public void OnPlayerRespawn(ref Player.State playerState, ref Vector3 position, ref Quaternion rotation)
{
m_GameModeSystemServer.GetRandomSpawnTransform(playerState.teamIndex, ref position, ref rotation);
}
enum Phase
{
Undefined,
Countdown,
Active,
Ended,
}
Phase m_Phase;
World m_world;
GameModeSystemServer m_GameModeSystemServer;
}