Skip to content

Instantly share code, notes, and snippets.

@JohnnyTurbo
Last active September 2, 2024 02:26
Show Gist options
  • Save JohnnyTurbo/b46d383389f5615682ac713046ff8277 to your computer and use it in GitHub Desktop.
Save JohnnyTurbo/b46d383389f5615682ac713046ff8277 to your computer and use it in GitHub Desktop.
Code used in ECS Single Unit Selection tutorial video on the Turbo Makes Games YouTube Channel - https://youtu.be/x8pVhWCewjU
using System;
namespace TMG.UnitSelection
{
[Flags]
public enum CollisionLayers
{
Selection = 1 << 0,
Ground = 1 << 1,
Units = 1 << 2
}
}
using Unity.Entities;
namespace TMG.UnitSelection
{
[GenerateAuthoringComponent]
public struct SelectableUnitTag : IComponentData
{
}
}
using Unity.Entities;
namespace TMG.UnitSelection
{
public struct SelectedEntityTag : IComponentData{}
}
using Unity.Entities;
namespace TMG.UnitSelection
{
[GenerateAuthoringComponent]
public struct SelectionUIPrefab : IComponentData
{
public Entity Value;
}
}
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
namespace TMG.UnitSelection
{
public struct SelectionRingStateData : ISystemStateComponentData
{
public Entity SelectionUI;
}
[UpdateAfter(typeof(UnitSelectionSystem))]
public class SpawnSelectionRingSystem : SystemBase
{
private SelectionUIPrefab _selectionUIPrefab;
private EndSimulationEntityCommandBufferSystem _endSimulationEntityCommandBufferSystem;
protected override void OnStartRunning()
{
_selectionUIPrefab = GetSingleton<SelectionUIPrefab>();
_endSimulationEntityCommandBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
}
protected override void OnUpdate()
{
var ecb = _endSimulationEntityCommandBufferSystem.CreateCommandBuffer();
var selectionPrefab = _selectionUIPrefab.Value;
Entities
.WithAll<SelectedEntityTag>()
.WithNone<SelectionRingStateData>()
.ForEach((Entity selectedEntity) =>
{
var selectionUI = ecb.Instantiate(selectionPrefab);
var newSelectionStateData = new SelectionRingStateData()
{
SelectionUI = selectionUI
};
ecb.AddComponent<SelectionRingStateData>(selectedEntity);
ecb.SetComponent(selectedEntity, newSelectionStateData);
ecb.AddComponent<Parent>(selectionUI);
ecb.SetComponent(selectionUI, new Parent{Value = selectedEntity});
ecb.AddComponent<LocalToParent>(selectionUI);
ecb.SetComponent(selectionUI, new LocalToParent{Value = float4x4.zero});
}).Run();
}
}
[UpdateAfter(typeof(SpawnSelectionRingSystem))]
public class CleanupSelectionRingSystem : SystemBase
{
private EndSimulationEntityCommandBufferSystem _endSimulationEntityCommandBufferSystem;
protected override void OnCreate()
{
_endSimulationEntityCommandBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
}
protected override void OnUpdate()
{
var ecb = _endSimulationEntityCommandBufferSystem.CreateCommandBuffer();
Entities
.WithNone<SelectedEntityTag>()
.ForEach((Entity e, in SelectionRingStateData selectionStateData) =>
{
ecb.DestroyEntity(selectionStateData.SelectionUI);
ecb.RemoveComponent<SelectionRingStateData>(e);
}).Run();
}
}
}
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Physics.Systems;
using Unity.Transforms;
using UnityEngine;
using RaycastHit = Unity.Physics.RaycastHit;
namespace TMG.UnitSelection
{
[AlwaysUpdateSystem]
public class UnitSelectionSystem : SystemBase
{
private Camera _mainCamera;
private BuildPhysicsWorld _buildPhysicsWorld;
private CollisionWorld _collisionWorld;
protected override void OnCreate()
{
_mainCamera = Camera.main;
_buildPhysicsWorld = World.GetOrCreateSystem<BuildPhysicsWorld>();
}
protected override void OnUpdate()
{
if (Input.GetMouseButtonUp(0))
{
if (!Input.GetKey(KeyCode.LeftShift))
{
DeselectUnits();
}
SelectSingleUnit();
}
}
private void DeselectUnits()
{
EntityManager.RemoveComponent<SelectedEntityTag>(GetEntityQuery(typeof(SelectedEntityTag)));
}
private void SelectSingleUnit()
{
_collisionWorld = _buildPhysicsWorld.PhysicsWorld.CollisionWorld;
var ray = _mainCamera.ScreenPointToRay(Input.mousePosition);
var rayStart = ray.origin;
var rayEnd = ray.GetPoint(100f);
if (Raycast(rayStart, rayEnd, out var raycastHit))
{
var hitEntity = _buildPhysicsWorld.PhysicsWorld.Bodies[raycastHit.RigidBodyIndex].Entity;
if (EntityManager.HasComponent<SelectableUnitTag>(hitEntity))
{
EntityManager.AddComponent<SelectedEntityTag>(hitEntity);
}
}
}
private bool Raycast(float3 rayStart, float3 rayEnd, out RaycastHit raycastHit)
{
var raycastInput = new RaycastInput
{
Start = rayStart,
End = rayEnd,
Filter = new CollisionFilter
{
BelongsTo = (uint) CollisionLayers.Selection,
CollidesWith = (uint) (CollisionLayers.Ground | CollisionLayers.Units)
}
};
return _collisionWorld.CastRay(raycastInput, out raycastHit);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment