200810_TopDownShooting.zip
2.33MB
1. Player
a. Head, Body 구분하여 Animation 출력
[ Isaac class (Player) ]
더보기
#pragma once
#include "Framework/Math/Transform.h"
#include "Object/GameObject/Isaac_Head.h"
#include "Object/GameObject/Isaac_Body.h"
#include "Object/GameObject/Bullet.h"
class Isaac
{
public:
Isaac_Head* head;
Isaac_Body* body;
//
vector<Bullet*> bullets;
int bulletCount;
//
Vector2 moveDir;
Vector2 dir;
//
float speed;
bool isAttack;
public:
Isaac();
~Isaac();
//
void Init();
//
void Update();
void Render();
void PostRender();
//
void Control();
void Move();
void Attack();
void SetDir();
};
/////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "Isaac.h"
Isaac::Isaac()
:speed(400.0f), bulletCount(50), moveDir(0, 0), dir(0, 0),
isAttack(false)
{
Init();
}
Isaac::~Isaac()
{
delete head;
delete body;
//
for (auto bullet : bullets)
delete bullet;
bullets.clear();
}
void Isaac::Init()
{
head = new Isaac_Head;
body = new Isaac_Body;
//
Bullet* bullet{};
for (int i = 0; i < bulletCount; ++i)
{
bullet = new Bullet;
bullet->isActive = false;
bullets.emplace_back(bullet);
}
}
void Isaac::Update()
{
Control();
//
head->Update();
body->Update();
//
for (auto bullet : bullets)
bullet->Update();
}
void Isaac::Render()
{
body->Render();
head->Render();
//
for (auto bullet : bullets)
bullet->Render();
}
void Isaac::PostRender()
{
ImGui::Text("[Isaac]");
ImGui::Text("Dir : %.3f, %.3f", dir.x, dir.y);
ImGui::Text("[Head]");
ImGui::SliderFloat2("headPos", (float*)&head->pos, 0.0f, 1000.0f);
ImGui::Text("[Body]");
ImGui::SliderFloat2("bodyPos", (float*)&body->pos, 0.0f, 1000.0f);
}
void Isaac::Control()
{
SetDir();
Attack();
Move();
}
void Isaac::Move()
{
if (isAttack)
return;
//
head->Move(moveDir, speed);
body->Move(moveDir, speed);
}
void Isaac::Attack()
{
if (KEY_DOWN(VK_LBUTTON))
{
isAttack = true;
for (auto bullet : bullets)
{
if (bullet->isActive)
continue;
//
bullet->Fire(dir, head->pos);
return;
}
}
if (KEY_UP(VK_LBUTTON))
isAttack = false;
}
void Isaac::SetDir()
{
moveDir = {};
if (KEY_PRESS('D'))
{
moveDir.x = 1.0f;
dir.x = 1.0f;
}
if (KEY_PRESS('A'))
{
moveDir.x = -1.0f;
dir.x = -1.0f;
}
if (KEY_PRESS('W'))
{
moveDir.y = 1.0f;
dir.y = 1.0f;
}
if (KEY_PRESS('S'))
{
moveDir.y = -1.0f;
dir.y = -1.0f;
}
//
if (KEY_UP('A') || KEY_UP('D'))
dir.x = 0;
if (KEY_UP('W') || KEY_UP('S'))
dir.y = 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////
[ Isaac_Head class ]
더보기
#pragma once
#include "Framework/Math/Transform.h"
class Isaac_Head : public Transform
{
public:
enum ActionType
{
HEAD_LEFT,
HEAD_UP,
HEAD_RIGHT,
HEAD_DOWN,
};
//
public:
Sprite* sprite;
//
vector<Action*> actions;
int curAction;
//
public:
Isaac_Head();
~Isaac_Head();
//
void Update();
void Render();
//
void LoadAction(string file, Action::Type type, float speed = 0.1f);
//
void SetAction(int type);
//
void Move(Vector2 moveDir, float speed);
};
/////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "Isaac_Head.h"
Isaac_Head::Isaac_Head()
:curAction(HEAD_DOWN)
{
sprite = new Sprite;
string path = "Textures/Isaac/";
LoadAction(path + "Isaac_Head", Action::LOOP);
}
Isaac_Head::~Isaac_Head()
{
delete sprite;
//
for (auto action : actions)
delete action;
actions.clear();
}
void Isaac_Head::Update()
{
Action::Clip curClip = actions[curAction]->GetCurClip();
sprite->SetAction(curClip);
actions[curAction]->Update();
sprite->Update();
scale = curClip.size;
UpdateWorld();
}
void Isaac_Head::Render()
{
ALPHA_BLEND_STATE->SetState();
SetWorldBuffer();
sprite->Render();
}
void Isaac_Head::LoadAction(string file, Action::Type type, float speed)
{
XmlDocument* document = new XmlDocument();
string xmlfile = file + ".xml";
document->LoadFile(xmlfile.c_str());
//
XmlElement* atlas = document->FirstChildElement();
//
string pngfile = file + ".png";
wstring imagePath{};
imagePath.assign(pngfile.begin(), pngfile.end()); // string -> wstring
//
Texture* texture = Texture::Add(imagePath);
//
XmlElement* action = atlas->FirstChildElement();
for (; action != nullptr; action = action->NextSiblingElement())
{
vector<Action::Clip> clips{};
XmlElement* sprite = action->FirstChildElement();
//
while (sprite != nullptr)
{
float x{}, y{}, w{}, h{};
x = sprite->FloatAttribute("x");
y = sprite->FloatAttribute("y");
w = sprite->FloatAttribute("w");
h = sprite->FloatAttribute("h");
clips.emplace_back(x, y, w, h, texture);
//
sprite = sprite->NextSiblingElement();
}
//
actions.emplace_back(new Action(clips, type, speed));
}
//
delete document;
}
void Isaac_Head::SetAction(int type)
{
if (curAction != type)
{
curAction = type;
actions[curAction]->Play();
}
}
void Isaac_Head::Move(Vector2 moveDir, float speed)
{
pos.x += moveDir.x * speed * DELTA;
pos.y += moveDir.y * speed * DELTA;
//
if (moveDir.x == 1.0f)
SetAction(HEAD_RIGHT);
else if (moveDir.x == -1.0f)
SetAction(HEAD_LEFT);
if (moveDir.y == 1.0f)
SetAction(HEAD_UP);
else if (moveDir.y == -1.0f)
SetAction(HEAD_DOWN);
}
[ Isaac_Body class ]
더보기
#pragma once
#include "Framework/Math/Transform.h"
class Isaac_Body : public Transform
{
public:
enum ActionType
{
BODY_IDLE_H,
BODY_MOVE_H,
BODY_IDLE_V,
BODY_MOVE_V,
};
//
public:
Sprite* sprite;
//
vector<Action*> actions;
int curAction;
//
bool isRight;
//
public:
Isaac_Body();
~Isaac_Body();
//
void Update();
void Render();
//
void LoadAction(string file, Action::Type type, float speed = 0.1f);
//
void SetAction(int type);
//
void Move(Vector2 moveDir, float speed);
};
/////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "Isaac_Body.h"
Isaac_Body::Isaac_Body()
:curAction(BODY_IDLE_V), isRight(false)
{
sprite = new Sprite;
pos = { 0, -15.0f };
string path = "Textures/Isaac/";
LoadAction(path + "Isaac_Body", Action::LOOP);
}
Isaac_Body::~Isaac_Body()
{
delete sprite;
//
for (auto action : actions)
delete action;
actions.clear();
}
void Isaac_Body::Update()
{
Action::Clip curClip = actions[curAction]->GetCurClip();
sprite->SetAction(curClip);
actions[curAction]->Update();
sprite->Update();
scale = curClip.size;
UpdateWorld();
}
void Isaac_Body::Render()
{
ALPHA_BLEND_STATE->SetState();
SetWorldBuffer();
sprite->Render();
}
void Isaac_Body::LoadAction(string file, Action::Type type, float speed)
{
XmlDocument* document = new XmlDocument();
string xmlfile = file + ".xml";
document->LoadFile(xmlfile.c_str());
//
XmlElement* atlas = document->FirstChildElement();
//
string pngfile = file + ".png";
wstring imagePath{};
imagePath.assign(pngfile.begin(), pngfile.end()); // string -> wstring
//
Texture* texture = Texture::Add(imagePath);
//
XmlElement* action = atlas->FirstChildElement();
for (; action != nullptr; action = action->NextSiblingElement())
{
vector<Action::Clip> clips{};
XmlElement* sprite = action->FirstChildElement();
//
while (sprite != nullptr)
{
float x{}, y{}, w{}, h{};
x = sprite->FloatAttribute("x");
y = sprite->FloatAttribute("y");
w = sprite->FloatAttribute("w");
h = sprite->FloatAttribute("h");
clips.emplace_back(x, y, w, h, texture);
//
sprite = sprite->NextSiblingElement();
}
//
actions.emplace_back(new Action(clips, type, speed));
}
//
delete document;
}
void Isaac_Body::SetAction(int type)
{
if (curAction != type)
{
curAction = type;
actions[curAction]->Play();
}
}
void Isaac_Body::Move(Vector2 moveDir, float speed)
{
if (moveDir.x == -1)
{
if (isRight)
{
rot.y = PI;
isRight = false;
}
}
if (moveDir.x == 1)
{
if (!isRight)
{
rot.y = 0;
isRight = true;
}
}
//
pos.x += moveDir.x * speed * DELTA;
pos.y += moveDir.y * speed * DELTA;
//
if (moveDir.x == 1.0f || moveDir.x == -1.0f)
SetAction(BODY_MOVE_H);
else if (moveDir.y == 1.0f || moveDir.y == -1.0f)
SetAction(BODY_MOVE_V);
//
if (KEY_UP('D') || KEY_UP('A'))
SetAction(BODY_IDLE_H);
else if (KEY_UP('W') || KEY_UP('S'))
SetAction(BODY_IDLE_V);
}
2. Bullet
a. 오브젝트 풀링, Player에 포함되어 Scene에서 충돌 처리
더보기
#pragma once
#include "Framework/Math/Transform.h"
#include "Framework/Animation/Action.h"
class Bullet : public Transform
{
private:
Sprite* sprite;
Vector2 dir;
//
Action::Clip curClip;
//
float speed;
float lifeTime;
float lifeTimeCounter;
//
Collider* collider;
public:
Bullet();
~Bullet();
//
void Update();
void Render();
//
void Fire(Vector2 dir, Vector2 pos);
void Move();
void Hit();
//
void LifeTime();
Collider* GetCollider() { return collider; }
};
/////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "Bullet.h"
Bullet::Bullet()
:dir(0, 0), speed(500.0f), lifeTime(3.0f), lifeTimeCounter(0)
{
sprite = new Sprite;
sprite->SetTexture(L"Textures/Isaac/Bullet.png");
/* SetClip */
curClip.startPos = { 0,0 };
curClip.size = { sprite->GetSize().x, sprite->GetSize().y };
curClip.texture = sprite->GetTexture();
//
collider = new RectCollider(sprite->GetSize(), this);
collider->isActive = false;
}
Bullet::~Bullet()
{
delete sprite;
delete collider;
}
void Bullet::Update()
{
if (!isActive) return;
//
Move();
LifeTime();
//
sprite->SetAction(curClip);
sprite->Update();
scale = sprite->GetSize();
UpdateWorld();
//
collider->Update();
}
void Bullet::Render()
{
if (!isActive) return;
ALPHA_BLEND_STATE->SetState();
//
SetWorldBuffer();
//
sprite->Render();
//
collider->Render();
}
void Bullet::Fire(Vector2 dir, Vector2 pos)
{
if (dir.x == 0 && dir.y == 0)
return;
//
isActive = true;
//
collider->isActive = true;
//
this->dir = dir;
this->pos = pos;
}
void Bullet::Move()
{
pos.x += dir.x * speed * DELTA;
pos.y += dir.y * speed * DELTA;
}
void Bullet::Hit()
{
isActive = false;
EFFECT->Play("hit", pos);
}
void Bullet::LifeTime()
{
lifeTimeCounter += DELTA;
if (lifeTimeCounter >= lifeTime)
{
lifeTimeCounter = 0;
isActive = false;
}
}
2. Enemy
a. Move 애니메이션, 패턴 구현
b. Scene에서 vector Container로 관리
더보기
#pragma once
#include "Framework/Math/Transform.h"
class Enemy : public Transform
{
public:
enum ActionType
{
DOWN,
RIGHT,
UP,
};
//
public:
Sprite* sprite;
//
vector<Action*> actions;
int curAction;
//
int curPattern;
float patternTime;
float patternCounter;
//
Vector2 moveDir;
float speed;
//
Collider* collider;
//
public:
Enemy();
~Enemy();
//
void Update();
void Render();
//
void LoadAction(string file, Action::Type type, float speed = 0.1f);
//
void SetAction(int type);
//
void Move();
void AIPattern();
//
void SetPos(Vector2 value) { pos = value; }
void Damage();
};
/////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "Enemy.h"
Enemy::Enemy()
:curAction(DOWN), speed(100.0f), moveDir(0, 0),
patternCounter(0), patternTime(3.0f)
{
sprite = new Sprite;
string path = "Textures/Isaac/";
LoadAction(path + "Enemy", Action::LOOP);
//
Vector2 colSize = actions[curAction]->GetCurClip().size;
collider = new RectCollider(colSize, this);
}
Enemy::~Enemy()
{
delete collider;
//
for (auto action : actions)
delete action;
actions.clear();
//
delete sprite;
}
void Enemy::Update()
{
if (!isActive) return;
//
Action::Clip curClip = actions[curAction]->GetCurClip();
sprite->SetAction(curClip);
actions[curAction]->Update();
sprite->Update();
scale = curClip.size;
UpdateWorld();
//
AIPattern();
Move();
//
collider->Update();
}
void Enemy::Render()
{
ALPHA_BLEND_STATE->SetState();
SetWorldBuffer();
sprite->Render();
//
collider->Render();
}
void Enemy::LoadAction(string file, Action::Type type, float speed)
{
XmlDocument* document = new XmlDocument();
string xmlfile = file + ".xml";
document->LoadFile(xmlfile.c_str());
//
XmlElement* atlas = document->FirstChildElement();
//
string pngfile = file + ".png";
wstring imagePath{};
imagePath.assign(pngfile.begin(), pngfile.end()); // string -> wstring
//
Texture* texture = Texture::Add(imagePath);
//
XmlElement* action = atlas->FirstChildElement();
for (; action != nullptr; action = action->NextSiblingElement())
{
vector<Action::Clip> clips{};
XmlElement* sprite = action->FirstChildElement();
//
while (sprite != nullptr)
{
float x{}, y{}, w{}, h{};
x = sprite->FloatAttribute("x");
y = sprite->FloatAttribute("y");
w = sprite->FloatAttribute("w");
h = sprite->FloatAttribute("h");
clips.emplace_back(x, y, w, h, texture);
//
sprite = sprite->NextSiblingElement();
}
//
actions.emplace_back(new Action(clips, type, speed));
}
//
delete document;
}
void Enemy::SetAction(int type)
{
if (curAction != type)
{
curAction = type;
actions[curAction]->Play();
}
}
void Enemy::Move()
{
pos.x += moveDir.x * speed * DELTA;
pos.y += moveDir.y * speed * DELTA;
//
if(moveDir.x == -1)
rot.y = PI;
else
rot.y = 0;
}
void Enemy::AIPattern()
{
patternCounter += DELTA;
if (patternCounter < patternTime)
return;
//
curPattern = rand() % 4;
switch (curPattern)
{
case 0: // Down
moveDir = { 0, -1.0f };
SetAction(DOWN);
break;
case 1: // Right
moveDir = { +1.0f, 0 };
SetAction(RIGHT);
break;
case 2: // Up
moveDir = { 0, +1.0f };
SetAction(UP);
break;
case 3: // Left
moveDir = { -1.0f, 0 };
SetAction(RIGHT);
break;
default:
break;
}
patternCounter = 0;
}
void Enemy::Damage()
{
}
3. Game Scene
a. Camera Action ( Shake, Zoom ) 구현
a-1. Transform* mouseTF를 선언하여 마우스 우클릭 시 Camera로 mouse 위치 Follow
b-1. a-1 상태에서 마우스 좌클릭시 이펙트 출력 및 Camera 상태 초기화(Player Target Follow)
b. Enemy <-> Player->Bullet 간 충돌처리
더보기
#pragma once
#include "Object/GameObject/BackGround.h"
#include "Object/GameObject/Isaac.h"
#include "Object/GameObject/Enemy.h"
class EffectScene : public Scene
{
private:
Isaac* isaac;
BackGround* bg;
vector<Enemy*> enemies;
int enemyCount;
//
Transform* mouseTF;
bool isSnipe;
public:
EffectScene();
~EffectScene();
//
virtual void Update() override;
virtual void Render() override;
virtual void PostRender() override;
//
void InitScene();
//
void Func();
void Func1_SetTarget();
void Func2_FreeTarget();
void Func3_SnipeMode();
//
void SetMouseTF();
//
void Collision();
void CollisionBulletToEnemy();
};
/////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "EffectScene.h"
EffectScene::EffectScene()
:enemyCount(10), isSnipe(false)
{
InitScene();
}
EffectScene::~EffectScene()
{
delete mouseTF;
delete isaac;
delete bg;
//
for (auto enemy : enemies)
delete enemy;
enemies.clear();
}
void EffectScene::Update()
{
bg->Update();
isaac->Update();
//
for (auto enemy : enemies)
enemy->Update();
//
Collision();
//
SetMouseTF();
//
Func();
//
}
void EffectScene::Render()
{
bg->Render();
isaac->Render();
//
for (auto enemy : enemies)
enemy->Render();
}
void EffectScene::PostRender()
{
ImGui::Text("MousePos : %.3f, %.3f", MOUSE->GetMousePos().x, MOUSE->GetMousePos().y);
ImGui::Text("MouseTF : %.3f, %.3f", mouseTF->pos.x, mouseTF->pos.y);
//bg->PostRender();
isaac->PostRender();
}
void EffectScene::InitScene()
{
/* Set MouseTransform */
mouseTF = new Transform;
/* Set Effects */
EFFECT->Add("hit", 20, L"Textures/Isaac/Effect_Bullet_Hit.png", 10, 1, 0.05f, true);
EFFECT->Add("snipe", 1, L"Textures/Isaac/Effect_Bullet_Hit.png", 6, 2, 0.05f, true);
/* Set Objects */
isaac = new Isaac;
bg = new BackGround;
/* Set Enemy */
Enemy* enemy{};
Vector2 tmpPos = { -CENTER_X * 0.5f, CENTER_Y * 0.5f };
for (int i = 0; i < enemyCount; ++i)
{
tmpPos.x += 50.0f;
//
enemy = new Enemy;
enemy->SetPos(tmpPos);
enemy->isActive = true;
//
enemies.emplace_back(enemy);
}
/* Set Camera */
Vector2 bgLeftBottom = bg->GetSize() * -0.5f;
Vector2 bgRightTop = bg->GetSize() * 0.5f;
//
CAMERA->SetLeftBottom(bgLeftBottom);
CAMERA->SetRightTop(bgRightTop);
//
CAMERA->SetTarget((Transform*)(isaac->head));
//CAMERA->scale *= 1.6f;
}
void EffectScene::Func()
{
Func1_SetTarget();
Func2_FreeTarget();
Func3_SnipeMode();
}
void EffectScene::Func1_SetTarget()
{
if (KEY_DOWN(VK_F3))
{
CAMERA->SetTarget((Transform*)isaac->head);
Vector2 scale = { 1.0f, 1.0f };
CAMERA->SetScale(scale);
}
}
void EffectScene::Func2_FreeTarget()
{
if (KEY_DOWN(VK_F2))
{
CAMERA->SetTarget(nullptr);
Vector2 scale = { 1.0f, 1.0f };
CAMERA->SetScale(scale);
}
}
void EffectScene::Func3_SnipeMode()
{
if (KEY_DOWN(VK_RBUTTON))
{
isSnipe = true;
CAMERA->SetTarget(mouseTF);
//Vector2 scale = { 1.0f, 1.0f };
Vector2 scale = { 3.0f, 3.0f };
CAMERA->SetScale(scale);
}
}
void EffectScene::SetMouseTF()
{
if (!isSnipe)
return;
/* Mouse Screen Pos To World Pos */
// 화면 중심을 기준으로 하기 위해 Mouse위치 비율값에 - 0.5f
float screenRate_X = (MOUSE->GetMousePos().x / (float)WIN_WIDTH) - 0.5f;
float screenRate_Y = (MOUSE->GetMousePos().y / (float)WIN_HEIGHT) - 0.5f;
float scaledWidth = ((float)WIN_WIDTH / CAMERA->scale.x);
float scaledHeight = ((float)WIN_HEIGHT / CAMERA->scale.y);
Vector2 camOffset = isaac->head->pos;
mouseTF->pos.x = (scaledWidth * screenRate_X) + camOffset.x;
mouseTF->pos.y = (scaledHeight * screenRate_Y) + camOffset.y;
// mouseTF->pos = MOUSE->GetMousePos() - CAMERA->pos;
if (KEY_DOWN(VK_LBUTTON))
{
EFFECT->Play("snipe", mouseTF->pos);
CAMERA->ShakeStart(20.0f, 2.0f, 20.0f);
//
CAMERA->SetTarget((Transform*)isaac->head);
Vector2 scale = { 1.0f, 1.0f };
CAMERA->SetScale(scale);
isSnipe = false;
}
}
void EffectScene::Collision()
{
CollisionBulletToEnemy();
}
void EffectScene::CollisionBulletToEnemy()
{
for (auto enemy : enemies)
{
if (!enemy->isActive)
//
continue;
//
for (auto bullet : isaac->bullets)
{
if (!bullet->isActive)
continue;
//
if (enemy->collider->IsCollision(bullet->GetCollider()))
{
bullet->Hit();
enemy->Damage();
return;
}
}
}
}
'DX11 2D Game Programming' 카테고리의 다른 글
DX11_2020_0814_금_Store_FileIO(tsv)_Button (0) | 2020.08.14 |
---|---|
DX11_2020_0812_화_OutLine_PSShader (0) | 2020.08.12 |
DX11_2020_0807_금_Camera (0) | 2020.08.07 |
DX11_2020_0806_목_FX (0) | 2020.08.05 |
DX11_2020_0730_목_Animation(XML) (0) | 2020.07.30 |