# How to calculate more precisely the position of the pupil in function of the eye ball and a direction?

I have a game in which I have an eye in a head that should always move towards a piece of food (or another piece of food). The head is moved by the player. The food has a fixed position (for some amount of time).

I have solved the maths somehow, but I do not get the precision I want. As I turn around the food, the eye moves almost perfectly, but it is (1) outside the circle sometimes and (2) not perfectly positioned.

Example (left: food, right: head with eye ball with pupil outside the eye ball):

The position of the eye ball is updated on each move of the player.

# Relevant code in MainWindow.xaml.cs

EyeBall eb = MyEyeBall;

eb.HorizontalAlignment = HorizontalAlignment.Stretch;
eb.VerticalAlignment = VerticalAlignment.Stretch;

c.Content = eb;

Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
{
Cell foodCell = GetFoodCell();

// A - eye center
// B - first food center (TODO : automatically the closest food)
// A' - pupil center
// d1 - distance from center of eye to boundary of pupil

// hard coded values from the proportions in EyeBall.xaml
double d1 = 6,
d3 = 9;

Point A = eb.TransformToAncestor(MyUniformGrid).Transform(new Point(eb.ActualWidth / 2, eb.ActualHeight / 2));

Point B = foodCell.TransformToAncestor(MyUniformGrid).Transform(
new Point(foodCell.ActualWidth / 2, foodCell.ActualHeight / 2));

double sum = (d1 + d3) * (((FrameworkElement)eb.Child).ActualHeight / eb.ActualHeight);
//double sum = eb.TransformToAncestor(MyUniformGrid).Transform(new Point(d1 + d3, 0)).X;

double k = sum / (DistDouble(A, B) - sum);

Point Ap = new Point(((A.X + k * B.X) / (1d + k)),
(A.Y + k * B.Y) / (1d + k));

Point Ap2 = MyUniformGrid.TransformToDescendant(eb).Transform(Ap);

Debug.WriteLine("===============================================");
Debug.WriteLine($"food cell position = {Board.Food.Pieces[0].Pos}"); Debug.WriteLine($"d1 = {d1}, d3 = {d3}");
Debug.WriteLine($"A = {A}, B = {B}"); Debug.WriteLine($"k = {k}");
Debug.WriteLine(\$"A': {Ap}     ->     {Ap2}");
Debug.WriteLine("===============================================");

eb.SetBallCenter(Ap2.X, Ap2.Y);
}));


# EyeBall.xaml.cs

public partial class EyeBall : Viewbox
{
public EyeBall()
{
InitializeComponent();
}

internal void SetBallCenter(double x, double y)
{
MyBallGeometry.Center = new Point(x, y);
}

internal Point GetBallCenter()
{
return MyBallGeometry.Center;
}
}


# EyeBall.xaml

<Viewbox x:Class="wpf_snake.EyeBall"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:wpf_snake"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Canvas Name="svg8" Width="61.809998" Height="60.000003">
<Canvas.RenderTransform>
<TranslateTransform X="0" Y="0"/>
</Canvas.RenderTransform>
<Canvas Name="layer1">
<Canvas.RenderTransform>
<TranslateTransform X="-46.272926" Y="-62.673704"/>
</Canvas.RenderTransform>
<Ellipse Canvas.Left="46.3" Width="61.8" Canvas.Top="62.7" Height="60" Name="ellipse971" Fill="#FF8A8EFF" StrokeThickness="0.45579806" StrokeMiterLimit="4" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Opacity="1"/>
<Ellipse Canvas.Left="52.9" Canvas.Top="68.4" Width="48.5" Height="48.5" Name="ellipse973" Fill="#FFFFFFFF" StrokeThickness="0.49706328" StrokeMiterLimit="4" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Opacity="1"/>
<Ellipse Canvas.Left="59.9" Canvas.Top="75.4" Width="34.5" Height="34.5" Name="circle979" Fill="#7BA9F2FF" StrokeThickness="0.07413793" StrokeMiterLimit="4" StrokeLineJoin="Round" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Opacity="1"/>
</Canvas>
<Path Stroke="Transparent" StrokeThickness="0" Fill="Blue" >
<Path.Data>
</Path.Data>
</Path>
</Canvas>
</Viewbox>


Thank you.

I can't provide you with the code solution, but here's some formulas you might find useful to do it yourself:

Calculate eyeball position:

position = normalize(food_piece - head_center) * head_radius

Vector normalization:

unit_vector = vector / length(vector)

be careful not to divide by zero here, so check length before performing division

Vector length:

length = sqrt(vector.x^2 + vector.y^2)

Alternatively, you may also use atan2(y, x), if available, to get angle between head and food piece. And then convert the angle to the unit vector using vector = (cos(angle), sin(angle)) and then multiply it by the head radius.

atan2(food.y - head.y, food.x - head.x)