Mouse movement interpretation

Given that at a certain moment I know that I want to perform a specific action (make circular movements with my mouse to rotate a valve), any suggestions on how I should proceed to detect how much of a full circle the mouse has moved?

For example moving always on X axis will only slightly rotate the valve, I need to actually “draw a circle” to rotate the valve all the way.

First thing that comes to mind is gestures, but I’m not sure if there’s a simpler way…

Thanks!

I have a vested interest in this so I will take on helping you on it.

This all kind of spawns back to the game Black and White. You cast spells by making gestures in the air. W, Z, O, triangle, whatever the gesture was recognized and once you got to the recognition point then the spell intiated and it did a casting effect showing you did it right. You had to be good, because sometimes it didn’t recognize the pattern.

OK, so lets work with some theory and see where we can go.

First lets record the mouse only while the mouse button is down and every 0.05 seconds. This way we are not wasting memory.

Now, when we release the mouse button, we should do a check to see if we have achieved the correct gesture. So we need to convert the mouse data into a bitmap. (just like drawing in photoshop, eh) To do that, we need to get the bounds of the trail, min max all the way and you get a the correct bounds. (for some dumb reason Encapsulate didnt like starting with one point, so I had to actually use Min and Max. Annoying) Compare the min and max to a standard width and height for our gesture. So I chose a simple 32 x 32 bitmap. Black on white.

Now, with good luck, we have a texture of “points”, now we simply compare our bitmap to a gesture map. So we create a Z in the screen, and what we are looking for is 90% of the points in our z to match a point in the gesture map.

594681--21186--$O.png
594681--21187--$Z.png

OK, lastly, onto some code. (you will notice that you have to have a textured cube to display your texture and I put a emitter in there to make the gesture visible, but you can drop all of that and make it your own.

http://www.lod3dx.net/Unity/Gesture.html

I hope this helps. :wink:

var O : Texture2D;
var Z : Texture2D;

var testCube : Transform;

var emitter : Transform;
private var mouseData : Array=Array();
var captureMouseEvery=0.05;
private var nextCapture=0.0;
private var screenMessage="";

function Update () {
	if(Input.GetMouseButtonUp(0)){
		var mousePattern : Texture2D=MapPattern();
		if(mousePattern){
			var msg="";
			var testO=TestPattern(mousePattern, O);
			var testZ=TestPattern(mousePattern, Z);
			if(testO > 0.9) msg="Matched O at "+ Mathf.Round(testO * 100) +"%";
			if(testZ > 0.9) msg="Matched Z at "+ Mathf.Round(testZ * 100) +"%";
			if(msg!="")
				StartCoroutine(showEffect(mouseData, msg));
		}
		mouseData=Array();
	}
}

function OnGUI(){
	if(screenMessage!=""){
		GUI.Label (Rect (10, 10, 200, 20), screenMessage);
	}
}

function FixedUpdate(){
	// capture mouse
	if(Time.time>nextCapture  Input.GetMouseButton(0)){
		mouseData.Add(Input.mousePosition);
		nextCapture=Time.time + captureMouseEvery;
	}
}

function MapPattern() : Texture2D{
	if(mouseData.length<10) return null;
	var bounds = Bounds (mouseData[0], Vector3.zero);
	for(i=1; i<mouseData.length; i++){
		bounds.min=Vector3.Min(bounds.min, mouseData[i]);
		bounds.max=Vector3.Max(bounds.max, mouseData[i]);
	}
	var texture = new Texture2D (32, 32);
	var pix=texture.GetPixels();
	for(i=0; i<pix.length; i++){
		pix[i]=Color.white;
	}
	if(bounds.size.magnitude < 20) return null;
	for(i=0; i<mouseData.length; i++){
		var x : int=Mathf.Clamp((mouseData[i].x - bounds.min.x)/bounds.size.x * 32,0,31);
		var y : int=Mathf.Clamp((mouseData[i].y - bounds.min.y)/bounds.size.y * 32,0,31);
		pix[x + y * 32]=Color.black;
	}
	texture.SetPixels(pix);
	texture.Apply();
	testCube.renderer.material.mainTexture=texture;
	return texture;
}

function TestPattern(fromTexture : Texture2D,toTexture : Texture2D){
	var fromPix=fromTexture.GetPixels();
	var toPix=toTexture.GetPixels();
	var total : float=0;
	var correct : float=0;
	for(var i=0; i<fromPix.length; i++){
		if(fromPix[i]==Color.black){
			total++;
			if(toPix[i]==Color.black) correct++;
		}
	}
	var r : float=correct / total;
	return r;
}

function showEffect(data : Array, message : String){
	screenMessage=message;
	for(i=0; i<data.length; i++){
		var point=data[i];
		var ray=Camera.main.ScreenPointToRay(point);
		emitter.position=ray.GetPoint(10.0);
		emitter.particleEmitter.Emit();
		yield WaitForSeconds(captureMouseEvery/2);
		point=Vector3.Lerp(data[i], data[(i+1) % data.length], 0.5);
		ay=Camera.main.ScreenPointToRay(point);
		emitter.position=ray.GetPoint(10.0);
		emitter.particleEmitter.Emit();
		yield WaitForSeconds(captureMouseEvery/2);
	}
	screenMessage="";
}
1 Like

Thanks a lot for your response… I still haven’t had time to look into this as my focus has been forcefully diverted to another problem at the moment. Once I get back to this I’ll read this again patiently… But I liked your idea much better than what I had found previously. Thanks! :slight_smile: