// Use this for initialization void Start() { gameObject.SetActive(false); ComponentLocator.instance.GetDependency <PlayerIdentifierComponent>().playerGameObject.GetComponent <HealthComponent>().dieEvent += GameOver; playerScoreComponent = ComponentLocator.instance.GetDependency <PlayerScoreComponent>(); ComponentLocator.instance.GetDependency <PlayerIdentifierComponent>().GetComponent <PlayerReviveComponent>().playerRevivedEvent += playerRevived; aISpawnComponent = ComponentLocator.instance.GetDependency <AISpawnComponent>(); }
protected override void OnUpdate() { //Here we set the prefab we will use if (m_Prefab == Entity.Null) { //We grab the converted PrefabCollection Entity's PlayerScoreAuthoringComponent //and set m_Prefab to its Prefab value m_Prefab = GetSingleton <PlayerScoreAuthoringComponent>().Prefab; //We then initialize by creating the first PlayerScore var initialPlayerScore = EntityManager.Instantiate(m_Prefab); //We set the initial player score to 1 so the first player will be assigned this PlayerScore EntityManager.SetComponentData <PlayerScoreComponent>(initialPlayerScore, new PlayerScoreComponent { networkId = 1 }); //we must "return" after setting this prefab because if we were to continue into the Job //we would run into errors because the variable was JUST set (ECS funny business) //comment out return and see the error return; } //We need to declare our local variables before the .ForEach() var commandBuffer = m_BeginSimEcb.CreateCommandBuffer(); //We use this to check for disconnects var rpcFromEntity = GetBufferFromEntity <OutgoingRpcDataStreamBufferComponent>(); //We are going to grab all existing player scores because we need to check if the new player has an old NetworkId var currentPlayerScoreEntities = m_PlayerScoresQuery.ToEntityArray(Allocator.TempJob); //We are going to need to grab the Player score from the entity var playerScoreComponent = GetComponentDataFromEntity <PlayerScoreComponent>(); //We grab the prefab in case we need to create a new PlayerScore for a new NetworkId var scorePrefab = m_Prefab; //We are going to need to be able to grab the NetworkIdComponent from the RPC source to know what the player's NetworkId is var networkIdFromEntity = GetComponentDataFromEntity <NetworkIdComponent>(); Entities .WithDisposeOnCompletion(currentPlayerScoreEntities) .ForEach((Entity entity, in SendServerPlayerNameRpc request, in ReceiveRpcCommandRequestComponent requestSource) => { //Delete the rpc commandBuffer.DestroyEntity(entity); //Check for disconnects if (!rpcFromEntity.HasComponent(requestSource.SourceConnection)) { return; } //Grab the NetworkIdComponent's Value var newPlayersNetworkId = networkIdFromEntity[requestSource.SourceConnection].Value; //We create a clean PlayerScore component with the player's name and the player's NetworkId value var newPlayerScore = new PlayerScoreComponent { networkId = newPlayersNetworkId, playerName = request.playerName, currentScore = 0, highScore = 0 }; //Now we are going to check all current PlayerScores and see if this NetworkId has been used before //If it has we set it to our new PlayerScoreComponent bool uniqueNetworkId = true; for (int i = 0; i < currentPlayerScoreEntities.Length; i++) { //We call the data componentData just to make it more legible on the if() line var componentData = playerScoreComponent[currentPlayerScoreEntities[i]]; if (componentData.networkId == newPlayersNetworkId) { commandBuffer.SetComponent <PlayerScoreComponent>(currentPlayerScoreEntities[i], newPlayerScore); uniqueNetworkId = false; } } //If this NetworkId has not been used before we create a new PlayerScore if (uniqueNetworkId) { var playerScoreEntity = commandBuffer.Instantiate(scorePrefab); //We set the initial player score to 1 so the first player will be assigned this PlayerScore commandBuffer.SetComponent <PlayerScoreComponent>(playerScoreEntity, newPlayerScore); } }).Schedule();
protected override void OnUpdate() { // Need this extra variable here so that it can // be captured by Entities.ForEach loop below var nonTriggerMask = m_NonTriggerMask; //We grab all the player scores because we don't know who will need to be assigned points var playerScoreEntities = m_PlayerScores.ToEntityArray(Allocator.TempJob); //we will need to grab the PlayerScoreComponent from our player score entities to compare values var playerScoreComponent = GetComponentDataFromEntity <PlayerScoreComponent>(); //We grab the 1 HighestScore engity var highestScoreEntities = m_HighestScore.ToEntityArray(Allocator.TempJob); //We will need to grab the HighestScoreComponent from our highest score entity to compare values var highestScoreComponent = GetComponentDataFromEntity <HighestScoreComponent>(); //We are going to use this to pull the GhostOwnerComponent from the bullets to see who they belong to var ghostOwner = GetComponentDataFromEntity <GhostOwnerComponent>(); //We need to dispose our entities Entities .WithDisposeOnCompletion(playerScoreEntities) .WithDisposeOnCompletion(highestScoreEntities) .WithName("ChangeMaterialOnTriggerEnter") .ForEach((Entity e, ref DynamicBuffer <StatefulTriggerEvent> triggerEventBuffer) => { for (int i = 0; i < triggerEventBuffer.Length; i++) { //Here we grab our bullet entity and the other entity it collided with var triggerEvent = triggerEventBuffer[i]; var otherEntity = triggerEvent.GetOtherEntity(e); // exclude other triggers and processed events if (triggerEvent.State == EventOverlapState.Stay || !nonTriggerMask.Matches(otherEntity)) { continue; } //We want our code to run on the first intersection of Bullet and other entity else if (triggerEvent.State == EventOverlapState.Enter) { //We grab the NetworkId of the bullet so we know who to assign points to var bulletsPlayerNetworkId = ghostOwner[e].NetworkId; //We start with 0 points to add int pointsToAdd = 0; if (HasComponent <PlayerTag>(otherEntity)) { //Now we check if the bullet came from the same player if (ghostOwner[otherEntity].NetworkId == bulletsPlayerNetworkId) { //If it is from the same player no points return; } pointsToAdd += 10; } if (HasComponent <AsteroidTag>(otherEntity)) { //Bullet hitting an Asteroid is 1 point pointsToAdd += 1; } //After updating the points to add we check the PlayerScore entities and find the one with the //correct NetworkId so we can update the scores for the PlayerScoreComponent //If the updated score is higher than the highest score it updates the highest score for (int j = 0; j < playerScoreEntities.Length; j++) { //Grab the PlayerScore var currentPlayScoreComponent = playerScoreComponent[playerScoreEntities[j]]; if (currentPlayScoreComponent.networkId == bulletsPlayerNetworkId) { //We create a new component with updated values var newPlayerScore = new PlayerScoreComponent { networkId = currentPlayScoreComponent.networkId, playerName = currentPlayScoreComponent.playerName, currentScore = currentPlayScoreComponent.currentScore + pointsToAdd, highScore = currentPlayScoreComponent.highScore }; //Here we check if the player beat their own high score if (newPlayerScore.currentScore > newPlayerScore.highScore) { newPlayerScore.highScore = newPlayerScore.currentScore; } //Here we check if the player beat the highest score var currentHighScore = highestScoreComponent[highestScoreEntities[0]]; if (newPlayerScore.highScore > currentHighScore.highestScore) { //If it does we make a new HighestScoreComponent var updatedHighestScore = new HighestScoreComponent { highestScore = newPlayerScore.highScore, playerName = newPlayerScore.playerName }; //The reason why we don't go with: //SetComponent<HighestScoreComponent>(highestScoreEntities[0], updatedHighestScore); //is because SetComponent<HighestScoreComponent>() gets codegen'd into ComponentDataFromEntity<HighestScoreComponent>() //and you can't use 2 different ones or else you get an 'two containers may not be the same (aliasing)' error highestScoreComponent[highestScoreEntities[0]] = updatedHighestScore; } // SetComponent<PlayerScoreComponent>(playerScoreEntities[j], newPlayerScore); //The reason why we don't go with: //SetComponent<PlayerScoreComponent>(playerScoreEntities[j], newPlayerScore); //is because SetComponent<PlayerScoreComponent>() gets codegen'd into ComponentDataFromEntity<PlayerScoreComponent>() //and you can't use 2 different ones or else you get an 'two containers may not be the same (aliasing)' error playerScoreComponent[playerScoreEntities[j]] = newPlayerScore; } } } else { continue; } } }).Schedule(); }
protected override void OnUpdate() { //We add "AsParallelWriter" when we create our command buffer because we want //to run our jobs in parallel var commandBuffer = m_EndSimEcb.CreateCommandBuffer().AsParallelWriter(); //We are going to need to update the NCE CommandTargetComponent so we set the argument to false (not read-only) var commandTargetFromEntity = GetComponentDataFromEntity <CommandTargetComponent>(false); JobHandle playerScoresDep; //We grab all the player scores because we don't know who will need to be assigned points var playerScoreEntities = m_PlayerScores.ToEntityArrayAsync(Allocator.TempJob, out playerScoresDep); //we will need to grab the PlayerScoreComponent from our player score entities to compare values var playerScoreComponent = GetComponentDataFromEntity <PlayerScoreComponent>(); //We now any entities with a DestroyTag and an PlayerTag //We could just query for a DestroyTag, but we might want to run different processes //if different entities are destroyed, so we made this one specifically for Players //We query specifically for players because we need to clear the NCE when they are destroyed //In order to write over a variable that we pass through to a job we must include "WithNativeDisableParallelForRestricion" //It means "yes we know what we are doing, allow us to write over this variable" var playerDestructionJob = Entities .WithDisposeOnCompletion(playerScoreEntities) .WithReadOnly(playerScoreEntities) .WithNativeDisableParallelForRestriction(playerScoreComponent) .WithNativeDisableParallelForRestriction(commandTargetFromEntity) .WithAll <DestroyTag, PlayerTag>() .ForEach((Entity entity, int nativeThreadIndex, in PlayerEntityComponent playerEntity, in GhostOwnerComponent ghostOwnerComponent) => { // Reset the CommandTargetComponent on the Network Connection Entity to the player //We are able to find the NCE the player belongs to through the PlayerEntity component var state = commandTargetFromEntity[playerEntity.PlayerEntity]; state.targetEntity = Entity.Null; commandTargetFromEntity[playerEntity.PlayerEntity] = state; //Now we cycle through PlayerScores till we find the right onw for (int j = 0; j < playerScoreEntities.Length; j++) { //Grab the PlayerScore var currentPlayScoreComponent = playerScoreComponent[playerScoreEntities[j]]; //Check if the player to destroy has the same NetworkId as the current PlayerScore if (currentPlayScoreComponent.networkId == ghostOwnerComponent.NetworkId) { //We create a new component with updated values var newPlayerScore = new PlayerScoreComponent { networkId = currentPlayScoreComponent.networkId, playerName = currentPlayScoreComponent.playerName, currentScore = 0, highScore = currentPlayScoreComponent.highScore }; // SetComponent<PlayerScoreComponent>(playerScoreEntities[j], newPlayerScore); //The reason why we don't go with: //SetComponent<PlayerScoreComponent>(playerScoreEntities[j], newPlayerScore); //is because SetComponent<PlayerScoreComponent>() gets codegen'd into ComponentDataFromEntity<PlayerScoreComponent>() //and you can't use 2 different ones or else you get an 'two containers may not be the same (aliasing)' error playerScoreComponent[playerScoreEntities[j]] = newPlayerScore; } } //Then destroy the entity commandBuffer.DestroyEntity(nativeThreadIndex, entity); }).ScheduleParallel(JobHandle.CombineDependencies(Dependency, playerScoresDep));