DX11 2D Game Programming
DX11_2020_0730_목_Animation(XML)
HI2
2020. 7. 30. 17:31
200730_Animation(XML).zip
1.81MB
0. Sprite Atals 생성 및 설정, Data Load & Animation 생성
a. [Texture Packer]를 사용하여 개별 이미지 파일을 하나의 Sprite Atlas로 만들고,
각각 이미지의 정보가 담긴 XML 파일 생성
b. XML 파일을 HTML 문법을 이용하여 수정
c. Animation을 사용하는 class에 XML data를 Load하고, Animation(Clip->Action)을 생성하는 함수 구현
더보기
void Player::LoadXMLAndCreateActions(string file)
{
XmlDocument* document = new XmlDocument();
document->LoadFile(file.c_str());
//
XmlElement* textureAtlas = document->FirstChildElement();
XmlElement* action = textureAtlas->FirstChildElement();
//
for (; action != nullptr; action = action->NextSiblingElement())
{
/* declair temp clip values */
vector<Action::Clip> clips{};
Action::Type repeatType{};
float speed = 0.1f; // default = 0.1f;
// Set loop And pingpong
bool loop = action->IntAttribute("loop");
bool pingpong = action->IntAttribute("pingpong");
if (loop && pingpong)
repeatType = Action::Type::LOOPANDPINGPONG;
else if (!loop && !pingpong)
repeatType = Action::Type::END;
else
{
if (loop)
repeatType = Action::Type::LOOP;
else // if (pingpong)
repeatType = Action::Type::PINGPONG;
}
XmlElement* sprite = action->FirstChildElement();
for (; sprite != nullptr; sprite = sprite->NextSiblingElement())
{
int x = sprite->IntAttribute("x");
int y = sprite->IntAttribute("y");
int w = sprite->IntAttribute("w");
int h = sprite->IntAttribute("h");
clips.emplace_back(x, y, w, h);
}
Action* tmpAction = new Action(clips, repeatType, speed);
actions.emplace_back(tmpAction);
}
}
1. Player class
- move, jump, attack 구현
더보기
#pragma once
class Player
{
public:
enum Type
{
ATTACK,
IDLE,
JUMP,
WALK,
};
public:
Sprite* sprite;
Collider* collider;
//
float moveSpeed;
float gravity;
float jumpPower;
float forceOfJump;
//
float velocity;
float accelate;
float decelerate;
bool isJump;
bool isAttack;
//
float groundLevel;
//
vector<Action*> actions;
Type curAction;
//
Vector2 dir;
public:
Player();
~Player();
//
void Update();
void Render();
void PostRender();
//
void Control();
void Move();
void Jump();
void Attack();
//
void LoadXMLAndCreateActions(string file);
//
void SetAction(int value);
void SetAnims();
void SetIdle();
};
/////////////////////////////////////////////////////////////////////////////////////////////
#include "Framework.h"
#include "Player.h"
Player::Player()
: moveSpeed(500.0f), velocity(0), accelate(5.0f), decelerate(3.0f),
gravity(-980.0f), jumpPower(0.0f), forceOfJump(300.0f), isJump(false),
curAction(IDLE),
groundLevel(0), dir(1.0f, 0)
{
/* Set Sprite */
sprite = new Sprite(L"Textures/Knight.png");
// Set Anims
LoadXMLAndCreateActions("Textures/Knight_data.xml");
// Set Anim Events
SetAnims();
// Set Sprite pos
sprite->pos = { WIN_WIDTH * 0.5f, WIN_HEIGHT * 0.5f };
/* Set Collider */
Vector2 colliderSize(60.0f, 80.0f);
collider = new RectCollider({ colliderSize }, (Transform*)sprite);
// Set Collider Offset
collider->SetOffset({ 0, -20.0f });
//
groundLevel = 100.0f;
}
Player::~Player()
{
delete sprite;
sprite = nullptr;
//
delete collider;
collider = nullptr;
//
for (auto action : actions)
delete action;
actions.clear();
}
void Player::Update()
{
Control();
//
actions[curAction]->Update();
sprite->SetAction(actions[curAction]->GetCurClip());
//
sprite->Update();
collider->Update();
//
}
void Player::Render()
{
sprite->Render();
collider->Render();
}
void Player::PostRender()
{
ImGui::Text("[Player]");
ImGui::SliderFloat2("Pos", (float*)&(sprite->pos), 0, WIN_WIDTH);
ImGui::SliderFloat2("Scale", (float*)&(sprite->scale), 0, WIN_WIDTH);
ImGui::Text("Dir : %f, %f", dir.x, dir.y);
ImGui::Text("isJump : %d", isJump);
}
void Player::Control()
{
Attack();
Jump();
Move();
}
void Player::Move()
{
if (KEY_PRESS(VK_RIGHT))
{
sprite->pos.x += moveSpeed * DELTA;
dir.x = 1.0f;
if (!isJump && !isAttack)
SetAction(WALK);
}
if (KEY_PRESS(VK_LEFT))
{
sprite->pos.x -= moveSpeed * DELTA;
dir.x = -1.0f;
if (!isJump && !isAttack)
SetAction(WALK);
}
//
sprite->scale.x *= dir.x;
if (KEY_UP(VK_RIGHT) || KEY_UP(VK_LEFT))
{
if (!isJump && !isAttack)
SetAction(IDLE);
}
}
void Player::Jump()
{
if (KEY_DOWN(VK_LCONTROL))
{
isJump = true;
SetAction(JUMP);
jumpPower = 800.0f;
}
jumpPower += gravity * DELTA;
sprite->pos.y += jumpPower * DELTA;
//
float col_Height_half = (collider->GetSize().y * 0.5f);
float col_Bottom = sprite->pos.y - col_Height_half;
if (col_Bottom < groundLevel)
{
if(isJump)
SetAction(IDLE);
sprite->pos.y = groundLevel + col_Height_half;
jumpPower = 0;
isJump = false;
}
}
void Player::Attack()
{
if (KEY_DOWN(VK_SPACE))
{
isAttack = true;
SetAction(ATTACK);
}
}
void Player::LoadXMLAndCreateActions(string file)
{
// 생략
}
void Player::SetAction(int value)
{
if (curAction != value)
{
curAction = (Type)value;
actions[curAction]->Play();
}
}
void Player::SetIdle()
{
SetAction(IDLE);
if (isAttack)
isAttack = false;
}
void Player::SetAnims()
{
// 인자 있는 int Func 세팅
//actions[ATTACK]->SetEndEvent(bind(&Player::SetAction, this, placeholders::_1), (int)IDLE);
// 인자 없는 void Func 세팅
actions[ATTACK]->SetEndEvent(bind(&Player::SetIdle, this));
}