Limegarden.net Personal site of Wouter Lindenhof

6Apr/100

Combo hit!! in code

I have always wondered how hard it would be to write a combo system. Not that hard I guess. And after a bit of morning programming I already got it working.

The only reason it took longer than anticipated was because of muscle memory. One of the features I wanted to test was the delay. For example you want to do the "asdf" combo, but you are for some reason not fast enough, than the combo should not start. Simulating this is easy, just begin the combo and stop somewhere for a second and then complete the combo. So "asd", pause and then "f".
However when I tried that for some reason the combo was sometimes completed. Only after adding the debug messages I noticed that I often automatically did complete the combo. The problem was muscle memory.

Anyway below is the code and if anyone wants to extend it (wrong next key, combo breakers, roman cancel, and follow-up combos) feel free to do so and let me know.


/*******************************************************************************
 * The MIT License
 *
 * Licensed under the MIT license:
 *   http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2010 Wouter Lindenhof (http://limegarden.net)
 *
 * Demonstration of a simple ComboHit system
 *******************************************************************************/

#include <Windows.h>
#include <iostream>
#include <vector>
#pragma comment(lib, "Winmm.lib")

#define DEBUGLOG 1 // Set to 0 to turn debug messages off

class KeyHit
{
public:
	UINT m_Key;
	UINT m_Delay;
	UINT m_Waiting;
public:
	KeyHit(UINT key, UINT delay) : m_Key(key), m_Delay(delay), m_Waiting(0) { }
};

class HitCombo
{
	UINT m_SequenceIndex;
	std::vector<KeyHit> m_Keys;
public:
	HitCombo() : m_SequenceIndex(0) { }

	void Cancel();
	void Update(DWORD ms);
	operator bool();
	HitCombo& operator << (const KeyHit& hit);
};

int main(int argc, const char* argv[])
{
	std::cout << "-----------------------------------------------" << std::endl;
	std::cout << "This is a combo key tester: " << std::endl;
	std::cout << "Press \"ASDF\" quickly to do a combo hit" << std::endl;
	std::cout << "Press \"Wouter\" quickly to write my name" << std::endl;
	std::cout << "Press SHIFT and then escape to quit" << std::endl;
	std::cout << "-----------------------------------------------" << std::endl;
	HitCombo QuitApplication, ComboHit, WouterCombo;
	QuitApplication << KeyHit(VK_SHIFT, 250) << KeyHit(VK_ESCAPE, 250);
	ComboHit		<< KeyHit('A', 250) << KeyHit('S', 250) << KeyHit('D', 250)
					<< KeyHit('F', 250);
	WouterCombo		<< KeyHit('W', 250) << KeyHit('O', 250) << KeyHit('U', 250)
					<< KeyHit('T', 250) << KeyHit('E', 250) << KeyHit('R', 250);

	DWORD lastTime = timeGetTime();
	DWORD curTime = lastTime;
	DWORD difference = 0;

	while(true)
	{
		curTime = timeGetTime();
		difference = curTime - lastTime;
		lastTime = curTime;
		if(ComboHit)
		{
			std::cout << "You did a combo hit!!" << std::endl;
			WouterCombo.Cancel();
			QuitApplication.Cancel();
		}
		if(WouterCombo)
		{
			std::cout << "You wrote 'Wouter', good for you!" << std::endl;
			ComboHit.Cancel();
			QuitApplication.Cancel();
		}
		if(QuitApplication)
		{
			std::cout << "You quit the application!" << std::endl;
			ComboHit.Cancel();
			WouterCombo.Cancel();
			break;
		}
		ComboHit.Update(difference);
		QuitApplication.Update(difference);
		WouterCombo.Update(difference);
	}

	return 0;
}

void HitCombo::Cancel() {
	m_SequenceIndex = 0;
}

// Implementation
HitCombo& HitCombo::operator <<(const KeyHit &hit) {
	m_Keys.push_back(hit);
	return *this;
}

HitCombo::operator bool() {
	return m_SequenceIndex == m_Keys.size();
}
void HitCombo::Update(DWORD ms)
{
	if(m_SequenceIndex < m_Keys.size())
	{
		KeyHit& hit = m_Keys[m_SequenceIndex];
		hit.m_Waiting += ms;
		if(GetAsyncKeyState(hit.m_Key) != 0)
		{
			if(hit.m_Waiting < hit.m_Delay)
			{
				hit.m_Waiting = 0;
				m_SequenceIndex++;
#if DEBUGLOG = 1
				std::cout << "you pressed key " << (char)hit.m_Key << std::endl;
#endif
			}else
			{
#if DEBUGLOG = 1
				std::cout << "Delay too long" << std::endl;
#endif
				hit.m_Waiting = 0;
				m_SequenceIndex = 0;
			}
			if(m_SequenceIndex == 0)
			{
				hit.m_Waiting = 0;
			}
		}else if(m_SequenceIndex==0)
		{
			hit.m_Waiting = 0;
		}else
		{
			if(hit.m_Waiting > hit.m_Delay)
			{
				m_SequenceIndex = 0;
				hit.m_Waiting = 0;
#if DEBUGLOG
				std::cout << "Delay too long" << std::endl;
#endif
			}
		}
	}else
	{
		m_SequenceIndex = 0;
		KeyHit& hit = m_Keys[m_SequenceIndex];
		hit.m_Waiting = 0;
	}
}
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

(required)

No trackbacks yet.