Quick Time Events (QTEs) can add an extra bit of interaction between our players and our games, rewarding them for their focus. So let’s take a look at how we can event one type of QTEs: timed hits.
For this tutorial, we’ll be making a minigame where the player needs to hit a button when the moving pointer is in the green goal. To make it more interesting, let’s have the goal randomly placed each time and have the player need to hit it twice to succeed. To balance that difficulty out, we’ll let the pointer go back and forth continuously until the player decides to hit the button.
The first things we need to make this work are some images for the timed hits. Since we want the goal to be able to be placed randomly each time we’ll need three images to make this work:
• The bar’s background:
• The bar’s goal:
• The pointer that moves:
We’ll be adding all three of these images to our pictures folder in our project’s img folder. Once they’re there, we’ll be able to call them with the Show Picture event command to create our QTE. The next step will be figuring out exactly where we need our pictures to go, which requires one of the most important and most difficult parts of game development:
Show Pictures uses pixel coordinates to place the images, so we’ll need to know just how big our screen’s width and height are so we can center our QTE on the screen. If we forget or don’t know what those numbers are offhand, we can check the System 2 tab in the Database.
For this project our width is 1104 and our height is 624, which means we can find the center of the screen by just dividing both by two. If we choose the center option for our background image then we can use those numbers as the X and Y to make our picture show up in the middle or the screen.
Direct designations for pictures won’t work for all of our images though, because we need both our goal and pointer to be able to move around the screen. So before we can think about the Show Pictures for those two, we need to set up 6 variables, 1 switch, and do some more math.
The first 2 variables will be focused on the pointer’s X and Y. Since we want the pointer to move left and right along the bar, we’ll set the Y to the same number as the background’s Y, 312. The X is a bit more complicated to get. It’s easiest if we start the pointer at the far left part of the bar, so first we’ll check how wide our background bar’s red part is. For the one we’re using in this tutorial, it’s 408 which means that we can find it’s left and right side locations by subtracting and adding half that to the screen’ center amount, respectively. We’ll need both numbers later, so if we do both equations we’ll end up with the left side being at 348 and the right side at 756. For the pointer’s X, we’ll be setting the variable to 348.
The next variable we’re setting will control the pointer’s speed. The speed will affect how far the pointer moves each frame, so we don’t want to make it some crazy high number. 1-5 is a comfortable range for myself, but since we don’t have player feedback yet it’s safest to set it to 1 for now. We can always adjust it later to be faster if we need it.
The last set of variables will be for randomly placing the goal on the background. We need to find the left side, right side, and center of the goal, so let’s start with the left side. We’ll use the Random option to set our variable, and to make sure the goal doesn’t accidentally get placed outside of the QTE background we’ll have the variable set between 400 and 700. To get the right and center numbers, we’ll be using the Script option to do a bit more math. The right side is straightforward to find, we just need to take the left side’s amount and add the goal’s width to it. Since our goal’s width is 48, our script used is $gameVariables.value(24) + 48 . Lastly, we can find our goal’s center by adding the left and right sides’ amounts together and dividing by 2, which can be done with ($gameVariables.value(24) + $gameVariables.value(25)) / 2 .
Before we get to actually showing all our images, let’s set a switch up to know if the pointer will be moving left or right. If the switch is On, then it’s moving right and if the switch is Off then the pointer will be going left.
With all those variables now ready, we can add in all the necessary Show Pictures to bring our QTE to life. Both the goal and pointer will share the pointer Y variable to set their Y since it won’t be changing later, though their Xs will be pointer X for the pointer and the goal’s center for the goal’s X. Add in a Tint Screen command to help the player focus on the QTE and short message so they know what to do, and our event’s setup looks like this:
And that makes our event look like this in-game:
We’ve got it looking good, so the next step is to make things actually work. To make the pointer move, we’ll be setting up a Loop (similar to what we did in the push/pull tutorial) so that the pointer’s X variable will keep changing, and after each change we’ll copy the pointer’s Show Picture command so that it will move along the background.
To make sure the pointer is moving in the right direction we need a Conditional Branch to check if the direction switch is On or Off. If it’s On, then we’ll be adding the speed variable’s amount to the pointer’s X variable and if the switch is Off then we’ll be subtracting the speed variable from the pointer’s X. Once that variable has been changed, we just need to copy the Show Picture for the pointer we used earlier and it’ll move!
Of course, if we leave it as-is, the pointer will continue to move right indefinitely, leaving not just the background’s red area but also the screen itself… Which is not exactly what we want to happen. So let’s add two Conditional Branches to check when the pointer hits the left and right sides of the bar and flips the direction switch so the pointer will start moving in the opposite direction. Luckily we already did the math, so when the pointer is at or less than 348 it has hit the left side and the direction switch needs turned On and when the pointer is at or more than 756 then we’ll flip the switch to Off. Now our pointer will properly move back and forth along the QTE’s background.
Of course, having the pointer move means nothing until we add in a way for the player to interact with the QTE! So our next step is to add in some more Conditional Branches.
The first one is straightforward, we just need to check if the player is hitting the ‘Ok’ button. We’ll set it to ‘is being triggered’ so that the event will only register it once (useful if we later decide to change how missing works). Nestled inside that Conditional Branch is another one that checks if the pointer is in the goal, by comparing the pointer’s X variable to the variables that hold the goal’s left and right sides. So by using $gameVariables.value(21) >= $gameVariables.value(24) && $gameVariables.value(21) <= $gameVariables.value(25) in the Conditional Branch’s script section we can see if the pointer’s X is both more than the goal’s left side variable and less than the goal’s right side variable. If it is, then the player hit the goal and we can reward them properly! And if they didn’t, then the Conditional Branch’s Else will play the failure condition.
When the player hits the goal, we’ll play a happy SE and flash the screen green. And since we want the player to hit the goal two times to win, we can increase the pointer’s speed variable by 1 for each successful hit and use that in two more Conditional Branches, the first which moves the goal to another random place (which we can just copy and paste from the setup), and the second which will tell the player they won the minigame and turn on a ‘won the minigame’ switch that we’ll check at the end of the event to give the player whatever reward they deserve.
If the player fails, then we’ll play a sad SE and flash the screen red, as well as break the Loop so that the QTE ends.
All together, this part of the event turns out like this:
I like to sometimes add an option for players to back out of the QTE if they want, so we’ll drop a small Conditional Branch to check if the player hit the ‘Cancel’ button and breaks the Loop if they did.
All that’s left is setting up the end of the event. The two most important things we need to do is erase all three pictures so they don’t stick around once we’re done and tint the screen back to its normal tone. With those two things done our player can jump back into the normal gameplay without issue.
Once that’s taken care of, we can add the last little touch: the player’s reward! A Conditional Branch that checks if the ‘won the minigame’ switch is On is all we need. We can have whatever we want inside there, be it items, a variable increase, or even just a message to show the party is pleased with winning. If the QTE can be repeated, then we’ll want to turn the switch Off so that the player tries it again and fails, they don’t get the reward.
With the end of the event finished, it all comes together to look like this:
And with that, we’ve got our timed hit QTE! There are plenty of places it could be changed to better fit certain games, such as adding in lives that decrease if the player misses or leaving the speed the same and just keeping count of how high the player can get their streak. What would you add to this event to make it work in your game?
Steam Next Fest is here, and it is a time to explore tons of upcoming games, and the team at AstralShift in cooperation with the VisuStella team and Komodo, has joined the festivities with the release of the Demo for their RPG Maker Game Pocket Mirror ~ GoldenerTraum!