0
\$\begingroup\$

I want to simulate eyeballs roll in eyes and I have found and forked this implementation in codepen.io. This is exactly what I need.

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var border = 10;
var centerX = c.width / 2;
var centerY = c.height / 2;
var radius = 40;

var radiusEye = 12;

var faceCenterX = centerX;
var faceCenterY = border+radius + 60;

var radiusEyeIn = 6;

var eyeYPosition = faceCenterY-8
    
var reyedx = faceCenterX+(radiusEyeIn/2)+13;
var reyedy = eyeYPosition;

var leyedx = faceCenterX-(radiusEyeIn/2)-13;
var leyedy = eyeYPosition;

var eyesgap = 4;

var eyeXGap = (radiusEye/2)+9;

var reyedxafter = reyedx;
var reyedyafter = reyedy;

var leyedxafter = leyedx;
var leyedyafter = leyedy;



function drawscreen(){

  ctx.beginPath();
  ctx.arc(faceCenterX, faceCenterY, radius, 0, 2 * Math.PI, false);
  ctx.fillStyle = 'rgba(100,100,100,0.5)';
  ctx.fill();
  ctx.stroke();

  var radiusEye = 12;
  ctx.beginPath();
  ctx.arc(faceCenterX-eyeXGap, eyeYPosition, radiusEye, 0, 2 * Math.PI, false);
  ctx.fillStyle = 'rgba(255,255,255,1)';
  ctx.fill();
  ctx.stroke();

  ctx.beginPath();
  ctx.arc(faceCenterX+eyeXGap, eyeYPosition, radiusEye, 0, 2 * Math.PI, false);
  ctx.fillStyle = 'rgba(255,255,255,1)';
  ctx.fill();
  ctx.stroke();
}

function draweyes() {
  
  ctx.beginPath();
  ctx.arc(reyedxafter, reyedyafter, radiusEyeIn, 0, 2 * Math.PI, false);
  ctx.fillStyle = 'rgba(0,0,0,1)';
  ctx.fill();
  
  ctx.beginPath();
  ctx.arc(leyedxafter, leyedyafter, radiusEyeIn, 0, 2 * Math.PI, false);
  ctx.fillStyle = 'rgba(0,0,0,1)';
  ctx.fill();
}

//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

function mouseMove(e) {
        var mouseX = e.pageX - this.offsetLeft - faceCenterX;
        var mouseY = e.pageY - this.offsetTop - eyeYPosition;
  
        var ratioX = Math.abs(mouseX)/(Math.abs(mouseX)+Math.abs(mouseY));
        var ratioY = Math.abs(mouseY)/(Math.abs(mouseX)+Math.abs(mouseY));
  
        
        if(mouseX > 0){
          reyedxafter = reyedx + (ratioX*eyesgap);        
        } else {
          reyedxafter = reyedx - (ratioX*eyesgap);
        }
        
        if(mouseY > 0){
          reyedyafter = reyedy + (ratioY*eyesgap);
        } else {
          reyedyafter = reyedy - (ratioY*eyesgap);         
        }
  
        if(mouseX > 0){
          leyedxafter = leyedx + (ratioX*eyesgap);
        } else {
          leyedxafter = leyedx - (ratioX*eyesgap);
        }
  
        if(mouseY > 0){
          leyedyafter = leyedy + (ratioY*eyesgap);
        } else {
          leyedyafter = leyedy - (ratioY*eyesgap);
        }
  
        ctx.clearRect(0, 0, c.width, c.height);
        drawscreen();
        draweyes();
}

function init() {
    //c.addEventListener('mousedown', mouseDown, false);
   // c.addEventListener('mouseup', mouseUp, false);
    c.addEventListener('mousemove', mouseMove, false);
    drawscreen();
    draweyes();
}

init();
<canvas id="myCanvas" width="500" height="400" style="border:1px solid #000000;">
</canvas>

I can just use this one but I don't understand the mathematical explanation behind this solution. I can only think of limiting the movement of the eyeballs in the eyes. Why do I have to do it like this one? What is the purpose of calculating ratioX and ratioY? Is there a simpler way to do similar simulation?

\$\endgroup\$
1
\$\begingroup\$

It's much easier to just get the vectors of the point between the two eyes and the mouse, subtract the face vector from the mouse and normalize the result. The vector you get is the position of the pupils relative to the center of the eyes.

normalize(mouse - face)

You'll need a vector library for this. Without vectors:

x = mouseX - faceX
y = mouseY - faceY
mag = √(x² + y²)
if mag > 0 then
    x /= mag
    y /= mag
\$\endgroup\$
  • \$\begingroup\$ Wow this is much more succinct. I have my own Vector library but most parts of my game are written without Vectors so I try not to use it too much in the code. So it is just one line of code (with mouse and face positions all converted to vectors)? \$\endgroup\$ – newguy Jun 24 '17 at 10:09
  • \$\begingroup\$ @newguy yeah it is \$\endgroup\$ – Bálint Jun 24 '17 at 10:45
  • \$\begingroup\$ What are the x and y in the non-vector version? Are they the relative coordinate to the center of the eyes too? \$\endgroup\$ – newguy Jun 24 '17 at 10:50
  • \$\begingroup\$ @newguy the latter is the translation from vector to vectorless. Yes they are \$\endgroup\$ – Bálint Jun 24 '17 at 11:00
  • \$\begingroup\$ Thanks I have made it work: codepen.io/caymanbruce/pen/WOEWwg?editors=0011. One more question though. This method uses square root function while the original one I posted use simple algebra operations. In regards to performance, if I need to roll the pupils a lot in the eyes when playing my game will this approach be slower? \$\endgroup\$ – newguy Jun 24 '17 at 11:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.