Time Sensitive Buttons Presses

This topic is 1513 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Hey guys!

Sorry for the poorly titled thread. Basically I'm working on a music game, and want there to be an accuracy factor to when the player hits the note. My current code is as follows:

void Gameplay::detectHit(note_buttons pressed, double time)
{
if ((note_gems_left.empty() && current_track == &note_gems_left) ||
(note_gems_right.empty() && current_track == &note_gems_right))
{
return;
}

if (current_track == &note_gems_left)
{
if (pressed == notes_left_s.front()->getButton())
{
if (time <= notes_left_s.front()->getTimeStamp()  + great_t
&& time >= notes_left_s.front()->getTimeStamp()  - great_t)
{
score += points * great;
note_hit = GREAT;
note_gems_left.erase(note_gems_left.begin());
notes_left_s.erase(notes_left_s.begin());
}
else if (time <= notes_left_s.front()->getTimeStamp()  + nice_t
&& time >= notes_left_s.front()->getTimeStamp()  - nice_t)
{
score += points * nice;
note_hit = NICE;
note_gems_left.erase(note_gems_left.begin());
notes_left_s.erase(notes_left_s.begin());
}
else if (time <= notes_left_s.front()->getTimeStamp()  + good_t
&& time >= notes_left_s.front()->getTimeStamp() - good_t)
{
score += points * good;
note_hit = GOOD;
note_gems_left.erase(note_gems_left.begin());
notes_left_s.erase(notes_left_s.begin());
}
else if (time <= notes_left_s.front()->getTimeStamp()  + poor_t
&& time >= notes_left_s.front()->getTimeStamp()  - poor_t)
{
score += points * poor;
note_hit = POOR;
note_gems_left.erase(note_gems_left.begin());
notes_left_s.erase(notes_left_s.begin());
}
else
{
note_hit = MISS;
note_gems_left.erase(note_gems_left.begin());
notes_left_s.erase(notes_left_s.begin());
}
}
else
{
note_hit = MISS;
}
}
else if (current_track == &note_gems_right)
{
if (pressed == notes_right_s.front()->getButton())
{
if (time <= notes_right_s.front()->getTimeStamp()  + great_t
&& time >= notes_right_s.front()->getTimeStamp()  - great_t)
{
score += points * great;
note_hit = GREAT;
note_gems_right.erase(note_gems_right.begin());
notes_right_s.erase(notes_right_s.begin());
}
else if (time <= notes_right_s.front()->getTimeStamp()  + nice_t
&& time >= notes_right_s.front()->getTimeStamp()  - nice_t)
{
score += points * nice;
note_hit = NICE;
note_gems_right.erase(note_gems_right.begin());
notes_right_s.erase(notes_right_s.begin());
}
else if (time <= notes_right_s.front()->getTimeStamp() + good_t
&& time >= notes_right_s.front()->getTimeStamp()  - good_t)
{
score += points * good;
note_hit = GOOD;
note_gems_right.erase(note_gems_right.begin());
notes_right_s.erase(notes_right_s.begin());
}
else if (time <= notes_right_s.front()->getTimeStamp()  + poor_t
&& time >= notes_right_s.front()->getTimeStamp()  - poor_t)
{
score += points * poor;
note_hit = POOR;
note_gems_right.erase(note_gems_right.begin());
notes_right_s.erase(notes_right_s.begin());
}
else
{
note_hit = MISS;
note_gems_right.erase(note_gems_right.begin());
notes_right_s.erase(notes_right_s.begin());
}
}
else
{
note_hit = MISS;
}
}
}


My main issue is that I feel like this could be done in a MUCH better way. I'm just not sure how to go about it. Basically there are different accuracy levels for hitting the note - ranging from MISS to GREAT (with POOR, GOOD, & NICE in between). It affects the score, and the amount of "life" the player has.

Anyone got any suggestions?

Thanks a ton!

Share on other sites
A table would be best.

enum HIT_TYPE {
HIT_GREAT,
HIT_NICE,
HIT_GOOD,
HIT_POOR,
HIT_MISS,
};
struct TIMINGS {
UINT64 ui64Range;
DWORD dwPoints;
HIT_TYPE htHitType;
};

static const TIMINGS tTimes[] = {
{ great_t, great, HIT_GREAT },
{ nice_t, nice, HIT_NICE },
{ good_t, good, HIT_GOOD },
{ poor_t, poor, HIT_POOR },
{ miss_t, 0, HIT_MISS },  // miss_t = 100000000 or something safe for your needs.
};

UINT64 ui64TimeStamp = pressed == notes_left_s.front()->getButton() ? notes_left_s.front()->getTimeStamp() : notes_right_s.front()->getTimeStamp();
std::vector<BLAH> * pvGemsErase = pressed == notes_left_s.front()->getButton() ? &note_gems_left : &note_gems_right;
std::vector<BLAH> * pvNotesErase = pressed == notes_left_s.front()->getButton() ? &notes_left_s : &notes_right_s;

for ( DWORD I = 0; I < sizeof( tTimes ) / sizeof( tTimes[0] ); ++I ) {
if (time <= ui64TimeStamp + tTimes[I].ui64Range
&& time >= ui64TimeStamp - tTimes[I].ui64Range)
{
score += points * tTimes[I].dwPoints;
note_hit = tTimes[I].htHitType;
pvGemsErase->erase(pvGemsErase->begin());
pvNotesErase->erase(pvNotesErase->begin());
break;
}
}

I could be more elegant with a bit more knowledge of the overall design but you get the idea.

L. Spiro

Share on other sites

Oooh that makes sense. My only remaining question then is where/how to define the table if I'm reading in the values for for great_t, etc. and great, etc. from a script? Because as it stands I can't define the table in a header file, because the values will not have been read in, and defining it in my init() function gives me a syntax error about incomplete types when I go to use sizeof(timing_table).

Thanks!

Share on other sites
Then you should have some way of reading it at load-time and storing it for later use.
If not, something is wrong.

L. Spiro