System postaci w grze
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 107 z 107.
Wyzwanie
ŁatwyStwórzmy system postaci do gry, który łączy osadzanie struktur, interfejsy i wzorzec Strategia, aby tworzyć elastyczne mechaniki walki! Zaprojektujesz różne typy postaci, które mogą atakować i bronić się na wyjątkowe sposoby, a ich zdolności będzie można zmieniać w czasie działania programu.
Rozmieścisz kod w pięciu plikach:
character.go: Zdefiniuj bazową strukturęCharacterze wspólnymi polami:Name(string),Health(int) iMaxHealth(int). Dodaj konstruktorNewCharacteroraz metody:IsAlive() bool: zwraca true, jeśli zdrowie jest większe niż 0Status() string: zwraca format:[Name]: [Health]/[MaxHealth] HP
interfaces.go: Zdefiniuj interfejsy walki umożliwiające polimorfizm:- Interfejs
Attackerz metodąAttack() int: zwraca zadane obrażenia - Interfejs
Defenderz metodąTakeDamage(damage int) int: zmniejsza obrażenia i zwraca faktycznie otrzymane obrażenia - Interfejs
Abilityz metodąUse() string: zwraca opis efektu zdolności
- Interfejs
characters.go: Utwórz trzy typy postaci, które osadzająCharacteri implementują zarównoAttacker, jak iDefender:Warrior: ma polaStrength(int) iArmor(int). Attack zwraca Strength jako zadawane obrażenia. TakeDamage zmniejsza otrzymywane obrażenia o Armor (otrzymane obrażenia wynoszą co najmniej 1).Mage: ma polaIntelligence(int) iMagicResist(int). Attack zwraca Intelligence * 2 jako zadawane obrażenia. TakeDamage zmniejsza otrzymywane obrażenia o MagicResist / 2 (otrzymane obrażenia wynoszą co najmniej 1).Archer: ma polaAgility(int) iEvasion(int). Attack zwraca Agility + 5 jako zadawane obrażenia. TakeDamage: jeśli Evasion > 10, zmniejsza obrażenia o 25% (dzielenie całkowitoliczbowe); w przeciwnym razie postać otrzymuje pełne obrażenia (otrzymane obrażenia wynoszą co najmniej 1).Dodaj konstruktory dla każdego typu:
NewWarrior,NewMage,NewArcher, które przyjmują imię, zdrowie i wartości odpowiednich statystyk.abilities.go: Zaimplementuj wzorzec Strategia z wymiennymi zdolnościami:Struktura
FireSpellz polemPower(int). Jej metodaUse()zwraca:Casts fireball for [Power] damageStruktura
IceSpellz polemPower(int). Jej metodaUse()zwraca:Casts ice shard for [Power] damageStruktura
PowerStrikez polemMultiplier(int). Jej metodaUse()zwraca:Performs power strike at [Multiplier]x damageDodaj do struktury Mage pole
ability(typuAbility) oraz metodySetAbility(a Ability)iUseAbility() string. UseAbility zwracaNo ability set, jeśli ability ma wartość nil.main.go: Utwórz postacie i pokaż mechanikę walki.Wczytaj typ postaci (
warrior,magelubarcher), a następnie imię postaci, zdrowie i statystyki właściwe dla danego typu. Utwórz odpowiednią postać.Następnie wczytaj liczbę akcji. Każda akcja jest jednym z poniższych poleceń:
status: wypisz status postaciattack: wypisz[Name] attacks for [damage] damagedefend [amount]: zastosuj obrażenia i wypisz[Name] takes [actual] damagesetability [type] [power]: tylko dla magów, ustaw zdolność (type tofire,icelubstrike)useability: tylko dla magów, wypisz wynik metody Use()
Podane zostaną następujące dane wejściowe:
- Typ postaci, imię, zdrowie i statystyki właściwe dla danego typu
- Liczba akcji, a następnie każda akcja w osobnym wierszu
Na przykład dla danych:
warrior
Thorin
100
15
8
5
status
attack
defend 20
status
defend 100Wynik powinien wyglądać następująco:
Thorin: 100/100 HP
Thorin attacks for 15 damage
Thorin takes 12 damage
Thorin: 88/100 HP
Thorin takes 92 damageA dla danych:
mage
Gandalf
80
25
10
6
attack
useability
setability fire 30
useability
setability ice 25
useability
defend 40Wynik powinien wyglądać następująco:
Gandalf attacks for 50 damage
No ability set
Casts fireball for 30 damage
Casts ice shard for 25 damage
Gandalf takes 35 damageA dla danych:
archer
Legolas
90
18
15
4
status
attack
defend 24
statusWynik powinien wyglądać następująco:
Legolas: 90/90 HP
Legolas attacks for 23 damage
Legolas takes 18 damage
Legolas: 72/90 HPZwróć uwagę, że osadzanie struktur pozwala każdemu typowi postaci współdzielić pola i metody bazowego Character, a interfejsy umożliwiają polimorficzną walkę, w której każdy Attacker może zadawać obrażenia, a każdy Defender może je otrzymywać. Wzorzec Strategia doskonale sprawdza się w przypadku wymiennych zdolności Maga: ta sama postać może używać różnych zaklęć bez zmieniania swojej podstawowej implementacji!
Spróbuj swoich sił
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Odczytaj typ postaci
scanner.Scan()
charType := strings.TrimSpace(scanner.Text())
// Odczytaj imię postaci
scanner.Scan()
name := strings.TrimSpace(scanner.Text())
// Odczytaj punkty zdrowia
scanner.Scan()
health, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Odczytaj pierwszą statystykę właściwą dla danego typu
scanner.Scan()
stat1, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Odczytaj drugą statystykę właściwą dla danego typu
scanner.Scan()
stat2, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// TODO: Utwórz odpowiednią postać na podstawie charType
// Użyj zmiennych: charType, name, health, stat1, stat2
// Dla wojownika: stat1 = Strength, stat2 = Armor
// Dla maga: stat1 = Intelligence, stat2 = MagicResist
// Dla łucznika: stat1 = Agility, stat2 = Evasion
// Odczytaj liczbę akcji
scanner.Scan()
numActions, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// Przetwórz każdą akcję
for i := 0; i < numActions; i++ {
scanner.Scan()
line := strings.TrimSpace(scanner.Text())
parts := strings.Fields(line)
action := parts[0]
// TODO: Obsłuż każdy typ akcji:
// - "status": wypisz wynik Status() postaci
// - "attack": wypisz "[Name] attacks for [damage] damage"
// - "defend [amount]": zastosuj obrażenia i wypisz "[Name] takes [actual] damage"
// - "setability [type] [power]": dla magów ustaw zdolność (fire, ice lub strike)
// - "useability": dla magów wypisz wynik UseAbility()
_ = action // Usuń tę linię podczas implementacji
_ = fmt.Println // Usuń tę linię podczas implementacji
}
}
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP w Go
Pliki zewnętrzneObszar roboczy i moduły GoPakiety i importyNazwy eksportowane i nieeksportowaneWprowadzenie do OOP w GoStruktury jako klasyDefiniowanie metod dla strukturOdbiorniki wskaźnikowe i wartościoweInicjalizacja strukturFunkcje konstruktoraPodsumowanie – prosty kalkulator4Interfejsy
Wprowadzenie do interfejsówImplementacja niejawnaInterfejs jako kontraktPusty interfejs (any)Asercja typuPrzełącznik typówKompozycja interfejsówInterfejsy Stringer i ErrorPowtórka — kalkulator figur7Hermetyzacja
Pola eksportowane i nieeksportowaneHermetyzacja na poziomie pakietuMetody pobierające i ustawiająceUkrywanie informacji w GoPowtórka – dane studentów10Typy generyczne (Go 1.18+)
Wprowadzenie do typów generycznychParametry typówOgraniczenia typówStruktury generyczneObejście ograniczeń metod generycznychPodsumowanie — generyczna kolekcja2Typy i struktury w praktyce
Typy proste i złożoneDefiniowanie własnych typówTagi pól strukturStruktury anonimoweStruktury zagnieżdżoneWartości zerowe i domyślnePodsumowanie – książka kontaktów5Kompozycja zamiast dziedziczenia
Dlaczego Go nie ma dziedziczeniaPodstawy osadzania strukturPromowanie metodOsadzanie wielu strukturOsadzanie a agregacjaPrzesłanianie osadzonych metodPodsumowanie — hierarchia pracowników8Obsługa błędów i programowanie obiektowe
Interfejs błęduWłasne typy błędówOpakowywanie błędów (fmt.Errorf)Błędy wartowniczeerrors.Is() i errors.As()Panic, Defer i RecoverPodsumowanie — parser plików3Wskaźniki i pamięć
Podstawy wskaźników w GoWskaźniki do strukturPrzekazywanie przez wartość a przez referencjęFunkcja new()Odśmiecanie pamięci w GoPowtórka — kreator listy wiązanej6Polimorfizm w Go
Polimorfizm za pomocą interfejsówDuck typing w GoZasady spełniania interfejsówKolekcje polimorficzneWstrzykiwanie zależnościPowtórka — procesor płatności9Współbieżność i OOP
Podstawy goroutinesKanały i komunikacjaKanały buforowane i niebuforowaneInstrukcja selectsync.Mutex i sync.RWMutexsync.WaitGroupProjektowanie struktur bezpiecznych wątkowoPowtórka – pula workerów12Zaawansowane zagadnienia programowania obiektowego
Wzorzec opcji funkcyjnychWzorzec Builder w GoŁańcuchowe wywoływanie metodAliasy typów a definicje typówPodstawy refleksjiPrzegląd generowania koduPoćwicz samodzielnie: Kompilator Go online