Ball2D.monkey2 22 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. #Import "PoolMod"
  2. Class VectorObject
  3. Global Gravityx:Float
  4. Global Gravityy:Float
  5. Global ApplicableGravityx:Float
  6. Global ApplicableGravityy:Float
  7. Global SurfaceFriction:Float
  8. Global ApplicableSurfaceFriction:Float
  9. Field image:Image
  10. Field P:PVector2D
  11. Field V:PVector2D
  12. Field D:PVector2D
  13. Field cp:PVector2D
  14. Field name:String=""
  15. Field friction:Float
  16. Field bounce:Float
  17. Field animation:ObjectAnimation
  18. Field L:Float
  19. Field cdx:Float
  20. Field cdy:Float
  21. Field tp:PVector2D
  22. Function SetGlobalGravity(t_gx:Float,t_gy:Float)
  23. Gravityx=t_gx
  24. Gravityy=t_gy
  25. ApplicableGravityx=t_gx
  26. ApplicableGravityy=t_gy
  27. End
  28. Function SetGlobalFriction(f:Float)
  29. SurfaceFriction=f
  30. ApplicableSurfaceFriction=f
  31. End
  32. Method Magnitude:Float(vx:Float,vy:Float)
  33. Return Sqrt(Self.V.x*Self.V.x+Self.V.y*Self.V.y)
  34. End
  35. Method Init(vx:Float,vy:Float)
  36. Self.V.x=vx
  37. Self.V.y=vy
  38. Self.L=Self.Magnitude(vx,vy)
  39. If(Self.L>0.0)
  40. Self.D.x=Self.V.x/Self.L
  41. Self.D.y=Self.V.y/Self.L
  42. Else
  43. Self.D.x=0.0
  44. Self.D.y=0.0
  45. End
  46. End
  47. Method SetAnimation(animation:ObjectAnimation)
  48. Self.animation=animation
  49. End
  50. Field num:Int
  51. Field node:List<Ball>.Node
  52. Method Distance:Float(b:Ball)Virtual
  53. Return 0
  54. End
  55. Method Bounce(ball:Ball,px:Float,py:Float) Abstract
  56. Method Render(canvas:Canvas) Abstract
  57. Method CollisionDistanceB2RW:Float(ball:Ball,x:Float,y:Float,radius:Float)
  58. Self.tp = Null
  59. Local vx:Float=x-ball.P.x
  60. Local vy:Float=y-ball.P.y
  61. Local totRadiusSq:Float=(ball.radius+radius)*(ball.radius+radius)
  62. Local distSq:Float=vx*vx+vy*vy
  63. If(distSq<totRadiusSq And distSq>radius*radius)
  64. If((ball.P.x-x)*(0.0-ball.V.x)+(ball.P.y-y)*(0.0-ball.V.y)>0.0)
  65. Local len:Float=Sqrt(distSq)
  66. Self.cdx=vx/len
  67. Self.cdy=vy/len
  68. Self.cp.x=ball.P.x+Self.cdx*ball.radius
  69. Self.cp.y=ball.P.y+Self.cdy*ball.radius
  70. Self.tp=Self.cp
  71. Return 0.0
  72. End
  73. End
  74. Local vx2:Float=x-(ball.P.x+ball.V.x)
  75. Local vy2:Float=y-(ball.P.y+ball.V.y)
  76. Local dp:Float=vx*ball.D.x+vy*ball.D.y
  77. If(dp>0.0)
  78. Local tvx:Float=dp*ball.D.x
  79. Local tvy:Float=dp*ball.D.y
  80. Local x1:Float=ball.P.x+tvx
  81. Local y1:Float=ball.P.y+tvy
  82. tvx=x-x1
  83. tvy=y-y1
  84. Local llSq:Float=tvx*tvx+tvy*tvy
  85. Local maxDist:Float=radius+ball.radius
  86. If(llSq<=maxDist*maxDist)
  87. Local c:Float=ball.radius+radius
  88. Local b:Float=Sqrt(llSq)
  89. Local a:Float=Sqrt(c*c-b*b)
  90. Local x2:Float=x1-ball.D.x*a
  91. Local y2:Float=y1-ball.D.y*a
  92. Local rvx:Float=x2-ball.P.x
  93. Local rvy:Float=y2-ball.P.y
  94. Local distSq2:Float=rvx*rvx+rvy*rvy
  95. If(distSq2<=ball.L*ball.L And vx*rvx+vy*rvy>=0.0)
  96. vx=x-(ball.P.x+rvx)
  97. vy=y-(ball.P.y+rvy)
  98. If((c)<>0.0)
  99. Self.cdx=vx/c
  100. Self.cdy=vy/c
  101. Else
  102. Self.cdx=0.0
  103. Self.cdy=0.0
  104. End
  105. Self.cp.x=ball.P.x+rvx+Self.cdx*ball.radius
  106. Self.cp.y=ball.P.y+rvy+Self.cdy*ball.radius
  107. Self.tp=Self.cp
  108. Local t_:Float=Sqrt(distSq2)/ball.L
  109. Return t_
  110. End
  111. End
  112. End
  113. Return INVALID_DISTANCE
  114. End Method
  115. Method Bounce2Fixed(ball:Ball,dx:Float,dy:Float)
  116. Local dp:Float=ball.V.x*dx+ball.V.y*dy
  117. Local vx1:Float=-dp*dx
  118. Local vy1:Float=-dp*dy
  119. dp=ball.V.x*dy-ball.V.y*dx
  120. Local vx2:Float=dp*dy
  121. Local vy2:Float=-dp*dx
  122. Local vx:Float=vx1+vx2
  123. Local vy:Float=vy1+vy2
  124. ball.Init(vx,vy)
  125. dp=ball.tvx*dx+ball.tvy*dy
  126. vx1=-dp*dx
  127. vy1=-dp*dy
  128. dp=ball.tvx*dy-ball.tvy*dx
  129. vx2=dp*dy
  130. vy2=-dp*dx
  131. ball.tvx=vx1+vx2
  132. ball.tvy=vy1+vy2
  133. Local n:Float=ball.tvx+ball.V.x
  134. If(n<5.0) n=0.0
  135. If(n>=5.0) n=1.0
  136. media.PlayRailCol(n)
  137. End
  138. Method CollisionDistance2Ghost:Float(ball:GhostBall) Abstract
  139. Method Distance2Ghost:Float(ghost:GhostBall,x:Float,y:Float,radius:Float)
  140. Local vx:Float=x-ghost.position.x
  141. Local vy:Float=y-ghost.position.y
  142. Local dp:Float=vx*ghost.dy-vy*ghost.dx
  143. Local c:Float=ghost.radius+radius
  144. If Abs(dp) < c
  145. Local dp2:Float=vx*ghost.dx+vy*ghost.dy
  146. If dp2 > 0.0
  147. dp2-=Sqrt(c*c-dp*dp)
  148. vx=ghost.position.x+ghost.dx*dp2-x
  149. vy=ghost.position.y+ghost.dy*dp2-y
  150. dp=Sqrt(vx*vx+vy*vy)
  151. ghost.cn.x=vx/dp
  152. ghost.cn.y=vy/dp
  153. Return dp2
  154. End
  155. End
  156. Return INVALID_DISTANCE
  157. End
  158. End Class
  159. '************************************************************************
  160. '
  161. ' Movable vector ball
  162. '
  163. '************************************************************************
  164. Class Ball Extends VectorObject
  165. Field tv:PVector2D
  166. Field radius:Float
  167. Field mass:Float
  168. Field displayFloat:Bool
  169. Field tvx:Float
  170. Field tvy:Float
  171. Method New()
  172. P=New PVector2D()
  173. V=New PVector2D()
  174. D=New PVector2D()
  175. tv=New PVector2D()
  176. cp=New PVector2D()
  177. name="Ball"
  178. End
  179. Method New(x:Float,y:Float,radius:Float,vx:Float,vy:Float,animation:ObjectAnimation,frictn:Float,bounse:Float,mass:Float,num:Int,displayFloat:Bool)
  180. P=New PVector2D()
  181. V=New PVector2D()
  182. D=New PVector2D()
  183. tv=New PVector2D()
  184. cp=New PVector2D()
  185. name="Ball"
  186. P.x=x
  187. P.y=y
  188. Self.radius=radius
  189. Init(vx,vy)
  190. friction=frictn
  191. bounce=bounse
  192. Self.mass=mass
  193. Self.num=num
  194. Self.displayFloat=displayFloat
  195. Self.animation=animation
  196. End
  197. Method SetPosition(x:Float,y:Float)
  198. P.x=x
  199. P.y=y
  200. End
  201. Method ResetAnimation()
  202. animation.Reset()
  203. End
  204. Method updateIn(timeFrame:Float)
  205. V.x+=VectorObject.ApplicableGravityx
  206. V.y+=VectorObject.ApplicableGravityy
  207. V.x*=VectorObject.ApplicableSurfaceFriction
  208. V.y*=VectorObject.ApplicableSurfaceFriction
  209. V.x*=timeFrame
  210. V.y*=timeFrame
  211. Init(V.x,V.y)
  212. End
  213. Method IsMoving:Bool()
  214. Return ((V.x)<>0.0) Or ((V.y)<>0.0)
  215. End
  216. Method MovingToBall:Bool(ball:Ball)
  217. Return (ball.P.x-P.x)*(V.x-ball.V.x)+(ball.P.y-P.y)*(V.y-ball.V.y)>0.0
  218. End
  219. Method Distance:Float(ball:Ball) Override
  220. Local vx:Float=ball.P.x-P.x
  221. Local vy:Float=ball.P.y-P.y
  222. If(vx*vx+vy*vy<(radius+ball.radius)*(radius+ball.radius))
  223. If(MovingToBall(ball))
  224. Local len:Float=Sqrt(vx*vx+vy*vy)
  225. cdx=vx/len
  226. cdy=vy/len
  227. Return 0.0
  228. End
  229. End
  230. If(-vx*ball.V.x-vy*ball.V.y<0.0)
  231. Return INVALID_DISTANCE
  232. End
  233. Local vx1:Float=V.x-ball.V.x
  234. Local vy1:Float=V.y-ball.V.y
  235. Local totalRadius:Float=radius+ball.radius
  236. Local l1:Float=Sqrt(vx1*vx1+vy1*vy1)
  237. Local dx1:Float=vx1/l1
  238. Local dy1:Float=vy1/l1
  239. Local dp:Float=vx*dx1+vy*dy1
  240. Local vx2:Float=dp*dx1
  241. Local vy2:Float=dp*dy1
  242. Local lengt:Float=Sqrt(Pow(ball.P.x-(P.x+vx2),2.0)+Pow(ball.P.y-(P.y+vy2),2.0))
  243. Local diff:Float=totalRadius-lengt
  244. tp = Null
  245. If(diff>0.0)
  246. Local moveBack:Float=Sqrt(totalRadius*totalRadius-lengt*lengt)
  247. Local vx4:Float=vx2-moveBack*dx1
  248. Local vy4:Float=vy2-moveBack*dy1
  249. Local l4:Float=Sqrt(vx4*vx4+vy4*vy4)
  250. If(l4<=l1 And vx4*V.x+vy4*V.y>=0.0)
  251. Local dist:Float=l4/l1
  252. Local x1:Float=ball.P.x+ball.V.x*dist
  253. Local y1:Float=ball.P.y+ball.V.y*dist
  254. Local x2:Float=P.x+V.x*dist
  255. Local y2:Float=P.y+V.y*dist
  256. Local vx3:Float=x2-x1
  257. Local vy3:Float=y2-y1
  258. l1=Sqrt(vx3*vx3+vy3*vy3)
  259. If((l1)<>0.0)
  260. cdx=vx3/l1
  261. cdy=vy3/l1
  262. Else
  263. cdx=0.0
  264. cdy=0.0
  265. End
  266. cp.x=x1+cdx*ball.radius
  267. cp.y=y1+cdy*ball.radius
  268. tp=cp
  269. Return dist
  270. End
  271. End
  272. Return INVALID_DISTANCE
  273. End
  274. Method Advance(distance:Float)
  275. Local vx:Float=V.x*distance
  276. Local vy:Float=V.y*distance
  277. If(vx=0.0 And vy=0.0)
  278. Return
  279. End
  280. V.x-=vx
  281. V.y-=vy
  282. P.x+=vx
  283. P.y+=vy
  284. tvx+=vx
  285. tvy+=vy
  286. L-=Sqrt(vx*vx+vy*vy)
  287. End
  288. Method updateOut(timeFrame:Float)
  289. V.x=tvx
  290. V.y=tvy
  291. If(cast<ABall3D>(animation)<>Null)
  292. Cast<ABall3D>(animation).Rotate(tvx,tvy)
  293. End
  294. tvx=0.0
  295. tvy=0.0
  296. V.x/=timeFrame
  297. V.y/=timeFrame
  298. If(Abs(V.x)<0.1 And Abs(V.y)<0.1)
  299. V.x=0.0
  300. V.y=0.0
  301. End
  302. Init(V.x,V.y)
  303. End
  304. Method Render(canvas:Canvas) Override
  305. If((animation)<>Null)
  306. animation.Render(canvas)
  307. End
  308. If(displayFloat)
  309. canvas.DrawText(num,P.x,P.y,0.0,0.0)
  310. End
  311. End
  312. Method BounceB2B(ball:Ball,dx:Float,dy:Float)
  313. Local vx1:Float=ball.tvx+ball.V.x
  314. Local vy1:Float=ball.tvy+ball.V.y
  315. Local dp:Float=V.x*dx+V.y*dy
  316. Local a1:Float=dp*dx
  317. Local b1:Float=dp*dy
  318. dp=V.x*dy-V.y*dx
  319. Local a2:Float=dp*dy
  320. Local b2:Float=dp*-dx
  321. dp=ball.V.x*dx+ball.V.y*dy
  322. Local a21:Float=dp*dx
  323. Local b21:Float=dp*dy
  324. dp=ball.V.x*dy-ball.V.y*dx
  325. Local a22:Float=dp*dy
  326. Local b22:Float=dp*-dx
  327. Local t_P:Float=mass*a1+ball.mass*a21
  328. Local t_Vn:Float=a1-a21
  329. Local v2fx:Float=(t_P+t_Vn*mass)/(mass+ball.mass)
  330. Local v1fx:Float=v2fx-t_Vn
  331. t_P=mass*b1+ball.mass*b21
  332. t_Vn=b1-b21
  333. Local v2fy:Float=(t_P+t_Vn*mass)/(mass+ball.mass)
  334. Local v1fy:Float=v2fy-t_Vn
  335. V.x=friction*ball.friction*a2+bounce*ball.bounce*v1fx
  336. V.y=friction*ball.friction*b2+bounce*ball.bounce*v1fy
  337. ball.V.x=friction*ball.friction*a22+bounce*ball.bounce*v2fx
  338. ball.V.y=friction*ball.friction*b22+bounce*ball.bounce*v2fy
  339. Init(V.x,V.y)
  340. ball.Init(ball.V.x,ball.V.y)
  341. dp=tvx*dx+tvy*dy
  342. a1=dp*dx
  343. b1=dp*dy
  344. dp=tvx*dy-tvy*dx
  345. a2=dp*dy
  346. b2=dp*-dx
  347. dp=ball.tvx*dx+ball.tvy*dy
  348. a21=dp*dx
  349. b21=dp*dy
  350. dp=ball.tvx*dy-ball.tvy*dx
  351. a22=dp*dy
  352. b22=dp*-dx
  353. t_P=mass*a1+ball.mass*a21
  354. t_Vn=a1-a21
  355. v2fx=(t_P+t_Vn*mass)/(mass+ball.mass)
  356. v1fx=v2fx-t_Vn
  357. t_P=mass*b1+ball.mass*b21
  358. t_Vn=b1-b21
  359. v2fy=(t_P+t_Vn*mass)/(mass+ball.mass)
  360. v1fy=v2fy-t_Vn
  361. tvx=friction*ball.friction*a2+bounce*ball.bounce*v1fx
  362. tvy=friction*ball.friction*b2+bounce*ball.bounce*v1fy
  363. ball.tvx=friction*ball.friction*a22+bounce*ball.bounce*v2fx
  364. ball.tvy=friction*ball.friction*b22+bounce*ball.bounce*v2fy
  365. vx1-=ball.V.x+ball.tvx
  366. vy1-=ball.V.y+ball.tvy
  367. dp=Sqrt(vx1*vx1+vy1*vy1)
  368. If(dp>20.0)
  369. media.PlayBallCol(3)
  370. Else
  371. If(dp>10.0)
  372. media.PlayBallCol(2)
  373. Else
  374. If(dp>2.0)
  375. media.PlayBallCol(1)
  376. Else
  377. media.PlayBallCol(0)
  378. End
  379. End
  380. End
  381. End
  382. Method Bounce(ball:Ball,dx:Float,dy:Float) Override
  383. BounceB2B(ball,dx,dy)
  384. End
  385. Method CollisionDistance2Ghost:Float(ball:GhostBall) Override
  386. If num=16 Return INVALID_DISTANCE
  387. Return Distance2Ghost(ball,P.x,P.y,radius)
  388. End
  389. End
  390. Class LineWall Extends VectorObject
  391. Method New()
  392. Self.P=New PVector2D()
  393. Self.V=New PVector2D()
  394. Self.D=New PVector2D()
  395. Self.cp=New PVector2D()
  396. Self.name="Straight wall"
  397. End
  398. Method New(x1:Float,y1:Float,x2:Float,y2:Float,animation:ObjectAnimation,friction:Float,bounce:Float)
  399. Self.P=New PVector2D()
  400. Self.V=New PVector2D()
  401. Self.D=New PVector2D()
  402. Self.cp=New PVector2D()
  403. Self.name="Straight wall"
  404. Self.P.x=x1
  405. Self.P.y=y1
  406. Self.Init(x2-x1,y2-y1)
  407. Self.friction=friction
  408. Self.bounce=bounce
  409. Self.animation=animation
  410. End
  411. Method Distance:Float(ball:Ball) Override
  412. Self.tp = null
  413. Local a:Float=ball.P.x-Self.P.x
  414. Local b:Float=ball.P.y-Self.P.y
  415. Local a1:Float=ball.P.x+ball.V.x-Self.P.x
  416. Local b1:Float=ball.P.y+ball.V.y-Self.P.y
  417. Local d1:Float=a*Self.D.y-b*Self.D.x
  418. Local d2:Float=a1*Self.D.y-b1*Self.D.x
  419. If(Abs(d1)<ball.radius)
  420. Local vx:Float=ball.P.x-(Self.P.x+Self.V.x)
  421. Local vy:Float=ball.P.y-(Self.P.y+Self.V.y)
  422. If(vx*Self.V.x+vy*Self.V.y<=0.0 And a*Self.V.x+b*Self.V.y>=0.0)
  423. If(d1>0.0 And d1>d2)
  424. Self.cdx=-Self.D.y
  425. Self.cdy=Self.D.x
  426. Return 0.0
  427. Else
  428. If(d1<0.0 And d1<d2)
  429. Self.cdx=Self.D.y
  430. Self.cdy=-Self.D.x
  431. Return 0.0
  432. End
  433. End
  434. End
  435. End
  436. Local t:Float=0.0
  437. If(d1>0.0)
  438. t=(ball.radius-d1)/(d2-d1)
  439. Else
  440. If(d1<0.0)
  441. t=(ball.radius+d1)/(d1-d2)
  442. End
  443. End
  444. If(d1>0.0 And d2>=d1 Or d1<0.0 And d2<=d1)
  445. Local vx2:Float=ball.P.x-(Self.P.x+Self.V.x)
  446. Local vy2:Float=ball.P.y-(Self.P.y+Self.V.y)
  447. If(a*Self.D.x+b*Self.D.y>=0.0 And vx2*Self.D.x+vy2*Self.D.y<0.0)
  448. Return INVALID_DISTANCE
  449. End
  450. End
  451. If(t<=1.0 And t>=0.0)
  452. a=ball.V.x*t
  453. b=ball.V.y*t
  454. Self.cp.x=ball.P.x+a
  455. Self.cp.y=ball.P.y+b
  456. Local vx3:Float=Self.cp.x-Self.P.x
  457. Local vy3:Float=Self.cp.y-Self.P.y
  458. Local dp:Float=vx3*Self.D.x+vy3*Self.D.y
  459. If(dp>0.0)
  460. vx3=Self.cp.x-(Self.P.x+Self.V.x)
  461. vy3=Self.cp.y-(Self.P.y+Self.V.y)
  462. Self.cp.x=Self.P.x+dp*Self.D.x
  463. Self.cp.y=Self.P.y+dp*Self.D.y
  464. dp=vx3*Self.D.x+vy3*Self.D.y
  465. If(dp<0.0)
  466. If(Abs(d1)<ball.radius)
  467. Local diff:Float=ball.radius-Abs(d1)
  468. ball.P.x+=diff*Self.D.y
  469. ball.P.y-=diff*Self.D.x
  470. End
  471. Self.cdx=Self.D.y
  472. Self.cdy=-Self.D.x
  473. Self.tp=Self.cp
  474. Return t
  475. End
  476. End
  477. End
  478. Local dist:Float=Self.CollisionDistanceB2RW(ball,Self.P.x+Self.V.x,Self.P.y+Self.V.y,0.0)
  479. If(dist<>INVALID_DISTANCE)
  480. Return dist
  481. End
  482. dist=Self.CollisionDistanceB2RW(ball,Self.P.x,Self.P.y,0.0)
  483. If(dist=INVALID_DISTANCE)
  484. Self.tp = null
  485. End
  486. Return dist
  487. End
  488. Method Bounce(ball:Ball,dx:Float,dy:Float) Override
  489. Self.Bounce2Fixed(ball,dx,dy)
  490. End
  491. Method Render(canvas:Canvas) Override
  492. If((Self.animation)<>Null)
  493. Self.animation.Render(canvas)
  494. End
  495. End
  496. Method CollisionDistance2Ghost:Float(ball:GhostBall) Override
  497. Self.tp = null
  498. Local a:Float=ball.position.x-Self.P.x
  499. Local b:Float=ball.position.y-Self.P.y
  500. Local a1:Float=ball.position.x+ball.dx-Self.P.x
  501. Local b1:Float=ball.position.y+ball.dy-Self.P.y
  502. Local d1:Float=a*Self.D.y-b*Self.D.x
  503. Local d2:Float=a1*Self.D.y-b1*Self.D.x
  504. Local t:Float=0.0
  505. If(d1>0.0)
  506. t=(ball.radius-d1)/(d2-d1)
  507. Else
  508. If(d1<0.0)
  509. t=(ball.radius+d1)/(d1-d2)
  510. End
  511. End
  512. If(d1>0.0 And d2>=d1 Or d1<0.0 And d2<=d1)
  513. Return INVALID_DISTANCE
  514. End
  515. If(t>=0.0)
  516. Local px:Float=ball.position.x+ball.dx*t
  517. Local py:Float=ball.position.y+ball.dy*t
  518. Local vx:Float=px-Self.P.x
  519. Local vy:Float=py-Self.P.y
  520. Local dp:Float=vx*Self.D.x+vy*Self.D.y
  521. If(dp>0.0)
  522. vx=px-(Self.P.x+Self.V.x)
  523. vy=py-(Self.P.y+Self.V.y)
  524. dp=vx*Self.D.x+vy*Self.D.y
  525. If(dp<0.0)
  526. ball.cn.x=-Self.D.y
  527. ball.cn.y=Self.D.x
  528. Return t
  529. End
  530. End
  531. End
  532. Local dist:Float=Self.Distance2Ghost(ball,P.x+V.x,P.y+V.y,0.0)
  533. Local dx1:Float=ball.cn.x
  534. Local dy1:Float=ball.cn.y
  535. Local dist2:Float=Self.Distance2Ghost(ball,P.x,P.y,0.0)
  536. If dist2<dist
  537. dist=dist2
  538. Else
  539. ball.cn.x=dx1
  540. ball.cn.y=dy1
  541. End
  542. Return dist
  543. End
  544. End
  545. '*******************************************************
  546. '
  547. ' static roundwall(circle)
  548. '
  549. '*******************************************************
  550. Class CircleWall Extends VectorObject
  551. Field radius:Float 'circle radius
  552. Method New()
  553. P = New PVector2D
  554. cp = New PVector2D
  555. name = "round wall"
  556. End Method
  557. Method New(x:Float,y:Float,radius:Float,animation:ObjectAnimation = Null,friction:Float = 1,bounce:Float=1)
  558. P = New PVector2D
  559. cp = New PVector2D
  560. name = "round wall"
  561. P.x = x
  562. P.y = y
  563. Self.radius = radius
  564. Self.friction = friction
  565. Self.bounce = bounce
  566. Self.animation = animation
  567. End Method
  568. Method SetFriction(f:Float)
  569. friction = f
  570. End Method
  571. Method Update()
  572. End Method
  573. '************************************************************************
  574. '
  575. ' distance of ball to wall(circle)
  576. ' returned values
  577. ' valid distance distance 0.0 - 1.0.
  578. '
  579. '************************************************************************
  580. Method Distance:Float(ball:Ball) Override
  581. Return CollisionDistanceB2RW(ball,P.x,P.y,radius)
  582. End Method
  583. '************************************************************************
  584. '
  585. ' change movement vector after collision with wal(circle)
  586. '
  587. '************************************************************************
  588. Method Bounce(ball:Ball,dx:Float,dy:Float) Override
  589. Bounce2Fixed(ball,dx,dy)
  590. End Method
  591. Method Render(canvas:Canvas) Override
  592. If animation
  593. animation.Render(canvas)
  594. Else
  595. RenderCircle(canvas,P.x,P.y,radius)
  596. Endif
  597. End Method
  598. End Class
  599. Class ArcWall Extends VectorObject
  600. Field pa:PVector2D
  601. Field np:PVector2D
  602. Field target:PVector2D
  603. Field radius:Float
  604. Field startAngle:Float
  605. Field endAngle:Float
  606. Method New()
  607. P = New PVector2D()
  608. V = New PVector2D()
  609. D = New PVector2D()
  610. pa = New PVector2D()
  611. cp = New PVector2D()
  612. np = New PVector2D()
  613. name="Arc Wall"
  614. End Method
  615. Method SetAperture()
  616. pa.x = P.x+Cos(startAngle*ATR)*radius
  617. pa.y = P.y+Sin(startAngle*ATR)*radius
  618. V.x = P.x+Cos(endAngle*ATR)*radius-pa.x
  619. V.y = P.y+Sin(endAngle*ATR)*radius-pa.y
  620. Init(V.x,V.y)
  621. End Method
  622. Method New(x:Float,y:Float,radius:Float,startAngle:Float,endAngle:Float,animation:ObjectAnimation=Null,friction:Float=1.0,bounce:Float=1.0)
  623. P=New PVector2D()
  624. V=New PVector2D()
  625. D=New PVector2D()
  626. pa=New PVector2D()
  627. cp=New PVector2D()
  628. np=New PVector2D()
  629. target=New PVector2D()
  630. name="Arc Wall"
  631. P.x=x
  632. P.y=y
  633. target.x=x
  634. target.y=y
  635. Self.radius=radius
  636. Self.startAngle=startAngle
  637. Self.endAngle=endAngle
  638. SetAperture()
  639. Self.friction=friction
  640. Self.bounce=bounce
  641. Self.animation=animation
  642. End Method
  643. Method SetTarget(x:Float,y:Float)
  644. target.x=x
  645. target.y=y
  646. End Method
  647. Method BallInside:Bool(ball:Ball)
  648. Local vx:Float=ball.P.x-P.x
  649. Local vy:Float=ball.P.y-P.y
  650. Return (vx*vx+vy*vy) < (radius * radius)
  651. End Method
  652. Method Distance:float(ball:Ball) Override
  653. If(ball.L = 0.0) Return INVALID_DISTANCE
  654. tp=Null
  655. Local tcdx:Float
  656. Local tcdy:Float
  657. Local dist:Float=Self.CollisionDistanceB2RW(ball,P.x,P.y,radius)
  658. If(dist<>INVALID_DISTANCE)
  659. Local vx:Float=tp.x-pa.x
  660. Local vy:Float=tp.y-pa.y
  661. If(vx*Self.V.y-vy*Self.V.x>=0.0) Return dist
  662. Self.tp=Null
  663. dist=INVALID_DISTANCE
  664. Endif
  665. Local vx2:Float=P.x-ball.P.x
  666. Local vy2:Float=P.y-ball.P.y
  667. Local vx1:Float=-vx2
  668. Local vy1:Float=-vy2
  669. Local totRadius:Float=radius-ball.radius
  670. Local distSq:Float=vx2*vx2+vy2*vy2
  671. Local totRadSq:Float=totRadius*totRadius
  672. If(distSq>totRadSq And distSq < radius*radius)
  673. Local dst:Float=Sqrt(distSq)
  674. if(dst>0.0)
  675. cdx=vx1/dst
  676. cdy=vy1/dst
  677. Else
  678. cdx=ball.D.x
  679. cdy=ball.D.y
  680. Endif
  681. vx1=cdx*radius
  682. vy1=cdy*radius
  683. cp.x=P.x+vx1
  684. cp.y=P.y+vy1
  685. If(vx1*D.y-vy1*D.x>0.0 And vx1*ball.D.x+vy1*ball.D.y>=0.0)
  686. tp=cp
  687. Return 0.0
  688. Endif
  689. Endif
  690. Local dp:Float=vx2*ball.D.y-vy2*ball.D.x
  691. If(Abs(dp)<radius)
  692. vx2=dp*ball.D.y
  693. vy2=dp*-ball.D.x
  694. Local a:Float=Sqrt(totRadSq-dp*dp)
  695. Local px:Float=P.x-vx2+a*ball.D.x
  696. Local py:Float=P.y-vy2+a*ball.D.y
  697. vx2=px-ball.P.x
  698. vy2=py-ball.P.y
  699. dp=vx2*ball.D.x+vy2*ball.D.y
  700. If(Abs(dp)<=ball.L And dp >= 0.0)
  701. vx2=px-P.x
  702. vy2=py-P.y
  703. Local len:Float=radius-ball.radius
  704. If(len>0.0)
  705. cdx=vx2/len
  706. cdy=vy2/len
  707. Else
  708. cdx=ball.D.x
  709. cdy=ball.D.y
  710. Endif
  711. px=P.x+cdx*radius
  712. py=P.y+cdy*radius
  713. vx2=px-pa.x
  714. vy2=py-pa.y
  715. Local dp2:Float=vx2*D.y-vy2*D.x
  716. If(dp2>=0.0 And ball.L>0.0)
  717. cp.x=px
  718. cp.y=py
  719. tp=Self.cp
  720. dist=dp/ball.L
  721. Return dist
  722. Endif
  723. tp=Null
  724. dist=INVALID_DISTANCE
  725. Endif
  726. Endif
  727. Local nextDist:Float = CollisionDistanceB2RW(ball,pa.x,pa.y,0.0)
  728. If(nextDist<dist)
  729. dist=nextDist
  730. np.x=tp.x
  731. np.y=tp.y
  732. tcdx=cdx
  733. tcdy=cdy
  734. Endif
  735. nextDist=CollisionDistanceB2RW(ball,pa.x+D.x*L,pa.y+D.y*L,0.0)
  736. If(nextDist<dist)
  737. dist=nextDist
  738. np.x=tp.x
  739. np.y=tp.y
  740. tcdx=cdx
  741. tcdy=cdy
  742. Endif
  743. tp=np
  744. cdx=tcdx
  745. cdy=tcdy
  746. If dist = INVALID_DISTANCE
  747. tp=Null
  748. Endif
  749. Return dist
  750. End Method
  751. Method Bounce(ball:Ball,dx:Float,dy:Float) Override
  752. Self.Bounce2Fixed(ball,dx,dy)
  753. End Method
  754. Method Render(canvas:Canvas) Override
  755. If Self.animation
  756. Self.animation.Render(canvas)
  757. Endif
  758. End Method
  759. Method CollisionDistance2Ghost:Float(ball:GhostBall) Override
  760. Local dx:Float=.0
  761. Local dy:Float=.0
  762. Local dist:Float=Distance2Ghost(ball,P.x,P.y,radius)
  763. If(dist <> INVALID_DISTANCE)
  764. Local px:Float=ball.position.x+ball.dx*dist
  765. Local py:Float=ball.position.y+ball.dy*dist
  766. Local vx:Float=px-P.x
  767. Local vy:Float=py-P.y
  768. Local ln:Float=Sqrt(vx*vx+vy*vy)
  769. If(ln > 0.0)
  770. dx=vx/ln
  771. dy=vy/ln
  772. px=P.x+dx*radius
  773. py=P.y+dy*radius
  774. Endif
  775. vx=px-pa.x
  776. vy=py-pa.y
  777. If(vx*D.y-vy*D.x>=0.0)
  778. Return dist
  779. Endif
  780. dist=INVALID_DISTANCE
  781. Endif
  782. Local vx2:Float=P.x-ball.position.x
  783. Local vy2:Float=P.y-ball.position.y
  784. Local vx1:Float=-vx2
  785. Local vy1:Float=-vy2
  786. Local totRadius:Float=radius-ball.radius
  787. Local distSq:Float=vx2*vx2+vy2*vy2
  788. Local totRadSq:Float=totRadius*totRadius
  789. Local dp:Float=vx2*ball.dy-vy2*ball.dx
  790. if(Abs(dp)<radius)
  791. vx2=dp*ball.dy
  792. vy2=dp*-ball.dx
  793. Local a:Float=Sqrt(totRadSq-dp*dp)
  794. Local px2:Float=P.x-vx2+a*ball.dx
  795. Local py2:Float=P.y-vy2+a*ball.dy
  796. vx2=px2-ball.position.x
  797. vy2=py2-ball.position.y
  798. dp=vx2*ball.dx+vy2*ball.dy
  799. If(dp>=0.0)
  800. vx2=px2-P.x
  801. vy2=py2-P.y
  802. Local len:Float=radius-ball.radius
  803. If(len>0.0)
  804. cdx=vx2/len
  805. cdy=vy2/len
  806. Else
  807. cdx=ball.dx
  808. cdy=ball.dy
  809. Endif
  810. px2=P.x+cdx*radius
  811. py2=P.y+cdy*radius
  812. vx2=px2-pa.x
  813. vy2=py2-pa.y
  814. Local dp2:Float=vx2*D.y-vy2*D.x
  815. If(dp2>=0.0)
  816. ball.cn.x=-cdx
  817. ball.cn.y=-cdy
  818. Return dp
  819. Endif
  820. dist=INVALID_DISTANCE
  821. Endif
  822. Endif
  823. dx=ball.cn.x
  824. dy=ball.cn.y
  825. Local nextDist:Float=Distance2Ghost(ball,pa.x,pa.y,0.0)
  826. If(nextDist<dist)
  827. dist=nextDist
  828. dx=ball.cn.x
  829. dy=ball.cn.y
  830. Endif
  831. nextDist=Distance2Ghost(ball,pa.x+D.x*L,pa.y+D.y*L,0.0)
  832. If(nextDist<dist)
  833. dist=nextDist
  834. dx=ball.cn.x
  835. dy=ball.cn.y
  836. Endif
  837. ball.cn.x=dx
  838. ball.cn.y=dy
  839. Return dist
  840. End Method
  841. End Class
  842. Class GhostBall
  843. Field position:PVector2D
  844. Field cn:PVector2D
  845. Field radius:Float=.0
  846. Field image:Image[]
  847. Field dx:Float=.0
  848. Field dy:Float=.0
  849. Field frame:Int=0
  850. Field delay:Int=0
  851. Field stripImg:Image
  852. Field time:Int=0
  853. Field colBall:Ball
  854. Field distance:Float
  855. Method New(position:PVector2D,radius:Float,image:Image[],angle:Float,stpImg:Image)
  856. Self.position=position
  857. Self.cn=New PVector2D()
  858. Self.radius=radius
  859. Self.image=image
  860. Self.dx=Cos(angle*ATR)
  861. Self.dy=Sin(angle*ATR)
  862. Self.frame=0
  863. Self.delay=1
  864. Self.stripImg=stpImg
  865. Self.time=Millisecs()
  866. End
  867. Method Render(canvas:Canvas)
  868. Local x:Float=position.x+dx*distance
  869. Local y:Float=position.y+dy*distance
  870. If Millisecs()>time+delay
  871. frame=(frame+1) Mod 3
  872. time=Millisecs()
  873. End
  874. Local ang:Float=-ATan2(dy,dx)
  875. canvas.DrawImage(image[frame],x,y)
  876. canvas.DrawImage(stripImg,position.x,position.y,ang,distance,1.0)
  877. If colBall
  878. Local r2:Float=colBall.radius*2.0
  879. canvas.DrawLine(colBall.P.x,colBall.P.y,colBall.P.x-cn.x*r2,colBall.P.y-cn.y*r2)
  880. Local dp:Float=cn.x*-dx+cn.y*-dy
  881. Local dx1:Float=dp*cn.x
  882. Local dy1:Float=dp*cn.y
  883. dp=cn.y*dx-cn.x*dy
  884. dx1=dp*cn.y
  885. dy1=-dp*cn.x
  886. canvas.DrawLine(x,y,x+dx1*20.0,y+dy1*20.0)
  887. Else
  888. Local dp2:Float=cn.x*-dx+cn.y*-dy
  889. Local dx12:Float=dp2*cn.x
  890. Local dy12:Float=dp2*cn.y
  891. dp2=cn.y*dx-cn.x*dy
  892. dx12+=dp2*cn.y
  893. dy12+=dp2*-cn.x
  894. canvas.DrawLine(x,y,x+dx12*20.0,y+dy12*20.0)
  895. End
  896. End
  897. End