An EventHandler[] toy: 25 particles (circles) interact with each other. They eventually settle down into some sort of flow, with the occasional random circle deciding they like someone else. Click and drag to move one and upset the status quo.
DynamicModule[{
n = 25, (* number of pts (constant) *)
pts,
drag = {} (* index of pt being dragged *)
},
pts = RandomReal[{-1, 1} 25/Sqrt[3 n], {n, 2}];
EventHandler[
Deploy@Graphics[ (* Deploy[] turns off the usual Graphics interactions *)
Dynamic@GraphicsComplex[ (* efficient way to manage a figure that is a function of points *)
pts = (* move[] the points, except the one being dragged *)
ReplacePart[pts + move[pts], # :> MousePosition["Graphics"] & /@ drag],
{Hue[#/n], Sphere[#, 0.7/Sqrt[n]]} & /@ Range[n]],
PlotRange -> 25/Sqrt[n]
],
(* mouse up/down: de/register which point is to be dragged *)
{"MouseDown" :> (drag = Nearest[pts -> Automatic, MousePosition["Graphics"]]),
"MouseUp" :> (drag = {})}
],
Initialization :> ( (* define how the points move *)
ClearAll[move];
(* it returns changes in position for each point in the list p *)
move[p_List] := Module[{$n, interaction},
$n = Length[p];
interaction = Array[
Function[{row, col},
Exp[-Abs[(row - col)/4] + 0.5 UnitStep[row - col] - 0.25]]
, {$n, $n}
]/(IdentityMatrix[n] + DistanceMatrix[p])^2 // Function[mat,
DiagonalMatrix[Total[mat] - 0.01 $n] - mat];
0.2*(interaction . p)
];)
]

I would have posted a cloud notebook, but it didn't render. Maybe Dynamic[] doesn't work so well there?