Hướng dẫn: chơi một nhiệm vụ từ đầu đến cuối
Trong hướng dẫn này bạn theo một nhiệm vụ qua ba scene: trang Campaign bắt đầu nhiệm vụ, scene gameplay chơi nó và gửi kết quả, và Lobby hiện những gì đã thay đổi. Bạn sẽ dùng năm thứ:
IProjectVCampaignScreen: thứ trang Campaign giao tiếp;ProjectVCampaignMission: một nhiệm vụ trong danh sách;IProjectVGameplayDataConsumer: thứ scene gameplay implement;IProjectVGameplayDataPolicy: lượt chơi, kèm các helper dựng kết quả;ProjectVGameplayDataResult: thứ việc kết thúc lượt chơi trả về.
Trước khi bắt đầu: hoàn thành hướng dẫn trước,
Lên cấp cho nhân vật. Bạn cần một scene
Campaign có scope kế thừa từ ProjectVAuthenticatedSceneScope
(Tích hợp scene),
và một scene gameplay trong build settings.
1. Đăng ký trang Campaign
Trang Campaign là một MonoBehaviour trong scene Campaign. Đăng ký nó trong
scene scope, giống như với Shop:
public sealed class CampaignSceneScope : ProjectVAuthenticatedSceneScope
{
protected override void ConfigureAuthenticated(IContainerBuilder builder)
{
builder.RegisterComponentInHierarchy<CampaignPage>();
}
}
2. Liệt kê các nhiệm vụ
Inject IProjectVCampaignScreen, theo dõi nó trong OnEnable và dispose
(giải phóng) observation trong OnDisable. Mỗi nhiệm vụ hiện số sao, stamina
(thể lực) để vào và lý do bị khoá. Đọc trạng thái khoá từ view; đừng bao giờ
tự suy ra từ tiến trình ở máy.
private static string LockReason(ProjectVCampaignMission mission)
{
if (mission.IsClosed)
{
return "Not open yet";
}
if (mission.Stars.IsLocked)
{
return $"Needs {mission.Stars.RequiresTotalStars} stars";
}
return mission.IsLocked ? "Complete the previous mission" : string.Empty;
}
Hiện sao dạng Stars.BestStars / Stars.MaxStars; MaxStars là 0 với
nhiệm vụ không có sao. MissionId.Value chỉ là một ID: ánh xạ nó sang tên và
art của riêng bạn.
3. Bắt đầu một nhiệm vụ
Gọi BeginMissionAsync(missionId). Khi thành công, ánh xạ GameplayKey.Value
sang một scene bằng bảng của riêng bạn và load scene đó. Lúc này stamina để
vào chỉ được kiểm tra; nó bị trừ khi lượt chơi kết thúc.
if (starting)
{
return;
}
starting = true;
var result = await campaign.BeginMissionAsync(mission.MissionId.Value);
if (this == null)
{
return;
}
Giữ cờ starting. Bấm lần hai vào cùng nhiệm vụ nhận kết quả của lần bấm đầu,
còn bấm vào nhiệm vụ khác sẽ thất bại với "Another mission is starting."; không
có cờ, trang có thể load một scene hai lần hoặc hiện lỗi đó. Nếu bảng của bạn không có scene
cho nhiệm vụ đó, gọi CancelSceneLoadAsync(): lượt chơi được giải phóng và
không tốn stamina. Làm tương tự nếu scene loader của riêng bạn thất bại.
4. Gắn lượt chơi trong scene gameplay
Scene gameplay không cần scope. Thêm một component MissionBinding implement
IProjectVGameplayDataConsumer. Khi scene load, SDK tìm thấy nó và gọi
BindGameplayData trên Unity main thread. Giữ đúng một component như vậy
trong scene, tính cả các object đang inactive; nếu không có hoặc có hai, không
có gì được gắn.
public void BindGameplayData(IProjectVGameplayDataPresenter presenter, ProjectVGameplayStartingDataView startingData)
{
// If Bind throws, the SDK cancels the run; it costs no stamina.
run = presenter as IProjectVGameplayDataPolicy
?? throw new InvalidOperationException("The run has no gameplay data policy.");
data = startingData;
SpawnCharacter(startingData);
foreach (var drop in startingData.Drops)
{
Instantiate(enemyPrefab, enemyRoot).Activate(this, drop.SlotId);
}
}
Spawn ActiveCharacterId, không phải nhân vật được chọn ở máy, và áp dụng
Stats thay cho giá trị trong asset của bạn. UnbindGameplayData được gọi
khi lượt chơi kết thúc hoặc scene unload; xoá các tham chiếu của bạn ở đó, vì
từ lúc đó mọi lần gọi trên presenter đều thất bại.
Một scene thật còn kiểm tra các asset kỹ năng trước khi bắt đầu chơi; xem Kiểm tra asset kỹ năng.
5. Theo dõi kẻ địch có phần thưởng
Mỗi phần tử trong Drops là một kẻ địch có phần thưởng, với một SlotId.
Đăng ký kẻ địch khi nó active, ghi nhận khi nó chết, và huỷ đăng ký khi nó bị
deactivate. Lease (ở đây là spawnCount) phải thay đổi ở mỗi lần activate,
để một kẻ địch dùng lại từ pool không bao giờ bị nhầm với lần sống trước của
nó.
public void OnRewardEnemyActivated(RewardEnemy enemy, string slotId, long spawnCount)
{
if (run == null)
{
return;
}
var result = run.RegisterDropOwner(enemy, slotId, spawnCount, out var registration);
if (result.IsSuccess)
{
drops[enemy] = registration;
}
}
RecordDropDefeated(registration) ghi nhận cái chết, và
UnregisterDropOwner(registration) không huỷ ghi nhận đó. Bạn không bao giờ
tự quyết định người chơi nhận được vật rơi nào; SDK và server làm việc đó dựa
trên những gì bạn báo.
6. Ghi nhận lượt dùng kỹ năng
Mỗi lần người chơi dùng một kỹ năng, báo SkillId của slot tương ứng trong
CastSkills:
foreach (var cast in data.CastSkills)
{
if (cast.Slot == slot)
{
run.RecordSkillActivated(cast.SkillId, slot);
}
}
7. Kết thúc lượt chơi
Khi người chơi thắng hoặc thua, gọi ObserveOutcome(outcome, kills) với số
kẻ địch bị hạ từ 0 đến 1024. Nó khoá lượt chơi: từ lúc đó, lượt dùng kỹ năng
và Restart đều bị từ chối. Sau đó gọi CompleteObservedAsync(health, armor, experience, token) và chỉ hiện những gì nó trả về.
var result = await current.CompleteObservedAsync(health, armor, experience, CancellationToken.None);
if (this == null)
{
return;
}
if (!result.IsSuccess)
{
ShowResult(result.SafeMessage, canRetry: true, canLeave: false);
return;
}
ShowResult(Describe(result), canRetry: false, canLeave: true);
Khi thành công, hiện Rewards, nhắc tới MailedRewards (những phần thưởng
không vừa và đã được gửi vào hộp thư) và hiện Stars, giá trị này là null khi
thua. Khi thất bại, giữ màn kết quả mở với nút thử lại (Retry), và Retry thực
hiện đúng lần gọi đó. Lần gọi đầu tiên đã chốt kết quả; một lần thử lại gửi
lại kết quả đó và bỏ qua giá trị mới.