✅ 복합 대입 연산자
| 연산자 | 의미 | 예시 | 설명 |
|---|---|---|---|
| += | 더해서 저장 | a += 2; | a = a + 2; 와 같음 |
| -= | 빼서 저장 | a -= 3; | a = a - 3; 와 같음 |
| *= | 곱해서 저장 | a *= 4; | a = a * 4; 와 같음 |
| /= | 나눠서 저장 | a /= 2; | a = a / 2; 와 같음 |
| %= | 나머지를 저장 | a %= 5; | a = a % 5; 와 같음 |
✅ 증가/감소 연산자
| 연산자 | 의미 | 예시 | 설명 |
|---|---|---|---|
++a | 전위 증가 | int b = ++a; | 증가 후 대입 (먼저 +1, 그다음 대입) |
a++ | 후위 증가 | int b = a++; | 대입 후 증가 (먼저 대입, 그다음 +1) |
--a | 전위 감소 | --a; | a에서 1 감소시킴 (바로 적용) |
a-- | 후위 감소 | a--; | a에서 1 감소시킴 (뒤에서 적용) |
🧩 예시
int a = 5;
a += 3; // a = 8
a *= 2; // a = 16
a--; // a = 15
int b = a++; // b = 15, a = 16
#pragma once
#include "Actor.h" // Actor 클래스 상속
class Character : public Actor
{
public:
Character(int hp, int ad); // 생성자
void Damaged(int damage) override; // 데미지 입는 함수 (오버라이드)
void Heal(); // 회복 함수
private:
int Healcount;
int HealSlot[3] = { 3, 2, 1 }; // 회복량 저장 슬롯
};
public Actor Actor 클래스를 공개 상속 – 외부에서 접근 가능함 override 부모 클래스의 Damaged 함수 등을 **재정의(오버라이드)**할 때 사용 HealSlot[] 회복 가능한 값 3개를 저장하는 배열#include "Character.h"
#include <iostream>
Character::Character(int hp, int ad) : Actor(hp, ad, "용사") // 부모 생성자 호출
{
Healcount = 0;
}
void Character::Damaged(int damage)
{
std::cout << damage << "의 데미지를 입었다!" << std::endl;
std::cout << "남은 체력: " << ((HP - damage > 0) ? HP - damage : 0) << std::endl;
Actor::Damaged(damage); // 부모 클래스의 Damaged 함수 호출
}
void Character::Heal()
{
if (Healcount < 3)
{
HP += HealSlot[Healcount];
Healcount++;
std::cout << HealSlot[Healcount - 1] << "를 회복했다! 남은 회복 횟수: "<< 3 - Healcount << std::endl;
}
}
Character::Character 생성자 ➡ Actor 부모 클래스의 생성자에 값 전달 Actor(hp, ad, "용사") 부모 클래스 Actor에 hp, ad, "용사" 값을 전달 Healcount 회복 가능 횟수 ➡ 최대 3회로 제한 ? 삼항 연산자 ➡ 조건이 참이면 앞의 값, 거짓이면 뒤의 값 반환HP - damage > 0) ? HP - damage : 0 ➡ 체력이 0보다 작으면 0으로 대체하여 음수 방지✅ 코드 비교
if (Healcount < 3)
{
HP += HealSlot[Healcount]; // HP에 회복량을 더해서 저장
// ↓ 같은 의미
HP = HP + HealSlot[Healcount]; // HP에 회복량을 더한 값을 다시 대입
}
#pragma once
#include "Actor.h"
class Enemy : public Actor
{
public:
Enemy(int hp, int ad, std::string name, bool named); // 생성자
bool Named; // 네임드 여부
void Damaged(int damage) override; // 데미지 처리 (부모 함수 재정의)
void Move(bool front) override; // 이동 처리 (부모 함수 재정의)
};
public Actor Actor 클래스를 공개 상속 Enemy(...) 생성자, 체력/공격력/이름/네임드 여부를 초기화 bool Named; 네임드 몬스터인지 여부를 저장 override 부모 클래스의 함수를 재정의 한다는 의미Move(bool front) 방향에 따라 위치 이동을 구현할 예정#include "Enemy.h"
#include <iostream>
// 생성자: Actor 생성자 호출 + Named 변수 초기화
Enemy::Enemy(int hp, int ad, std::string name, bool named) : Actor(hp, ad, name)
{
Named = named;
}
// 데미지 처리 함수 (부모 함수 오버라이드)
void Enemy::Damaged(int damage)
{
if (Named)
{
std::cout << "울부짖으며," << std::endl;
}
std::cout << "감히 나를 때렸겠다?" << std::endl;
Actor::Damaged(damage); // 부모 함수 호출
}
// 이동 처리 함수 (앞/뒤로 이동)
void Enemy::Move(bool front)
{
if (front)
{
Position--; // 전위 감소 (앞으로 이동)
}
else
{
Position++; // 후위 증가 (뒤로 이동)
}
}
Enemy::Enemy(...) : Actor(...) 부모 생성자에 값 넘김 (hp, ad, name) Named = named; 매개변수로 받은 값을 멤버 변수에 저장 if (Named) 네임드 적이면 특별한 출력 추가 Actor::Damaged(damage); 부모 함수 재사용 Position-- / Position++ 위치 이동. 앞이면 감소, 뒤면 증가✅ 앞이면 감소(--), 뒤면 증가(++)
1차원 배열/좌표에서
[0] [1] [2] [3] [4]
↑ ↑ ↑ ↑ ↑
왼쪽 → 오른쪽
왼쪽으로 한 칸 ➡ index가 작아짐 (감소)
오른쪽으로 한 칸 ➡ index가 커짐 (증가)
🔻
앞(front) : 보통 왼쪽/전진/앞으로 가는 것 ➡ Position--
뒤(back) : 보통 오른쪽/후진/뒤로 가는 것 ➡ Position++
🧩 예시
int Position = 3;
if (front)
Position--; // 앞으로 한 칸 이동 (ex. 3 → 2)
else
Position++; // 뒤로 한 칸 이동 (ex. 3 → 4)
| 항목 | 필요 여부 | 이유 |
|---|---|---|
main.cpp | ✅ 반드시 필요 | 실행 시작점 |
main.h | ❌ 거의 필요 없음 | 다른 곳에서 main() 호출 안 함 |
✅ 주요 흐름
1. 캐릭터 생성
2. 반복문에서 적 생성 (switch 사용)
3. 위치 초기화
4. 행동 선택 (e, a, f, b, h)
5. 공격 조건 확인
6. 체력 확인 후 객체 삭제
7. 게임 종료
✅ 코드
#include "Character.h"
#include "Enemy.h"
#include <iostream>
void main()
{
Character* character = new Character(20, 3); // 체력 20, 공격력 3
for (int i = 0; i < 3; i++) // 총 3명의 적과 전투
{
Enemy* enemy = nullptr; // 아직 생성 안 됨, 후에 실제 객체 할당 예정
switch (i)
{
case 0:
enemy = new Enemy(3, 1, "잡몹", false); // 여기서 실제 객체 생성!
std::cout << "잡몹을 만났습니다." << std::endl;
break;
case 1:
enemy = new Enemy(5, 3, "네임드몹", true);
std::cout << "네임드몹을 만났습니다." << std::endl;
break;
case 2:
enemy = new Enemy(5, 6, "보스", true);
std::cout << "보스를 만났습니다." << std::endl;
break;
}
enemy->SetPosition(5); // 적 위치는 5
character->SetPosition(0); // 플레이어는 0에서 시작
while (enemy != nullptr)
{
std::cout << "내 위치: " << character->GetPosition()
<< " 적 위치: " << enemy->GetPosition() << std::endl;
char input;
std::cout << "행동을 선택해주세요 (a: 공격, f: 전진, b: 후진, h: 회복, e: 도망)" << std::endl;
std::cin >> input;
if (input == 'e') // 도망
{
std::cout << "도망쳤습니다" << std::endl;
break;
}
else if (input == 'a') // 공격
{
if (enemy->GetPosition() == character->GetPosition() + 1)
character->Attack(enemy);
else
std::cout << "공격을 했으나 닿지 않습니다." << std::endl;
}
else if (input == 'f') // 전진
{
if (enemy->GetPosition() > character->GetPosition() + 1)
character->Move(true);
else
std::cout << "적이 가로막고있습니다" << std::endl;
}
else if (input == 'b') // 후진
{
if (0 < character->GetPosition())
character->Move(false);
else
std::cout << "막다른 골목입니다." << std::endl;
}
else if (input == 'h') // 회복
{
character->Heal();
}
if (enemy->GetHP() <= 0) // 적 사망 처리
{
delete enemy; // 적이 죽으면 메모리 해제
enemy = nullptr; // 안전하게 포인터 초기화
}
if (enemy == nullptr)
break;
// 적이 공격 범위 안에 들어왔는지 확인
if (enemy->GetPosition() == character->GetPosition() + 1)
enemy->Attack(character);
else
enemy->Move(true);
if (character->GetHP() <= 0) // 캐릭터 사망 처리
{
delete character;
character = nullptr;
}
if (character == nullptr)
break;
}
if (character == nullptr)
break;
}
std::cout << "게임 끝" << std::endl;
}
| 개념 | 설명 |
|---|---|
new Class() | 동적 객체 생성 (힙 메모리) |
-> | 포인터로 멤버 접근 |
nullptr | 포인터가 아무 것도 가리키지 않음 |
delete | 동적 메모리 해제 |
switch | 적의 종류를 조건별로 분기 |
while | 캐릭터 vs 적 전투 루프 |
| 입력 키 | e: 도망, a: 공격, f: 전진, b: 후퇴, h: 힐 |
✅ new
Enemy* enemy = new Enemy(...); // heap에 적 객체 생성
✅ delete
delete enemy;
enemy = nullptr;
📌 nullptr
| 코드 / 구문 | 의미 |
|---|---|
nullptr | 아무 것도 가리키지 않는 포인터 |
Enemy* enemy = nullptr; | 비어 있는 포인터 선언 (초기화) |
enemy == nullptr | 적이 아직 생성되지 않았는지 확인 |
enemy != nullptr | 적 객체가 생성되어 유효한 상태인지 확인 |
enemy = new Enemy(...); | 실제 적 객체를 생성하고 포인터에 연결 |
if (enemy != nullptr) | 널 체크: 적이 존재할 때만 실행되는 조건 |
delete enemy; enemy = nullptr; | 적 객체 메모리 해제 후 포인터 초기화 |
🧠 요약
| 키워드 | 의미 |
|---|---|
new | 객체를 heap에 동적 생성 |
delete | heap에 생성한 객체 메모리 해제 |
nullptr | 포인터를 비운다 (해제 후 초기화 용) |
🔁 switch문 구조
switch (조건값)
{
case 값1:
// 조건값이 값1일 때 실행할 코드
break;
case 값2:
// 조건값이 값2일 때 실행할 코드
break;
default:
// 조건값이 어떤 case에도 해당하지 않을 때 실행
break;
}
case 비교할 값break 해당 case 실행 후 switch문 종료 / 없으면 아래 case까지 연쇄 실행 (fall-through)default 모든 case와 맞지 않을 때 실행 (선택 사항)🔁 반복문 📎강의 자료
🔁 for문 구조
for (초기식; 조건식; 증감식)
{
// 반복할 코드
}
for (int i = 0; i < 3; i++)
{
// 매 반복마다 enemy를 하나 생성함
}
| 구성 | 의미 |
|---|---|
int i = 0 | i라는 변수를 0으로 시작함 |
i < 3 | i가 3보다 작을 동안 반복 |
i++ | 한 번 반복할 때마다 i를 1 증가시킴 |
| i 값 | 생성되는 적 | 설명 |
|---|---|---|
| 0 | 잡몹 | 일반 몬스터 |
| 1 | 네임드몹 | 이름 있는 중간 보스 |
| 2 | 보스몹 | 최종 보스 |
🔁 while문 구조
while (조건)
{
// 조건이 참인 동안 계속 실행될 코드
}
delete enemy; enemy = nullptr; 되면 반복 종료🔁 for vs while
| 구분 | for문 | while문 |
|---|---|---|
| 반복 횟수 | 정해져 있는 경우 (예: 3번 반복 등) | 언제 끝날지 모를 조건 반복 |
| 예시 | for (int i = 0; i < 3; i++) | while (enemy != nullptr) |
| 쓰임새 | 카운팅, 순차적 처리 | 생존 여부, 네트워크 대기, 입력 반복 등 |