게임 캐릭터 시스템
Coddy GO 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 107개 중 107번째.
챌린지
쉬움구조체 임베딩, 인터페이스, Strategy 패턴을 결합하여 유연한 전투 메커니즘을 만드는 게임 캐릭터 시스템을 구축해 봅시다! 런타임에 교체할 수 있는 능력과 함께, 고유한 방식으로 공격하고 방어할 수 있는 다양한 캐릭터 유형을 설계하게 됩니다.
코드를 다섯 개의 파일로 구성합니다:
character.go: 공통 Fields인Name(string),Health(int),MaxHealth(int)를 포함하는 기본Character구조체를 Define합니다.NewCharacter생성자와 다음 메서드를 포함합니다:IsAlive() bool: Health가 0보다 크면 true를 반환합니다Status() string: 다음 형식으로 반환합니다:[Name]: [Health]/[MaxHealth] HP
interfaces.go: 다형성을 가능하게 하는 전투 인터페이스를 Define합니다:Attacker인터페이스와Attack() int: dealt damage를 반환합니다Defender인터페이스와TakeDamage(damage int) int: damage reduction을 적용하고 actual damage taken을 반환합니다Ability인터페이스와Use() string: ability effect에 대한 description을 반환합니다
characters.go:Character를 임베드하고Attacker와Defender를 모두 구현하는 세 가지 character 유형을 Create합니다:Warrior:Strength(int)와Armor(int) Fields를 가집니다. Attack은 Strength를 damage로 반환합니다. TakeDamage는 들어오는 damage를 Armor만큼 줄입니다 (최소 1 damage taken).Mage:Intelligence(int)와MagicResist(int) Fields를 가집니다. Attack은 Intelligence * 2를 damage로 반환합니다. TakeDamage는 들어오는 damage를 MagicResist / 2만큼 줄입니다 (최소 1 damage taken).Archer:Agility(int)와Evasion(int) Fields를 가집니다. Attack은 Agility + 5를 damage로 반환합니다. TakeDamage: Evasion > 10이면 damage를 25% 줄이고 (정수 나눗셈), 그렇지 않으면 전체 damage를 받습니다 (최소 1 damage taken).각 유형에 대한 생성자도 포함합니다: name, health 및 각 유형의 특정 stat 값을 받는
NewWarrior,NewMage,NewArcher입니다.abilities.go: 교체 가능한 ability를 사용하여 Strategy 패턴을 구현합니다:FireSpell구조체에Power(int)를 포함합니다.Use()는 다음을 반환합니다:Casts fireball for [Power] damageIceSpell구조체에Power(int)를 포함합니다.Use()는 다음을 반환합니다:Casts ice shard for [Power] damagePowerStrike구조체에Multiplier(int)를 포함합니다.Use()는 다음을 반환합니다:Performs power strike at [Multiplier]x damageMage 구조체에
Ability타입의abilityField를 추가하고,SetAbility(a Ability)및UseAbility() string메서드를 추가합니다. UseAbility는 ability가 nil이면No ability set을 반환합니다.main.go: character를 Create하고 전투 메커니즘을 시연합니다.character 유형(
warrior,mage또는archer)을 읽은 다음 character의 name, health 및 유형별 stats를 읽습니다. 적절한 character를 Create합니다.그런 다음 action의 수를 읽습니다. 각 action은 다음 중 하나입니다:
status: character의 status를 출력합니다attack:[Name] attacks for [damage] damage를 출력합니다defend [amount]: damage를 적용하고[Name] takes [actual] damage를 출력합니다setability [type] [power]: mage만 사용할 수 있으며, ability를 설정합니다 (type은fire,ice또는strike입니다)useability: mage만 사용할 수 있으며, ability의 Use() 결과를 출력합니다
다음 입력이 제공됩니다:
- Character type, name, health 및 type-specific stats
- Number of actions, 그다음 각 action이 별도의 줄에 제공됩니다
예를 들어 다음이 주어졌을 때:
warrior
Thorin
100
15
8
5
status
attack
defend 20
status
defend 100출력은 다음과 같아야 합니다:
Thorin: 100/100 HP
Thorin attacks for 15 damage
Thorin takes 12 damage
Thorin: 88/100 HP
Thorin takes 92 damage또한 다음이 주어졌을 때:
mage
Gandalf
80
25
10
6
attack
useability
setability fire 30
useability
setability ice 25
useability
defend 40출력은 다음과 같아야 합니다:
Gandalf attacks for 50 damage
No ability set
Casts fireball for 30 damage
Casts ice shard for 25 damage
Gandalf takes 35 damage또한 다음이 주어졌을 때:
archer
Legolas
90
18
15
4
status
attack
defend 24
status출력은 다음과 같아야 합니다:
Legolas: 90/90 HP
Legolas attacks for 23 damage
Legolas takes 18 damage
Legolas: 72/90 HP구조체 임베딩을 사용하면 각 character 유형이 기본 Character의 Fields와 메서드를 공유할 수 있고, 인터페이스를 사용하면 어떤 Attacker든 damage를 가하고 어떤 Defender든 damage를 받을 수 있는 다형적 전투가 가능해진다는 점에 주목하세요. Strategy 패턴은 Mage의 교체 가능한 ability에서 특히 빛을 발합니다. 동일한 character가 핵심 구현을 변경하지 않고도 서로 다른 주문을 사용할 수 있습니다!
직접 해보기
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// 캐릭터 유형 읽기
scanner.Scan()
charType := strings.TrimSpace(scanner.Text())
// 캐릭터 이름 읽기
scanner.Scan()
name := strings.TrimSpace(scanner.Text())
// 체력 읽기
scanner.Scan()
health, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// 첫 번째 유형별 스탯 읽기
scanner.Scan()
stat1, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// 두 번째 유형별 스탯 읽기
scanner.Scan()
stat2, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// TODO: charType에 따라 적절한 캐릭터 생성
// 변수 사용: charType, name, health, stat1, stat2
// warrior의 경우: stat1 = Strength, stat2 = Armor
// mage의 경우: stat1 = Intelligence, stat2 = MagicResist
// archer의 경우: stat1 = Agility, stat2 = Evasion
// 행동 수 읽기
scanner.Scan()
numActions, _ := strconv.Atoi(strings.TrimSpace(scanner.Text()))
// 각 행동 처리
for i := 0; i < numActions; i++ {
scanner.Scan()
line := strings.TrimSpace(scanner.Text())
parts := strings.Fields(line)
action := parts[0]
// TODO: 각 액션 유형을 처리하세요:
// - "status": 캐릭터의 Status()를 출력
// - "attack": "[Name] attacks for [damage] damage"를 출력
// - "defend [amount]": 데미지를 적용하고 "[Name] takes [actual] damage"를 출력
// - "setability [type] [power]": 마법사의 경우, 능력 설정 (fire, ice, 또는 strike)
// - "useability": 마법사의 경우, UseAbility() 결과를 출력
_ = action // 구현할 때 이 줄을 제거하세요
_ = fmt.Println // 구현할 때 이 줄을 제거하세요
}
}
객체 지향 프로그래밍의 모든 레슨
8에러 처리와 OOP
error 인터페이스사용자 정의 에러 타입에러 래핑 (fmt.Errorf)센티넬 에러errors.Is()와 errors.As()Panic, Defer, Recover요약 - 파일 파서직접 연습해 보세요: 온라인 Go 컴파일러