JumpKing(4)

JUSTICE_DER·2024년 2월 8일

WinAPI

목록 보기
8/9

rigid body

점프킹

  • 겉보기상
    ㄴ공주 만나서 fade out 하는 엔딩
    ㄴUI - 굳이 - Game시작은 있어도 좋을 듯
    (그냥 단순히 Press Sapce to Start)
    ㄴ점프 위치 미리표시? - 점프 잔상 남기기?
    ㄴ점프 게이지? - 35단계임을 알리기
    ㄴ점프 수치조정 UI만들기?

  • 코드상
    ㄴeffective cpp
    ㄴexcel 에 적어놓은것들
    ㄴnamespace 등

rigid 안될 경우 비상책

cpp

#include "stdafx.h"
#include "Player.h"

HRESULT Player::init(void)
{
	// 애니메이션 추가. 상태에 따라 전환할 이미지들.
	_pWalk = IMAGEMANAGER->addFrameImage("걷기", "Resources/Images/Walk.bmp", 124*ZOOM, 54*ZOOM, 4, 2, true, RGB(255, 0, 255));		// 31 x 27
	_pJump = IMAGEMANAGER->addFrameImage("점프", "Resources/Images/Jump.bmp", 90*ZOOM, 64*ZOOM, 3, 2, true, RGB(255, 0, 255));		// 30 x 32
	_pStatus = IMAGEMANAGER->addFrameImage("상태", "Resources/Images/Status.bmp", 87*ZOOM, 56*ZOOM, 3, 2, true, RGB(255, 0, 255));	// 29 x 28	// 최대 : 31 x 32

	// px, py는 플레이어 사각형의 실제 위치를 의미, 시작위치
	_px = WINSIZE_X / 2;
	_py = WINSIZE_Y / 2;

	// px, py를 중앙으로 하는 캐릭터 최대크기의 사각형을 생성.
	_rcPlayer = RectMakeCenter(_px, _py, P_WIDTH, P_HEIGHT);

	// _probeY - 실제로 충돌을 판단할 개체
	// _probeY는 최종적으로 _pWalk의 바닥이 된다. 맨 바닥으로 둔다.
	//_probeY = _py + P_HEIGHT;
	//
	//_probeLX = _px - P_WIDTH / 2;
	//_probeRX = _px + P_WIDTH / 2;

	isGround = false;
	isHit = false;
	isCharge = false;
	isLeft = false;
	isIdle = true;


	tIsInAirStart = chrono::system_clock::now();

	return S_OK;
}

void Player::release(void)
{
	SAFE_DELETE(_pWalk);
}

void Player::update(void)
{
	// 중앙이 이동한다.
	/// 좌 우 이동.
	if (KEYMANAGER->isStayKeyDown(VK_RIGHT))
	{
		if (!isJump)
		{
		isLeft = false;
		isIdle = false;
		}
		if (isGround && !isCharge )
		{
			_px += 4.0f;

			_walkCnt++;
			if (_walkCnt % 7 == 0)
			{
				_walkIdx++;
				if (_walkIdx > 4)
				{
					_walkIdx = 0;		// 최소로 다시 
				}
			}
			IMAGEMANAGER->findImage("걷기")->setFrameX(_walkIdx);
		}
	}
	if (KEYMANAGER->isStayKeyDown(VK_LEFT))
	{
		if (!isJump)
		{
			isLeft = true;
			isIdle = false;
		}
		if (isGround && !isCharge )
		{
			_px -= 4.0f;

			_walkCnt++;
			if (_walkCnt % 7 == 0)
			{
				_walkIdx--;
				if (_walkIdx < 0)
				{
					_walkIdx = 4;		// 최대로 다시 
				}
			}
			IMAGEMANAGER->findImage("걷기")->setFrameX(_walkIdx);
		}
	}
	// 방향
	_pWalk->setFrameY(isLeft);
	_pJump->setFrameY(isLeft);
	_pStatus->setFrameY(isLeft);

	if(KEYMANAGER->isOnceKeyUp(VK_RIGHT) || KEYMANAGER->isOnceKeyUp(VK_LEFT))	
	{
		isIdle = true;
		IMAGEMANAGER->findImage("상태")->setFrameX(0);
		IMAGEMANAGER->findImage("상태")->setFrameY(isLeft);
	}

	if (KEYMANAGER->isStayKeyDown(VK_SPACE) && isGround)
	{
		if (!isCharge)
		{
			tChargeStart = chrono::system_clock::now();
		}

		isCharge = true;

		IMAGEMANAGER->findImage("점프")->setFrameX(0);
		IMAGEMANAGER->findImage("점프")->setFrameY(isLeft);
	}
	
	// 안의 내용물을 함수로 만들어 일정 초 이상이면 강제점프 구현할 수 있을 듯
	if (KEYMANAGER->isOnceKeyUp(VK_SPACE) && isCharge)
	{
		// 여기서 점프 함수가 들어와야 할 듯 
		isCharge = false;

		_pJumpPower = (std::chrono::duration_cast<std::chrono::milliseconds>(chrono::system_clock::now() - tChargeStart)).count();

		///_py -= 500.0f; 이게 실질적으로 점프시켜줬던 것..

		IMAGEMANAGER->findImage("점프")->setFrameX(1);
		IMAGEMANAGER->findImage("점프")->setFrameY(isLeft);

		cout << "aaaaaaaaaaaaaaaaa";
		isJump = true;
	}

	/// 아래 2개는 없어져야 함.
	if (KEYMANAGER->isStayKeyDown(VK_UP))
	{
		_py -= 130.0f;
	}
	if (KEYMANAGER->isStayKeyDown(VK_DOWN))
	{
		_py += 30.0f;
	}

	_probeLX = _px - P_WIDTH / 2;
	_probeRX = _px + P_WIDTH / 2;
	_probeFOOT = _py + P_HEIGHT/2; // 그냥 갱신되는 값을 의미하는 건가?? - probeY의 위치는 항상 밑바닥이어야 함
	_probeHEAD = _py - P_HEIGHT / 2;
	_rcPlayer = RectMakeCenter(_px, _py, P_WIDTH, P_HEIGHT);

	/// _probeFOOT - 30 으로 해야만 땅에 안 박힘?? - 항상 안쪽부터 하자 . 그렇지 않으면 자석 - 함수화하는게?
	//for (int i = _probeFOOT; i > _probeFOOT- P_HEIGHT/2-10; i--)
	for (int i= _probeFOOT - P_HEIGHT / 2 - 10; i < _probeFOOT + 10; i++)
	{
		// px라는 rc의 중앙값, 그리고 현재 비교중인 i값을 가져와 pixel을 검출한다.
		COLORREF pixelColor = GetPixel(IMAGEMANAGER->findImage("MapMaskPart")->getMemDC(), _px, i);

		COLORREF pixelColor2 = GetPixel(IMAGEMANAGER->findImage("MapMaskPart")->getMemDC(), _px - 25, i);
		COLORREF pixelColor3 = GetPixel(IMAGEMANAGER->findImage("MapMaskPart")->getMemDC(), _px + 25, i);


		//if (pixelColor == RGB(255,0,255))
		if (pixelColor == RGB(255,0,255) && pixelColor2 == RGB(255, 0, 255) && pixelColor3 == RGB(255, 0, 255))
		{			
			///_pInAirSec
			if (isGround)
			{
				tIsInAirStart = chrono::system_clock::now();
			}
			isGround = false;
		}
		else if (pixelColor == RGB(0, 0, 0) || pixelColor2 == RGB(0, 0, 0) || pixelColor3 == RGB(0, 0, 0)) // || pixelColor2 == RGB(0, 0, 0))
		{
			//if (isJump) isJump = false;

			isGround = true;

			/// 이거 일단 종료
			//isJump = false; _pJumpPower = 0;

			i <= _probeFOOT ? _py -= (_probeFOOT - i) : _py += (i-_probeFOOT);
			//cout << "i  :" << i << "  _probeFoot : " << _probeFOOT << "\n";
			break;																//break가 없어서 그랬다... ㅎㅎ
		}
		else if(pixelColor == RGB(255,0,0) || pixelColor2 == RGB(255, 0, 0) || pixelColor3 == RGB(255, 0, 0)) // || pixelColor2 == RGB(255, 0, 0))	// 빨강 or 회색 = 미끄러짐 - 추후 수정?
		{
			IMAGEMANAGER->findImage("점프")->setFrameX(2);
			_px -= 10;
		}
	}

	//Rectangle(getMemDC(), _px - 25 - 4, _probeHEAD + P_HEIGHT / 2 - 10, _px -25+ 4, _probeHEAD);

	/// _probeHEAD
	for (int i = _probeHEAD + P_HEIGHT / 2 - 10; i > _probeHEAD ; i--) /// 굳이 붙을 필요가 없다. 따라서 그냥 _probeHEAD 까지 - foot은 어쩔 수 없는 경우가 있었고, 바닥에 붙어야만 했다.
	{
		// px라는 rc의 중앙값, 그리고 현재 비교중인 i값을 가져와 pixel을 검출한다.
		COLORREF pixelColor = GetPixel(IMAGEMANAGER->findImage("MapMaskPart")->getMemDC(), _px, i);

		COLORREF pixelColor2 = GetPixel(IMAGEMANAGER->findImage("MapMaskPart")->getMemDC(), _px-25, i);
		COLORREF pixelColor3 = GetPixel(IMAGEMANAGER->findImage("MapMaskPart")->getMemDC(), _px+25, i);

		/// 중력
		if (pixelColor == RGB(0, 0, 0) || pixelColor2 == RGB(0, 0, 0) || pixelColor3 == RGB(0, 0, 0))
		{
			//_py += GRAVITY;

			i >= _probeHEAD ? _py += (i - _probeHEAD) : _py -= (_probeHEAD - i);
			//isJump = false;
			break;
		}
	}

	/// _probeLX, _probeRX
	for (int i = _probeLX + 10; i > _probeLX; i--) /// 굳이 붙을 필요가 없다. 
	{
		COLORREF pixelColor = GetPixel(IMAGEMANAGER->findImage("MapMaskPart")->getMemDC(), i, _py+20);

		/// 중력
		if (pixelColor == RGB(0, 0, 0))
		{
			//_py += GRAVITY;

			i >= _probeLX ? _px += (i - _probeLX) : _py -= (_probeLX - i);

			cout << "PROBE LX LX";
			break;
		}
	}
	for (int i = _probeRX - 10; i < _probeRX; i++) /// 굳이 붙을 필요가 없다. 
	{
		COLORREF pixelColor = GetPixel(IMAGEMANAGER->findImage("MapMaskPart")->getMemDC(), i, _py + 20);

		/// 중력
		if (pixelColor == RGB(0, 0, 0))
		{
			//_py += GRAVITY;

			i <= _probeRX ? _px -= (_probeRX - i) : _px += (i - _probeRX);

			cout << "PROBE RX RX";
			break;
		}
	}

	//cout << "isGround?? : " << isGround << "\n";
	

	_pInAirSec = (std::chrono::duration_cast<std::chrono::milliseconds>(chrono::system_clock::now() - tIsInAirStart)).count();
	if (!isGround && !isJump)
	{
		/* - 이런식으로 잘게 쪼개서 10프레임마다 진행되도록 어떻게?
		static int jum = 0;
		static bool isPeak = false;

		_pInAirSec = (std::chrono::duration_cast<std::chrono::milliseconds>(chrono::system_clock::now() - tIsInAirStart)).count();
		//_py += GRAVITY * (_pInAirSec/300) -_pJumpPower/100;
		if (jum <= _pJumpPower && !isPeak)
		{
			jum++;
		}
		else
		{
			jum--;
			if (jum <= 0)
			{
				jum = 0;
			}
		}
		*/
		// 점프는 하는데.. y값이 서서히 변하게부터 어떻게 해보자..
		_py += GRAVITY * (_pInAirSec / 200);

		// isJump는 점프가 다 완료한 후에만 false로 변환  
		// JumpPower도 0으로 전환							- 일단 둘 다 그냥 땅에 닿는경우 초기화..
	}

	// 여기부분 수정
	if (isJump)
	{
		/* 원본
		_py += GRAVITY * (_pInAirSec / 200);

		int dx, dy;
		_pJumpPower >= MAX_JUMP ? _pJumpPower = MAX_JUMP : _pJumpPower;
		//(_pJumpPower / 10) >= MAX_JUMP ? dy = MAX_JUMP : dy = (_pJumpPower / 10);

		dy = (_pJumpPower / 10);

		_py -= dy;				/// _pJumpPower = milliseconds  765 735
		_py += GRAVITY;

		_pJumpPower -= 10;

		if (_pJumpPower <= 0)
		{
			isJump = false;
		}
		*/

		_pJumpPower >= MAX_JUMP ? _pJumpPower = MAX_JUMP : _pJumpPower;
		//(_pJumpPower / 10) >= MAX_JUMP ? dy = MAX_JUMP : dy = (_pJumpPower / 10);

		int jj = _pJumpPower;
		dy = jj / 20;

		_py -= dy;				/// _pJumpPower = milliseconds  765 735
		_py += GRAVITY * (_pInAirSec / 200)/ 2;


		if (isLeft) dx = -5;
		else dx = 5;
		_px += dx;

		_pJumpPower -= 5;

		if (_pJumpPower <= 0)
		{
			isJump = false;
		}
	}

	chrono::duration<double>s = chrono::system_clock::now() - SYS_TIME;
			// 여기서 초기화해줘야만 함

	//cout << _pJumpPower;
	if (isJump) cout << _pJumpPower << " : " << _pJumpPower / 10 << "\n";
}


/*
	bool isGround;	// 공중인가 땅인가
	bool isHit;		// 위든 옆이든 맞았는가 // 위면 바로 떨어지기, 옆이면 반사해서 살짝위로 갔다가 반대로 떨어기지
	bool isCharge;
	bool isIdle;	// 중앙

	bool isLeft;	
*/
// 3가지 애니메이션만 있어야 할 듯
void Player::render(void)	
{
	if (isGround && !isCharge && !isIdle)
	{
		_pWalk->frameRender(getMemDC(), _rcPlayer.left, _rcPlayer.top + 10);
	}
	else if ((isGround && isCharge) || !isGround)			// isHit 제외, isIdle 제외 - isLeft와 같이 사용해서 점프방향 정할거임.
	{
		_pJump->frameRender(getMemDC(), _rcPlayer.left, _rcPlayer.top-3);
	}
	else if (isIdle) // || isHit - 엎드리기도 있다. - 최고높이 기록?
	{
		_pStatus->frameRender(getMemDC(), _rcPlayer.left, _rcPlayer.top+10);
	}

	if (KEYMANAGER->isToggleKeyDown(VK_F1))
	{
		Rectangle(getMemDC(), _rcPlayer.left, _rcPlayer.top, _rcPlayer.right, _rcPlayer.bottom);

		// PROBE Foot
		Rectangle(getMemDC(), _px-4, _probeFOOT + 0, _px + 4, _probeFOOT - P_HEIGHT / 2 + 10);
		Rectangle(getMemDC(), _px - 25 -4, _probeFOOT + 0, _px - 25 + 4, _probeFOOT - P_HEIGHT / 2 + 10);
		Rectangle(getMemDC(), _px + 25 -4, _probeFOOT + 0, _px + 25 + 4, _probeFOOT - P_HEIGHT / 2 + 10);

		Rectangle(getMemDC(), _probeLX - 3, _py +20, _probeLX + 3, _py+26);
		Rectangle(getMemDC(), _probeRX - 3, _py +20, _probeRX + 3, _py+26);

		Rectangle(getMemDC(), _px - 4, _probeHEAD + P_HEIGHT / 2 - 10, _px + 4, _probeHEAD);
		Rectangle(getMemDC(), _px - 25 - 4, _probeHEAD + P_HEIGHT / 2 - 10, _px -25+ 4, _probeHEAD);
		Rectangle(getMemDC(), _px + 25 - 4, _probeHEAD + P_HEIGHT / 2 - 10, _px +25+ 4, _probeHEAD);
		
	}
}

void Player::SetPlayerY(float y)
{
	_py = y;
}

float Player::GetPlayerY()
{
	return _py;
}

h

#pragma once
#include "GameNode.h"

#define SPD		4
#define P_WIDTH 31 * ZOOM
#define P_HEIGHT 32 * ZOOM

const float GRAVITY = 4.0f;
const float MAX_JUMP = 450.0f;

struct stCollision
{
	RECT rc;
	bool bBlockBottom = true;
	
	// 여러 bool 값들.
	bool sdaf = false;
};


class Player : public GameNode
{
	// 이미지 넣어두기
	// 소리 넣어두기
	// 출력 적절히 하게 하기

// ImageManager 대신 사용.
private:
	
	/// Image
	GImage* _pWalk;	
	GImage* _pJump;
	GImage* _pStatus;	

	/// RECT / x, y / probe
	RECT	_rcPlayer;

	int		_probeFOOT;
	int		_probeHEAD;
	int		_probeLX;
	int		_probeRX;

	float	_px, _py;

	int dx = 0;	// x 변화량 - 이동량을 바탕으로 애니메이션을 변환
	int dy = 0;

	/// Animation Var
	int		_walkCnt = 0;
	int		_walkIdx = 0;

	/// Status
	bool isGround;	// 공중인가 땅인가
	bool isHit;		// 위든 옆이든 맞았는가 // 위면 바로 떨어지기, 옆이면 반사해서 살짝위로 갔다가 반대로 떨어기지
	bool isCharge;
	bool isLeft;	// 0 = right / 1 = left / 2 = mid
	bool isJump;	// 그냥 !isGround의 떨어지는 것과 계산적으로만 구분하기 위함.

	bool isIdle;

	/// Time
	chrono::system_clock::time_point tChargeStart;
	chrono::system_clock::time_point tIsInAirStart;

	long long _pJumpPower;
	long long _pInAirSec;


public:
	HRESULT init(void);
	void release(void);
	void update(void);
	void render(void);

	float GetPlayerY();
	void SetPlayerY(float y);

	Player() { };
	~Player() { };
};

profile
Time Waits for No One

0개의 댓글