Bizzy Bees XNA to DirectX/DirectXTK – Part 7
This is part of a blog series… if you came here directly you might want to read the introduction first.
The final step to make the game playable is to add some user interaction.
Capturing the users input
In DirectX the user input is event based so what we need to do is to add a method to the BizzyBeesGame class called HandleInput and call this from BizzyBees::OnPointerPressed
1. Add a public HandleInput method to BizzyBeesGame
void HandleInput(Windows::Foundation::Point position);
2. Call the BizzyBeesGame::HandleInput method from BizzyBees::OnPointerPressed
void BizzyBees::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
{
// Insert your code here.
m_renderer->HandleInput(args->CurrentPoint->Position);
}
In the HandleInput method we will check to see if we are clicking in the beePicker area or in one of the columns and handle the input accordingly so we also need to add two more methods to BizzyBeesGame called HandleFlowerSelection and HandleBeeSelection
3. Add private methods for handling bee and flower selections to the BizzyBeesGame class
void HandleFlowerSelection(float x, float y);
void HandleBeeSelection(float x);
Handing bee selection
We are only going to worry about handling flower selections if there is a be selected already since the order of the game goes like this… a. select a bee, b. select a column c. if the selected bee matches the bottom flower in that column we have a match.
4. In order to do this we’ll add a new private member variable to the BeePicker class called selectedBee.
shared_ptr<Bee> selectedBee;
5. Reset the selectedBee in BeePicker::ResetBeePicker method so that no bee is selected at the start of the game
selectedBee = nullptr;
6. In the BizzyBeeGame::HandleInput method, check if we are in the bee picker area (anywhere between Y=700 and the bottom of the screen) and if so handle bee selection, if not handle flower selection (we’ll check later to make sure we’re touching inside a column area)
void BizzyBeeGame::HandleInput(Windows::Foundation::Point position){
if (position.Y > 700)
HandleBeeSelection(position.X);
else
HandleFlowerSelection(position.X, position.Y);
}
7. Add a new public bool IsSelected field in the Bee class which we’ll use to draw selected bees slightly differently, and initialize it to false in the Bee constructor
Bee::Bee(int color) : Color(color), IsSelected(false){}
8. In the BeePicker class add a new method SelectBeeAtPosition(float x) , in this method we will deselect any previously selected bee and select the bee at the given x position.
void BeePicker::SelectBeeAtPosition(float x)
{
//reset any previously selected bee
if (selectedBee){
selectedBee->IsSelected = false;
selectedBee = nullptr;
}
//select the new bee
auto beeIndex = (int)((x - beeStartX) / beeDeltaX);
if (beeIndex < 0) beeIndex = 0;
if (beeIndex > 4) beeIndex = 4;
bees[beeIndex]->IsSelected = true;
selectedBee = bees[beeIndex];
}
9. Handing the bee selection will be as simple as calling this method from BizzyBeeGame::HandleBeeSelection
void BizzyBeeGame::HandleBeeSelection(float x){
beePicker->SelectBeeAtPosition(x);
}
10. In the BeePicker::Draw method we will add a few lines to draw the selected bee with a DimGray light so that we get a visual cue when we select a bee
void BeePicker::Draw(shared_ptr<SpriteBatch> spriteBatch, ComPtr<ID3D11ShaderResourceView> texture){
for (int i = 0; i < 5; i++){
RECT sourceRect = { bees[i]->Color * 91, 0, (bees[i]->Color + 1) * 91, 91 };
Vector2 position = Vector2(beeStartX + i*beeDeltaX, beeStartY);
if (bees[i]->IsSelected)
spriteBatch->Draw(texture.Get(), position, &sourceRect, Colors::DimGray);
else
spriteBatch->Draw(texture.Get(), position, &sourceRect, Colors::White);
}
}
11. For now, leave the BizzyBeeGame::HandleFlowerSelection empty and run the app to make sure everything works as it should with the bee selection
Handle flower selection
OK, great, now we can select bees. Handling the flower selection will be a bit trickier though. These are the steps we’ll need to take
- check that we have a selected bee
- check that we are in a column
- get the bottom flower of that column
- if the bottom flower is a) a rainbow flower or b) a flower with the same color as the bee we have a match and if so
- … remove the bottom flower
- … replace the selected bee (making sure we have at least one possible match left so that we don’t get stuck without matches) – Note: ideally we should make this algorithm better but I’ll leave that up to the reader.
- … if the flower was a rainbow flower, increase the score
1. Implement the BizzyBeeGame::HandleFlowerSelection capturing all of the above
void BizzyBeeGame::HandleFlowerSelection(float x, float y){
//if we havent selected a bee, we have nothing to do
if (beePicker->selectedBee == nullptr)
return;
const int RAINBOWCOLOR = 6;
//only proceed if we are in the column area
if (x > 10 && x < 470 && y > 100 && y < 700)
{
//get the selected column
auto selectedColumnIndex = (int)((x - 10) / 92);
auto selectedColumn = columns[selectedColumnIndex];
//get the selected flower
auto selectedFlower = selectedColumn->GetBottomFlower();
//check if we have a match or if the flower is rainbow
if (selectedFlower != nullptr && (selectedFlower->Color == RAINBOWCOLOR || selectedFlower->Color == beePicker->selectedBee->Color)){
//remove the bottom flower
selectedColumn->RemoveBottomFlower();
//replace the bee - making sure we have a match by selecting a random bottom flower
auto randomMatchingColor = columns[rand() % 5]->GetBottomFlower()->Color;
beePicker->RemoveAndReplaceSelectedBee(randomMatchingColor);
//check if we should add points
if (selectedFlower->Color == RAINBOWCOLOR)
{
score++;
}
}
}
}
OK so now we have to implement a few of the supporting methods so let’s add definitions in the h files for the following
- public shared_ptr<Flower> Column::GetBottomFlower()
- public void Column::RemoveBottomFlower()
- public void BeePicker::RemoveAndReplaceSelectedBee(int color)
- and a private field in BizzyBeeGame called int score;
2. The bottom flower is the flower at position 0 in the flowers vector so Column::GetBottomFlower and Column::RemoveBottomFlower are pretty straight forward
shared_ptr<Flower> Column::GetBottomFlower(){
if (flowers.size() > 0)
return flowers[0];
else
return nullptr;
}
void Column::RemoveBottomFlower(){
if (flowers.size() > 0)
flowers.erase(begin(flowers));
}
3. In the BeePicker::RemoveAndReplaceSelectedBee we don’t actually remove anything, we just replace it but it has the same effect
void BeePicker::RemoveAndReplaceSelectedBee(int color){
//Deselect the selected bee
selectedBee->IsSelected = false;
//set the new bee color -
//if the flower suggested was rainbow just randomize, anything will match
if (color > numBeeColors)
selectedBee->Color = rand() % (numBeeColors + 1);
else
selectedBee->Color = color;
//clear the selectedBee pointer
selectedBee = nullptr;
}
4. We need to do something about the score, right now, we get points but noone is really there to see it:). In the BizzyBeeGame::DrawHUD method add the following line to print the score
DrawString(score.ToString()->Data(), Vector2(127, 45), Colors::Yellow);
5. For good measure we’ll also set the score = 0 in the BizzyBeeGame::ResetGame method so that we’ll start with a fresh slate. It won’t matter now but will be good later
And with that my friends, we actually have a fully functioning game. In the final article we’ll add on a few nice to haves to make it even better.