본문으로 바로가기

DX11_2020_0730_목_Animation(XML)

category DX11 2D Game Programming 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));
}

'DX11 2D Game Programming' 카테고리의 다른 글

DX11_2020_0807_금_Camera  (0) 2020.08.07
DX11_2020_0806_목_FX  (0) 2020.08.05
DX11_2020_0729_수_Animation  (0) 2020.07.29
DX11_2020_0728_화_Collider Offset  (0) 2020.07.28
DX11_2020_0727_월_Collision(OBB_Circle)  (0) 2020.07.27