Land Explorer in HomeCamp with boot loading, journal UI, and CDN publish tooling.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HotUpdate.Gameplay
|
||||
{
|
||||
/// <summary>
|
||||
/// 3D 营地主角探险家控制器:响应点击路面/建筑、平滑移动至目标位置并驱动待机与行走动画,支持到达事件与地面指示光圈。
|
||||
/// </summary>
|
||||
public sealed class CampExplorerController : MonoBehaviour
|
||||
{
|
||||
[Header("Movement Settings")]
|
||||
public float moveSpeed = 4.8f;
|
||||
public float turnSpeed = 720f;
|
||||
public float stopDistance = 0.35f;
|
||||
|
||||
[Header("Ground Boundaries")]
|
||||
public float minX = -10f;
|
||||
public float maxX = 10f;
|
||||
public float minZ = -14f;
|
||||
public float maxZ = 12f;
|
||||
|
||||
Animator _animator;
|
||||
Vector3 _targetPosition;
|
||||
bool _isMoving;
|
||||
int _animParamIsMoving;
|
||||
int _animParamSpeed;
|
||||
|
||||
Action _onArrival;
|
||||
Vector3? _targetFacing;
|
||||
GameObject _indicator;
|
||||
|
||||
public bool IsMoving => _isMoving;
|
||||
public Vector3 TargetPosition => _targetPosition;
|
||||
public Animator ExplorerAnimator => _animator;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
EnsureInit();
|
||||
EnsureIndicator();
|
||||
}
|
||||
|
||||
public void EnsureInit()
|
||||
{
|
||||
if (_animator == null) _animator = GetComponent<Animator>();
|
||||
if (_animParamIsMoving == 0) _animParamIsMoving = Animator.StringToHash("isMoving");
|
||||
if (_animParamSpeed == 0) _animParamSpeed = Animator.StringToHash("speed");
|
||||
}
|
||||
|
||||
public void EnsureIndicator()
|
||||
{
|
||||
if (_indicator != null) return;
|
||||
Transform parentTf = transform.parent != null ? transform.parent : transform;
|
||||
var existing = parentTf.Find("ClickIndicator");
|
||||
if (existing != null)
|
||||
{
|
||||
_indicator = existing.gameObject;
|
||||
return;
|
||||
}
|
||||
|
||||
_indicator = new GameObject("ClickIndicator");
|
||||
_indicator.transform.SetParent(parentTf, false);
|
||||
_indicator.layer = gameObject.layer;
|
||||
|
||||
var mf = _indicator.AddComponent<MeshFilter>();
|
||||
var mr = _indicator.AddComponent<MeshRenderer>();
|
||||
mf.sharedMesh = CreateRingMesh(0.85f, 1.25f, 32);
|
||||
|
||||
var smr = GetComponentInChildren<SkinnedMeshRenderer>();
|
||||
if (smr != null && smr.sharedMaterial != null)
|
||||
{
|
||||
mr.sharedMaterial = smr.sharedMaterial;
|
||||
}
|
||||
_indicator.SetActive(false);
|
||||
}
|
||||
|
||||
static Mesh CreateRingMesh(float innerRadius, float outerRadius, int segments)
|
||||
{
|
||||
var mesh = new Mesh { name = "RingMesh" };
|
||||
var verts = new Vector3[segments * 2];
|
||||
var uvs = new Vector2[segments * 2];
|
||||
var tris = new int[segments * 6];
|
||||
|
||||
float angleStep = 360f / segments * Mathf.Deg2Rad;
|
||||
for (int i = 0; i < segments; i++)
|
||||
{
|
||||
float a = i * angleStep;
|
||||
float cos = Mathf.Cos(a);
|
||||
float sin = Mathf.Sin(a);
|
||||
|
||||
verts[i * 2] = new Vector3(cos * innerRadius, 0.04f, sin * innerRadius);
|
||||
verts[i * 2 + 1] = new Vector3(cos * outerRadius, 0.04f, sin * outerRadius);
|
||||
|
||||
uvs[i * 2] = new Vector2((float)i / segments, 0);
|
||||
uvs[i * 2 + 1] = new Vector2((float)i / segments, 1);
|
||||
|
||||
int next = (i + 1) % segments;
|
||||
int baseIdx = i * 6;
|
||||
tris[baseIdx] = i * 2;
|
||||
tris[baseIdx + 1] = next * 2;
|
||||
tris[baseIdx + 2] = i * 2 + 1;
|
||||
|
||||
tris[baseIdx + 3] = next * 2;
|
||||
tris[baseIdx + 4] = next * 2 + 1;
|
||||
tris[baseIdx + 5] = i * 2 + 1;
|
||||
}
|
||||
|
||||
mesh.vertices = verts;
|
||||
mesh.uv = uvs;
|
||||
mesh.triangles = tris;
|
||||
mesh.RecalculateNormals();
|
||||
return mesh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指挥探险家移动到指定世界坐标(单参数重载,保持反射与旧接口兼容)。
|
||||
/// </summary>
|
||||
public void MoveTo(Vector3 worldPos) => MoveTo(worldPos, null, null);
|
||||
|
||||
/// <summary>
|
||||
/// 指挥探险家移动到指定世界坐标(自动对齐路面并做边界 Clamp)。
|
||||
/// 可选指定到达回调与到达时的最终朝向。
|
||||
/// </summary>
|
||||
public void MoveTo(Vector3 worldPos, Action onArrival, Vector3? targetFacing = null)
|
||||
{
|
||||
EnsureInit();
|
||||
EnsureIndicator();
|
||||
|
||||
float clampedX = Mathf.Clamp(worldPos.x, minX, maxX);
|
||||
float clampedZ = Mathf.Clamp(worldPos.z, minZ, maxZ);
|
||||
|
||||
// 避开中央喷泉碰撞体中心
|
||||
Vector2 fountainCenter = new Vector2(0f, 0.8f);
|
||||
Vector2 target2D = new Vector2(clampedX, clampedZ);
|
||||
if (Vector2.Distance(target2D, fountainCenter) < 2.3f)
|
||||
{
|
||||
Vector2 dir = (target2D - fountainCenter).normalized;
|
||||
if (dir.sqrMagnitude < 0.001f) dir = Vector2.down;
|
||||
target2D = fountainCenter + dir * 2.35f;
|
||||
clampedX = target2D.x;
|
||||
clampedZ = target2D.y;
|
||||
}
|
||||
|
||||
_targetPosition = new Vector3(clampedX, transform.position.y, clampedZ);
|
||||
_onArrival = onArrival;
|
||||
_targetFacing = targetFacing;
|
||||
_isMoving = true;
|
||||
|
||||
if (_animator != null)
|
||||
{
|
||||
_animator.SetBool(_animParamIsMoving, true);
|
||||
_animator.SetFloat(_animParamSpeed, 1.0f);
|
||||
}
|
||||
|
||||
if (_indicator != null)
|
||||
{
|
||||
_indicator.transform.position = _targetPosition;
|
||||
_indicator.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
EnsureInit();
|
||||
_isMoving = false;
|
||||
_targetPosition = transform.position;
|
||||
if (_animator != null)
|
||||
{
|
||||
_animator.SetBool(_animParamIsMoving, false);
|
||||
_animator.SetFloat(_animParamSpeed, 0f);
|
||||
}
|
||||
|
||||
if (_targetFacing.HasValue && _targetFacing.Value.sqrMagnitude > 0.001f)
|
||||
{
|
||||
transform.rotation = Quaternion.LookRotation(_targetFacing.Value.normalized, Vector3.up);
|
||||
}
|
||||
|
||||
if (_indicator != null)
|
||||
{
|
||||
_indicator.SetActive(false);
|
||||
}
|
||||
|
||||
var callback = _onArrival;
|
||||
_onArrival = null;
|
||||
_targetFacing = null;
|
||||
callback?.Invoke();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!_isMoving) return;
|
||||
|
||||
Vector3 toTarget = _targetPosition - transform.position;
|
||||
toTarget.y = 0;
|
||||
float dist = toTarget.magnitude;
|
||||
|
||||
if (dist <= stopDistance)
|
||||
{
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// 平滑转向目标
|
||||
if (toTarget.sqrMagnitude > 0.0001f)
|
||||
{
|
||||
Quaternion targetRot = Quaternion.LookRotation(toTarget.normalized, Vector3.up);
|
||||
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRot, turnSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
// 平滑移动前进
|
||||
float step = Mathf.Min(moveSpeed * Time.deltaTime, dist);
|
||||
transform.position += toTarget.normalized * step;
|
||||
|
||||
// 光圈轻微脉冲缩放
|
||||
if (_indicator != null && _indicator.activeSelf)
|
||||
{
|
||||
float pulse = 1.0f + 0.12f * Mathf.Sin(Time.time * 6.5f);
|
||||
_indicator.transform.localScale = new Vector3(pulse, 1.0f, pulse);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (_indicator != null)
|
||||
{
|
||||
Destroy(_indicator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56e097e35ae00204cb39f05183b5c317
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,153 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace HotUpdate.Gameplay
|
||||
{
|
||||
/// <summary>
|
||||
/// 营地伙伴闲逛控制器:在指定区域内随机漫步、呼吸待机,并在探险家靠近时好奇转身打招呼。
|
||||
/// </summary>
|
||||
public sealed class CampPetWanderer : MonoBehaviour
|
||||
{
|
||||
[Header("Wander Settings")]
|
||||
public Vector3 wanderCenter;
|
||||
public float wanderRadius = 2.8f;
|
||||
public float moveSpeed = 1.6f;
|
||||
public float turnSpeed = 480f;
|
||||
public float stopDistance = 0.35f;
|
||||
|
||||
[Header("Timing")]
|
||||
public float minIdleTime = 2.5f;
|
||||
public float maxIdleTime = 6.0f;
|
||||
|
||||
[Header("Social")]
|
||||
public float greetingDistance = 4.8f;
|
||||
|
||||
[Header("Model Facing Convention")]
|
||||
[Tooltip("既有伙伴动物模型正面为局部 -Z(2026-10-24 之前旧资产规范),开启后使正面朝向移动方向")]
|
||||
public bool modelFacesMinusZ = true;
|
||||
|
||||
Animator _animator;
|
||||
Transform _playerTransform;
|
||||
Vector3 _targetPosition;
|
||||
bool _isMoving;
|
||||
float _idleTimer;
|
||||
int _animParamMotion;
|
||||
|
||||
public bool IsMoving => _isMoving;
|
||||
public Vector3 TargetPosition => _targetPosition;
|
||||
public Animator PetAnimator => _animator;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
EnsureInit();
|
||||
}
|
||||
|
||||
public void EnsureInit()
|
||||
{
|
||||
if (_animator == null) _animator = GetComponentInChildren<Animator>();
|
||||
if (_animParamMotion == 0) _animParamMotion = Animator.StringToHash("Motion");
|
||||
if (wanderCenter == Vector3.zero) wanderCenter = transform.position;
|
||||
_targetPosition = transform.position;
|
||||
if (_idleTimer <= 0f) _idleTimer = Random.Range(minIdleTime * 0.5f, maxIdleTime);
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
var explorer = GameObject.Find("Explorer");
|
||||
if (explorer != null) _playerTransform = explorer.transform;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指挥伙伴移动到指定目标点。
|
||||
/// </summary>
|
||||
public void MoveTo(Vector3 target)
|
||||
{
|
||||
EnsureInit();
|
||||
_targetPosition = target;
|
||||
_isMoving = true;
|
||||
if (_animator != null) _animator.SetInteger(_animParamMotion, 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停步并进入待机状态。
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
EnsureInit();
|
||||
_isMoving = false;
|
||||
_targetPosition = transform.position;
|
||||
_idleTimer = Random.Range(minIdleTime, maxIdleTime);
|
||||
if (_animator != null) _animator.SetInteger(_animParamMotion, 0);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
float dt = Time.deltaTime;
|
||||
|
||||
// 探险家靠近时好奇注视
|
||||
if (_playerTransform != null)
|
||||
{
|
||||
Vector3 toPlayer = _playerTransform.position - transform.position;
|
||||
toPlayer.y = 0;
|
||||
if (toPlayer.sqrMagnitude < greetingDistance * greetingDistance)
|
||||
{
|
||||
if (_isMoving) Stop();
|
||||
if (toPlayer.sqrMagnitude > 0.001f)
|
||||
{
|
||||
Vector3 lookDir = modelFacesMinusZ ? -toPlayer.normalized : toPlayer.normalized;
|
||||
Quaternion facePlayer = Quaternion.LookRotation(lookDir, Vector3.up);
|
||||
transform.rotation = Quaternion.RotateTowards(transform.rotation, facePlayer, turnSpeed * dt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_isMoving)
|
||||
{
|
||||
Vector3 toTarget = _targetPosition - transform.position;
|
||||
toTarget.y = 0;
|
||||
float dist = toTarget.magnitude;
|
||||
|
||||
if (dist <= stopDistance)
|
||||
{
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// 平滑转向并前进(结合模型正向规范)
|
||||
if (toTarget.sqrMagnitude > 0.0001f)
|
||||
{
|
||||
Vector3 lookDir = modelFacesMinusZ ? -toTarget.normalized : toTarget.normalized;
|
||||
Quaternion rot = Quaternion.LookRotation(lookDir, Vector3.up);
|
||||
transform.rotation = Quaternion.RotateTowards(transform.rotation, rot, turnSpeed * dt);
|
||||
}
|
||||
|
||||
float step = Mathf.Min(moveSpeed * dt, dist);
|
||||
transform.position += toTarget.normalized * step;
|
||||
}
|
||||
else
|
||||
{
|
||||
_idleTimer -= dt;
|
||||
if (_idleTimer <= 0f)
|
||||
{
|
||||
PickNextDestination();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PickNextDestination()
|
||||
{
|
||||
Vector2 rand2D = Random.insideUnitCircle * wanderRadius;
|
||||
Vector3 dest = wanderCenter + new Vector3(rand2D.x, 0, rand2D.y);
|
||||
|
||||
// 避开喷泉中心
|
||||
Vector2 fountainCenter = new Vector2(0f, 0.8f);
|
||||
if (Vector2.Distance(new Vector2(dest.x, dest.z), fountainCenter) < 2.3f)
|
||||
{
|
||||
_idleTimer = 1.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
MoveTo(dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b7c725436994f74686b18726434446f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,18 +6,25 @@ namespace HotUpdate.Gameplay
|
||||
public sealed class ExplorerLocomotion : MonoBehaviour
|
||||
{
|
||||
Animator _animator;
|
||||
bool _hasMotion;
|
||||
Vector3 _last;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
_animator = GetComponentInChildren<Animator>();
|
||||
if (_animator != null) _animator.applyRootMotion = false;
|
||||
if (_animator != null)
|
||||
{
|
||||
_animator.applyRootMotion = false;
|
||||
foreach (var parameter in _animator.parameters)
|
||||
if (parameter.name == "Motion" && parameter.type == AnimatorControllerParameterType.Int)
|
||||
_hasMotion = true;
|
||||
}
|
||||
_last = transform.position;
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (_animator == null) return;
|
||||
if (_animator == null || !_hasMotion) return;
|
||||
Vector3 delta = transform.position - _last;
|
||||
_last = transform.position;
|
||||
float speed = new Vector2(delta.x, delta.z).magnitude / Mathf.Max(Time.deltaTime, 0.0001f);
|
||||
|
||||
@@ -59,6 +59,16 @@ namespace HotUpdate.Gameplay
|
||||
_hud.OnReconnectClicked += () => _net?.RequestReconnect();
|
||||
_hud.OnHomeActionClicked += ShowHomeFeature;
|
||||
}
|
||||
// Reveal the HUD after its camp is ready, avoiding a brief illustrated fallback.
|
||||
var camp = hudGo.GetComponentInChildren<HomeCampPresenter>(true);
|
||||
float campDeadline = Time.realtimeSinceStartup + 90f;
|
||||
while (camp != null && camp.Loading && Time.realtimeSinceStartup < campDeadline)
|
||||
yield return null;
|
||||
if (camp != null && camp.Loading)
|
||||
{
|
||||
if (_ctx != null) _ctx.MainUiError = "营地加载超时,请重新进入游戏";
|
||||
yield break;
|
||||
}
|
||||
if (_ctx != null) _ctx.MainUiReady = true;
|
||||
Debug.Log("[UI] Main HUD ready");
|
||||
|
||||
@@ -143,7 +153,9 @@ namespace HotUpdate.Gameplay
|
||||
case "Rank": title = "冒险排行"; break;
|
||||
case "Friends": title = "好友"; break;
|
||||
case "Mail": title = "小镇邮件"; break;
|
||||
case "Rewards": title = "宝箱奖励"; break;
|
||||
case "Fountain": case "Rewards": title = "宝箱奖励"; break;
|
||||
case "MainHouse": case "Camp": title = "营地大厅"; break;
|
||||
case "Stall": title = "集市货摊"; break;
|
||||
case "Bag": title = "背包"; break;
|
||||
case "Adventure": case "Battle": title = "开始冒险"; break;
|
||||
case "Shop": title = "小镇商店"; break;
|
||||
|
||||
@@ -691,7 +691,7 @@ namespace HotUpdate.Gameplay
|
||||
var mails = _game.State.mails ?? new PrototypeMail[0];
|
||||
int pages = Math.Max(1, (mails.Length + 4) / 5);
|
||||
_mailPage = Mathf.Clamp(_mailPage, 0, pages - 1);
|
||||
_page.Text("MailWallet", "金币 " + _game.State.coins + " 糖果 " + _game.State.candy + " 弹珠 " + _game.State.balls + " 券 " + _game.State.tickets);
|
||||
_page.Text("MailWallet", mails.Length + " 封来信 · " + mails.Count(m => m.CanClaim(ServerNow)) + " 份待领附件");
|
||||
_page.Text("MailPage", (_mailPage + 1) + " / " + pages + " 页 共 " + mails.Length + " 封");
|
||||
_page.Node("Txt_MailEmpty").gameObject.SetActive(mails.Length == 0);
|
||||
for (int row = 0; row < 5; row++)
|
||||
@@ -700,8 +700,11 @@ namespace HotUpdate.Gameplay
|
||||
_page.Button("Mail" + row).gameObject.SetActive(exists);
|
||||
if (!exists) continue;
|
||||
var m = mails[index];
|
||||
_page.Text("MailTitle" + row, (_mailSelected == m.mailId ? "▶ " : "") + m.title);
|
||||
_page.Text("MailTitle" + row, (_mailSelected == m.mailId ? "• " : "") + m.title);
|
||||
_page.Text("MailStatus" + row, (m.read ? "已读" : "未读") + " · " + MailStatus(m));
|
||||
_page.Node("MailUnread" + row).gameObject.SetActive(!m.read);
|
||||
_page.Button("Mail" + row).GetComponent<Image>().color = _mailSelected == m.mailId
|
||||
? new Color(.79f, .92f, 1f) : Color.white;
|
||||
_page.Button("Mail" + row).interactable = !Blocked;
|
||||
}
|
||||
_page.Button("MailPrev").interactable = !Blocked && _mailPage > 0;
|
||||
@@ -716,6 +719,12 @@ namespace HotUpdate.Gameplay
|
||||
int available = mails.Count(m => m.CanClaim(ServerNow));
|
||||
_page.Text("ClaimAllMail", available == 0 ? "暂无可领取附件" : "一键领取 · " + Math.Min(20, available) + " 封");
|
||||
_page.Button("ClaimAllMail").interactable = !Blocked && available > 0;
|
||||
// Authored vertical layout collapses absent rows; a short inbox does
|
||||
// not leave blank placeholder space above the selected letter.
|
||||
var stack = (RectTransform)_page.Node("MailStack");
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(stack);
|
||||
((RectTransform)_page.Node("Content_Page")).SetSizeWithCurrentAnchors(
|
||||
RectTransform.Axis.Vertical, -stack.anchoredPosition.y + stack.rect.height + 36);
|
||||
}
|
||||
void ShowMailReward(PrototypeReply reply)
|
||||
{
|
||||
@@ -885,30 +894,60 @@ namespace HotUpdate.Gameplay
|
||||
void RefreshTasks()
|
||||
{
|
||||
var s = _game.State; long seconds = Math.Max(0, _reply.daily.resetAt - _serverUnix - (long)(Time.realtimeSinceStartupAsDouble - _receivedAt));
|
||||
_page.Text("TaskSummary", "每日目标 · 已领取 " + s.dailyClaimed.Sum() + " / 3\n" + (seconds == 0 ? "正在确认新一天的进度…" : "距重置 " + seconds / 3600 + "小时" + seconds % 3600 / 60 + "分 · UTC+8"));
|
||||
_page.Text("GoalInfo", "首次通过1-1 · 弹珠 " + _config.economy.goalBalls + "\n" + (s.goalClaimed ? "奖励已领取" : s.cleared ? "目标已完成,可以领取" : "发射弹珠、培养伙伴并守住营地"));
|
||||
_page.Text("ClaimGoal", s.goalClaimed ? "已领取" : s.cleared ? "领取奖励" : "未完成");
|
||||
_page.Button("ClaimGoal").interactable = !Blocked && s.cleared && !s.goalClaimed;
|
||||
_page.Button("GoGoal").interactable = !Blocked && !s.goalClaimed;
|
||||
int claimedCount = s.dailyClaimed.Sum();
|
||||
_page.Text("TaskSummary", claimedCount + " / 3 份奖励已领取");
|
||||
_page.Text("TaskReset", seconds == 0 ? "正在更新今日委托…" : "距更新 " + seconds / 3600 + "小时" + seconds % 3600 / 60 + "分 · 每日零点");
|
||||
_page.Text("GoalInfo", s.goalClaimed ? "首次通关 1-1\n营地初守已完成" : "首次通关 1-1\n成长奖励永久保留");
|
||||
_page.Text("GoalReward", "弹珠 ×" + _config.economy.goalBalls);
|
||||
SetTaskAction("ClaimGoal", "GoGoal", "Txt_GoalDone", s.goalClaimed, s.cleared, true);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
var task = _config.daily.tasks[i]; bool claimed = s.dailyClaimed[i] == 1, ready = s.dailyProgress[i] >= task.target;
|
||||
_page.Text("DailyName" + i, task.title);
|
||||
_page.Text("DailyInfo" + i, "进度 " + s.dailyProgress[i] + " / " + task.target + " · " + DailyRewardText(task.reward) + "\n" + (i == 2 ? !CampUnlocked(_config.camp.restUnlockStage) ? "通过1-3开放伙伴休息区" : "在营地与已拥有伙伴打招呼" : i == 1 ? "正常结束计数 · 主动离开不计入" : "弹珠落入奖励区并结算后计入"));
|
||||
_page.Text("ClaimDaily" + i, claimed ? "已领取" : ready ? "领取奖励" : "未完成");
|
||||
_page.Button("ClaimDaily" + i).interactable = !Blocked && !claimed && ready && seconds > 0;
|
||||
_page.Button("GoDaily" + i).interactable = !Blocked && !claimed;
|
||||
_page.Text("DailyInfo" + i, claimed ? "今日奖励已放入背包" : ready ? "委托完成,收下这份奖励吧" :
|
||||
i == 2 ? !CampUnlocked(_config.camp.restUnlockStage) ? "通关 1-3 后开放伙伴互动" : "在营地与伙伴打个招呼" :
|
||||
i == 1 ? "完成结算,主动离开不计入" : "弹珠落入奖励区并完成结算");
|
||||
_page.Text("DailyReward" + i, DailyRewardText(task.reward));
|
||||
_page.Text("DailyCount" + i, Math.Min(s.dailyProgress[i], task.target) + " / " + task.target);
|
||||
_page.Text("GoDaily" + i, i == 0 ? "去发射" : i == 1 ? "去冒险" : CampUnlocked(_config.camp.restUnlockStage) ? "去互动" : "去解锁");
|
||||
SetTaskAction("ClaimDaily" + i, "GoDaily" + i, "Txt_DailyDone" + i, claimed, ready, seconds > 0);
|
||||
SetTaskProgress("DailyProgress" + i, task.target > 0 ? (float)s.dailyProgress[i] / task.target : 0);
|
||||
_page.Node("DailyMilestone" + i).GetComponent<Image>().color = i < claimedCount
|
||||
? Color.white : new Color(.55f, .64f, .69f, .5f);
|
||||
_page.Node("TaskCard" + (i + 1)).GetComponent<Image>().color = claimed ? new Color(.89f, .93f, .92f) : Color.white;
|
||||
}
|
||||
}
|
||||
void SetTaskAction(string claim, string go, string done, bool claimed, bool ready, bool current)
|
||||
{
|
||||
var claimButton = _page.Button(claim); var goButton = _page.Button(go);
|
||||
claimButton.gameObject.SetActive(!claimed && ready);
|
||||
claimButton.interactable = !Blocked && current && ready && !claimed;
|
||||
goButton.gameObject.SetActive(!claimed && !ready);
|
||||
goButton.interactable = !Blocked && current && !claimed && !ready;
|
||||
_page.Node(done).gameObject.SetActive(claimed);
|
||||
}
|
||||
void SetTaskProgress(string name, float value)
|
||||
{
|
||||
var fill = (RectTransform)_page.Node(name + "Fill");
|
||||
var track = (RectTransform)_page.Node(name + "Track");
|
||||
float progress = Mathf.Clamp01(value);
|
||||
fill.gameObject.SetActive(progress > 0);
|
||||
fill.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, track.rect.width * progress);
|
||||
}
|
||||
void RefreshSignin()
|
||||
{
|
||||
var s = _game.State;
|
||||
_page.Text("SigninSummary", "累计登录 " + s.signinDays + " / 7 天 · 已领取 " + s.signinClaimed.Sum() + " / 7\n漏登不重置 · 每天首次进入计一次");
|
||||
_page.Text("SigninSummary", "已相伴 " + s.signinDays + " 天 · 收获 " + s.signinClaimed.Sum() + " / 7");
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
bool unlocked = i < s.signinDays, claimed = s.signinClaimed[i] == 1;
|
||||
_page.Text("SigninReward" + i, DailyRewardText(_config.daily.signin[i]));
|
||||
_page.Text("Signin" + i, claimed ? "已领取" : unlocked ? "领取奖励" : "未解锁");
|
||||
_page.Text("Signin" + i, "领取");
|
||||
_page.Button("Signin" + i).gameObject.SetActive(unlocked && !claimed);
|
||||
_page.Node("Txt_SigninState" + i).gameObject.SetActive(!unlocked || claimed);
|
||||
_page.Text("SigninState" + i, claimed ? "已领取" : "第 " + (i + 1) + " 天解锁");
|
||||
_page.Node("SigninCard" + i).GetComponent<Image>().color = claimed
|
||||
? new Color(.86f, .91f, .90f) : i == 6 ? new Color(1, .94f, .8f) : Color.white;
|
||||
_page.Button("Signin" + i).interactable = !Blocked && unlocked && !claimed;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user