Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


[dx10/11] Weird problem with gigantic texture when drawing paddle


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
No replies to this topic

#1 molehill mountaineer   Members   -  Reputation: 595

Like
0Likes
Like

Posted 12 June 2013 - 11:52 AM

Hi folks,

 

I'm working on a simple 2D pong/arkanoid game in dx11 so I can learn the API (which is much more difficult than I had anticipated!).

 

To render the objects I'm creating quads and putting a simple texture on them - this worked fine in my previous version of the project where the Game class has a few game objects (bricks, balls & 2 paddles) and renders them in the Game::Draw() method.

 

In this newer version, I've introducted a  class "player" which contains the balls a player has, the paddle he's controlling and a number of powerups. So naturally I wanted to move the code for rendering the paddle and balls to this new class since it's the owner of these objects. The idea being that Game::Draw() then calls humanPlayer::Draw() and AIPlayer::Draw() which both inherit this method from the base class player.

 

Unfortunately the paddle I'm drawing is HUGE and for some reason my game now runs at a speed of 1FPS. This is really weird considering that the code for drawing the paddle is exactly the same in the version that works and the worldViewProjection matrix I'm using to draw the paddle is as well. When I uncomment the old code it still works (albeit very slowly).

 

This is the code that works (with severe performance issues) in Game::Draw()

XMMATRIX view = XMMatrixIdentity();
XMMATRIX projection = XMMatrixOrthographicOffCenterLH(0.0f, SOLIPSIST.getWindowWidth(), 0.0f,     SOLIPSIST.getWindowHeight(), 0.1f, 100.0f);

XMMATRIX viewProjection = XMMatrixMultiply(view, projection);
XMMATRIX world;
XMMATRIX wvp;

//----------------player paddle matrices-------------------
Paddle* m_pPlayerPaddle = m_pHumanPlayer->getPaddle();

world = m_pPlayerPaddle->getBitmap()->getWorldMatrix();
wvp = XMMatrixMultiply(world, viewProjection);
		
//transpose wvp to feed to shader
wvp = XMMatrixTranspose(wvp);

m_pParentProject->getGraphics()->getContext()->UpdateSubresource(m_pConstantBuffer, NULL, NULL, &wvp, NULL, NULL);

m_pParentProject->getGraphics()->getContext()->VSSetConstantBuffers(0, 1, &m_pConstantBuffer);

	


//draw the paddle
m_pPlayerPaddle->getBitmap()->loadRenderSettings();
m_pPlayerPaddle->draw();

which results in:

30wxt3c.jpg

 

 

This is the code that doesn't in Player::Draw()

void Player::draw(XMMATRIX& p_viewProjection)
{
	if(m_bInitialized)
	{
		XMMATRIX world;
		XMMATRIX wvp; //world*view*projection
		//draw paddle
		if(m_pPaddle != NULL)
		{
			world = m_pPaddle->getBitmap()->getWorldMatrix();
			wvp = XMMatrixMultiply(world, p_viewProjection);

			//transpose to feed to shader
			XMMatrixTranspose(wvp);			
			m_pGraphics->getContext()->UpdateSubresource(m_pConstantBuffer, NULL, NULL, &wvp, NULL, NULL);
			m_pGraphics->getContext()->VSSetConstantBuffers(0, 1, &m_pConstantBuffer);

			m_pPaddle->getBitmap()->loadRenderSettings();
			m_pPaddle->draw();
		}

which results in:

 

10rmrzk.png

 

 

Obviously I'm making some big mistakes here - anybody care to enlighten me? Also any good articles or advice on how to properly debug memory leaks and finetune performance would be welcome.

 

 

 

EDIT: These are the full source files for Player & Game. You'll see a few things like "SOLIPSIST" because I'm making a little framework so 

I can use the code for my next game. Maybe that was a mistake since I clearly need some more DirectX practice

 

Player.cpp

#include "Player.h"


Player::Player()
	: m_pPaddle(NULL),
	  m_pPowerUpChain(NULL),
	  m_bInitialized(false),
	  m_ballsLeft(3)
{
}


Player::~Player()
{
	cleanup();
}

void Player::cleanup()
{
	if(m_pPaddle)
		delete m_pPaddle;

	if(m_pPowerUpChain)
		delete m_pPowerUpChain;

	if(m_balls.size() != 0)
	{
		std::vector<Ball*>::iterator it = m_balls.begin();
		while(it != m_balls.end())
		{
			delete *it;
			++it;
		}

		m_balls.clear();
	}

}




void Player::draw(XMMATRIX& p_viewProjection)
{
	if(m_bInitialized)
	{
		XMMATRIX world;
		XMMATRIX wvp; //world*view*projection
		//draw paddle
		if(m_pPaddle != NULL)
		{
			world = m_pPaddle->getBitmap()->getWorldMatrix();
			wvp = XMMatrixMultiply(world, p_viewProjection);

			//transpose to feed to shader
			XMMatrixTranspose(wvp);			
			m_pGraphics->getContext()->UpdateSubresource(m_pConstantBuffer, NULL, NULL, &wvp, NULL, NULL);
			m_pGraphics->getContext()->VSSetConstantBuffers(0, 1, &m_pConstantBuffer);

			m_pPaddle->getBitmap()->loadRenderSettings();
			m_pPaddle->draw();
		}
	    //draw balls
		if(m_balls.size() != 0)
		{
			std::vector<Ball*>::iterator it = m_balls.begin();

			for(it; it != m_balls.end(); ++it)
			{
				if((*it) != NULL)
				{
					(*it)->getBitmap()->loadRenderSettings();


					world = (*it)->getWorldMatrix();
					wvp = XMMatrixMultiply(world, p_viewProjection);

					//transpose to feed to shader
					wvp = XMMatrixTranspose(wvp);

					m_pGraphics->getContext()->UpdateSubresource(m_pConstantBuffer, NULL, NULL, &wvp, NULL, NULL);
					m_pGraphics->getContext()->VSSetConstantBuffers(0,1,&m_pConstantBuffer);

					//draw ball
					(*it)->draw();
				}
			}
		}
	}
}



void Player::tick(float p_dtime)
{
	if(m_bInitialized)
	{
		m_pPaddle->tick(p_dtime);

		for(std::vector<Ball*>::iterator ballIt = m_balls.begin(); 
			ballIt != m_balls.end(); ++ballIt)
		{
			(*ballIt)->tick(p_dtime);
		}
	}
}



Paddle* Player::getPaddle()
{
	return m_pPaddle;
}


PowerUpChain* Player::getPowerUpChain()
{
	return m_pPowerUpChain;
}

std::vector<Ball*>& Player::getBalls()
{
	return m_balls;
}

unsigned short Player::getScore()
{
	return m_score;
}

unsigned short Player::getReserveBallCount()
{
	return m_ballsLeft;
}
#include "PongPrototype.h"
#include "defines.h"

PongPrototype::PongPrototype()
	: m_pHumanPlayer(NULL),
	  m_pAIPlayer(NULL),
	  m_pConstantBuffer(NULL),
	  m_pSpriteBatcher(NULL),
	  m_enemyScore(0),
	  m_playerScore(0)
{
}


PongPrototype::~PongPrototype()
{
	cleanup();
}


void PongPrototype::cleanup()
{
	//delete paddles
	if(m_pHumanPlayer)
		delete m_pHumanPlayer;
	if(m_pAIPlayer)
		delete m_pAIPlayer;

	////delete balls
	//std::vector<Ball*>::iterator ballIt = m_balls.begin();
	//for(ballIt; ballIt != m_balls.end(); ++ballIt)
	//{
	//	if(*ballIt != NULL)
	//	{
	//		delete *ballIt;
	//	}
	//}
	//m_balls.clear();


	//delete remaining bricks
	std::vector<PowerupBrick*>::iterator brickIt = m_bricks.begin();
	for(brickIt; brickIt != m_bricks.end(); ++brickIt)
	{
		if(*brickIt != NULL)
		{
			delete *brickIt;
		}
	}
	m_bricks.clear();


	//delete constantbuffer (used to interact with shader)
	if(m_pConstantBuffer)
		m_pConstantBuffer->Release();


	if(m_pSpriteBatcher)
		delete m_pSpriteBatcher;
	
}




bool PongPrototype::initialize(Graphics* p_graphics)
{

	m_pSpriteBatcher = new SpriteBatcher(p_graphics);

	//setup constant buffer (to feed to shader)
	D3D11_BUFFER_DESC bufferDescriptor;
	ZeroMemory(&bufferDescriptor, sizeof(bufferDescriptor));
	bufferDescriptor.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bufferDescriptor.Usage = D3D11_USAGE_DEFAULT;
	bufferDescriptor.ByteWidth = sizeof(XMMATRIX);

	m_pParentProject->getGraphics()->getDevice()->CreateBuffer(&bufferDescriptor, NULL, &m_pConstantBuffer);



	//scene positions for paddles
	XMFLOAT2 position1((float)SOLIPSIST.getWindowWidth() / 2 ,50.0f);
	XMFLOAT2 position2((float)SOLIPSIST.getWindowWidth() / 2, (float)SOLIPSIST.getWindowHeight() - 50);



	m_pHumanPlayer = new HumanPlayer();
	if(!m_pHumanPlayer->initialize(m_pParentProject->getGraphics(),
									 m_pConstantBuffer,
									 m_pSpriteBatcher,
									 position1))
	{
		m_pParentProject->log(_T("could not initialize human player object!"));
		return false;
	}

	m_pAIPlayer = new AIPlayer();
	if(!m_pAIPlayer->initialize(m_pParentProject->getGraphics(),
								m_pConstantBuffer,
								m_pSpriteBatcher,
								position2))
	{
		m_pParentProject->log(_T("could not initialize AI player object!"));
		return false;
	}

	//-------------------------------------INITIALIZE PADDLES---------------------------------
	////initialize player paddle
	//m_pPlayerPaddle = new Paddle();
	//if(!m_pPlayerPaddle->initialize(p_graphics, _T("Graphics/Sprites/playerPaddle.dds")))
	//	return false;
	//else //paddle initialized, place in scene
	//{
	//	m_pPlayerPaddle->move(position1);
	//	m_pPlayerPaddle->setFriendly(true);
	//}

	////initialize enemy paddle
	//m_pEnemyPaddle = new Paddle();
	//if(!m_pEnemyPaddle->initialize(p_graphics, _T("Graphics/Sprites/enemyPaddle.dds")))
	//	return false;
	//else
	//{
	//	m_pEnemyPaddle->move(position2);
	//	m_pEnemyPaddle->setFriendly(false);
	//}
	//-----------------------------------------------------------------------------------------
	//-------------------------------------INITIALIZE BALLS------------------------------------
	//position1.y += 50;
	//position2.y -= 50;
	//Ball* playerBall = new Ball();
	//playerBall->setFriendly(true);

	//Ball* enemyBall = new Ball();
	//enemyBall->setFriendly(false);

	//player ball initialization
	/*
	//initialize bitmap
	m_pBitmap = new Sprite(p_graphics);
	if(!m_pBitmap->initialize(p_texture))
		return false;
	*/
	
	//add player ball texture to sprite batcher
	//if(!m_pSpriteBatcher->addSprite(_T("playerBall"),  _T("Graphics/Sprites/playerBall.dds")))
	//	return false;
	//else
	//{
	//	playerBall->setSprite(*(m_pSpriteBatcher->getSprite(_T("playerBall"))));
	//	playerBall->initialize();
	//	playerBall->move(position1); //position on map
	//	playerBall->moveTowards(position2);
		/*//------------------------set direction (DEBUG STUFF)----------------------------
		XMFLOAT2 ballDirection; 
		ballDirection.x = 0;
		ballDirection.y = 300;
		m_pPlayerBall->moveTowards(ballDirection);
		//-----------------------------------------------------------------------------------*/
	//}


	////enemy ball initialization
	//if(!m_pSpriteBatcher->addSprite(_T("enemyBall"),  _T("Graphics/Sprites/enemyBall.dds")))
	//	return false;
	//else
	//{
	//	enemyBall->setSprite(*(m_pSpriteBatcher->getSprite(_T("enemyBall"))));
	//	enemyBall->initialize();
	//	enemyBall->move(position2);
	//	//------------------------set direction (DEBUG STUFF)----------------------------
	//	enemyBall->moveTowards(position1); //move enemy ball towards player
	//	//-----------------------------------------------------------------------------------
	//}

	////add balls to ballvector
	//m_balls.push_back(playerBall);
	//m_balls.push_back(enemyBall);
	//----------------------------------------------------------------------------------------------


	//add brick texture to spriteBatcher
	if(!m_pSpriteBatcher->addSprite(_T("brick"), _T("Graphics/Sprites/powerUpBrick.dds")))
		return false;

	//place brick in scene
	if(!setupBricks())
		return false;


	//all checks passed, initialization complete
	m_pParentProject->log(_T("[pong prototype initialization] all checks passed, prototype initialized"));




	m_bInitialized = true;
	return true;
}


bool PongPrototype::setupBricks()
{
	//-----------------------------------------INITIALIZE BRICKS-------------------------------------
	int brickRowNumber = SOLIPSIST.getWindowWidth() / 50; //window width divided by brick width, the amount of bricks in a single row
	float startingY = (SOLIPSIST.getWindowHeight() / 2) + 30; //brick is 20 pixels high, hence +30 for three rows
	for(int line = 0; line < 3; ++line)
	{
		float startingX = (((SOLIPSIST.getWindowWidth()) % brickRowNumber) / 2) + 25;
		for(int kolom = 0; kolom < brickRowNumber; ++kolom)
		{
			PowerupBrick* brick = new PowerupBrick();
			if(!brick->initialize(m_pSpriteBatcher->getSprite(_T("brick"))))
				return false;
			else
			{
				brick->move(XMFLOAT2(startingX ,startingY));
			}
			m_bricks.push_back(brick);
			startingX += 50;
		}
		startingY -= 40;
	}

	return true;
	//-----------------------------------------------------------------------------------------------
}


void PongPrototype::tick()
{

		float accumulator = 0.0f;

		double frameTime = m_pParentProject->getDeltaTime();
		if(frameTime > 0.25f)
			frameTime = 0.25f;

		double fps = m_pParentProject->getFps();
		float dt = 0.01f;


		accumulator += frameTime;
		while(accumulator >= dt)
		{
			accumulator -= dt;

			m_pHumanPlayer->tick(dt);
			m_pAIPlayer->tick(dt);



			////move balls
			//for(std::vector<Ball*>::iterator ballIt = m_balls.begin(); ballIt != m_balls.end(); ++ballIt)
			//{
			//	if((*ballIt) != NULL)
			//		(*ballIt)->tick(dt);
			//}



			//m_pPlayerPaddle->tick(dt);
			//m_pEnemyPaddle->tick(dt);

		
		}
		//check for collisions
		performCollisionChecks();

		//tick bricks
		for(std::vector<PowerupBrick*>::iterator brickIt = m_bricks.begin(); brickIt != m_bricks.end(); ++brickIt)
		{
			//brick has not yet been deleted yet and hitcounter is smaller or equal to zero
			if(((*brickIt) != NULL) && (*brickIt)->getHitCounter() <= 0)
			{
				delete (*brickIt);
				(*brickIt) = 0;
			}
		}


		//reset directions for paddles
		XMFLOAT2 blancDirection(0.0f, 0.0f);
		m_pHumanPlayer->getPaddle()->setDirection(blancDirection);
		m_pAIPlayer->getPaddle()->setDirection(blancDirection);

}



void PongPrototype::performCollisionChecks()
{
	std::vector<Ball*> balls;
	balls.insert(balls.end(), m_pHumanPlayer->getBalls().begin(), m_pHumanPlayer->getBalls().end());
	balls.insert(balls.end(), m_pAIPlayer->getBalls().begin(), m_pAIPlayer->getBalls().end());


	HitRegion* playerRegion			= m_pHumanPlayer->getPaddle()->getHitRegion();
	HitRegion* enemyRegion			= m_pAIPlayer->getPaddle()->getHitRegion();
	
	HitRegion* ballRegion			= NULL;
	HitRegion* brickRegion			= NULL;
	

	//check player collisions against level border and correct if necessary
	if(checkBorderCollision(playerRegion))
	{
		correctPaddleOverschoot(m_pHumanPlayer->getPaddle());
	}
	if(checkBorderCollision(enemyRegion))
	{
		correctPaddleOverschoot(m_pAIPlayer->getPaddle());
	}


	//iterate over balls and perform collision checks 
	std::vector<Ball*>::iterator it = m_balls.begin();
	for(it; it != m_balls.end(); ++it)
	{
		if((*it) != NULL)  //is there a ball to check?
		{

			ballRegion = (*it)->getHitRegion();

			//check ball collision against border 
			if(checkBorderCollision(ballRegion))
			{
				correctBallovershoot((*it));
				bounceBallOffWall((*it));
			}


			
			//it's important that we check the ball against paddle (in checkRegionCollision) and not the other way around
			//-> because of the way that the collision is calculated a larger hitregion checked against a 
			//smaller one will not return true. 
			//check ball collision against players
			if(m_pParentProject->checkRegionCollision(ballRegion, playerRegion)) //did ball hit player paddle?
			{
				bounceBallOffPaddle((*it), m_pHumanPlayer->getPaddle());
			}
			if(m_pParentProject->checkRegionCollision(ballRegion, enemyRegion)) //did ball hit player paddle?
			{
				bounceBallOffPaddle((*it), m_pAIPlayer->getPaddle());
			}


			//iterate over bricks and perform checks


			//iterate over bricks and perform collision checks 
			std::vector<PowerupBrick*>::iterator brickIt = m_bricks.begin();
			for(brickIt; brickIt != m_bricks.end(); ++brickIt)
			{
				if((*brickIt) != NULL)  //is there a brick to check?
				{
					brickRegion = (*brickIt)->getHitRegion();
					if(m_pParentProject->checkRegionCollision(ballRegion, brickRegion))
					{
						bounceBallOffBrick((*brickIt), (*it));
					}
				}
			}
	
			//finally iterate over entire ball vector to perform collision checks with other balls
			std::vector<Ball*>::iterator it2 = m_balls.begin();
			for(it2; it2 != m_balls.end(); ++it2)
			{
				//we've got to make sure that there is a ball to collide and that 
				//we don't "collide" with ourself
				if((*it2 != NULL) && (it2 != it))
				{
					HitRegion* otherBallRegion = (*it2)->getHitRegion();

					//did the balls hit each other?
					if(m_pParentProject->checkRegionCollision(ballRegion, otherBallRegion))
						bounceBallsOffEachOther(*it, *it2);
				}
			}
		}
	}

}


void PongPrototype::correctBallovershoot(Ball* p_ball)
{
	
	floatRect region = p_ball->getHitRegion()->getRegion();
	
	XMFLOAT2 offset;
	offset.x = 0.0f;
	offset.y = 0.0f;

	if(region.left <= 0)
		offset.x -= region.left; //negative number so we subtract

	if(region.right > SOLIPSIST.getWindowWidth())
		offset.x -= (region.right - SOLIPSIST.getWindowWidth());

	//hit top or bottom? adjust overshoot and flip y direction
	if(region.bottom <= 0)
		offset.y -= region.bottom;

	if(region.top > SOLIPSIST.getWindowHeight())
		offset.y -= (region.top - SOLIPSIST.getWindowHeight());


	//adjust overshoot
	p_ball->move(offset);

}





void PongPrototype::bounceBallsOffEachOther(Ball* p_ballOne, Ball* p_ballTwo)
{
	
	//hitregion is a bit smaller than the actual ball so we add a margin
	int ballOneRadius = (p_ballOne->getHitRegion()->getRegionWidth()  / 2) + 2;
	int ballTwoRadius = (p_ballTwo->getHitRegion()->getRegionWidth()  / 2) + 2;

	//find out the normal to the collision plane (by normalizing the distance between the centerpoints
	//position = centerpoint
	XMFLOAT2 ballOnePosition = p_ballOne->getBitmap()->getPosition();
	XMFLOAT2 ballTwoPosition = p_ballTwo->getBitmap()->getPosition();

	XMFLOAT2 normalVector;
	normalVector.x = ballOnePosition.x - ballTwoPosition.x;
	normalVector.y = ballOnePosition.y - ballTwoPosition.y;

	//find out magnitude (=length) of directional vector by taking square root of squared components
	//(brush up on vector math if you don't understand this bit)
	float normalMagnitude = sqrt((normalVector.x * normalVector.x) + (normalVector.y * normalVector.y));


	if(normalMagnitude <= (ballOneRadius + ballTwoRadius)) //collision? 
	{
		//move balls back a little to correct any overshoot so the hitregions don't get stuck inside eachother
		float overshoot =  (ballOneRadius + ballTwoRadius) - normalMagnitude;

		XMFLOAT2 overshootCorrection;
		overshootCorrection.x = (-p_ballOne->getDirection().x * overshoot);
		overshootCorrection.y = (-p_ballOne->getDirection().y * overshoot);
		p_ballOne->move(overshootCorrection);

		overshootCorrection.x = (-p_ballTwo->getDirection().x * overshoot);
		overshootCorrection.y = (-p_ballTwo->getDirection().y * overshoot);
		p_ballTwo->move(overshootCorrection);



		//make normal to collision plane a unit vector 
		XMFLOAT2 unitNormal;
		unitNormal.x = normalVector.x / normalMagnitude;
		unitNormal.y = normalVector.y / normalMagnitude;


		//find unit tangent to collision plane
		//since tangent is perpendicular to collision plane we can 
		//get the unit tangent from the unit normal 
		XMFLOAT2 unitTangent;
		unitTangent.x = -unitNormal.y;
		unitTangent.y = unitNormal.x;

	
		//project velocity onto normal and tangent (= decomposing the velocity vector into tangent & normal)
		XMFLOAT2 ball1Velocity;
		ball1Velocity.x = p_ballOne->getDirection().x * p_ballOne->getSpeed();
		ball1Velocity.y = p_ballOne->getDirection().y * p_ballOne->getSpeed();

		float normalSpeed1, tangentSpeed1;
		float xDot, yDot;

		//project velocity onto normal
		xDot = ball1Velocity.x * unitNormal.x;
		yDot = ball1Velocity.y * unitNormal.y;
		normalSpeed1 = xDot + yDot;

		//project velocity onto tangent
		xDot = ball1Velocity.x * unitTangent.x;
		yDot = ball1Velocity.y * unitTangent.y;
		tangentSpeed1 = xDot + yDot;


		//preserve tangent and normal velocities (unlike pool, where normal velocity would be affected from collision)
		XMFLOAT2 newDirection1;
		newDirection1.x =  -(unitNormal.x * normalSpeed1) + (unitTangent.x * tangentSpeed1);
		newDirection1.y = -(unitNormal.y * normalSpeed1) + (unitTangent.y * tangentSpeed1);
		float directionalMagnitude = sqrt((newDirection1.x * newDirection1.x) + (newDirection1.y * newDirection1.y));
		newDirection1.x /= directionalMagnitude;
		newDirection1.y /= directionalMagnitude;
		p_ballOne->setDirection(newDirection1);






		//project velocity onto normal and tangent (= decomposing the velocity vector into tangent & normal)
		XMFLOAT2 ball2Velocity;
		ball2Velocity.x = p_ballTwo->getDirection().x * p_ballTwo->getSpeed();
		ball2Velocity.y = p_ballTwo->getDirection().y * p_ballTwo->getSpeed();

		float normalSpeed2, tangentSpeed2;

		//project velocity onto normal
		xDot = ball2Velocity.x * unitNormal.x;
		yDot = ball2Velocity.y * unitNormal.y;
		normalSpeed2 = xDot + yDot;

		//project velocity onto tangent
		xDot = ball2Velocity.x * unitTangent.x;
		yDot = ball2Velocity.y * unitTangent.y;
		tangentSpeed2 = xDot + yDot;


		//preserve tangent and normal velocities (unlike pool, where normal velocity would be affected from collision)
		XMFLOAT2 newDirection2;
		newDirection2.x =  (unitNormal.x * normalSpeed1) + (unitTangent.x * tangentSpeed2);
		newDirection2.y = (unitNormal.y * normalSpeed1) + (unitTangent.y * tangentSpeed2);
		directionalMagnitude = sqrt((newDirection2.x * newDirection2.x) + (newDirection2.y * newDirection2.y));
		newDirection2.x /= directionalMagnitude;
		newDirection2.y /= directionalMagnitude;


		p_ballTwo->setDirection(newDirection2);
	
	}

}


void PongPrototype::bounceBallOffWall(Ball* &p_ball)
{
	bool markedForDeletion = false;

	XMFLOAT2 direction = p_ball->getDirection();
	floatRect region = p_ball->getHitRegion()->getRegion();
	
	//hit left or right? adjust overshoot and flip x direction
	if(region.left <= 0)
	{
		direction.x = -direction.x;
	}

	if(region.right >= SOLIPSIST.getWindowWidth())
	{
		direction.x = -direction.x;
	}

	//hit top or bottom? adjust overshoot and flip y direction + check scoring conditions
	if(region.bottom <= 0)
	{
		//player ball bounces of bottom, otherwise score
		if(p_ball->isFriendly())
			direction.y = -direction.y;
		else //ball wasn't friendly, score ball
		{
			m_enemyScore++;

			markedForDeletion = true;
		}
	}
	if(region.top >= SOLIPSIST.getWindowHeight())
	{
		if(p_ball->isFriendly())
		{
			m_playerScore++;

			markedForDeletion = true;
		}
		else
		{
			direction.y = -direction.y;
		}
	}

	//change direction
	p_ball->setDirection(direction);

	if(markedForDeletion)
	{
		//TODO: let pass pass through hitregion before deleting
		delete p_ball;
		p_ball = 0;
	}
}

//this function is only called when a collision is already detected, so 
//we just have to check which side of the paddle was hit
void PongPrototype::bounceBallOffPaddle(Ball* p_ball, Paddle* p_paddle)
{
	//these variables are used to nudge the ball when it comes into contact with the paddle
	//otherwise the hitregions might get stuck inside each other
	XMFLOAT2 overshootNudge;
	overshootNudge.x = 0.0f;
	overshootNudge.y = 0.0f;
	float ballRadius = p_ball->getHitRegion()->getRegionWidth() / 2;


	//centerpoints of colliding objects
	XMFLOAT2 paddlePosition = p_paddle->getBitmap()->getPosition();
	XMFLOAT2 ballPosition = p_ball->getBitmap()->getPosition();

	//direction of ball after hitting paddle (we "flip" these values)
	XMFLOAT2 ballDirectionPrime;
	ballDirectionPrime.x = p_ball->getDirection().x;
	ballDirectionPrime.y = p_ball->getDirection().y; 

	//vector from center of paddle to center of ball
	XMFLOAT2 impactDirection;
	impactDirection.x = ballPosition.x - paddlePosition.x;
	impactDirection.y = ballPosition.y - paddlePosition.y;

	//upper right corner of paddle in vector form
	XMFLOAT2 urCorner;
	urCorner.x = (paddlePosition.x + p_paddle->getHitRegion()->getRegionWidth() /2) - paddlePosition.x;
	urCorner.y = (paddlePosition.y + p_paddle->getHitRegion()->getRegionHeight() / 2) - paddlePosition.y;

	//lower left corner of paddle in vector form
	XMFLOAT2 llCorner;
	llCorner.x = (paddlePosition.x - p_paddle->getHitRegion()->getRegionWidth() /2) - paddlePosition.x;
	llCorner.y = (paddlePosition.y - p_paddle->getHitRegion()->getRegionHeight() / 2) - paddlePosition.y;


	bool collisionOccured = false;
	bool noFlip = true;

	//check if ball hit sides of paddle
	if( urCorner.y >= impactDirection.y && llCorner.y <= impactDirection.y)
	{
		collisionOccured = true;
		noFlip = false;
		ballDirectionPrime.x = -ballDirectionPrime.x;	
		

		//calculate amount of overlapping x-axis pixels and reverse direction
		float disparity = (paddlePosition.x - ballPosition.x);
		float regionArea = (urCorner.y + ballRadius + 2); // (2 is an extra "nudge" value to ensure we left the hitregion)
		float nudge = 0.0f;
		if(disparity > 0) //collision is upwards so nudge downwards
			nudge = (disparity - regionArea);
		else
			nudge = (disparity + regionArea);

		overshootNudge.x = nudge;


	}

	//check if ball hit top or bottom of padddle
	if(llCorner.x <= impactDirection.x && urCorner.x >= impactDirection.x)
	{
		collisionOccured = true;
		noFlip = false;
		ballDirectionPrime.y = -ballDirectionPrime.y;



		//calculate amount of overlapping y-axis pixels and reverse direction 
		float disparity = (paddlePosition.y - ballPosition.y);
		float regionArea = (urCorner.y + ballRadius + 2); // (2 is an extra "nudge" value to ensure we left the hitregion)
		float nudge = 0.0f;
		if(disparity > 0) //collision is upwards so nudge downwards
			nudge = (disparity - regionArea);
		else
			nudge = (disparity + regionArea);

		overshootNudge.y = nudge;
	}

	if(noFlip)
	{
		collisionOccured = true;

		//this happens when the corner is hit, switch axis unless you want funky behaviour
		if((impactDirection.x < 0 && impactDirection.y < 0) || 
			(impactDirection.x > 0 && impactDirection.y > 0))
		{
			ballDirectionPrime.x = -ballDirectionPrime.y;
			ballDirectionPrime.y = ballDirectionPrime.x;
		}
		else //same thing, but the axii are flipped (draw a picture of this if you want to understand it)
		{
			ballDirectionPrime.x = ballDirectionPrime.y;
			ballDirectionPrime.y = ballDirectionPrime.x;
		}
	}
	p_ball->move(overshootNudge);
	p_ball->setDirection(ballDirectionPrime);


	//ball becomes friendly or enemy depending on wether the other side's paddle touched it 
	//(second check is to ensure that a ball doesn't flip if it gets touched by its owner)
	if(collisionOccured && (p_paddle->isFriendly() != p_ball->isFriendly()))
	{

		if(p_ball->isFriendly())
			p_ball->setSprite(*(m_pSpriteBatcher->getSprite(_T("enemyBall"))));
		else
			p_ball->setSprite(*(m_pSpriteBatcher->getSprite(_T("playerBall"))));

		p_ball->flipFriendly();
	}
}


//TODO: dit heeft eigenlijk geen aparte functie nodig
void PongPrototype::bounceBallOffBrick(PowerupBrick* p_brick, Ball* p_ball)
{
	XMFLOAT2 overshootNudge;
	overshootNudge.x = 0.0f;
	overshootNudge.y = 0.0f;
	float ballRadius = p_ball->getHitRegion()->getRegionWidth() / 2;

	//centerpoints of colliding objects
	XMFLOAT2 brickPosition = p_brick->getPosition();
	XMFLOAT2 ballPosition = p_ball->getBitmap()->getPosition();

	//direction of ball after hitting paddle (we "flip" these values)
	XMFLOAT2 ballDirectionPrime;
	ballDirectionPrime.x = p_ball->getDirection().x;
	ballDirectionPrime.y = p_ball->getDirection().y; 

	//vector from center of paddle to center of ball
	XMFLOAT2 impactDirection;
	impactDirection.x = ballPosition.x - brickPosition.x;
	impactDirection.y = ballPosition.y - brickPosition.y;

	//upper right corner of paddle in vector form
	XMFLOAT2 urCorner;
	urCorner.x = (brickPosition.x + p_brick->getHitRegion()->getRegionWidth() /2) - brickPosition.x;
	urCorner.y = (brickPosition.y + p_brick->getHitRegion()->getRegionHeight() / 2) - brickPosition.y;

	//lower left corner of paddle in vector form
	XMFLOAT2 llCorner;
	llCorner.x = (brickPosition.x - p_brick->getHitRegion()->getRegionWidth() /2) - brickPosition.x;
	llCorner.y = (brickPosition.y - p_brick->getHitRegion()->getRegionHeight() / 2) - brickPosition.y;



	bool noFlip = true;

	//check if ball hit sides of brick
	if( urCorner.y >= impactDirection.y && llCorner.y <= impactDirection.y)
	{
		noFlip = false;
		ballDirectionPrime.x = -ballDirectionPrime.x;	

		//calculate amount of overlapping x-axis pixels and reverse direction
		float disparity = (brickPosition.x - ballPosition.x);
		float regionArea = (urCorner.y + ballRadius + 2); // (2 is an extra "nudge" value to ensure we left the hitregion)
		float nudge = 0.0f;
		if(disparity > 0) //collision is upwards so nudge downwards
			nudge = (disparity - regionArea);
		else
			nudge = (disparity + regionArea);

		overshootNudge.x = nudge;
	}

	//check if ball hit top or bottom of padddle
	if(llCorner.x <= impactDirection.x && urCorner.x >= impactDirection.x)
	{
		noFlip = false;
		ballDirectionPrime.y = -ballDirectionPrime.y;
		
		//calculate amount of overlapping y-axis pixels and reverse direction 
		float disparity = (brickPosition.y - ballPosition.y);
		float regionArea = (urCorner.y + ballRadius + 2); // (2 is an extra "nudge" value to ensure we left the hitregion)
		float nudge = 0.0f;
		if(disparity > 0) //collision is upwards so nudge downwards
			nudge = (disparity - regionArea);
		else
			nudge = (disparity + regionArea);

		overshootNudge.y = nudge;
	}

	if(noFlip)
	{
		//this happens when the corner is hit, switch axis unless you want funky behaviour
		if((impactDirection.x < 0 && impactDirection.y < 0) || 
			(impactDirection.x > 0 && impactDirection.y > 0))
		{
			ballDirectionPrime.x = -ballDirectionPrime.y;
			ballDirectionPrime.y = ballDirectionPrime.x;
		}
		else //same thing, but the axii are flipped (draw a picture of this if you want to understand it)
		{
			ballDirectionPrime.x = ballDirectionPrime.y;
			ballDirectionPrime.y = ballDirectionPrime.x;
		}
	}


	p_ball->move(overshootNudge);
	p_ball->setDirection(ballDirectionPrime);
	p_brick->decreaseHitCounter();
}





//The purpose of this function is to keep the paddle within the confines of the WIN32 window 
//and prevent the player from moving his paddle out of sight
void PongPrototype::correctPaddleOverschoot(Paddle* p_paddle)
{
	XMFLOAT2 offset;
	offset.x = 0.0f;
	offset.y = 0.0f;

	int windowWidth = SOLIPSIST.getWindow()->getWidth();
	int windowHeight = SOLIPSIST.getWindow()->getHeight();
	floatRect region = p_paddle->getHitRegion()->getRegion();



	//store overshoot corrections
	if(region.left < 0)
		offset.x -= region.left; //subtract because region.left is a negative value

	if(region.bottom < 0)
		offset.y -= region.bottom; //same here, subtract because it's a negative value

	if(region.right > windowWidth)
		offset.x -= (region.right - windowWidth); 
	
	if(region.top > windowHeight)
		offset.y -= (region.top - windowHeight);


	p_paddle->move(offset);

}



//check collision against edges of window 
bool PongPrototype::checkBorderCollision(HitRegion* p_region)
{	
	bool collision = false;
	floatRect rect = p_region->getRegion(); //retrieve the location of the hitregion (HitRegion is a wrapper for floatRect)

	//check the border of the map and adjust any overshoots
	if(	rect.bottom <= 0 || rect.top >= SOLIPSIST.getWindow()->getHeight() 
		|| rect.left <= 0 || rect.right >= SOLIPSIST.getWindow()->getWidth())
		collision = true;
	
	return collision;
}




void PongPrototype::spawnBall()
{
	if(m_pHumanPlayer)
	{
		POINT mousePosition;
		GetCursorPos(&mousePosition);
		ScreenToClient(SOLIPSIST.getWindow()->getHandle(), &mousePosition);

		m_pHumanPlayer->spawnBall(mousePosition.x, mousePosition.y, m_pSpriteBatcher);
	}
}

void PongPrototype::keyDown()
{
	XMFLOAT2 direction;
	direction.x = 0.0f;
	direction.y = 0.0f;

	//move player paddle according to directional keys
	if(m_bInitialized)
	{
		if(GetAsyncKeyState(0x5A ) || GetAsyncKeyState(VK_UP)) //Z or up
			direction.y = 1.0f;

		if(GetAsyncKeyState(0x53) || GetAsyncKeyState(VK_DOWN))//S or down
			direction.y = -1.0f;

		if(GetAsyncKeyState(0x51) || GetAsyncKeyState(VK_LEFT))//Q or left
			direction.x = -1.0f;

		if(GetAsyncKeyState(0x44) || GetAsyncKeyState(VK_RIGHT))//D or right
			direction.x = 1.0f;


		m_pHumanPlayer->getPaddle()->setDirection(direction);



		
	}
}


void PongPrototype::mouseButtonDown(UINT p_button)
{
	if(p_button == WM_LBUTTONUP)
		spawnBall();
}

void PongPrototype::draw()
{
	if(m_bInitialized)
	{


		//clear background
		SOLIPSIST.getGraphics()->clearRenderTarget(0.2f, 0.22f, 0.24f, 1.0f);

		tstringstream message;
		message << _T("PLAYER SCORE") << m_playerScore;
		SOLIPSIST.drawString(message.str(), -1.0f, 0.9f);
		message.str(_T(""));
		message << _T("CPU SCORE ") << m_enemyScore;
		SOLIPSIST.drawString(message.str(), 0.55f, 0.9f);
		message.str(_T(""));
		message << _T("FPS ") << m_pParentProject->getFps();
		SOLIPSIST.drawString(message.str(), -1.0f, 0.8f);
		message.str(_T(""));
		message << _T("FRAME TIME ") << m_pParentProject->getDeltaTime() << "SECONDS";
		SOLIPSIST.drawString(message.str(), -1.0f, 0.7f);
		message.str(_T(""));
		/*message << _T("GAME TIME ") << (int) m_pParentProject->getGameTime() << " SECONDS"; 
		SOLIPSIST.drawString(message.str(), -1.0f, -0.9f);
	    message.str(_T(""));*/
		message  << m_pHumanPlayer->getReserveBallCount() << _T("BALLS LEFT "); 
		SOLIPSIST.drawString(message.str(), -1.0f, -0.6f);
		
		//------------------------------------DISPLAYING DEBUG STUFF-------------------------------------
		/*
		tstringstream playerInfo;
		playerInfo << "X " << m_pEnemyBall->getBitmap()->getPosition().x;
		playerInfo << "Y " << m_pEnemyBall->getBitmap()->getPosition().y;
		m_pParentProject->drawString(playerInfo.str(),-1.0f, 0.9f);
		playerInfo.str(_T("")); //empty filestream

		playerInfo  << "REGBOT " << m_pEnemyPaddle->getHitRegion()->getRegion().bottom;
		m_pParentProject->drawString(playerInfo.str(),-1.0f, 0.8f);
		playerInfo.str(_T(""));
	
		playerInfo  << "REGTOP " << m_pEnemyPaddle->getHitRegion()->getRegion().top;
		m_pParentProject->drawString(playerInfo.str(),-1.0f, 0.7f);
		playerInfo.str(_T(""));
	
		playerInfo  << "REGLEFT " << m_pEnemyPaddle->getHitRegion()->getRegion().left;
		m_pParentProject->drawString(playerInfo.str(),-1.0f, 0.6f);
		playerInfo.str(_T(""));
	
		playerInfo <<  "REGRIGHT " << m_pEnemyPaddle->getHitRegion()->getRegion().right;
		m_pParentProject->drawString(playerInfo.str(),-1.0f, 0.5f);
		playerInfo.str(_T(""));
		*/
		//-------------------------------------------------------------------------------------------------
		


		//-----------------------------------setup shader matrices-----------------------------------------


		XMMATRIX view = XMMatrixIdentity();
		XMMATRIX projection = XMMatrixOrthographicOffCenterLH(0.0f, SOLIPSIST.getWindowWidth(), 0.0f, SOLIPSIST.getWindowHeight(), 0.1f, 100.0f);
		XMMATRIX viewProjection = XMMatrixMultiply(view, projection);
		XMMATRIX world;
		XMMATRIX wvp;

		//----------------player paddle matrices-------------------
		Paddle* m_pPlayerPaddle = m_pHumanPlayer->getPaddle();

		world = m_pPlayerPaddle->getBitmap()->getWorldMatrix();
		wvp = XMMatrixMultiply(world, viewProjection);
		
		//transpose wvp to feed to shader
		wvp = XMMatrixTranspose(wvp);

		m_pParentProject->getGraphics()->getContext()->UpdateSubresource(m_pConstantBuffer, NULL, NULL, &wvp, NULL, NULL);
		m_pParentProject->getGraphics()->getContext()->VSSetConstantBuffers(0, 1, &m_pConstantBuffer);

	


		//draw the paddle
		m_pPlayerPaddle->getBitmap()->loadRenderSettings();
		m_pPlayerPaddle->draw();


		////----------------enemy paddle matrices-------------------
		//world = m_pEnemyPaddle->getBitmap()->getWorldMatrix();
		//wvp = XMMatrixMultiply(world, viewProjection);
		//
		////transpose wvp to feed to shader
		//wvp = XMMatrixTranspose(wvp);

		//m_pParentProject->getGraphics()->getContext()->UpdateSubresource(m_pConstantBuffer, NULL, NULL, &wvp, NULL, NULL);
		//m_pParentProject->getGraphics()->getContext()->VSSetConstantBuffers(0, 1, &m_pConstantBuffer);


		////draw paddle
		//m_pEnemyPaddle->getBitmap()->loadRenderSettings();
		//m_pEnemyPaddle->draw();
		//



		////-----------------------------------------------DRAW BALLS------------------------------------
		//std::vector<Ball*>::iterator it = m_balls.begin();

		//

		//for(it; it != m_balls.end(); ++it)
		//{
		//	if((*it) != NULL)
		//	{
		//		(*it)->getBitmap()->loadRenderSettings();


		//		world = (*it)->getWorldMatrix();
		//		wvp = XMMatrixMultiply(world, viewProjection);

		//		//transpose to feed to shader
		//		wvp = XMMatrixTranspose(wvp);

		//		m_pParentProject->getGraphics()->getContext()->UpdateSubresource(m_pConstantBuffer, NULL, NULL, &wvp, NULL, NULL);
		//		m_pParentProject->getGraphics()->getContext()->VSSetConstantBuffers(0,1,&m_pConstantBuffer);

		//		//draw ball
		//		(*it)->draw();
		//	}
		//}

		m_pHumanPlayer->draw(viewProjection);
		//m_pAIPlayer->draw(viewProjection);

		//----------------bricks matrices-------------------
		std::vector<PowerupBrick*>::iterator brickIt = m_bricks.begin();

		for(brickIt; brickIt != m_bricks.end(); ++brickIt)
		{
			if((*brickIt) != NULL)
			{
				(*brickIt)->getBitmap()->loadRenderSettings();


				//get brick matrixes
				world = (*brickIt)->getWorldMatrix();
				wvp = XMMatrixMultiply(world, viewProjection);

				//transpose to feed to shader
				wvp = XMMatrixTranspose(wvp);

				m_pParentProject->getGraphics()->getContext()->UpdateSubresource(m_pConstantBuffer, NULL, NULL, &wvp, NULL, NULL);
				m_pParentProject->getGraphics()->getContext()->VSSetConstantBuffers(0,1,&m_pConstantBuffer);

				//draw brick
				(*brickIt)->draw();



				//display number of hits left over brick
				XMFLOAT2 position = (*brickIt)->getPosition();
				//center numberquad on brick bitmap
				position.x -= 10;
				position.y -= 8;
				//transform to screen coordinates (map to [-1;1])
				position.x /= (SOLIPSIST.getWindowWidth() / 2);
				position.y /= (SOLIPSIST.getWindowHeight() / 2);
				position.x -= 1; 
				position.y -= 1;

				unsigned short hitcount = (*brickIt)->getHitCounter();
				tstringstream number;
				number << hitcount;
				m_pParentProject->drawString(number.str(), position.x, position.y);
			}
		}


	}
}



Sponsor:



Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS