1. 新增模型区域点击接口,同时为Windows添加了完美的透明区域鼠标透穿功能,以及Linux的基本点击区域识别功能(即非完美透传)

2. 更新了LICENSE
This commit is contained in:
Misaki
2025-12-25 17:35:12 +08:00
parent e9a9d483db
commit 702b083e47
8 changed files with 226 additions and 46 deletions
+21
View File
@@ -80,7 +80,19 @@ public:
*/
void StopLipSync();
/**
* @brief 获取模型是否有命中区域定义
* @return 是否有命中区域
*/
[[nodiscard]] bool HasHitAreas() const;
/**
* @brief 检测点是否在模型的任何可见部分上
* @param x 视图坐标X
* @param y 视图坐标Y
* @return 是否命中
*/
[[nodiscard]] bool IsPointOnModel(Csm::csmFloat32 x, Csm::csmFloat32 y);
/**
* @brief model3.jsonが置かれたディレクトリとファイルパスからモデルを生成する \n
@@ -177,6 +189,15 @@ protected:
*/
void DoDraw();
private:
/**
* @brief 使用Drawable检测(当没有命中区域时使用)
* @param x 视图坐标X
* @param y 视图坐标Y
* @return 是否命中
*/
[[nodiscard]] bool IsPointOnDrawable(Csm::csmFloat32 x, Csm::csmFloat32 y);
private:
/**
* @brief model3.jsonからモデルを生成する。<br>
+70
View File
@@ -82,6 +82,76 @@ LAppModel::~LAppModel()
}
delete(_modelSetting);
}
bool LAppModel::HasHitAreas() const {
return _modelSetting && _modelSetting->GetHitAreasCount() > 0;
}
bool LAppModel::IsPointOnModel(const csmFloat32 x, const csmFloat32 y)
{
if (_model == nullptr || _opacity < 0.1f)
{
return false;
}
// 如果有命中区域,使用HitTest(是否存在命中区域,这取决于模型是否定义这两部分信息)
/* 通常是这样的信息,在.model3.json当中
"HitAreas": [
{
"Id": "HitAreaHead",
"Name": "Head"
},
{
"Id": "HitAreaBody",
"Name": "Body"
}
]
*/
if (HasHitAreas())
{
// 检查常用命中区域
const bool hit = HitTest(LAppDefine::HitAreaNameHead, x, y) ||
HitTest(LAppDefine::HitAreaNameBody, x, y);
if (_debugMode && hit)
{
LAppPal::PrintLogLn("[APP]Hit model via HitArea at (%.2f, %.2f)", x, y);
}
return hit;
}
// 如果没有命中区域,使用Drawable检测
return IsPointOnDrawable(x, y);
}
bool LAppModel::IsPointOnDrawable(const csmFloat32 x, const csmFloat32 y)
{
if (_model == nullptr || _opacity < 0.01f) // 接近完全透明
{
return false;
}
// 获取所有Drawable的数量
const csmInt32 drawableCount = _model->GetDrawableCount();
// 遍历所有Drawable
for (csmInt32 i = 0; i < drawableCount; ++i)
{
// 获取Drawable的ID
const CubismIdHandle drawableId = _model->GetDrawableId(i);
// 检查Drawable是否可见
if (_model->GetDrawableDynamicFlagIsVisible(i))
{
// 使用CubismUserModel提供的IsHit函数检测
if (IsHit(drawableId, x, y))
{
if (_debugMode)
{
const csmChar* drawableName = _model->GetDrawableId(i)->GetString().GetRawString();
LAppPal::PrintLogLn("[APP]Hit drawable: %s at (%.2f, %.2f)",
drawableName, x, y);
}
return true;
}
}
}
return false;
}
void LAppModel::LoadAssets(const csmChar* dir, const csmChar* fileName)
{
+11 -23
View File
@@ -269,35 +269,23 @@ float LAppView::TransformScreenY(float deviceY) const
#include "Id/CubismIdManager.hpp"
bool LAppView::IsModelHit(const float deviceX, const float deviceY) const {
const LAppLive2DManager* live2DManager = LAppLive2DManager::GetInstance();
if (!live2DManager || live2DManager->GetModelNum() == 0) {
if (!live2DManager || live2DManager->GetModelNum() == 0)
{
return false;
}
// 坐标转换(设备坐标 -> Live2D View 坐标)
const csmFloat32 viewX = _deviceToScreen->TransformX(deviceX);
const csmFloat32 viewY = _deviceToScreen->TransformY(deviceY);
// 转换到视图坐标
const csmFloat32 viewX = TransformViewX(deviceX);
const csmFloat32 viewY = TransformViewY(deviceY);
// 正确获取 ID Handle(在 SDK 初始化后调用)
static const Csm::CubismId* bodyId = nullptr;
static const Csm::CubismId* headId = nullptr;
if (!bodyId) {
bodyId = CubismFramework::GetIdManager()->GetId("Body");
headId = CubismFramework::GetIdManager()->GetId("Head");
// 遍历所有模型
LAppModel* model = live2DManager->GetModel(0);
if (model && model->IsPointOnModel(viewX, viewY)) // 调用二次封装的IsPointOnModel函数
{
return true;
}
// 遍历所有模型进行碰撞检测
const csmUint32 modelCount = live2DManager->GetModelNum();
for (csmUint32 i = 0; i < modelCount; ++i) {
LAppModel* model = live2DManager->GetModel(i);
if (!model || !model->GetModel()) continue;
// 检查命中区域(修正:使用 SDK 提供的 ID)
if (model->IsHit(bodyId, viewX, viewY) || model->IsHit(headId, viewX, viewY)) {
return true; // 击中模型
}
}
return false; // 未击中模型
return false;
}
void LAppView::PreModelDraw(LAppModel& refModel)