Saat ini saya sedang membuat proyek hobi kecil untuk kembali ke pengembangan game, dan saya telah memutuskan untuk membuat struktur entitas saya menggunakan ECS (Entity Component System). Implementasi ECS ini disusun seperti:
- Entitas : Dalam kasus saya ini adalah
int
pengidentifikasi unik yang digunakan sebagai kunci untuk daftar komponen. - Komponen : Memegang hanya data, mis.
Position
Komponen menampungx
dany
mengoordinasikan, danMovement
komponen menyimpanspeed
dandirection
variabel. - Sistem : Menangani komponen, misalnya dibutuhkan
Position
danMovement
komponen dan menambahkanspeed
dandirection
ke posisi inix
dany
koordinat.
Ini berfungsi dengan baik, tapi sekarang saya ingin menerapkan skrip ke dalam permainan saya, dalam bentuk bahasa scripting. Dalam proyek-proyek sebelumnya saya telah menggunakan implementasi OOP objek game, yang berarti bahwa scripting cukup lurus ke depan. Misalnya, skrip sederhana dapat terlihat seperti ini:
function start()
local future = entity:moveTo(pos1)
wait(future)
local response = entity:showDialog(dialog1)
if wait(response) == 1 then
local itemStack = entity:getInventory():removeItemByName("apple", 1)
world:getPlayer():getInventory():addItemStack(itemStack)
else
entity:setBehavior(world:getPlayer(), BEHAVIOR_HOSTILE)
end
end
Namun, ketika menggunakan ECS, entitas itu sendiri tidak memiliki fungsi seperti moveTo
atau getInventory
, sebaliknya skrip di atas yang ditulis dengan gaya ECS akan terlihat seperti ini:
function start()
local movement = world:getComponent(MOVEMENT, entity)
movement:moveTo(pos1)
local position = world:getComponent(POSITION, entity)
local future = Future:untilEquals(position.pos, pos1)
wait(future)
local dialogComp = world:getComponent(DIALOG, entity)
local response = dialogComp:showDialog(dialog1)
if wait(response) == 1 then
local entityInventory = world:getComponent(INVENTORY, entity)
local playerInventory = world:getComponent(INVENTORY, world:getPlayer())
local itemStack = entityInventory:removeItemByName("apple", 1)
playerInventory:addItemStack(itemStack)
else
local entityBehavior = world:getComponent(BEHAVIOR, entity)
local playerBehavior = world:getComponent(BEHAVIOR, world:getPlayer())
entityBehavior:set(playerBehavior, BEHAVIOR_HOSTILE)
end
end
Ini jauh lebih banyak verbose dibandingkan dengan versi OOP, yang tidak diinginkan ketika skrip ditujukan untuk sebagian besar non-programmer (pemain game).
Salah satu solusinya adalah memiliki semacam objek pembungkus yang merangkum Entity
dan memasok fungsi-fungsi seperti moveTo
secara langsung, dan menangani sisanya secara internal, meskipun solusi semacam itu tampaknya kurang optimal karena butuh banyak pekerjaan untuk mencakup semua komponen, dan setiap saat komponen baru ditambahkan, Anda perlu mengubah objek pembungkus dengan fungsi baru.
Untuk semua pengembang game yang telah mengimplementasikan skrip di ECS sebelumnya - bagaimana Anda melakukannya? Fokus utama di sini adalah kegunaan untuk pengguna akhir, dengan biaya "pemeliharaan" sesedikit mungkin (sebaiknya Anda tidak perlu mengubahnya setiap kali Anda menambahkan komponen).
moveTo
metode ini sebagai bagian dari sistem yang mendasari dalam kasus penggunaan Anda, misalnya MovementSystem? Dengan cara ini Anda tidak hanya dapat menggunakannya dalam skrip yang Anda tulis, tetapi Anda juga dapat menggunakannya sebagai bagian dari kode C ++ di mana pun Anda membutuhkannya. Jadi ya Anda harus memaparkan metode baru ketika sistem baru ditambahkan, tapi itu diharapkan sebagai perilaku yang sama sekali baru yang diperkenalkan sistem ini.
System
kelas / s untuk memungkinkan komponen tetap struct data.