HitboxDisplay lots of broken stuff
This commit is contained in:
1 parent
9203f269db
commit
f40a10912c
78 files changed
+12768
-309066
No files matched your search
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Code.OfficeGame.BattleMode.Timeline;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.OfficeGame.BattleMode.HitBoxes
|
||||
@@ -26,6 +27,8 @@ namespace Code.OfficeGame.BattleMode.HitBoxes
|
||||
BoxCollider box = bodyParts[hitBoxPartType];
|
||||
Transform boxTransform = box.transform;
|
||||
|
||||
HitboxDrawer.DrawBox(box, Color.red, BattleTimeline.TickDelta);
|
||||
|
||||
Vector3 worldCenter = boxTransform.TransformPoint(box.center);
|
||||
Vector3 worldHalfExtents = Vector3.Scale(box.size * 0.5f, boxTransform.lossyScale);
|
||||
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Code.OfficeGame.BattleMode.HitBoxes
|
||||
{
|
||||
public static class HitboxDrawer
|
||||
{
|
||||
private struct ActiveBox
|
||||
{
|
||||
public Matrix4x4 Matrix;
|
||||
public Color Color;
|
||||
public float ExpireTime;
|
||||
}
|
||||
|
||||
private static readonly List<ActiveBox> _boxes = new(16);
|
||||
private static Mesh _cubeMesh;
|
||||
private static Material _material;
|
||||
private static MaterialPropertyBlock _propertyBlock;
|
||||
private static readonly int BaseColorPropId = Shader.PropertyToID("_BaseColor");
|
||||
|
||||
private static bool _initialized;
|
||||
|
||||
/// <summary>
|
||||
/// Отрисовка хитбокса напрямую по BoxCollider
|
||||
/// </summary>
|
||||
public static void DrawBox(BoxCollider collider, Color color, float duration = 1.0f)
|
||||
{
|
||||
if (collider == null) return;
|
||||
|
||||
Transform t = collider.transform;
|
||||
Vector3 worldCenter = t.TransformPoint(collider.center);
|
||||
Vector3 worldSize = Vector3.Scale(collider.size, t.lossyScale);
|
||||
|
||||
DrawBox(worldCenter, worldSize, t.rotation, color, duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отрисовка хитбокса по параметрам позиции, габаритов и вращения
|
||||
/// </summary>
|
||||
public static void DrawBox(Vector3 center, Vector3 size, Quaternion rotation, Color color,
|
||||
float duration = 1.0f)
|
||||
{
|
||||
EnsureInitialized();
|
||||
if (_material == null) return;
|
||||
|
||||
_boxes.Add(new ActiveBox
|
||||
{
|
||||
Matrix = Matrix4x4.TRS(center, rotation, size),
|
||||
Color = color,
|
||||
ExpireTime = Time.unscaledTime + duration
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Принудительная очистка всех активных хитбоксов
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
_boxes.Clear();
|
||||
}
|
||||
|
||||
private static void EnsureInitialized()
|
||||
{
|
||||
if (_initialized) return;
|
||||
|
||||
_cubeMesh = GenerateUnitCubeMesh();
|
||||
_propertyBlock = new MaterialPropertyBlock();
|
||||
|
||||
var shader = Shader.Find("Custom/HitboxVisualizer");
|
||||
if (shader != null)
|
||||
{
|
||||
_material = new Material(shader) { hideFlags = HideFlags.HideAndDontSave };
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[HitboxDrawer] Не найден шейдер 'Custom/HitboxVisualizer'!");
|
||||
return;
|
||||
}
|
||||
|
||||
RenderPipelineManager.beginContextRendering += OnRender;
|
||||
Camera.onPreCull += OnPreCullLegacy;
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
private static void OnRender(ScriptableRenderContext ctx, List<Camera> cameras) => RenderBoxes();
|
||||
|
||||
private static void OnPreCullLegacy(Camera cam)
|
||||
{
|
||||
if (GraphicsSettings.currentRenderPipeline == null) RenderBoxes();
|
||||
}
|
||||
|
||||
private static void RenderBoxes()
|
||||
{
|
||||
int count = _boxes.Count;
|
||||
if (count == 0) return;
|
||||
|
||||
float now = Time.unscaledTime;
|
||||
|
||||
for (int i = count - 1; i >= 0; i--)
|
||||
{
|
||||
ActiveBox box = _boxes[i];
|
||||
|
||||
if (now >= box.ExpireTime)
|
||||
{
|
||||
// Быстрое удаление за O(1)
|
||||
_boxes[i] = _boxes[_boxes.Count - 1];
|
||||
_boxes.RemoveAt(_boxes.Count - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
_propertyBlock.SetColor(BaseColorPropId, box.Color);
|
||||
|
||||
Graphics.DrawMesh(
|
||||
_cubeMesh,
|
||||
box.Matrix,
|
||||
_material,
|
||||
0,
|
||||
null,
|
||||
0,
|
||||
_propertyBlock,
|
||||
castShadows: false,
|
||||
receiveShadows: false,
|
||||
useLightProbes: false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static Mesh GenerateUnitCubeMesh()
|
||||
{
|
||||
Mesh mesh = new Mesh { name = "Hitbox_UnitCube" };
|
||||
|
||||
// 24 вершины с уникальными UV на каждой грани для точной границы
|
||||
Vector3[] vertices = new Vector3[24]
|
||||
{
|
||||
// Передняя (+Z)
|
||||
new(-0.5f, -0.5f, 0.5f), new(0.5f, -0.5f, 0.5f), new(0.5f, 0.5f, 0.5f), new(-0.5f, 0.5f, 0.5f),
|
||||
// Задняя (-Z)
|
||||
new(0.5f, -0.5f, -0.5f), new(-0.5f, -0.5f, -0.5f), new(-0.5f, 0.5f, -0.5f), new(0.5f, 0.5f, -0.5f),
|
||||
// Правая (+X)
|
||||
new(0.5f, -0.5f, 0.5f), new(0.5f, -0.5f, -0.5f), new(0.5f, 0.5f, -0.5f), new(0.5f, 0.5f, 0.5f),
|
||||
// Левая (-X)
|
||||
new(-0.5f, -0.5f, -0.5f), new(-0.5f, -0.5f, 0.5f), new(-0.5f, 0.5f, 0.5f), new(-0.5f, 0.5f, -0.5f),
|
||||
// Верхняя (+Y)
|
||||
new(-0.5f, 0.5f, 0.5f), new(0.5f, 0.5f, 0.5f), new(0.5f, 0.5f, -0.5f), new(-0.5f, 0.5f, -0.5f),
|
||||
// Нижняя (-Y)
|
||||
new(-0.5f, -0.5f, -0.5f), new(0.5f, -0.5f, -0.5f), new(0.5f, -0.5f, 0.5f), new(-0.5f, -0.5f, 0.5f)
|
||||
};
|
||||
|
||||
Vector2[] uvs = new Vector2[24];
|
||||
int[] triangles = new int[36];
|
||||
|
||||
for (int face = 0; face < 6; face++)
|
||||
{
|
||||
int v = face * 4;
|
||||
uvs[v + 0] = new Vector2(0, 0);
|
||||
uvs[v + 1] = new Vector2(1, 0);
|
||||
uvs[v + 2] = new Vector2(1, 1);
|
||||
uvs[v + 3] = new Vector2(0, 1);
|
||||
|
||||
int t = face * 6;
|
||||
triangles[t + 0] = v + 0;
|
||||
triangles[t + 1] = v + 2;
|
||||
triangles[t + 2] = v + 1;
|
||||
triangles[t + 3] = v + 0;
|
||||
triangles[t + 4] = v + 3;
|
||||
triangles[t + 5] = v + 2;
|
||||
}
|
||||
|
||||
mesh.vertices = vertices;
|
||||
mesh.uv = uvs;
|
||||
mesh.triangles = triangles;
|
||||
mesh.RecalculateBounds();
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c609b6a872240fca020c17b9a66723c
|
||||
timeCreated: 1794178985
|
||||
@@ -0,0 +1,89 @@
|
||||
Shader "Custom/HitboxVisualizer"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
[HDR] _BaseColor ("Color", Color) = (1, 0, 0, 0.7)
|
||||
_BorderWidth ("Border Width", Range(0.005, 0.15)) = 0.035
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"RenderType" = "Transparent"
|
||||
"Queue" = "Transparent+200"
|
||||
"RenderPipeline" = "UniversalPipeline"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Name "HitboxPass"
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZWrite Off
|
||||
Cull Off
|
||||
ZTest LEqual
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma multi_compile_instancing
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||||
|
||||
struct Attributes
|
||||
{
|
||||
float4 positionOS : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
struct Varyings
|
||||
{
|
||||
float4 positionCS : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||||
};
|
||||
|
||||
CBUFFER_START(UnityPerMaterial)
|
||||
float _BorderWidth;
|
||||
CBUFFER_END
|
||||
|
||||
UNITY_INSTANCING_BUFFER_START(Props)
|
||||
UNITY_DEFINE_INSTANCED_PROP(float4, _BaseColor)
|
||||
UNITY_INSTANCING_BUFFER_END(Props)
|
||||
|
||||
Varyings vert(Attributes input)
|
||||
{
|
||||
Varyings output = (Varyings)0;
|
||||
UNITY_SETUP_INSTANCE_ID(input);
|
||||
UNITY_TRANSFER_INSTANCE_ID(input, output);
|
||||
|
||||
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
|
||||
output.uv = input.uv;
|
||||
return output;
|
||||
}
|
||||
|
||||
half4 frag(Varyings input) : SV_Target
|
||||
{
|
||||
UNITY_SETUP_INSTANCE_ID(input);
|
||||
half4 baseColor = UNITY_ACCESS_INSTANCED_PROP(Props, _BaseColor);
|
||||
|
||||
// Дистанция до края полигона (грани куба)
|
||||
float2 dist = min(input.uv, 1.0 - input.uv);
|
||||
float edgeDist = min(dist.x, dist.y);
|
||||
|
||||
// 1.0 если пиксель на краю грани, иначе 0.0
|
||||
float isEdge = step(edgeDist, _BorderWidth);
|
||||
|
||||
half4 finalColor = baseColor;
|
||||
// Внутри объема цвет прозрачный, на гранях — яркий и четкий
|
||||
finalColor.a = lerp(baseColor.a * 0.25, saturate(baseColor.a * 1.5), isEdge);
|
||||
finalColor.rgb = lerp(baseColor.rgb, baseColor.rgb * 1.3, isEdge);
|
||||
|
||||
return finalColor;
|
||||
}
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
FallBack Off
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17ecf4fbd19d4a63ad7b3b6a943166be
|
||||
timeCreated: 1794178806
|
||||
Reference in new issue
Block a user