【问题标题】:Making eyeball look at/follow cursor movement (C#)使眼球注视/跟随光标移动(C#)
【发布时间】:2015-10-07 20:04:16
【问题描述】:

我被困在这里了。我想在“看”光标(角度)时画出眼睛。此外,它应该包含在更大的圆圈/象限内(就像眼球一样)。可悲的是,它不会在正确的位置/角度和每次鼠标移动时吸引我的眼球。它唯一会做的就是最初在 (0,0) 处绘制一个椭圆,但这不是我想要的。

我的想法是用勾股定理计算三角形的比率。然后在drawEllipse(); 方法中应用正确的坐标(使用正确的比例)。每次移动光标时都应重复此操作。

您可以查看我的图片以了解数学推理。

这是我的代码,请注意,面板是在设计器模式下制作的,未包含在此代码中,但应该没什么大不了的:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace oogjes2
{
    public partial class Form1 : Form
    {
        public int mousex;
        public int mousey;

        public Form1()
        {
            InitializeComponent();
            panel1.Paint += paintpanel;
            panel1.MouseMove += panel1_MouseMove;     
        }

        //panel1 cover the screen from (0.0) and onwards,
        void panel1_MouseMove(object sender, MouseEventArgs mea)
        {
            int mousex = mea.X;
            int mousey = mea.Y;
        } 

        void paintpanel(object obj, PaintEventArgs pea)
        {
            Pen blackpen = new Pen(Color.Black, 3);

            // the black outer circle which doesnt move
            pea.Graphics.DrawEllipse(blackpen, -125, -125, 250, 250);

            // e = 63. Diagonal distance from (0,0) to starting point drawEllipse
            // factor = multiplication from mea.x and mea.y to the respective ex and ey of the small circle.
            // ey = factor * mousex (mea.X). Same for ex.

            float e = (float)Math.Sqrt(45 * 45 + 45 * 45); //=63
            float factor = (e / (float)Math.Sqrt(mousex * mousex + mousey * mousey));
            int ex = mousex * (int)factor;
            int ey = mousey * (int)factor;

            //  the eye that should be redrawn at every mousemovement
            pea.Graphics.DrawEllipse(blackpen, ex, ey, 50, 50);
            this.Invalidate();
        }
    }
}

【问题讨论】:

  • 是的。面板上只有 2D。

标签: c# mouseevent mouse-position drawellipse


【解决方案1】:

如果您想让眼睛跟随光标,则需要计算眼睛到光标的角度。

你只需要知道三件事:

眼睛的位置,鼠标的位置,以及瞳孔中心与眼睛中心的距离(我称你的内圈为瞳孔,外圈为眼睛)。 由于眼睛从不移动(仅围绕其中心旋转),因此您已经知道它的位置。

void direction_to_cursor(){
  float p = Math.sqrt((45 + r)*(45 + r)*2); // Distance from outer circle center to inner circle center
  // assuming you want the top left corner 63 away from 0, 0
  // r is radius of inner circle
  int x = mouseX - EyeX; // In your picture it looks like your eye is at 0,0
  int y = -(mouseY - EyeY); // inverted y axis (0 is at top)
  float dir = Math.atan2(x, y);
  int px = p * Math.cos(dir);   // x Center of inner circle
  int py = p * Math.cos(dir);   // y Center of inner circle
  px -= r;  // Get left x coordinate of circle
  py -= r;  // get right x coordinate of circle

  pea.Graphics.DrawEllipse(blackpen, px, py, 50, 50);
}

step1: Calculate distance from center of Eye to center of pupil
step2: Calculate x and y difference between the Mouse and Eye
step3: Calculate direction from eye to mouse.
step4: Calculate position of pupil from direction and distance from center of eye

你可以使用下面的

void paintpanel(object obj, PaintEventArgs pea)
{
    Pen blackpen = new Pen(Color.Black, 3);
    pea.Graphics.DrawEllipse(blackpen, -125, -125, 250, 250);

    float p = Math.sqrt(2*70*70); // (45+25)*(45+25)+(45+25)*(45+25)
    float dir = Math.atan(y, x);
    int ex = Math.cos(dir) * p - 25;
    int ey = Math.sin(dir) * p - 25; 

    //  the eye that should be redrawn at every mousemovement
    pea.Graphics.DrawEllipse(blackpen, ex, ey, 50, 50);
    this.Invalidate();
}

【讨论】:

    【解决方案2】:

    试试这个:

    public partial class Form1 : Form
    {
    
        private Timer tmr;
        private int PupilRadius = 20;
        private int EyeBallRadius = 50;
        private int DistanceBetweenEyes = 20;
    
        public Form1()
        {
            InitializeComponent();
            this.panel1.Paint += panel1_Paint;
    
            tmr = new Timer();
            tmr.Interval = 100;
            tmr.Tick += tmr_Tick;
            tmr.Start();
        }
    
        void tmr_Tick(object sender, EventArgs e)
        {
            panel1.Invalidate();
        }
    
        void panel1_Paint(object sender, PaintEventArgs e)
        {
            Point center = new Point(panel1.ClientSize.Width / 2, panel1.ClientSize.Height / 2);
            Point LeftEyeCenter = new Point(center.X - EyeBallRadius - (DistanceBetweenEyes / 2), center.Y);
            Point RightEyeCenter = new Point(center.X + EyeBallRadius + (DistanceBetweenEyes / 2), center.Y);
    
            Rectangle rc = new Rectangle(LeftEyeCenter, new Size(1, 1));
            rc.Inflate(EyeBallRadius, EyeBallRadius);
            e.Graphics.DrawEllipse(Pens.Black, rc);
    
            rc = new Rectangle(RightEyeCenter, new Size(1, 1));
            rc.Inflate(EyeBallRadius, EyeBallRadius);
            e.Graphics.DrawEllipse(Pens.Black, rc);
    
            Point curPos = panel1.PointToClient(Cursor.Position);
            Double DistanceFromLeftEyeToCursor = getDistance(LeftEyeCenter.X, LeftEyeCenter.Y, curPos.X, curPos.Y);
            Double DistanceFromRightEyeToCursor = getDistance(RightEyeCenter.X, RightEyeCenter.Y, curPos.X, curPos.Y);
            double angleLeft = getAngleInDegrees(LeftEyeCenter.X, LeftEyeCenter.Y, curPos.X, curPos.Y);
            double angleRight = getAngleInDegrees(RightEyeCenter.X, RightEyeCenter.Y, curPos.X, curPos.Y);
    
            rc = new Rectangle(new Point(Math.Min((int)DistanceFromLeftEyeToCursor, EyeBallRadius - PupilRadius), 0), new Size(1, 1));
            rc.Inflate(PupilRadius, PupilRadius);
            e.Graphics.TranslateTransform(LeftEyeCenter.X, LeftEyeCenter.Y);
            e.Graphics.RotateTransform((float)angleLeft);
            e.Graphics.FillEllipse(Brushes.Blue, rc);
    
            rc = new Rectangle(new Point(Math.Min((int)DistanceFromRightEyeToCursor, EyeBallRadius - PupilRadius), 0), new Size(1, 1));
            rc.Inflate(PupilRadius, PupilRadius);
            e.Graphics.ResetTransform();
            e.Graphics.TranslateTransform(RightEyeCenter.X, RightEyeCenter.Y);
            e.Graphics.RotateTransform((float)angleRight);
            e.Graphics.FillEllipse(Brushes.Blue, rc);
        }
    
        private Double getDistance(int Ax, int Ay, int Bx, int By)
        {
            return Math.Sqrt(Math.Pow((Double)Ax - Bx, 2) + Math.Pow((Double)Ay - By, 2));
        }
    
        private Double getAngleInDegrees(int cx, int cy, int X, int Y)
        {
            // draw a line from the center of the circle
            // to the where the cursor is...
            // If the line points:
            // up = 0 degrees
            // right = 90 degrees
            // down = 180 degrees
            // left = 270 degrees
    
            Double angle;
            int dy = Y - cy;
            int dx = X - cx;
            if (dx == 0) // Straight up and down | avoid divide by zero error!
            {
                if (dy <= 0)
                {
                    angle = 0;
                }
                else
                {
                    angle = 180;
                }
            }
            else
            {
                angle = Math.Atan((Double)dy / (Double)dx);
                angle = angle * ((Double)180 / Math.PI);
    
                if (X <= cx)
                {
                    angle = 180 + angle;
                }
            }
    
            return angle;
        }
    
    }
    

    【讨论】:

    • 啊,太好了 :D.. 不过只有一个问题,为什么角度(在 getAngleInDegrees(); 中)随后在“ RotateTransform((float)angleRight - 90); 中减去 90 和RotateTransform((float)angleLeft - 90); "?
    • 说真的?...已经很晚了,我可能应该在几个小时前就上床睡觉了。 =) 我已经在上面的编辑中修复了代码。 -90 已从 Paint() 事件中删除,并且 getAngleInDegrees() 已更改。考虑到这一点,仍然可能存在其他“未优化”!
    猜你喜欢
    • 1970-01-01
    • 2018-03-10
    • 2011-02-07
    • 2015-05-11
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多