2
0
Fork 0

攻击判定 几何计算

master
cd 2 years ago
parent 44d173d776
commit 385386c838

@ -21,6 +21,6 @@ MonoBehaviour:
mLastUsedPackagesHash: 1177269412
mLastUsedPackagesCount: 1
mLastBuildCode: 1
mLastEditorStartupTimeTicks: 638214577807241287
mLastEditorStartupTimeTicks: 638214577817722807
mNewVersionAvailable: 1
mLastAttachedFlowPlayerValue: 0

@ -16,7 +16,7 @@ namespace Game
private float _attackRoundTime;
private float _attackWaitTime;
private int _attackTimes;
private readonly List<int> _allEnemies = new List<int>();
private List<int> _allEnemies = new List<int>();
public void Reset()
{

@ -107,7 +107,7 @@ namespace Game
Do("更新敌人信息", () =>
{
var master = Util.GetMaster().ID();
Util.GetAllEnemies(_allEnemies);
Util.GetAllEntities(_allEnemies, ETeam.Monster);
_allEnemies.Sort((left, right) =>
(int)((Util.EntityDistance(master, left) - Util.EntityDistance(master, right)) * 10));
return ETaskStatus.Success;

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
namespace Game
@ -67,18 +68,30 @@ namespace Game
{
return _masterSoul?.ID() ?? 0;
}
public void GetAllEnemies(List<int> allEnemies)
public void GetAllEntities(List<int> allEnemies,ETeam teem)
{
var entities = Util.GetGroup(GameMatcher.Hp);
allEnemies.Clear();
foreach (var entity in entities)
{
if (entity.Team() == ETeam.Monster)
if (entity.Team() == teem)
{
allEnemies.Add(entity.ID());
}
}
}
public void ForeachEnemies(ETeam team, Action<GameEntity> f)
{
var entities = Util.GetGroup(GameMatcher.Hp);
foreach (var entity in entities)
{
if (entity.Team() != team)
{
f(entity);
}
}
}
}
public sealed class GameSystems : Feature

@ -30,7 +30,7 @@ public class SettleSystem : IExecuteSystem, IInitializeSystem
return;
}
Util.DrawShape(entity.hp.HitBoxShape, entity.Pos(), Vector3.right, Color.blue);
Util.DrawShape(entity.hp.HitBoxShape, entity.Pos(), Vector3.right, new Color(0, 1, 0, 0.4f));
}
private static void SettleSkill(SkillComponent skill)

@ -74,13 +74,7 @@ public partial class GameEntity
view.TransformViewOffset = go.transform.Find("view/viewRot/viewOffset");
view.TransformViewMain = go.transform.Find("view/viewRot/viewOffset/animator");
view.TransformViewOther = go.transform.Find("view/other");
var goInfo = go.GetComponent<EntityInfo>();
if (goInfo == null)
{
goInfo = go.AddComponent<EntityInfo>();
}
goInfo.entityId = ID();
view.SpriteRenderer = view.TransformViewMain.GetComponent<SpriteRenderer>();
view.SpriteRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
view.SpriteRenderer.receiveShadows = true;

@ -51,9 +51,14 @@ namespace Game
return EcsManager.Instance.GetMasterID();
}
public static void GetAllEnemies(List<int> allEnemies)
public static void GetAllEntities(List<int> allEnemies, ETeam team)
{
EcsManager.Instance.GetAllEnemies(allEnemies);
EcsManager.Instance.GetAllEntities(allEnemies, team);
}
public static void ForeachEnemies(ETeam team, Action<GameEntity> f)
{
EcsManager.Instance.ForeachEnemies(team, f);
}
public static GameEntity GetMasterSoul()

@ -1,9 +0,0 @@
using UnityEngine;
namespace Game
{
public class EntityInfo : MonoBehaviour
{
public int entityId;
}
}

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 44d9ff4532e7c6049955da64c965cd8f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -8,12 +8,9 @@ namespace Game
public AttackBehaviour SkillParam;
public float AttackRate;
public float StunkRate;
public float ExecutekRate;
public int OwnerEntity;
public int HitEntity; //0为非实体对象
public Vector3 HitPos;
public Vector3 HitDir;
public bool IsRight;
public bool IsDealed; //已经结算
public string SkillId; //是否技能造成的伤害
public uint Performance; //性能tag的mask
@ -33,38 +30,31 @@ namespace Game
public override void OnStay()
{
var param = _mRealAsset.template;
var skill = Owner.skill;
var castShape = param.Shape;
var castDir = Owner.skill.CastDir;
castDir = new Vector3(castDir.x, 0, castDir.z); //忽略y
var param = _mRealAsset.template;
var rot = Quaternion.FromToRotation(Vector3.right, castDir);
var castPos = rot * castShape.Offset + Owner.Pos();
void DealFunc(GameObject hitGo, Vector3 hitPos)
Util.DrawShape(castShape, castPos, castDir, Color.red);
Util.ForeachEnemies(Owner.Team(), target =>
{
var hitEntityId = 0;
EntityInfo info;
if (hitGo.TryGetComponent<EntityInfo>(out info))
{
hitEntityId = info.entityId;
if (Util.GetEntity(hitEntityId).Team() == Owner.Team())
{
return;
}
}
var hitKey = new Tuple<int, int>(hitEntityId, param.hitId);
if (!Owner.skill.SkillHitInfo.ContainsKey(hitKey))
var isHit = UtilShape.IsOverlap(castShape, castPos, castDir, target.hp.HitBoxShape, target.Pos());
if (isHit)
{
var skillHitInfo = new SkillHitInfo()
var targetID = target.ID();
var hitKey = new Tuple<int, int>(targetID, param.hitId);
if (Owner.skill.SkillHitInfo.ContainsKey(hitKey)) return;
var skillHitInfo = new SkillHitInfo
{
SkillParam = param,
AttackRate = 1,
StunkRate = 1,
ExecutekRate = 1,
OwnerEntity = Owner.ID(),
HitEntity = hitEntityId,
HitPos = hitPos,
HitEntity = targetID,
HitDir = castDir,
IsRight = Owner.move.IsRight,
IsDealed = false,
SkillId = skill.SkillId.Value,
Performance = 0,
@ -80,47 +70,12 @@ namespace Game
var featureSkill = skillCfg.GetFeatureSkill();
skillHitInfo.AttackRate = featureSkill.AttackRate;
skillHitInfo.StunkRate = featureSkill.StunRate;
skillHitInfo.ExecutekRate = featureSkill.ExecuteRate;
}
}
Owner.skill.SkillHitInfo[hitKey] = skillHitInfo;
}
}
if (param.isRaycast)
{
var posPre = Owner.PosPre();
var pos = Owner.Pos();
var distance = Vector3.Distance(pos, posPre);
var dir = pos - posPre;
var hitInfos = Physics.RaycastAll(posPre, dir, distance, UtilPhysics.LayerMaskHit);
Util.Draw(posPre, pos, Color.green);
foreach (var hitInfo in hitInfos)
{
var hitGo = hitInfo.transform.gameObject;
DealFunc(hitGo, hitInfo.point);
}
}
else
{
var rot = Quaternion.FromToRotation(Vector3.right, castDir);
var toGridSize = 16f / 64f;
var center = rot * param.center * toGridSize + Owner.Pos();
var halfExtents = param.halfExtents * toGridSize;
var hitInfos = Physics.BoxCastAll(center, halfExtents, castDir, rot, 0,
layerMask: UtilPhysics.LayerMaskHit);
Util.DrawBox(center, halfExtents, castDir, Color.green);
foreach (var hitInfo in hitInfos)
{
var hitGo = hitInfo.transform.gameObject;
DealFunc(hitGo, hitInfo.point);
}
}
});
}
public override void OnLeave()

@ -15,44 +15,8 @@ namespace Game
Debug.DrawLine(start, end, color, duration);
}
public static void DrawBox(Vector3 center, Vector3 halfExtents, Vector3 direction, Color color,
float duration = 0)
public static void DrawShape(Shape shape, Vector3 posReal, Vector3 direction, Color color)
{
if (!GameSetting.IsDebugDraw)
{
return;
}
var rot = Quaternion.FromToRotation(Vector3.right, direction);
var boxPoints = new Vector3[8];
boxPoints[0] = center + rot * new Vector3(halfExtents.x, halfExtents.y, halfExtents.z);
boxPoints[1] = center + rot * new Vector3(halfExtents.x, halfExtents.y, -halfExtents.z);
boxPoints[2] = center + rot * new Vector3(halfExtents.x, -halfExtents.y, halfExtents.z);
boxPoints[3] = center + rot * new Vector3(halfExtents.x, -halfExtents.y, -halfExtents.z);
boxPoints[4] = center + rot * new Vector3(-halfExtents.x, halfExtents.y, halfExtents.z);
boxPoints[5] = center + rot * new Vector3(-halfExtents.x, halfExtents.y, -halfExtents.z);
boxPoints[6] = center + rot * new Vector3(-halfExtents.x, -halfExtents.y, halfExtents.z);
boxPoints[7] = center + rot * new Vector3(-halfExtents.x, -halfExtents.y, -halfExtents.z);
for (int i = 0; i < 8; i++)
{
for (int j = i; j < 8; j++)
{
var p1 = boxPoints[i];
var p2 = boxPoints[j];
int defCount = 0;
defCount += (p1.x == p2.x ? 1 : 0);
defCount += (p1.y == p2.y ? 1 : 0);
defCount += (p1.z == p2.z ? 1 : 0);
Debug.DrawLine(boxPoints[i], boxPoints[j], color, duration);
}
}
}
public static void DrawShape(Shape shape, Vector3 pos, Vector3 direction, Color color)
{
var posReal = pos + shape.Offset;
var posRealTop = posReal + Vector3.up * shape.Height;
var posRealMid = posReal + Vector3.up * (shape.Height / 2);
switch (shape.Type)
@ -62,13 +26,13 @@ namespace Game
DrawShapeCenter(posReal, 1, color);
break;
case EShapeType.Box:
DrawShapeBody(shape, pos, direction, color);
DrawShapeBody(shape, posReal, direction, color);
break;
case EShapeType.Sector:
DrawShapeBody(shape, pos, direction, color);
DrawShapeBody(shape, posReal, direction, color);
break;
case EShapeType.Circle:
DrawShapeBody(shape, pos, direction, color);
DrawShapeBody(shape, posReal, direction, color);
DrawShapeCenter(posRealMid, shape.Height / 2, color);
DrawShapeCross(posReal, shape.Radius, color);
DrawShapeCross(posRealTop, shape.Radius, color);
@ -87,9 +51,8 @@ namespace Game
Debug.DrawLine(pos + Vector3.back * r, pos + Vector3.forward * r, color);
}
private static void DrawShapeBody(Shape shape, Vector3 pos, Vector3 direction, Color color)
private static void DrawShapeBody(Shape shape, Vector3 posReal, Vector3 direction, Color color)
{
var posReal = pos + shape.Offset;
var posRealTop = posReal + Vector3.up * shape.Height;
shape.ForeachVerticesPair(direction, (v1, v2) =>
{

@ -44,9 +44,7 @@ namespace Game
},
OwnerEntity = owner.ID(),
HitEntity = target.ID(),
HitPos = target.Pos(),
HitDir = Vector3.up,
IsRight = true,
IsDealed = false,
SkillId = "",
Performance = (uint)0,

@ -4,8 +4,7 @@ namespace Game
{
public static class UtilShape
{
public static bool IsOverlap(Shape shape, Shape circle,
Vector3 shapePos, Vector3 circlePos, Vector3 shapeDir, Vector3 circleDir)
public static bool IsOverlap(Shape shape, Vector3 shapePos, Vector3 shapeDir, Shape circle, Vector3 circlePos)
{
if (circle.Type != EShapeType.Circle)
{
@ -14,9 +13,8 @@ namespace Game
}
//检查Y
var (shapeCenter, circleCenter) = (shapePos + shape.Offset, circlePos + circle.Offset);
var (shapeYMin, shapeYMax) = (shapeCenter.y, shapeCenter.y + shape.Height);
var (circleYMin, circleYMax) = (circleCenter.y, circleCenter.y + circle.Height);
var (shapeYMin, shapeYMax) = (shapePos.y, shapePos.y + shape.Height);
var (circleYMin, circleYMax) = (circlePos.y, circlePos.y + circle.Height);
if (shapeYMin > circleYMax || shapeYMax < circleYMin)
{
@ -24,22 +22,22 @@ namespace Game
}
//保底距离
var dist = Vector3.Distance(shapeCenter, circleCenter);
if (dist < 0.01f)
var distance = Vector3.Distance(shapePos, circlePos);
if (distance < 0.01f)
{
return true;
}
//检查AABB
var (shapeAABB, circleAABB) = (shape.GetAABB(shapeDir), circle.GetAABB(circleDir));
var shapeXMin = shapeAABB.x + shapeCenter.x;
var shapeXMax = shapeAABB.y + shapeCenter.x;
var shapeZMin = shapeAABB.z + shapeCenter.z;
var shapeZMax = shapeAABB.w + shapeCenter.z;
var circleXMin = circleAABB.x + circleCenter.x;
var circleXMax = circleAABB.y + circleCenter.x;
var circleZMin = circleAABB.z + circleCenter.z;
var circleZMax = circleAABB.w + circleCenter.z;
var (shapeAABB, circleAABB) = (shape.GetAABB(shapeDir), circle.GetAABB(Vector3.zero));
var shapeXMin = shapeAABB.x + shapePos.x;
var shapeXMax = shapeAABB.y + shapePos.x;
var shapeZMin = shapeAABB.z + shapePos.z;
var shapeZMax = shapeAABB.w + shapePos.z;
var circleXMin = circleAABB.x + circlePos.x;
var circleXMax = circleAABB.y + circlePos.x;
var circleZMin = circleAABB.z + circlePos.z;
var circleZMax = circleAABB.w + circlePos.z;
if (shapeXMin > circleXMax || shapeXMax < circleXMin || shapeZMin > circleZMax || shapeZMax < circleZMin)
{
@ -47,25 +45,45 @@ namespace Game
}
//检查形状
Vector3 circleCenterNew;
switch (shape.Type)
{
case EShapeType.Dot:
return true;
return distance < circle.Radius;
case EShapeType.Circle:
case EShapeType.Sector: //TODO
var distance = Vector3.Distance(shapeCenter, circleCenter);
return distance < shape.Radius + circle.Radius;
case EShapeType.Sector:
if (distance > shape.Radius + circle.Radius)
return false;
circleCenterNew = CircleCenterNew(circlePos, shapePos, shapeDir);
return SectorCircle(shape.Radius, shape.Angle, circle.Radius, circleCenterNew);
case EShapeType.Box:
var dir = circleCenter - shapeCenter;
var circleCenterNew = Quaternion.FromToRotation(shapeDir, Vector3.right) * dir;
var (shapeSizeX, shapeSizeY) = (SizeX: shape.SizeX, SizeY: shape.SizeY);
return RectCircleIntersection(shapeSizeX, shapeSizeY, circle.Radius, circleCenterNew);
circleCenterNew = CircleCenterNew(circlePos, shapePos, shapeDir);
return RectCircle(shape.SizeX, shape.SizeY, circle.Radius, circleCenterNew);
}
return false;
}
private static bool RectCircleIntersection(float sizeX, float sizeY, float circleRadius, Vector3 circleCenter)
private static Vector3 CircleCenterNew(Vector3 circlePos, Vector3 shapePos, Vector3 shapeDir)
{
var dir = circlePos - shapePos;
return Quaternion.FromToRotation(shapeDir, Vector3.right) * dir;
}
private static bool SectorCircle(float radius, float angle, float circleRadius, Vector3 circleCenter)
{
if (circleCenter.z < 0)
circleCenter.z = -circleCenter.z;
var dist = circleCenter.magnitude; //到原点的距离
if (dist < circleRadius)
return true;
var circleAngle = Mathf.Asin(circleRadius / dist);
var circleRot = Util.Vec3ToRot(circleCenter);
return !(circleRot - circleAngle > angle / 2);//边缘情况不管
}
private static bool RectCircle(float sizeX, float sizeY, float circleRadius, Vector3 circleCenter)
{
var distX = Mathf.Abs(circleCenter.x) - sizeX;
var distY = Mathf.Abs(circleCenter.z) - sizeY;

@ -61,7 +61,6 @@ namespace Game
public static Shape NewBox(Vector3 offset, float height, float sizeX, float sizeY)
{
Util.Print("offset", offset);
var shape = new Shape
{
Type = EShapeType.Box,
@ -96,7 +95,7 @@ namespace Game
return aabb;
}
public void SetVertices(Vector3 direction)
private void SetVertices(Vector3 direction)
{
vertices.Clear();
switch (Type)
@ -114,7 +113,7 @@ namespace Game
case EShapeType.Sector:
var rotAdd = Util.Vec3ToRot(direction);
vertices.Add(Vector3.zero);
var vertNum = (int)(Angle / 15);
var vertNum = Angle > 15 ? (int)(Angle / 15) : 1;
var anglePerVertex = Angle / vertNum;
for (var i = 0; i <= vertNum; i++)
{
@ -128,8 +127,8 @@ namespace Game
case EShapeType.Box:
var (halfX, halfY) = (SizeX / 2, SizeY / 2);
var up = new Vector3(direction.z, 0, direction.x);
var right = new Vector3(direction.x, 0, -direction.z);
var up = new Vector3(direction.z, 0, -direction.x);
var right = new Vector3(direction.x, 0, direction.z);
var topLeft = right * halfX - up * halfY;
var topRight = right * halfX + up * halfY;
@ -137,8 +136,8 @@ namespace Game
var bottomRight = -right * halfX + up * halfY;
vertices.Add(topLeft);
vertices.Add(topRight);
vertices.Add(bottomLeft);
vertices.Add(bottomRight);
vertices.Add(bottomLeft);
break;
}
}

@ -712,9 +712,6 @@ MonoBehaviour:
m_Name: AttackClip
m_EditorClassIdentifier:
template:
isRaycast: 0
center: {x: 1, y: 1, z: 0}
halfExtents: {x: 1.5, y: 1, z: 0.5}
flowSpeed: {x: 2, y: 1, z: 0}
flowTime: 0
isFlow: 0
@ -725,12 +722,12 @@ MonoBehaviour:
hitId: 0
hitType: 0
Type: 2
Offset: {x: 1, y: 0, z: 0}
Height: 2.5
SizeX: 2
Offset: {x: 0, y: 0, z: 0}
Height: 2
SizeX: 10
SizeY: 2
Radius: 2
Angle: 98.6
Radius: 4
Angle: 180
--- !u!114 &5178577764301111608
MonoBehaviour:
m_ObjectHideFlags: 1

@ -6,11 +6,8 @@ using UnityEngine.Playables;
[Serializable]
public class AttackBehaviour : PlayableBehaviour
{
[Rename("使用射线检测")] public bool isRaycast;
[Rename("中心点")] public Vector3 center;
[Rename("半大小")] public Vector3 halfExtents;
[Rename("击飞方向")] public Vector3 flowSpeed;
[Rename("击飞持续时间")] public float flowTime;
[Rename("强制位移方向")] public Vector3 flowSpeed;
[Rename("强制位移持续时间")] public float flowTime;
[Rename("可以从地面击飞")] public bool isFlow;
[Rename("伤害修正")] public float damageRate;
[Rename("眩晕修正")] public float stunRate;
@ -30,10 +27,15 @@ public class AttackBehaviour : PlayableBehaviour
private const float ToGridSize = 16f / 64f;
public Shape Shape
{
get { return _shape ??= ShapeNew; }
}
public Shape ShapeNew
{
get
{
return _shape ??= Type switch
return Type switch
{
EShapeType.Dot =>
Shape.NewDot(Offset * ToGridSize),

@ -36,7 +36,8 @@ public class AttackMixerBehaviour : PlayableBehaviour
if (attackTimeClipTime > 0 && attackTimeClipTime + 0.01f < attackTimeClipTimeMax)
{
Util.DrawShape(input.Shape, trackBinding.position, Vector3.right, Color.green);
var shape = input.ShapeNew;
Util.DrawShape(input.ShapeNew, trackBinding.position + shape.Offset, Vector3.right, Color.green);
}
}
}

Loading…
Cancel
Save