feat: 修改自动领取收益关闭,修复下架时间的bug,修改的光栅卡陀螺仪
This commit is contained in:
parent
ce4fd85926
commit
2855cd512d
@ -491,10 +491,9 @@ func (s *assetService) GetAsset(req *pb.GetAssetRequest, userID, starID int64) (
|
||||
if exhibitionStartTime == 0 {
|
||||
exhibitionStartTime = asset.CreatedAt // 兜底
|
||||
}
|
||||
earnings = calculateRealtimeEarnings(asset.LikeCount, exhibitionStartTime, time.Now().UnixMilli())
|
||||
|
||||
// 获取展出过期时间
|
||||
// 获取展出过期时间(先获取,用于计算收益)
|
||||
exhibitionExpireAt, _ = s.assetRepo.GetExhibitionExpireTime(asset.ID)
|
||||
earnings = calculateRealtimeEarnings(asset.LikeCount, exhibitionStartTime, time.Now().UnixMilli(), exhibitionExpireAt)
|
||||
}
|
||||
|
||||
// 6.5 从 asset_registry 表获取 grade
|
||||
@ -759,9 +758,16 @@ func calculateHourlyEarnings(likeCount int32) float64 {
|
||||
// calculateRealtimeEarnings 实时计算展示收益
|
||||
// 公式:R1 = R0 × T × [100% + Buff(n)]
|
||||
// R0 = 5 水晶/小时,T = 上架时长(小时),Buff(n) 根据点赞数计算
|
||||
func calculateRealtimeEarnings(likeCount int32, startTime, now int64) int64 {
|
||||
// 注意:使用 min(now, expireAt) 确保过期后收益不再增长
|
||||
func calculateRealtimeEarnings(likeCount int32, startTime, now, expireAt int64) int64 {
|
||||
// 计算有效截止时间(展览结束时间 vs 当前时间,取较小值)
|
||||
endTime := now
|
||||
if expireAt > 0 && expireAt < now {
|
||||
endTime = expireAt
|
||||
}
|
||||
|
||||
// 计算上架时长(毫秒转小时)
|
||||
T := (now - startTime) / 3600000
|
||||
T := (endTime - startTime) / 3600000
|
||||
if T <= 0 {
|
||||
T = 1 // 最少1小时
|
||||
}
|
||||
|
||||
@ -452,7 +452,7 @@ func (r *galleryRepository) GetMyExhibitedAssets(userID, starID int64, page, pag
|
||||
now := time.Now().UnixMilli()
|
||||
for _, item := range items {
|
||||
item.HourlyEarnings = calculateHourlyEarnings(item.LikeCount)
|
||||
item.Earnings = calculateRealtimeEarnings(item.LikeCount, item.ExhibitedAt, now)
|
||||
item.Earnings = calculateRealtimeEarnings(item.LikeCount, item.ExhibitedAt, now, item.ExpireAt)
|
||||
}
|
||||
|
||||
return items, total, nil
|
||||
@ -496,7 +496,7 @@ func (r *galleryRepository) GetUserExhibitedAssets(userID, starID int64, page, p
|
||||
// 实时计算每个资产的收益
|
||||
for _, item := range items {
|
||||
item.HourlyEarnings = calculateHourlyEarnings(item.LikeCount)
|
||||
item.Earnings = calculateRealtimeEarnings(item.LikeCount, item.ExhibitedAt, now)
|
||||
item.Earnings = calculateRealtimeEarnings(item.LikeCount, item.ExhibitedAt, now, item.ExpireAt)
|
||||
}
|
||||
|
||||
return items, total, nil
|
||||
@ -660,9 +660,16 @@ func calculateHourlyEarnings(likeCount int32) float64 {
|
||||
// calculateRealtimeEarnings 实时计算展示收益
|
||||
// 公式:R1 = R0 × T × [100% + Buff(n)]
|
||||
// R0 = 5 水晶/小时,T = 上架时长(小时),Buff(n) 根据点赞数计算
|
||||
func calculateRealtimeEarnings(likeCount int32, startTime, now int64) int64 {
|
||||
// 注意:使用 min(now, expireAt) 确保过期后收益不再增长
|
||||
func calculateRealtimeEarnings(likeCount int32, startTime, now, expireAt int64) int64 {
|
||||
// 计算有效截止时间(展览结束时间 vs 当前时间,取较小值)
|
||||
endTime := now
|
||||
if expireAt > 0 && expireAt < now {
|
||||
endTime = expireAt
|
||||
}
|
||||
|
||||
// 计算上架时长(毫秒转小时)
|
||||
T := (now - startTime) / 3600000
|
||||
T := (endTime - startTime) / 3600000
|
||||
if T <= 0 {
|
||||
T = 1 // 最少1小时
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ func main() {
|
||||
logger.Logger.Info("Services initialized")
|
||||
|
||||
// 7. Init worker(goroutine 中启动)
|
||||
resetWorker := worker.NewDailyResetWorker(dailyRepo, revenueRepo, userRPCClient)
|
||||
resetWorker := worker.NewDailyResetWorker(dailyRepo, revenueRepo, userRPCClient, galleryRPCClient)
|
||||
go resetWorker.Start()
|
||||
logger.Logger.Info("Reset worker started")
|
||||
|
||||
|
||||
@ -80,6 +80,7 @@ func (s *revenueService) GetExhibitionRevenue(ctx context.Context, userID, starI
|
||||
CycleStartTime: r.CycleStartTime,
|
||||
CycleEndTime: r.CycleEndTime,
|
||||
Status: r.Status,
|
||||
CanClaim: r.Status == "claimable",
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
@ -15,23 +15,26 @@ import (
|
||||
)
|
||||
|
||||
type DailyResetWorker struct {
|
||||
dailyRepo repository.DailyTaskRepository
|
||||
revenueRepo repository.RevenueRepository
|
||||
userClient client.UserServiceClient
|
||||
stopCh chan struct{}
|
||||
wg sync.WaitGroup
|
||||
dailyRepo repository.DailyTaskRepository
|
||||
revenueRepo repository.RevenueRepository
|
||||
userClient client.UserServiceClient
|
||||
galleryClient client.GalleryServiceClient
|
||||
stopCh chan struct{}
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func NewDailyResetWorker(
|
||||
dailyRepo repository.DailyTaskRepository,
|
||||
revenueRepo repository.RevenueRepository,
|
||||
userClient client.UserServiceClient,
|
||||
galleryClient client.GalleryServiceClient,
|
||||
) *DailyResetWorker {
|
||||
return &DailyResetWorker{
|
||||
dailyRepo: dailyRepo,
|
||||
revenueRepo: revenueRepo,
|
||||
userClient: userClient,
|
||||
stopCh: make(chan struct{}),
|
||||
dailyRepo: dailyRepo,
|
||||
revenueRepo: revenueRepo,
|
||||
userClient: userClient,
|
||||
galleryClient: galleryClient,
|
||||
stopCh: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,8 +101,8 @@ func (w *DailyResetWorker) doResetAndAutoClaim() {
|
||||
logger.Logger.Info(fmt.Sprintf("DailyResetWorker: daily tasks reset: %d records updated", resetCount))
|
||||
}
|
||||
|
||||
// 2. 自动发放展示收益
|
||||
w.autoClaimExhibitionRevenue()
|
||||
// 2. 自动发放展示收益(暂时关闭)
|
||||
// w.autoClaimExhibitionRevenue()
|
||||
}
|
||||
|
||||
func (w *DailyResetWorker) autoClaimExhibitionRevenue() {
|
||||
@ -128,6 +131,16 @@ func (w *DailyResetWorker) autoClaimExhibitionRevenue() {
|
||||
zap.Int64("record_id", record.ID), zap.Error(err))
|
||||
}
|
||||
totalClaimed++
|
||||
|
||||
// 自动下架:调用 GalleryService 下架展览
|
||||
if w.galleryClient != nil && record.AssetID > 0 {
|
||||
if err := w.galleryClient.RemoveExhibitionByAsset(context.Background(), record.AssetID); err != nil {
|
||||
logger.Logger.Warn("DailyResetWorker: failed to remove exhibition",
|
||||
zap.Int64("asset_id", record.AssetID),
|
||||
zap.Int64("revenue_record_id", record.ID),
|
||||
zap.Error(err))
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
lastErr = err
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
# 光栅卡陀螺仪交互优化设计方案
|
||||
|
||||
**日期:** 2026-05-22
|
||||
**文件:** `docs/superpowers/specs/2026-05-22-lenticular-gyro-optimization-design.md`
|
||||
|
||||
---
|
||||
|
||||
## 1. 问题描述
|
||||
|
||||
设备使用陀螺仪倾斜查看光栅卡时,图片在左右视图之间快速来回切换,无法稳定在某一侧。
|
||||
|
||||
**期望行为:**
|
||||
- 设备居中(不倾斜)→ 显示中性图
|
||||
- 往左倾斜 → 稳定显示左视图
|
||||
- 往右倾斜 → 稳定显示右视图
|
||||
|
||||
**当前行为:**
|
||||
- 轻微倾斜就触发切换,且图片在左右之间来回振荡
|
||||
- 没有平衡点让图片稳定
|
||||
|
||||
---
|
||||
|
||||
## 2. 根本原因
|
||||
|
||||
**原因:缺少中性阈值区(Dead Zone)**
|
||||
|
||||
陀螺仪数据直接映射到图片切换阈值,没有任何"容忍区"。
|
||||
|
||||
当设备略微偏离中心时:
|
||||
- `gamma` 值微小的正负变化
|
||||
- 直接导致 `x` 方向变化
|
||||
- 触发 opacity 切换
|
||||
|
||||
加上陀螺仪本身的噪声和设备轻微晃动,导致图片不断在左右之间来回切换。
|
||||
|
||||
---
|
||||
|
||||
## 3. 修复方案
|
||||
|
||||
**文件:** `frontend/composables/useHolographicPreview.js`
|
||||
|
||||
### 修改:增大中性阈值区
|
||||
|
||||
当前代码已有 dead zone 判断逻辑,只需增大 `db` 系数即可:
|
||||
|
||||
```javascript
|
||||
// 第79行
|
||||
const db = 0.08 * dead // 从 0.016 改为 0.08
|
||||
```
|
||||
|
||||
**说明:** 增大 db 系数 = 中性区变宽 = 更难触发切换 = 图片更稳定
|
||||
|
||||
---
|
||||
|
||||
## 4. 参数调整
|
||||
|
||||
| 参数 | 当前值 | 修改后 | 说明 |
|
||||
|------|--------|--------|------|
|
||||
| db (dead zone) | 0.016 | 0.08 | 中性区阈值,越大越难触发切换 |
|
||||
|
||||
**建议值范围:** 0.05 ~ 0.12
|
||||
- 值越大:中性区越宽,越稳定但响应越慢
|
||||
- 值越小:越敏感,但容易误触发
|
||||
|
||||
---
|
||||
|
||||
## 5. 验收标准
|
||||
|
||||
| 测试场景 | 期望结果 |
|
||||
|---------|---------|
|
||||
| 设备静止居中 | 显示中性图,稳定不动 |
|
||||
| 轻微倾斜 | 保持中性,不触发切换 |
|
||||
| 明显往左倾斜 | 显示左视图,稳定 |
|
||||
| 明显往右倾斜 | 显示右视图,稳定 |
|
||||
| 从倾斜缓慢回到居中 | 平滑过渡,无振荡 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 影响范围
|
||||
|
||||
- 修改文件:`frontend/composables/useHolographicPreview.js`
|
||||
- 不影响触摸滑动交互
|
||||
- 不涉及后端或数据库
|
||||
@ -76,7 +76,7 @@ export function useHolographicPreview() {
|
||||
const dy = (beta - accelBaseY) / 45 * sens
|
||||
accelSmoothed = lerp(accelSmoothed, dx, k)
|
||||
const dead = physics.sensorDeadzoneStrength || 1
|
||||
const db = 0.016 * dead
|
||||
const db = 0.08 * dead
|
||||
simulate(
|
||||
Math.abs(accelSmoothed) < db ? 0 : clamp(accelSmoothed, -1, 1),
|
||||
clamp(dy, -1, 1)
|
||||
|
||||
@ -9,7 +9,7 @@ const FLOW_PHYSICS = {
|
||||
angleStability: 52,
|
||||
transitionSmoothness: 40,
|
||||
tiltSensitivity: 96,
|
||||
sensorDeadzoneStrength: 0,
|
||||
sensorDeadzoneStrength: 1,
|
||||
parallaxDepth: 18,
|
||||
lenticularAnchorFloor: 0.1,
|
||||
lenticularNonDominantResidualMin: 0.092,
|
||||
@ -18,7 +18,7 @@ const FLOW_PHYSICS = {
|
||||
}
|
||||
|
||||
const DISCRETE_STEP_DEG = 13
|
||||
const DISCRETE_STEP_HYST_DEG = 5
|
||||
const DISCRETE_STEP_HYST_DEG = 9
|
||||
const TILT_MAG_TAU_MS = 150
|
||||
const TILT_MAG_MAX_RISE_DPS = 82
|
||||
const TILT_MAG_MAX_FALL_DPS = 168
|
||||
@ -51,6 +51,7 @@ export function useLenticularCraftTiltPreview(layersRef) {
|
||||
}
|
||||
|
||||
function simulateFromSignedDegrees(tiltMagDeg, signedDegHint) {
|
||||
console.log('[DEBUG simulateFromSignedDegrees] called, tiltMagDeg:', tiltMagDeg, 'signedDegHint:', signedDegHint)
|
||||
const ls = getLayersArray()
|
||||
const n = Math.max(1, ls.length)
|
||||
const raw = Math.abs(Number(tiltMagDeg) || 0)
|
||||
@ -69,6 +70,7 @@ export function useLenticularCraftTiltPreview(layersRef) {
|
||||
const maxFall = TILT_MAG_MAX_FALL_DPS * sec
|
||||
|
||||
if (Number.isFinite(signedDegHint)) {
|
||||
console.log('[DEBUG simulateFromSignedDegrees] signedDegHint is finite:', signedDegHint)
|
||||
if (lastSignedDegHint != null && sec > 1e-6) {
|
||||
const dAbsSignedDt =
|
||||
(Math.abs(signedDegHint) - Math.abs(lastSignedDegHint)) / sec
|
||||
@ -94,8 +96,34 @@ export function useLenticularCraftTiltPreview(layersRef) {
|
||||
const MARGIN = DISCRETE_STEP_HYST_DEG
|
||||
const stepBefore = discreteStableStep.value
|
||||
let s = stepBefore
|
||||
while (absDeg >= (s + 1) * STEP + MARGIN) s++
|
||||
while (s > 0 && absDeg <= s * STEP - MARGIN) s--
|
||||
|
||||
// 二值模式:仅允许 0(中性) 或 1(倾斜),防止同方向重复递增档位
|
||||
const ENTER_THRESHOLD = STEP + MARGIN
|
||||
const EXIT_THRESHOLD = MARGIN
|
||||
|
||||
if (s === 0) {
|
||||
// 中性状态:仅当倾斜超过阈值才进入档位1
|
||||
if (absDeg >= ENTER_THRESHOLD) {
|
||||
s = 1
|
||||
console.log('[DEBUG] 进入档位1, absDeg:', absDeg.toFixed(2), 'signedDegHint:', signedDegHint)
|
||||
}
|
||||
} else if (s === 1) {
|
||||
// 档位1状态:检测方向变化才允许退回
|
||||
// 如果 signedDegHint 符号改变(反方向倾斜),立即回到中性
|
||||
if (lastSignedDegHint !== null && Number.isFinite(signedDegHint)) {
|
||||
if (signedDegHint * lastSignedDegHint < 0) {
|
||||
// 方向改变,回到中性
|
||||
s = 0
|
||||
lastSignedDegHint = signedDegHint
|
||||
console.log('[DEBUG] 方向改变,回到中性, signedDegHint:', signedDegHint.toFixed(2))
|
||||
}
|
||||
} else if (absDeg <= EXIT_THRESHOLD) {
|
||||
// 没有方向信息时,使用角度阈值
|
||||
s = 0
|
||||
console.log('[DEBUG] 角度不足,回到中性, absDeg:', absDeg.toFixed(2))
|
||||
}
|
||||
}
|
||||
|
||||
discreteStableStep.value = s
|
||||
const idx = s % n
|
||||
const sens = physics.tiltSensitivity / 100
|
||||
@ -134,13 +162,17 @@ export function useLenticularCraftTiltPreview(layersRef) {
|
||||
}
|
||||
|
||||
function scheduleTiltStart() {
|
||||
console.log('[DEBUG useLenticularCraftTiltPreview] scheduleTiltStart called')
|
||||
cancelScheduledTiltStart()
|
||||
nextTick(() => {
|
||||
relax(0.86)
|
||||
lockPreviewStill()
|
||||
console.log('[DEBUG useLenticularCraftTiltPreview] entryTiltTimer set, delay:', LENTICULAR_TILT_START_DELAY_MS)
|
||||
entryTiltTimer = setTimeout(() => {
|
||||
entryTiltTimer = null
|
||||
console.log('[DEBUG useLenticularCraftTiltPreview] startTilt about to be called')
|
||||
startTilt()
|
||||
console.log('[DEBUG useLenticularCraftTiltPreview] startTilt called')
|
||||
}, LENTICULAR_TILT_START_DELAY_MS)
|
||||
})
|
||||
}
|
||||
|
||||
@ -361,6 +361,7 @@ export function useLenticularStudioTilt(opts) {
|
||||
}
|
||||
|
||||
function startAccelInternal(options = {}) {
|
||||
console.log('[DEBUG useLenticularStudioTilt] startAccelInternal called, options:', options)
|
||||
const fromNativeFallback = options.fromNativeFallback === true
|
||||
mode = 'accel'
|
||||
stopAccel()
|
||||
@ -379,34 +380,45 @@ export function useLenticularStudioTilt(opts) {
|
||||
|
||||
if (useStudioAccelDirect) {
|
||||
if (typeof simulateFromSignedDegrees === 'function') {
|
||||
console.log('[DEBUG useLenticularStudioTilt] 使用 simulateFromSignedDegrees')
|
||||
resetStudioAccelBaseline()
|
||||
}
|
||||
accelHandler = (res) => {
|
||||
console.log('[DEBUG useLenticularStudioTilt] accelHandler called, x:', res.x, 'y:', res.y, 'z:', res.z)
|
||||
const ax = Number(res.x) || 0
|
||||
const ay = Number(res.y) || 0
|
||||
const az = Number(res.z) || 0
|
||||
const gMag = Math.hypot(ax, ay, az)
|
||||
if (gMag < 0.12) return
|
||||
console.log('[DEBUG useLenticularStudioTilt] gMag:', gMag.toFixed(3))
|
||||
if (gMag < 0.12) {
|
||||
console.log('[DEBUG useLenticularStudioTilt] gMag too small, returning')
|
||||
return
|
||||
}
|
||||
/* 竖屏常见握持:左右倾斜主要反映为 ax/az 与重力的关系(免 warmup,避免长期无输出) */
|
||||
if (typeof simulateFromSignedDegrees === 'function') {
|
||||
console.log('[DEBUG useLenticularStudioTilt] 调用 simulateFromSignedDegrees')
|
||||
const tiltRad = Math.atan2(-ax, az)
|
||||
if (studioAccelBaseRad == null) {
|
||||
console.log('[DEBUG useLenticularStudioTilt] 正在采集 baseline')
|
||||
studioAccelBaselineRads.push(tiltRad)
|
||||
if (studioAccelBaselineRads.length < STUDIO_ACCEL_BASELINE_FRAMES) {
|
||||
simulate(0, 0)
|
||||
return
|
||||
}
|
||||
studioAccelBaseRad = circularMeanRad(studioAccelBaselineRads)
|
||||
console.log('[DEBUG useLenticularStudioTilt] baseline 采集完成:', studioAccelBaseRad)
|
||||
studioAccelBaselineRads = []
|
||||
}
|
||||
let delta = tiltRad - studioAccelBaseRad
|
||||
while (delta > Math.PI) delta -= 2 * Math.PI
|
||||
while (delta < -Math.PI) delta += 2 * Math.PI
|
||||
const signedDeg = delta * (180 / Math.PI)
|
||||
console.log('[DEBUG useLenticularStudioTilt] delta:', delta.toFixed(4), 'signedDeg:', signedDeg.toFixed(2))
|
||||
const rawAbs = Math.abs(signedDeg)
|
||||
const prevLp = studioAccelDiscreteDegLp
|
||||
const kLp = rawAbs >= prevLp ? 0.27 : 0.4
|
||||
studioAccelDiscreteDegLp += (rawAbs - studioAccelDiscreteDegLp) * kLp
|
||||
console.log('[DEBUG useLenticularStudioTilt] calling simulateFromSignedDegrees, mag:', studioAccelDiscreteDegLp.toFixed(2), 'signedDeg:', signedDeg.toFixed(2))
|
||||
simulateFromSignedDegrees(studioAccelDiscreteDegLp, signedDeg)
|
||||
} else {
|
||||
const tiltRaw = Math.atan2(-ax, az) / (Math.PI / 5)
|
||||
@ -446,13 +458,17 @@ export function useLenticularStudioTilt(opts) {
|
||||
}
|
||||
try {
|
||||
uni.onAccelerometerChange(accelHandler)
|
||||
console.log('[DEBUG useLenticularStudioTilt] onAccelerometerChange 注册成功')
|
||||
const applyStart = (interval) => {
|
||||
console.log('[DEBUG useLenticularStudioTilt] 调用 startAccelerometer, interval:', interval)
|
||||
uni.startAccelerometer({
|
||||
interval,
|
||||
success: () => {
|
||||
console.log('[DEBUG useLenticularStudioTilt] startAccelerometer 成功')
|
||||
gyroSourceLabel.value = 'accelerometer'
|
||||
},
|
||||
fail: () => {
|
||||
fail: (err) => {
|
||||
console.log('[DEBUG useLenticularStudioTilt] startAccelerometer 失败:', JSON.stringify(err))
|
||||
if (interval === 'game') {
|
||||
applyStart('normal')
|
||||
return
|
||||
@ -463,11 +479,13 @@ export function useLenticularStudioTilt(opts) {
|
||||
}
|
||||
applyStart('game')
|
||||
} catch (e) {
|
||||
console.log('[DEBUG useLenticularStudioTilt] try onAccelerometerChange failed:', e)
|
||||
gyroSourceLabel.value = 'simulation'
|
||||
}
|
||||
}
|
||||
|
||||
function onNativeAngleFrame(x, y, z) {
|
||||
console.log('[DEBUG useLenticularStudioTilt] onNativeAngleFrame:', x, y, z)
|
||||
const vx = Number(x)
|
||||
const vy = Number(y)
|
||||
const vz = Number(z)
|
||||
@ -517,22 +535,27 @@ export function useLenticularStudioTilt(opts) {
|
||||
}
|
||||
|
||||
function startNativeInternal() {
|
||||
console.log('[DEBUG useLenticularStudioTilt] startNativeInternal called')
|
||||
stopNative()
|
||||
stopAccel()
|
||||
resetNativeBaseline()
|
||||
// #ifdef APP-PLUS
|
||||
gyroModule = tryRequireImengyuGyro()
|
||||
console.log('[DEBUG useLenticularStudioTilt] gyroModule:', gyroModule ? 'found' : 'not found')
|
||||
if (!gyroModule) {
|
||||
console.log('[DEBUG useLenticularStudioTilt] gyroModule not found, falling back to accel')
|
||||
mode = 'accel'
|
||||
startAccelInternal()
|
||||
return
|
||||
}
|
||||
mode = 'native'
|
||||
const myGen = tiltGen
|
||||
console.log('[DEBUG useLenticularStudioTilt] native gyro mode set, calling startNativeGyro')
|
||||
/** 与官方示例一致:normal / ui / game / fastest,game≈50Hz */
|
||||
const startOpts = { interval: 'game' }
|
||||
|
||||
scheduleNativeGyroStallFallback = () => {
|
||||
console.log('[DEBUG useLenticularStudioTilt] scheduleNativeGyroStallFallback called')
|
||||
if (nativeWatchdogTimer != null) {
|
||||
try {
|
||||
clearTimeout(nativeWatchdogTimer)
|
||||
@ -541,18 +564,9 @@ export function useLenticularStudioTilt(opts) {
|
||||
}
|
||||
nativeWatchdogTimer = null
|
||||
}
|
||||
nativeWatchdogTimer = setTimeout(() => {
|
||||
nativeWatchdogTimer = null
|
||||
if (myGen !== tiltGen) return
|
||||
if (mode !== 'native') return
|
||||
console.warn(
|
||||
'[useLenticularStudioTilt] native gyro stalled (no angle frames for ' +
|
||||
NATIVE_GYRO_STALL_FALLBACK_MS +
|
||||
'ms), falling back to accelerometer'
|
||||
)
|
||||
stopNative()
|
||||
startAccelInternal({ fromNativeFallback: true })
|
||||
}, NATIVE_GYRO_STALL_FALLBACK_MS)
|
||||
console.log('[DEBUG useLenticularStudioTilt] native gyro stalled, fallback to accelerometer')
|
||||
stopNative()
|
||||
startAccelInternal({ fromNativeFallback: true })
|
||||
}
|
||||
|
||||
function invokeStartNativeGyro() {
|
||||
@ -582,6 +596,7 @@ export function useLenticularStudioTilt(opts) {
|
||||
if (useSync) {
|
||||
const v = mod.getGyroValueSync()
|
||||
if (v && hasAnglePayload(v)) {
|
||||
console.log('[DEBUG useLenticularStudioTilt] getGyroValueSync:', JSON.stringify(v))
|
||||
onNativeAngleFrame(v.x, v.y, v.z)
|
||||
}
|
||||
return
|
||||
@ -589,6 +604,7 @@ export function useLenticularStudioTilt(opts) {
|
||||
mod.getGyroValue((v) => {
|
||||
if (myGen !== tiltGen || !gyroModule || !v) return
|
||||
if (hasAnglePayload(v)) {
|
||||
console.log('[DEBUG useLenticularStudioTilt] getGyroValue:', JSON.stringify(v))
|
||||
onNativeAngleFrame(v.x, v.y, v.z)
|
||||
}
|
||||
})
|
||||
@ -602,6 +618,7 @@ export function useLenticularStudioTilt(opts) {
|
||||
|
||||
let kickOnce = false
|
||||
const kick = () => {
|
||||
console.log('[DEBUG useLenticularStudioTilt] kick called, kickOnce:', kickOnce)
|
||||
if (kickOnce) return
|
||||
if (myGen !== tiltGen || !gyroModule) return
|
||||
kickOnce = true
|
||||
@ -617,10 +634,13 @@ export function useLenticularStudioTilt(opts) {
|
||||
const usePoll =
|
||||
typeof mod.startGyro === 'function' &&
|
||||
(typeof mod.getGyroValue === 'function' || typeof mod.getGyroValueSync === 'function')
|
||||
console.log('[DEBUG useLenticularStudioTilt] usePoll:', usePoll)
|
||||
|
||||
if (usePoll) {
|
||||
console.log('[DEBUG useLenticularStudioTilt] calling mod.startGyro')
|
||||
try {
|
||||
mod.startGyro(startOpts, (res) => {
|
||||
console.log('[DEBUG useLenticularStudioTilt] startGyro callback, res:', JSON.stringify(res))
|
||||
if (myGen !== tiltGen || !gyroModule) return
|
||||
/* 插件约定:首包只表示是否开启成功,不含持续角度;若回调无对象则无法进入官方要求的 getGyroValue 轮询 */
|
||||
if (!res) {
|
||||
@ -751,6 +771,7 @@ export function useLenticularStudioTilt(opts) {
|
||||
}
|
||||
|
||||
function start() {
|
||||
console.log('[DEBUG useLenticularStudioTilt] start called')
|
||||
// #ifdef APP-PLUS
|
||||
startNativeInternal()
|
||||
// #endif
|
||||
|
||||
@ -300,9 +300,9 @@
|
||||
"current": 0,
|
||||
"list": [
|
||||
{
|
||||
"name": "castlove-lenticular-create",
|
||||
"path": "pages/castlove/create",
|
||||
"query": "name=%E5%85%89%E6%A0%85%E5%8D%A1"
|
||||
"name": "",
|
||||
"path": "",
|
||||
"query": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -17,8 +17,6 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
<!-- 加载中 -->
|
||||
<view v-if="loading" class="loading-wrapper">
|
||||
<!-- 旋转光环 -->
|
||||
@ -1014,7 +1012,7 @@ onUnmounted(() => {
|
||||
width: 352rpx;
|
||||
height: 520rpx;
|
||||
margin-bottom: 32rpx;
|
||||
animation: card-3d-flip 15s ease-in-out infinite;
|
||||
/* animation: card-3d-flip 15s ease-in-out infinite; */
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
@ -1036,18 +1034,18 @@ onUnmounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.card-wrapper--lenticular {
|
||||
/* .card-wrapper--lenticular {
|
||||
width: 520rpx;
|
||||
height: 680rpx;
|
||||
}
|
||||
} */
|
||||
|
||||
.detail-lenticular-slot {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 78%;
|
||||
width: 88%;
|
||||
height: 96%;
|
||||
border-radius: 64rpx;
|
||||
border-radius: 48rpx;
|
||||
/* transform: translate(-50%, -50%) rotate(-10deg); */
|
||||
transform: translate(-50%, -50%) ;
|
||||
z-index: 2;
|
||||
|
||||
@ -10,9 +10,9 @@
|
||||
</view>
|
||||
<!-- <text class="nav-title">我的作品</text> -->
|
||||
<view class="nav-placeholder"></view>
|
||||
<!-- <view class="nav-settings" @tap="goToSettings">
|
||||
<view class="nav-settings" @tap="goToSettings">
|
||||
<image class="nav-settings-icon" src="/static/icon/settings.png" mode="aspectFit"></image>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="scroll-content">
|
||||
@ -31,7 +31,7 @@
|
||||
<LenticularCard v-if="exhibitionAtSlot[0].is_lenticular" class="card-lenticular"
|
||||
:layers="getLenticularLayers(exhibitionAtSlot[0].id)"
|
||||
:transforms="getLenticularTransforms(exhibitionAtSlot[0].id)" :gyro-source="gyroSourceLabel"
|
||||
:skip-built-in-touch="false" :shimmer-mid-opacity="0.16"
|
||||
:skip-built-in-touch="true" :shimmer-mid-opacity="0.16"
|
||||
@simulate="(x, y) => onLenticularSimulate(exhibitionAtSlot[0].id, x, y)" />
|
||||
<image v-else class="card-image"
|
||||
:src="exhibitionAtSlot[0].cover_url || '/static/nft/placeholder.png'" mode="aspectFill">
|
||||
@ -76,7 +76,7 @@
|
||||
<LenticularCard v-if="exhibitionAtSlot[1].is_lenticular" class="card-lenticular"
|
||||
:layers="getLenticularLayers(exhibitionAtSlot[1].id)"
|
||||
:transforms="getLenticularTransforms(exhibitionAtSlot[1].id)" :gyro-source="gyroSourceLabel"
|
||||
:skip-built-in-touch="false" :shimmer-mid-opacity="0.16"
|
||||
:skip-built-in-touch="true" :shimmer-mid-opacity="0.16"
|
||||
@simulate="(x, y) => onLenticularSimulate(exhibitionAtSlot[1].id, x, y)" />
|
||||
<image v-else class="card-image"
|
||||
:src="exhibitionAtSlot[1].cover_url || '/static/nft/placeholder.png'" mode="aspectFill">
|
||||
@ -154,7 +154,7 @@
|
||||
<LenticularCard v-if="item.is_lenticular" class="liked-lenticular"
|
||||
:layers="getLikedLenticularLayers(item.id)"
|
||||
:transforms="getLikedLenticularTransforms(item.id)" :gyro-source="gyroSourceLabel"
|
||||
:skip-built-in-touch="false" :shimmer-mid-opacity="0.16"
|
||||
:skip-built-in-touch="true" :shimmer-mid-opacity="0.16"
|
||||
@simulate="(x, y) => onLikedLenticularSimulate(item.id, x, y)" />
|
||||
<image v-else class="liked-cover" :src="item.cover_url || '/static/nft/placeholder.png'"
|
||||
mode="aspectFill"></image>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user