Sign in to follow this  
c_fried_rice

Time Sensitive Buttons Presses

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 this post


Link to post
Share on other sites
Data-driven is always the answer.
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 this post


Link to post
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 this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this