If you have many sprites, a collision system using QuadTrees should be predestined for those kind of tasks as it wouldn't need to iterate through all sprites but only down a few knots of the Tree.
Not sure how AppGameKit did the hit test or if it is overpowered and maybe even have a bigger overhead for your task than actally run through all your sprites, just one option.
QuadTree Code I had lying around.
type vec2
X#
Y#
endtype
type QuadTree_NodeData
Depth as integer
MinX# as float
MinY# as float
MaxX# as float
MaxY# as float
ChildID as integer[3]
Point as vec2[]
endtype
global MaxPoints
MaxPoints=4
global MaxDepth
MaxDepth=6
Node as QuadTree_NodeData
MyQuadTree as QuadTree_NodeData[]
RootNode as QuadTree_NodeData
RootNodeID=QuadTree_CreateNode(MyQuadTree, 0,0,100,100, Node)
function AddPoint(Node ref as QuadTree_NodeData,X#,Y#)
TempPoint as vec2
TempPoint.X#=X#
TempPoint.Y#=Y#
Node.Point.insert(TempPoint)
endfunction
function RemovePoint(Node ref as QuadTree_NodeData, PointID as integer)
Node.Point.remove(PointID)
endfunction
function QuadTree_Clear(QuadTree ref as QuadTree_NodeData[], Node ref as QuadTree_NodeData)
for ChildID=3 to 0 step -1
if Node.ChildID[ChildID]<>-1
QuadTree_Clear(QuadTree, QuadTree[Node.ChildID[ChildID]])
Node.ChildID.remove(ChildID)
endif
next ChildID
endfunction
function QuadTree_CreateNode(QuadTree ref as QuadTree_NodeData[], MinX#,MinY#,MaxX#,MaxY#,ParentNode ref as QuadTree_NodeData)
TempNode as QuadTree_NodeData
TempNode.Depth=ParentNode.Depth+1
TempNode.MinX#=MinX#
TempNode.MinY#=MinY#
TempNode.MaxX#=MaxX#
TempNode.MaxY#=MaxY#
for ChildID=0 to 3
TempNode.ChildID[ChildID]=-1
next ChildID
QuadTree.insert(TempNode)
endfunction QuadTree.length
function QuadTree_SplitNode(QuadTree ref as QuadTree_NodeData[], Node ref as QuadTree_NodeData)
X#=(Node.MinX#+Node.MaxX#)*0.5
Y#=(Node.MinY#+Node.MaxY#)*0.5
Node.ChildID[0]=QuadTree_CreateNode(QuadTree, Node.MinX#,Node.MinY#,X#,Y#,Node)
Node.ChildID[1]=QuadTree_CreateNode(QuadTree, X#,Node.MinY#,Node.MaxX#,Y#,Node)
Node.ChildID[2]=QuadTree_CreateNode(QuadTree, Node.MinX#,Y#,X#,Node.MaxY#,Node)
Node.ChildID[3]=QuadTree_CreateNode(QuadTree, X#,Y#,Node.MaxX#,Node.MaxY#,Node)
endfunction
function QuadTree_InsertPoint(QuadTree ref as QuadTree_NodeData[], Node ref as QuadTree_NodeData,X#,Y#)
if Node.Point.length<MaxPoints
AddPoint(Node,X#,Y#)
else
QuadTree_SplitNode(QuadTree, Node)
for ChildID=0 to 3
if QuadTree_InsideNode(QuadTree[Node.ChildID[ChildID]],X#,Y#)=1
QuadTree_InsertPoint(QuadTree, QuadTree[Node.ChildID[ChildID]],X#,Y#)
exit
endif
next ChildID
endif
endfunction
function QuadTree_Exist(QuadTree ref as QuadTree_NodeData[], NodeID,X#,Y#)
for ChildID=0 to 3
if QuadTree[NodeID].ChildID[ChildID]<>-1
if QuadTree_InsideNode(QuadTree[QuadTree[NodeID].ChildID[ChildID]],X#,Y#)=1
ID=QuadTree_Exist(QuadTree,QuadTree[NodeID].ChildID[ChildID],X#,Y#)
if ID<>-1 then exitfunction ID
endif
endif
next ChildID
if QuadTree_InsideNode(QuadTree[NodeID],X#,Y#)=1 then exitfunction NodeID
endfunction -1
function QuadTree_InsideNode(Node ref as QuadTree_NodeData,X#,Y#)
if X#>=Node.MinX# and X#<Node.MaxX#
if Y#>=Node.MinY# and Y#<Node.MaxY#
exitfunction 1
endif
endif
endfunction 0
function QuadTree_IntersectBounds(Node ref as QuadTree_NodeData,MinX#,MinY#,MaxX#,MaxY#)
endfunction Not (MinX#>Node.MaxX# or MaxX#<Node.MinX# or MinY#>=Node.MaxY# or MaxY#<Node.MinY#)
function QuadTree_InsideBounds(QuadTree ref as QuadTree_NodeData[], Node ref as QuadTree_NodeData,MinX#,MinY#,MaxX#,MaxY#, Points ref as vec2[])
if QuadTree_IntersectBounds(Node,MinX#,MinY#,MaxX#,MaxY#)
for p=0 to Node.Point.length
if Node.Point[p].X#>=MinX# and Node.Point[p].X#<MaxX#
if Node.Point[p].Y#>=MinY# and Node.Point[p].Y#<MaxY#
Points.insert(Node.Point[p])
endif
endif
next p
if Node.Point.length=MaxPoints
for ChildID=0 to 3
if Node.ChildID[ChildID]>-1
QuadTree_InsideBounds(QuadTree,QuadTree[Node.ChildID[ChildID]],MinX#,MinY#,MaxX#,MaxY#, Points)
endif
next ChildID
endif
endif
endfunction Points