Oyun Karakter Sistemi
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 107 / 107.
Görev
KolayEsnek dövüş mekanikleri oluşturmak için struct gömme (embedding), arayüzler (interfaces) ve Strateji (Strategy) desenini bir araya getiren bir Oyun Karakter Sistemi inşa edelim! Çalışma zamanında değiştirilebilen yeteneklerle, benzersiz şekillerde saldırabilen ve savunma yapabilen farklı karakter türleri tasarlayacaksınız.
Kodunuzu beş dosya halinde düzenleyeceksiniz:
character.go: Ortak alanlara sahip bir temelCharacterstruct'ı tanımlayın:Name(string),Health(int) veMaxHealth(int). BirNewCharacteryapıcı fonksiyonu (constructor) ve şu metotları ekleyin:IsAlive() bool— sağlık 0'dan büyükse true dönerStatus() string— şu formatı döner:[Name]: [Health]/[MaxHealth] HP
interfaces.go: Polimorfizmi (çok biçimlilik) sağlayan dövüş arayüzlerini tanımlayın:Attack() intmetoduna sahipAttackerarayüzü — verilen hasarı dönerTakeDamage(damage int) intmetoduna sahipDefenderarayüzü — hasar azaltmayı uygular ve alınan gerçek hasarı dönerUse() stringmetoduna sahipAbilityarayüzü — yetenek etkisinin bir açıklamasını döner
characters.go:Characterstruct'ını gömen ve hemAttackerhem deDefenderarayüzlerini uygulayan üç karakter türü oluşturun:Warrior—Strength(int) veArmor(int) alanlarına sahiptir. Attack, Strength değerini hasar olarak döner. TakeDamage, gelen hasarı Armor kadar azaltır (en az 1 hasar alınır).Mage—Intelligence(int) veMagicResist(int) alanlarına sahiptir. Attack, Intelligence * 2 değerini hasar olarak döner. TakeDamage, gelen hasarı MagicResist / 2 kadar azaltır (en az 1 hasar alınır).Archer—Agility(int) veEvasion(int) alanlarına sahiptir. Attack, Agility + 5 değerini hasar olarak döner. TakeDamage: Eğer Evasion > 10 ise, hasarı %25 oranında azaltır (tamsayı bölmesi), aksi takdirde tam hasar alır (en az 1 hasar alınır).Her biri için isim, sağlık ve özel istatistik değerlerini alan yapıcılar ekleyin:
NewWarrior,NewMage,NewArcher.abilities.go: Değiştirilebilir yeteneklerle Strateji desenini uygulayın:Power(int) alanına sahipFireSpellstruct'ı.Use()metodu şunu döner:Casts fireball for [Power] damagePower(int) alanına sahipIceSpellstruct'ı.Use()metodu şunu döner:Casts ice shard for [Power] damageMultiplier(int) alanına sahipPowerStrikestruct'ı.Use()metodu şunu döner:Performs power strike at [Multiplier]x damageMage struct'ına
Abilitytüründe birabilityalanı ekleyin;SetAbility(a Ability)veUseAbility() stringmetotlarını tanımlayın. Eğer yetenek nil ise UseAbilityNo ability setdöner.main.go: Karakterleri oluşturun ve dövüş mekaniklerini gösterin.Karakter türünü (
warrior,mageveyaarcher) okuyun, ardından karakterin adını, sağlığını ve türe özgü istatistiklerini okuyun. Uygun karakteri oluşturun.Ardından eylem sayısını okuyun. Her eylem şunlardan biridir:
status— karakterin durumunu yazdırınattack—[Name] attacks for [damage] damageyazdırındefend [amount]— hasarı uygulayın ve[Name] takes [actual] damageyazdırınsetability [type] [power]— sadece büyücüler (mage) için, yeteneği ayarlayın (tür:fire,iceveyastrike)useability— sadece büyücüler (mage) için, yeteneğin Use() sonucunu yazdırın
Aşağıdaki girdiler sağlanacaktır:
- Karakter türü, adı, sağlığı ve türe özgü istatistikler
- Eylem sayısı ve ardından her bir eylem ayrı bir satırda
Örneğin, şu girdi verildiğinde:
warrior
Thorin
100
15
8
5
status
attack
defend 20
status
defend 100Çıktınız şu olmalıdır:
Thorin: 100/100 HP
Thorin attacks for 15 damage
Thorin takes 12 damage
Thorin: 88/100 HP
Thorin takes 92 damageVe şu girdi verildiğinde:
mage
Gandalf
80
25
10
6
attack
useability
setability fire 30
useability
setability ice 25
useability
defend 40Çıktınız şu olmalıdır:
Gandalf attacks for 50 damage
No ability set
Casts fireball for 30 damage
Casts ice shard for 25 damage
Gandalf takes 35 damageVe şu girdi verildiğinde:
archer
Legolas
90
18
15
4
status
attack
defend 24
statusÇıktınız şu olmalıdır:
Legolas: 90/90 HP
Legolas attacks for 23 damage
Legolas takes 18 damage
Legolas: 72/90 HPStruct gömmenin her karakter türünün temel Character alanlarını ve metotlarını paylaşmasına nasıl izin verdiğine, arayüzlerin ise herhangi bir Attacker'ın hasar verebildiği ve herhangi bir Defender'ın hasar alabildiği polimorfik dövüşü nasıl mümkün kıldığına dikkat edin. Strateji deseni, Mage'in değiştirilebilir yetenekleriyle parlıyor; aynı karakter, temel uygulamasını değiştirmeden farklı büyüler kullanabiliyor!
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Karakter türünü oku
scanner.Scan()
charType := strings.TrimSpace(scanner.Text())
// Karakter adını oku
scanner.Scan()
name := strings.TrimSpace(scanner.Text())
// Sağlık değerini oku
scanner.Scan()
health, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Türe özgü ilk istatistiği oku
scanner.Scan()
stat1, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Türe özgü ikinci istatistiği oku
scanner.Scan()
stat2, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// TODO: charType değerine göre uygun karakteri oluştur
// Değişkenleri kullan: charType, name, health, stat1, stat2
// Savaşçı (warrior) için: stat1 = Strength, stat2 = Armor
// Büyücü (mage) için: stat1 = Intelligence, stat2 = MagicResist
// Okçu (archer) için: stat1 = Agility, stat2 = Evasion
// Eylem sayısını oku
scanner.Scan()
numActions, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Her bir eylemi işle
for i := 0; i < numActions; i++ {
scanner.Scan()
line := strings.TrimSpace(scanner.Text())
parts := strings.Fields(line)
action := parts[0]
// TODO: Her eylem türünü ele al:
// - "status": karakterin Status() sonucunu yazdır
// - "attack": "[Name] attacks for [damage] damage" yazdır
// - "defend [amount]": hasarı uygula ve "[Name] takes [actual] damage" yazdır
// - "setability [type] [power]": büyücüler için yetenek ayarla (fire, ice veya strike)
// - "useability": büyücüler için UseAbility() sonucunu yazdır
_ = action // Uygulama yaparken bu satırı kaldırın
_ = fmt.Println // Uygulama yaparken bu satırı kaldırın
}
}
Nesne Yönelimli Programlama bölümündeki tüm dersler
1Go OOP Temelleri
Harici DosyalarGo Çalışma Alanı ve ModüllerPaketler ve İçe AktarmalarDışa Aktarılan ve Aktarılmayan İsimlerGo'da OOP'ye GirişSınıf Olarak Struct'larStruct'larda Metot TanımlamaPointer ve Değer AlıcılarStruct BaşlatmaYapıcı FonksiyonlarÖzet - Basit Hesap Makinesi4Arayüzler
Arayüzlere GirişÖrtük UygulamaSözleşme Olarak ArayüzBoş Arayüz (any)Tür OnaylamaTür SeçimiArayüz BileşimiStringer ve Error ArayüzleriÖzet - Şekil Hesaplayıcı7Kapsülleme
Dışa Aktarılan ve Aktarılmayan AlanlarPaket Seviyesinde KapsüllemeGetter ve Setter MetotlarıGo'da Bilgi GizlemeÖzet - Öğrenci Kayıtları10Generics (Go 1.18+)
Generics'e GirişTür ParametreleriTür KısıtlamalarıGeneric Struct'larGeneric Metotlar İçin Geçici ÇözümÖzet - Generic Koleksiyon13Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıAbstract Factory KalıbıObserver KalıbıStrategy Kalıbı2Türler ve Struct'lar: Derinlemesine İnceleme
Temel ve Bileşik TürlerÖzel Tür TanımlamalarıStruct EtiketleriAnonim Struct'larİç İçe Geçmiş Struct'larSıfır Değerler ve VarsayılanlarÖzet - Rehber5Kalıtım Yerine Kompozisyon
Go'da Neden Kalıtım YokStruct Gömme TemelleriMetot YükseltmeBirden Fazla Struct GömmeGömme vs AgregasyonGömülü Metotları GölgelemeÖzet - Çalışan Hiyerarşisi8Hata Yönetimi ve OOP
error ArayüzüÖzel Hata TürleriHata Sarmalama (fmt.Errorf)Sentinel Hatalarerrors.Is() ve errors.As()Panic, Defer ve RecoverÖzet - Dosya Ayrıştırıcı3İşaretçiler ve Bellek
Go'da İşaretçi TemelleriStruct İşaretçileriDeğer ile Geçme ve Referans ile Geçmenew() FonksiyonuGo'da Garbage CollectionÖzet - Linked List Oluşturucu6Go'da Polimorfizm
Interface'ler ile PolimorfizmGo'da Duck TypingInterface Karşılama KurallarıPolimorfik KoleksiyonlarDependency InjectionÖzet - Payment Processor9Eşzamanlılık ve OOP
Goroutine TemelleriKanallar ve İletişimTamponlu ve Tamponsuz KanallarSelect İfadesisync.Mutex ve sync.RWMutexsync.WaitGroupThread-Safe Struct TasarımıÖzet - Worker Pool