Saya pikir semacam solusi yang kuat akan pergi dengan cara berorientasi objek.
Bergantung pada pencapaian seperti apa yang ingin Anda dukung, Anda perlu cara untuk menanyakan keadaan saat ini dari permainan Anda dan / atau sejarah tindakan / peristiwa yang dibuat oleh objek permainan (seperti pemain).
Katakanlah Anda memiliki kelas Prestasi dasar seperti:
class AbstractAchievement
{
GameState& gameState;
virtual bool IsEarned() = 0;
virtual string GetName() = 0;
};
AbstractAchievement
memegang referensi ke kondisi permainan. Ini digunakan untuk menanyakan hal-hal yang sedang terjadi.
Kemudian Anda membuat implementasi konkret. Mari kita gunakan contoh Anda:
class MasterSlicerAchievement : public AbstractAchievement
{
string GetName() { return "Master Slicer"; }
bool IsEarned()
{
Action lastAction = gameState.GetPlayerActionHistory().GetAction(0);
Action previousAction = gameState.GetPlayerActionHistory().GetAction(1);
if (lastAction.GetType() == ActionType::Slice &&
previousAction.GetType() == ActionType::Slice &&
lastAction.GetObjectType() == ObjectType::Watermelon &&
previousAction.GetObjectType() == ObjectType::Strawberry)
return true;
return false;
}
};
class InvinciblePipeRiderAchievement : public AbstractAchievement
{
string GetName() { return "Invincible Pipe Rider"; }
bool IsEarned()
{
if (gameState.GetLocationType(gameState.GetPlayerPosition()) == LocationType::OVER_PIPE &&
gameState.GetPlayerState() == EntityState::INVINCIBLE)
return true;
return false;
}
};
Maka terserah Anda untuk memutuskan kapan harus memeriksa menggunakan IsEarned()
metode. Anda dapat memeriksa di setiap pembaruan game.
Cara yang lebih efisien adalah, misalnya, memiliki semacam manajer acara. Dan kemudian mendaftarkan peristiwa (seperti PlayerHasSlicedSomethingEvent
atau PlayerGotInvicibleEvent
atau hanya PlayerStateChanged
) ke metode yang akan mengambil pencapaian dalam parameter. Contoh:
class Game
{
void Initialize()
{
eventManager.RegisterAchievementCheckByActionType(ActionType::Slice, masterSlicerAchievement);
// Each time an action of type Slice happens,
// the CheckAchievement() method is invoked with masterSlicerAchievement as parameter.
eventManager.RegisterAchievementCheckByPlayerState(EntityState::INVINCIBLE, invinciblePiperAchievement);
// Each time the player gets the INVINCIBLE state,
// the CheckAchievement() method is invoked with invinciblePipeRiderAchievement as parameter.
}
void CheckAchievement(const AbstractAchievement& achievement)
{
if (!HasAchievement(player, achievement) && achievement.IsEarned())
{
AddAchievement(player, achievement);
}
}
};
if(...) return true; else return false;
sama denganreturn (...)
Singkatnya, pencapaian tidak terkunci ketika kondisi tertentu terpenuhi. Jadi, Anda harus bisa menghasilkan pernyataan jika memeriksa kondisi yang Anda inginkan.
Misalnya, jika Anda ingin tahu bahwa level telah selesai atau bos dikalahkan, Anda harus membuat bendera boolean menjadi kenyataan ketika peristiwa ini terjadi.
Kemudian:
Anda dapat menjadikan ini serumit atau sesederhana yang diperlukan untuk mencocokkan kondisi yang Anda inginkan.
Beberapa info tentang pencapaian Xbox 360 dapat ditemukan di sini .
sumber
Bagaimana jika Anda setiap tindakan pemain mengambil pesan ke pesan
AchievementManager
? Kemudian manajer dapat memeriksa secara internal apakah kondisi tertentu telah dipenuhi. Objek pertama memposting pesan:Dan kemudian
AchievementManager
cek jika perlu melakukan apa pun:Anda mungkin ingin melakukan ini dengan enumerasi alih-alih string. ;)
sumber
AchievementManager
dalam setiap kelas (yang mana OP bertanya bagaimana untuk menghindari di tempat pertama). Dan menggunakan enum atau kelas terpisah untuk pesan Anda, bukan string-literal - menggunakan string literal untuk menyampaikan keadaan selalu merupakan ide yang buruk.Desain terakhir yang saya gunakan didasarkan pada memiliki satu set counter persisten per-pengguna dan kemudian memiliki kunci prestasi dari counter tertentu yang memukul nilai tertentu. Sebagian besar adalah pasangan pencapaian / penghitung tunggal di mana penghitung hanya akan menjadi 0 atau 1 (dan pencapaian dipicu pada> = 1), tetapi Anda dapat menggunakan ini untuk "membunuh X dudes" atau "menemukan X peti" juga. Ini juga berarti Anda dapat mengatur penghitung untuk sesuatu yang tidak memiliki pencapaian, dan itu masih akan dilacak untuk penggunaan di masa mendatang.
sumber
Ketika saya menerapkan pencapaian dalam game terakhir saya, saya menjadikan semuanya berdasarkan statistik. Pencapaian tidak terkunci saat statistik kami mencapai nilai tertentu. Pertimbangkan Modern Warfare 2: game ini melacak banyak statistik! Berapa banyak pemotretan yang Anda ambil dengan SCAR-H? Berapa mil Anda berlari saat menggunakan mer Lightweight?
Jadi dalam implementasi saya, saya hanya menciptakan mesin statistik, kemudian menciptakan manajer prestasi yang menjalankan pertanyaan yang sangat sederhana untuk memeriksa status prestasi di seluruh gameplay.
Meskipun implementasi saya cukup sederhana, itu menyelesaikan pekerjaan. Saya menulis tentang hal itu dan membagikan pertanyaan saya di sini .
sumber
Gunakan Kalkulus Peristiwa . Kemudian buat beberapa prasyarat dan tindakan yang diterapkan setelah prasyarat terpenuhi:
Gunakan seperti (tidak dioptimalkan untuk kecepatan!):
Jika Anda ingin membuatnya cepat:
Catatan
Sulit untuk memberikan saran terbaik karena semua hal memiliki pro dan kontra.
sumber
Apa yang salah dengan cek IF setelah acara pencapaian terjadi?
sumber