いろんなあたり判定できた
ネットを漁ってとりあえずRubyで実装。
基本アルゴリズムとしてはこれでOKだろう。
require "dxruby" Vector = Struct.new(:x, :y) Point = Struct.new(:x, :y) # 線分と直線 <0 交差する, =0 上, >0 交差しない def intersect(p1, p2, p3, p4) return ((p1.x - p2.x) * (p3.y - p1.y) + (p1.y - p2.y) * (p1.x - p3.x)) * ((p1.x - p2.x) * (p4.y - p1.y) + (p1.y - p2.y) * (p1.x - p4.x)) end # へこんでない右回りの四角と点 def checkbox(p, p1, p2, p3, p4) c = Point.new c.x = (p1.x + p2.x + p3.x + p4.x) / 4 # 中心点x c.y = (p1.y + p2.y + p3.y + p4.y) / 4 # 中心点y return false if intersect(p1, p2, p, c) < 0 or intersect(p2, p3, p, c) < 0 or intersect(p3, p4, p, c) < 0 or intersect(p4, p1, p, c) < 0 return true end # 線分同士 def checkline(a1, a2, b1, b2) s1 = (a1.y - a2.y) * (b1.x - a1.x) - (a1.x - a2.x) * (b1.y - a1.y) s2 = (a1.y - a2.y) * (b2.x - a1.x) - (a1.x - a2.x) * (b2.y - a1.y) s3 = (b1.y - b2.y) * (a1.x - b1.x) - (b1.x - b2.x) * (a1.y - b1.y) s4 = (b1.y - b2.y) * (a2.x - b1.x) - (b1.x - b2.x) * (a2.y - b1.y) return (s1 * s2 <= 0 and s3 * s4 <= 0) end # 内積 def dotProduct(vec1, vec2) vec1.x * vec2.x + vec1.y * vec2.y end # 距離 def distance(pt1, pt2) Math.sqrt((pt1.x - pt2.x)**2 + (pt1.y - pt2.y) **2) end # 円と線分の判定 def checkCrclCls(ptc, cr, pt1, pt2) # vは線分始点から終点 # cは線分始点から円中心 v = Vector.new(pt2.x - pt1.x, pt2.y - pt1.y) c = Vector.new(ptc.x - pt1.x, ptc.y - pt1.y) # 二つのベクトルの内積を求める n1 = dotProduct(v, c) if n1 < 0 then # cの長さが円の半径より小さい場合は交差している return distance(pt1, ptc) < cr ? true : false end n2 = dotProduct( v, v ) if n1 > n2 then # 線分の終点と円の中心の距離の二乗を求める len = distance(pt2, ptc)**2 # 円の半径の二乗よりも小さい場合は交差している return len < cr * cr ? true : false else n3 = dotProduct( c, c ) return ( n3-(n1/n2.to_f)*n1 < cr * cr ) ? true : false end end image = Image.new(640, 480) cimage = Image.new(101,101).circle(50,50,50,[255,255,255,255]) cimage2 = Image.new(101,101).circle(50,50,50,[255,0,255,255]) pt1 = nil pt2 = nil pt3 = Point.new(400,300) pt4 = Point.new(500,400) bp1 = Point.new(400,100) bp2 = Point.new(450,150) bp3 = Point.new(400,200) bp4 = Point.new(350,150) Window.loop do image.box(0, 0, 639, 479, [255,0,0,0]) # 背景 image.line(pt3.x, pt3.y, pt4.x, pt4.y, [255,255,255,255]) # せん image.line(bp1.x, bp1.y, bp2.x, bp2.y, [255,255,255,255]) # しかく1 image.line(bp2.x, bp2.y, bp3.x, bp3.y, [255,255,255,255]) # しかく2 image.line(bp3.x, bp3.y, bp4.x, bp4.y, [255,255,255,255]) # しかく3 image.line(bp4.x, bp4.y, bp1.x, bp1.y, [255,255,255,255]) # しかく4 Window.draw(100,100,cimage, 1) # まる pt2 = Point.new(Input.mousePosX, Input.mousePosY) # マウスが押されたらラインの始点を設定 if Input.mousePush?(M_LBUTTON) then pt1 = pt2 end # マウスが押されていたら当たり判定 if Input.mouseDown?(M_LBUTTON) then image.line(pt1.x, pt1.y, pt2.x, pt2.y, [255,255,255,255]) if pt1.x != pt2.x or pt1.y != pt2.y then # まると if checkCrclCls(Point.new(150, 150), 50, pt1, pt2) then Window.draw(100, 100, cimage2, 1) end # せんと if checkline(pt1, pt2, pt3, pt4) then image.line(pt3.x, pt3.y, pt4.x, pt4.y, [255,0,255,255]) end # しかくと if checkbox(pt1, bp1, bp2, bp3, bp4) or checkline(pt1, pt2, bp1, bp2) or checkline(pt1, pt2, bp2, bp3) or checkline(pt1, pt2, bp3, bp4) or checkline(pt1, pt2, bp4, bp1) then image.line(bp1.x, bp1.y, bp2.x, bp2.y, [255,0,255,255]) # しかく1 image.line(bp2.x, bp2.y, bp3.x, bp3.y, [255,0,255,255]) # しかく2 image.line(bp3.x, bp3.y, bp4.x, bp4.y, [255,0,255,255]) # しかく3 image.line(bp4.x, bp4.y, bp1.x, bp1.y, [255,0,255,255]) # しかく4 end end end break if Input.keyPush?(K_ESCAPE) Window.draw(0,0,image) end
なぜか丸だけイメージなのは、丸を描くのが遅いという話ではなく、はじめに画像を作ったけど線分と四角が面倒になったからというだけで、特に意味は無い。