public override void Update() { if (Input.HasMouse) { ClickResult clickResult; Utils.ScreenPositionToWorldPositionRaycast(Input.MousePosition, Camera, this.GetSimulation(), out clickResult); var isMoving = (Input.IsMouseButtonDown(MouseButton.Left) && lastClickResult.Type == ClickType.Ground && clickResult.Type == ClickType.Ground); var isHighlit = (!isMoving && clickResult.Type == ClickType.LootCrate); // Character continuous moving if (isMoving) { lastClickResult.WorldPosition = clickResult.WorldPosition; MoveDestinationEventKey.Broadcast(lastClickResult); } // Object highlighting if (isHighlit) { var modelComponentA = Highlight?.Get<ModelComponent>(); var modelComponentB = clickResult.ClickedEntity.Get<ModelComponent>(); if (modelComponentA != null && modelComponentB != null) { var materialCount = modelComponentB.Materials.Count; modelComponentA.Model = modelComponentB.Model; modelComponentA.Materials.Clear(); for (int i = 0; i < materialCount; i++) modelComponentA.Materials.Add(i, HighlightMaterial); modelComponentA.Entity.Transform.UseTRS = false; modelComponentA.Entity.Transform.LocalMatrix = modelComponentB.Entity.Transform.WorldMatrix; } } else { var modelComponentA = Highlight?.Get<ModelComponent>(); if (modelComponentA != null) modelComponentA.Entity.Transform.LocalMatrix = Matrix.Scaling(0); } } // Mouse-based camera rotation. Only enabled after you click the screen to lock your cursor, pressing escape cancels this foreach (var pointerEvent in Input.PointerEvents.Where(x => x.State == PointerState.Down)) { ClickResult clickResult; if (Utils.ScreenPositionToWorldPositionRaycast(pointerEvent.Position, Camera, this.GetSimulation(), out clickResult)) { lastClickResult = clickResult; MoveDestinationEventKey.Broadcast(clickResult); if (ClickEffect != null && clickResult.Type == ClickType.Ground) { this.SpawnPrefabInstance(ClickEffect, null, 1.2f, Matrix.RotationQuaternion(Quaternion.BetweenDirections(Vector3.UnitY, clickResult.HitResult.Normal)) * Matrix.Translation(clickResult.WorldPosition)); } } } }
public static bool ScreenPositionToWorldPositionRaycast(Vector2 screenPos, CameraComponent camera, Simulation simulation, out ClickResult clickResult) { Matrix invViewProj = Matrix.Invert(camera.ViewProjectionMatrix); Vector3 sPos; sPos.X = screenPos.X * 2f - 1f; sPos.Y = 1f - screenPos.Y * 2f; sPos.Z = 0f; var vectorNear = Vector3.Transform(sPos, invViewProj); vectorNear /= vectorNear.W; sPos.Z = 1f; var vectorFar = Vector3.Transform(sPos, invViewProj); vectorFar /= vectorFar.W; clickResult.ClickedEntity = null; clickResult.WorldPosition = Vector3.Zero; clickResult.Type = ClickType.Empty; clickResult.HitResult = new HitResult(); var minDistance = float.PositiveInfinity; var result = new FastList <HitResult>(); simulation.RaycastPenetrating(vectorNear.XYZ(), vectorFar.XYZ(), result); foreach (var hitResult in result) { ClickType type = ClickType.Empty; var staticBody = hitResult.Collider as StaticColliderComponent; if (staticBody != null) { if (staticBody.CollisionGroup == CollisionFilterGroups.CustomFilter1) { type = ClickType.Ground; } if (staticBody.CollisionGroup == CollisionFilterGroups.CustomFilter2) { type = ClickType.LootCrate; } if (type != ClickType.Empty) { var distance = (vectorNear.XYZ() - hitResult.Point).LengthSquared(); if (distance < minDistance) { minDistance = distance; clickResult.Type = type; clickResult.HitResult = hitResult; clickResult.WorldPosition = hitResult.Point; clickResult.ClickedEntity = hitResult.Collider.Entity; } } } } return(clickResult.Type != ClickType.Empty); }
public static bool ScreenPositionToWorldPositionRaycast(Vector2 screenPos, CameraComponent camera, Simulation simulation, out ClickResult clickResult) { Matrix invViewProj = Matrix.Invert(camera.ViewProjectionMatrix); Vector3 sPos; sPos.X = screenPos.X * 2f - 1f; sPos.Y = 1f - screenPos.Y * 2f; sPos.Z = 0f; var vectorNear = Vector3.Transform(sPos, invViewProj); vectorNear /= vectorNear.W; sPos.Z = 1f; var vectorFar = Vector3.Transform(sPos, invViewProj); vectorFar /= vectorFar.W; clickResult.ClickedEntity = null; clickResult.WorldPosition = Vector3.Zero; clickResult.Type = ClickType.Empty; clickResult.HitResult = new HitResult(); var minDistance = float.PositiveInfinity; var result = simulation.RaycastPenetrating(vectorNear.XYZ(), vectorFar.XYZ()); foreach (var hitResult in result) { ClickType type = ClickType.Empty; var staticBody = hitResult.Collider as StaticColliderComponent; if (staticBody != null) { if (staticBody.CollisionGroup == CollisionFilterGroups.CustomFilter1) type = ClickType.Ground; if (staticBody.CollisionGroup == CollisionFilterGroups.CustomFilter2) type = ClickType.LootCrate; if (type != ClickType.Empty) { var distance = (vectorNear.XYZ() - hitResult.Point).LengthSquared(); if (distance < minDistance) { minDistance = distance; clickResult.Type = type; clickResult.HitResult = hitResult; clickResult.WorldPosition = hitResult.Point; clickResult.ClickedEntity = hitResult.Collider.Entity; } } } } return (clickResult.Type != ClickType.Empty); }