Author Topic: Physics Engine  (Read 9257 times)

0 Members and 1 Guest are viewing this topic.

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Physics Engine
« on: August 21, 2018, 03:23:22 am »
Here's an attempt I made at a physics engine a while back. Move the mouse around inside the window. The program still has a few quirks.

Code: QB64: [Select]
  1. CONST FALSE = 0, TRUE = NOT FALSE
  2. CONST TIMESTEP = 1 / 30 '          total engine updates per second - should match any _LIMIT FPS in program
  3. CONST BALLS = 25
  4. CONST ROUND = 0, SQUARE = 1
  5. CONST SWIDTH = 800
  6. CONST SHEIGHT = 600
  7. CONST FIXED = TRUE
  8. CONST NONFIXED = FALSE
  9.  
  10. TYPE OBJECT
  11.     Inuse AS INTEGER '         is object currently in use (TRUE / FALSE)
  12.     Xpos AS SINGLE '           x position of object
  13.     Ypos AS SINGLE '           y position of object
  14.     Xvel AS SINGLE '           horizontal velocity of object
  15.     Yvel AS SINGLE '           vertical velocity of object
  16.     Radius AS SINGLE '         radius of object
  17.     Gravity AS SINGLE '        object is affected by gravity (0 = no gravity, >0 gravity present)
  18.     Friction AS SINGLE '       object has friction (0 = no friction, >0 friction present, use small increments of .1)
  19.     Attract AS SINGLE '        amount of attraction to another object (0 = no attraction, <0 = repulsion, >0 = attraction)
  20.     AttractedTo AS INTEGER '   handle of object attracted to
  21.     Elastic AS SINGLE '        object has elastic collisions
  22.     Fixed AS INTEGER '         object is in a fixed position (TRUE / FALSE)
  23.     MaxSpeed AS SINGLE '       object's maximum speed
  24.     Shape AS INTEGER '         object's shape (0 for circle, 1 for square)
  25.  
  26. REDIM Object(0) AS OBJECT '    array to hold objects
  27. DIM Ball%(BALLS)
  28. DIM Bcolor~&(BALLS)
  29. DIM Count%
  30. DIM rndRadius!, rndXpos!, rndYpos!, rndXvel!, rndYvel!
  31. DIM Dummy%
  32. DIM Paddle%
  33. DIM OldMouseX%, OldMouseY%
  34.  
  35. SCREEN _NEWIMAGE(SWIDTH, SHEIGHT, 32)
  36.  
  37. FOR Count% = 1 TO BALLS '                                                      create random ball objects
  38.     rndRadius! = INT(RND(1) * 20) + 10
  39.     Bcolor~&(Count%) = _RGB32(INT(RND(1) * 256), INT(RND(1) * 256), INT(RND(1) * 256))
  40.     Ball%(Count%) = DEFINEOBJECT(ROUND, rndRadius!)
  41.     APPLYFRICTION Ball%(Count%), .01
  42.     APPLYMAXSPEED Ball%(Count%), 100
  43.     APPLYELASTIC Ball%(Count%), 1
  44.     rndXpos! = INT(RND(1) * (SWIDTH - 1 - OBJECTRADIUS(Ball%(Count%)) * 2)) + OBJECTRADIUS(Ball%(Count%))
  45.     rndYpos! = INT(RND(1) * (SHEIGHT - 1 - OBJECTRADIUS(Ball%(Count%)) * 2)) + OBJECTRADIUS(Ball%(Count%))
  46.     rndXvel! = (RND(1) - RND(1)) '* 3
  47.     rndYvel! = (RND(1) - RND(1)) '* 3
  48.     PUTOBJECT Ball%(Count%), rndXpos!, rndYpos!, rndXvel!, rndYvel!, NONFIXED ' define where ball resides
  49. NEXT Count%
  50.  
  51. Paddle% = DEFINEOBJECT(ROUND, 40) '                                            create a fixed ball with radius of 40
  52. APPLYELASTIC Paddle%, .1 '                                                     give a slightly bouncy surface
  53. PUTOBJECT Paddle%, SWIDTH / 2 - 1, SHEIGHT / 2 - 1, 0, 0, FIXED '              define where object resides
  54. _MOUSEMOVE SWIDTH / 2 - 1, SHEIGHT / 2 - 1
  55.  
  56.     _LIMIT 30 ' we limit simulation to 30FPS - note that TIMESTEP constant should match this to avoid tunneling through objects
  57.     CLS
  58.     WHILE _MOUSEINPUT: WEND '                                                  get latest mouse information
  59.     SETOBJECTX Paddle%, _MOUSEX '                                              set paddle object X location
  60.     SETOBJECTY Paddle%, _MOUSEY '                                              set paddle object Y location
  61.     SETOBJECTXVEL Paddle%, OBJECTX(Paddle%) - OldMouseX% '                     set paddle object X velocity
  62.     SETOBJECTYVEL Paddle%, OBJECTY(Paddle%) - OldMouseY% '                     set paddle object Y velocity
  63.     OldMouseX% = OBJECTX(Paddle%) '                                            remember paddle X position
  64.     OldMouseY% = OBJECTY(Paddle%) '                                            remember paddle Y location
  65.     FOR Count% = 1 TO BALLS '
  66.         Dummy% = INTERACTION(Ball%(Count%)) '                                  check this ball's interaction with all other objects
  67.         IF OBJECTX(Ball%(Count%)) < OBJECTRADIUS(Ball%(Count%)) THEN '         keep balls constrained to screen
  68.             SETOBJECTXVEL Ball%(Count%), -OBJECTXVEL(Ball%(Count%))
  69.             SETOBJECTX Ball%(Count%), OBJECTRADIUS(Ball%(Count%))
  70.         END IF
  71.         IF OBJECTX(Ball%(Count%)) > SWIDTH - OBJECTRADIUS(Ball%(Count%)) THEN
  72.             SETOBJECTXVEL Ball%(Count%), -OBJECTXVEL(Ball%(Count%))
  73.             SETOBJECTX Ball%(Count%), SWIDTH - OBJECTRADIUS(Ball%(Count%))
  74.         END IF
  75.         IF OBJECTY(Ball%(Count%)) < OBJECTRADIUS(Ball%(Count%)) THEN
  76.             SETOBJECTYVEL Ball%(Count%), -OBJECTYVEL(Ball%(Count%))
  77.             SETOBJECTY Ball%(Count%), OBJECTRADIUS(Ball%(Count%))
  78.         END IF
  79.         IF OBJECTY(Ball%(Count%)) > SHEIGHT - OBJECTRADIUS(Ball%(Count%)) THEN
  80.             SETOBJECTYVEL Ball%(Count%), -OBJECTYVEL(Ball%(Count%))
  81.             SETOBJECTY Ball%(Count%), SHEIGHT - OBJECTRADIUS(Ball%(Count%))
  82.         END IF
  83.         CIRCLE (OBJECTX(Ball%(Count%)), OBJECTY(Ball%(Count%))), OBJECTRADIUS(Ball%(Count%)), Bcolor~&(Count%)
  84.         PAINT (OBJECTX(Ball%(Count%)), OBJECTY(Ball%(Count%))), Bcolor~&(Count%), Bcolor~&(Count%)
  85.     NEXT Count%
  86.     CIRCLE (OBJECTX(Paddle%), OBJECTY(Paddle%)), OBJECTRADIUS(Paddle%), _RGB32(255, 255, 255)
  87.     PAINT (OBJECTX(Paddle%), OBJECTY(Paddle%)), _RGB32(255, 255, 255), _RGB32(255, 255, 255)
  88.     _DISPLAY
  89.  
  90. '------------------------------------------------------------------------------
  91.  
  92. FUNCTION OBJECTYVEL (Handle%)
  93.  
  94. '**
  95. '** returns the Y velocity of an object
  96. '**
  97.  
  98. SHARED Object() AS OBJECT
  99.  
  100. OBJECTYVEL = Object(Handle%).Yvel
  101.  
  102.  
  103. '------------------------------------------------------------------------------
  104.  
  105. SUB SETOBJECTY (Handle%, Ypos!)
  106.  
  107. '**
  108. '** returns the Y location of an object
  109. '**
  110.  
  111. SHARED Object() AS OBJECT
  112.  
  113. Object(Handle%).Ypos = Ypos!
  114.  
  115.  
  116. '------------------------------------------------------------------------------
  117.  
  118. SUB SETOBJECTYVEL (Handle%, Yvel!)
  119.  
  120. '**
  121. '** sets the Y velocity of an object
  122. '**
  123.  
  124. SHARED Object() AS OBJECT
  125.  
  126. Object(Handle%).Yvel = Yvel!
  127.  
  128.  
  129. '------------------------------------------------------------------------------
  130.  
  131. SUB SETOBJECTX (Handle%, Xpos!)
  132.  
  133. '**
  134. '** sets the X location of an object
  135. '**
  136.  
  137. SHARED Object() AS OBJECT
  138.  
  139. Object(Handle%).Xpos = Xpos!
  140.  
  141.  
  142. '------------------------------------------------------------------------------
  143.  
  144. FUNCTION OBJECTXVEL (Handle%)
  145.  
  146. '**
  147. '** returns the X velocity of an object
  148. '**
  149.  
  150. SHARED Object() AS OBJECT
  151.  
  152. OBJECTXVEL = Object(Handle%).Xvel
  153.  
  154.  
  155. '------------------------------------------------------------------------------
  156.  
  157. SUB SETOBJECTXVEL (Handle%, Xvel!)
  158.  
  159. '**
  160. '** sets the X velocity of an object
  161. '**
  162.  
  163. SHARED Object() AS OBJECT
  164.  
  165. Object(Handle%).Xvel = Xvel!
  166.  
  167.  
  168. '------------------------------------------------------------------------------
  169.  
  170. FUNCTION DEFINEOBJECT (Shape%, Radius!)
  171.  
  172. '**
  173. '** defines an object (very basic, not finished yet)
  174. '**
  175.  
  176. SHARED Object() AS OBJECT
  177.  
  178. DIM ob%
  179.  
  180. ob% = UBOUND(Object) + 1
  181. REDIM _PRESERVE Object(ob%) AS OBJECT
  182.  
  183. Object(ob%).Inuse = -1
  184. Object(ob%).Xpos = 0
  185. Object(ob%).Ypos = 0
  186. Object(ob%).Xvel = 0
  187. Object(ob%).Yvel = 0
  188. Object(ob%).Radius = Radius!
  189. Object(ob%).Gravity = 0
  190. Object(ob%).Friction = 0
  191. Object(ob%).Attract = 0
  192. Object(ob%).AttractedTo = 0
  193. Object(ob%).Elastic = 1
  194. Object(ob%).Fixed = 0
  195. Object(ob%).MaxSpeed = 100
  196. Object(ob%).Shape = Shape%
  197.  
  198. DEFINEOBJECT = ob%
  199.  
  200.  
  201. '------------------------------------------------------------------------------
  202.  
  203. FUNCTION OBJECTRADIUS (Handle%)
  204.  
  205. '**
  206. '** returns the radius of an object
  207. '**
  208.  
  209. SHARED Object() AS OBJECT
  210.  
  211. OBJECTRADIUS = Object(Handle%).Radius
  212.  
  213.  
  214. '------------------------------------------------------------------------------
  215.  
  216. FUNCTION OBJECTY (Handle%)
  217.  
  218. '**
  219. '** returns the Y location of an object
  220. '**
  221.  
  222. SHARED Object() AS OBJECT
  223.  
  224. OBJECTY = Object(Handle%).Ypos
  225.  
  226.  
  227. '------------------------------------------------------------------------------
  228.  
  229. FUNCTION OBJECTX (Handle%)
  230.  
  231. '**
  232. '** returns the X location of an object
  233. '**
  234.  
  235. SHARED Object() AS OBJECT
  236.  
  237. OBJECTX = Object(Handle%).Xpos
  238.  
  239.  
  240. '------------------------------------------------------------------------------
  241.  
  242. SUB APPLYMAXSPEED (Handle%, Maxspeed!)
  243.  
  244. '**
  245. '** sets the maximum speed of an object (setting too low causes 45 degree movement, need to investigate)
  246. '**
  247.  
  248. SHARED Object() AS OBJECT
  249.  
  250. Object(Handle%).MaxSpeed = Maxspeed!
  251.  
  252.  
  253. '------------------------------------------------------------------------------
  254.  
  255. SUB APPLYELASTIC (Handle%, Elastic!)
  256.  
  257. '**
  258. '** sets the elastic property of an object (setting too low allows tunneling, need to investigate)
  259. '**
  260.  
  261. SHARED Object() AS OBJECT
  262.  
  263. Object(Handle%).Elastic = Elastic!
  264.  
  265.  
  266. '------------------------------------------------------------------------------
  267.  
  268. SUB APPLYATTRACTION (Handle%, HandleTo%, Attract!)
  269.  
  270. '**
  271. '** sets the attration to another object
  272. '**
  273.  
  274. SHARED Object() AS OBJECT
  275.  
  276. Object(Handle%).Attract = Attract!
  277. Object(Handle%).AttractedTo = HandleTo%
  278.  
  279.  
  280. '------------------------------------------------------------------------------
  281.  
  282. SUB APPLYFRICTION (Handle%, Friction!)
  283.  
  284. '**
  285. '** sets the friction amount for an object
  286. '**
  287.  
  288. SHARED Object() AS OBJECT
  289.  
  290. Object(Handle%).Friction = Friction!
  291.  
  292.  
  293. '------------------------------------------------------------------------------
  294.  
  295. SUB APPLYGRAVITY (Handle%, Gravity!)
  296.  
  297. '**
  298. '** sets the amount of gravity on an object
  299. '**
  300.  
  301. SHARED Object() AS OBJECT
  302.  
  303. Object(Handle%).Gravity = Gravity!
  304.  
  305.  
  306. '------------------------------------------------------------------------------
  307.  
  308. SUB PUTOBJECT (Handle%, Xpos!, Ypos!, Xvel!, Yvel!, Fixed%)
  309.  
  310. '**
  311. '** defines where object resides
  312. '**
  313.  
  314. SHARED Object() AS OBJECT
  315.  
  316. Object(Handle%).Xpos = Xpos!
  317. Object(Handle%).Ypos = Ypos!
  318. Object(Handle%).Xvel = Xvel!
  319. Object(Handle%).Yvel = Yvel!
  320. Object(Handle%).Fixed = Fixed%
  321.  
  322.  
  323. '------------------------------------------------------------------------------
  324.  
  325. FUNCTION INTERACTION (H1%)
  326.  
  327. '**
  328. '** Checks the interaction between objects for a collision then calculates
  329. '** the new object position based on those calculations.
  330. '**
  331. '** H1% - handle of object to test for collision
  332. '**
  333. '** Returns: 0 (FALSE) if no collision occured
  334. '**         >0 the object that was collided with
  335. '**
  336. '** Function also updates gravity, friction and repulsion/attraction between the two objects.
  337. '**
  338. '** Note: this function is far from complete. Variables need to be updated with variables names and
  339. '**       types identifiers that make sense.
  340. '**
  341.  
  342.  
  343. SHARED Object() AS OBJECT
  344.  
  345. DIM Diameter! '                                   the radius of object 1 plus the radius of object 2
  346. DIM Distance! '                                   the distance from the center point of object 1 to the center point of object 2
  347. DIM FrictionScale! '                              amount of frictional force to add to an object
  348. DIM Xdifference! '                                the distance between object 1 X position and object 2 X position
  349. DIM Ydifference! '                                the distance between object 1 Y position and onject 2 Y position
  350. DIM H1Xvel!, H1Yvel!, H1Xpos!, H1Ypos! '          object 1's X and Y velocities and X and Y positions
  351. DIM H2Xvel!, H2Yvel!, H2Xpos!, H2Ypos! '          object 2's X and Y velocities and X and Y positions
  352. DIM cH1Xvel!, cH1Yvel!, cH1Xpos!, cH1Ypos! '      object 1's X and Y velocities and X and Y positions
  353. DIM cH2Xvel!, cH2Yvel!, cH2Xpos!, cH2Ypos! '      object 2's X and Y velocities and X and Y positions
  354. DIM CoefA!, CoefB!, CoefC! '                      object collision time coefficients
  355. DIM TouchTime! '                                  actual time when object's touched
  356. DIM MomentumX!, MomentumY! '                      momentum loss of objects when collision occurred
  357. DIM OB! '                                         center line velocity vector
  358. DIM Elastic! '                                    amount of elasticity applied to objects
  359.  
  360. IF Object(H1%).Fixed THEN EXIT FUNCTION '                                                if object is in a fixed position no need to continue
  361.  
  362. FOR H2% = 1 TO UBOUND(Object) '                                                          cycle through all defined objects
  363.     IF (H2% <> H1%) AND Object(H2%).Inuse THEN '                                         object can't check itself or objects not in use
  364.  
  365.         diam = Object(H1%).Radius + Object(H2%).Radius '                                 calculate the length of both object radii
  366.  
  367.         '** update object position
  368.  
  369.         u = MIN(Object(H1%).MaxSpeed, MAX(Object(H1%).Xvel, -Object(H1%).MaxSpeed)) '    set maximum X velocity of object if needed
  370.         v = MIN(Object(H1%).MaxSpeed, MAX(Object(H1%).Yvel, -Object(H1%).MaxSpeed)) '    set maximum Y velocity of object if needed
  371.         x = Object(H1%).Xpos + TIMESTEP * u '                                            update object's X position
  372.         y = Object(H1%).Ypos + TIMESTEP * v '                                            update object's Y position
  373.  
  374.         ' ** Gravity and Friction
  375.  
  376.         u = Object(H1%).Xvel '                                                           get object's X velocity
  377.         v = Object(H1%).Yvel '                                                           get object's Y velocity
  378.         fricscale = 1 - Object(H1%).Friction / SQR(1 + u ^ 2 + v ^ 2) '                  calculate the amount of friction needed (if any)
  379.         Object(H1%).Xvel = fricscale * u '                                               apply friction amount to object's X velocity
  380.         Object(H1%).Yvel = fricscale * v + Object(H1%).Gravity '                         apply friction and gravity amounts tp object's Y velocity
  381.  
  382.         '** check for collision
  383.  
  384.         xi = x '                                                                         copy object's updated X position
  385.         yi = y '                                                                         copy object's updated Y position
  386.         xj = Object(H2%).Xpos '                                                          get 2nd object's X position
  387.         yj = Object(H2%).Ypos '                                                          get 2nd object's Y position
  388.         dx = xi - xj '                                                                   calculate X distance between objects
  389.         dy = yi - yj '                                                                   calculate Y distance between objetcs
  390.         dist = SQR(dx ^ 2 + dy ^ 2) '                                                    calculate center to center distance between objects
  391.         IF dist < diam THEN '                                                            is center to center distance less than diameter?
  392.             INTERACTION = H2% '                                                          yes, return object that was collided with
  393.  
  394.             '** get object vectors
  395.  
  396.             ui = Object(H1%).Xvel '                                                      get object's X velocity
  397.             vi = Object(H1%).Yvel '                                                      get object's Y velocity
  398.             uj = Object(H2%).Xvel '                                                      get 2nd object's X velocity
  399.             vj = Object(H2%).Yvel '                                                      get 2nd object's Y velocity
  400.  
  401.             '** move backwards in time until the two objects are just touching
  402.  
  403.             CoefA = (ui - uj) ^ 2 + (vi - vj) ^ 2 '                                      calculate time coefficiants of actual objects touching
  404.             CoefB = 2 * ((ui - uj) * (xi - xj) + (vi - vj) * (yi - yj))
  405.             CoefC = (xi - xj) ^ 2 + (yi - yj) ^ 2 - diam ^ 2
  406.             IF CoefA = 0 THEN
  407.                 t = -CoefC / CoefB
  408.             ELSE
  409.                 IF TIMESTEP >= 0 THEN
  410.                     t = (-CoefB - SQR(CoefB ^ 2 - 4 * CoefA * CoefC)) / (2 * CoefA)
  411.                 ELSE
  412.                     t = (-CoefB + SQR(CoefB ^ 2 - 4 * CoefA * CoefC)) / (2 * CoefA)
  413.                 END IF
  414.             END IF
  415.             xi = xi + t * ui '                                                           move object's X location to this point in time
  416.             yi = yi + t * vi '                                                           move object's Y location to this point in time
  417.             xj = xj + t * uj '                                                           move 2nd object's X location to this point in time
  418.             yj = yj + t * vj '                                                           move 2nd object's Y location to this point in time
  419.  
  420.             '** center of momentum coordinates
  421.  
  422.             mx = (ui + uj) / 2 '                                                         calculate horizontal loss of momentum between objects
  423.             my = (vi + vj) / 2 '                                                         calculate vertical loss of momentum between objects
  424.             ui = ui - mx '                                                               update object's X velocity based on momentum loss
  425.             vi = vi - my '                                                               update object's Y velocity based on momentum loss
  426.             uj = uj - mx '                                                               update 2nd object's X velocity based on momentum loss
  427.             vj = vj - my '                                                               update 2nd object's Y velocity based on momentum loss
  428.  
  429.             '** new center to center line
  430.  
  431.             dx = xi - xj '                                                               calculate X distance between objects
  432.             dy = yi - yj '                                                               calculate Y distance between objects
  433.             dist = SQR(dx ^ 2 + dy ^ 2) '                                                calculate center to center distance between objects
  434.             dx = dx / dist '
  435.             dy = dy / dist
  436.  
  437.             '** reflect object veolcity vectors in center to center line
  438.  
  439.             OB = -(dx * ui + dy * vi)
  440.             ui = ui + 2 * OB * dx
  441.             vi = vi + 2 * OB * dy
  442.             OB = -(dx * uj + dy * vj)
  443.             uj = uj + 2 * OB * dx
  444.             vj = vj + 2 * OB * dy
  445.  
  446.             '** back to moving coordinates with elastic velocity change
  447.  
  448.             e = SQR(Object(H1%).Elastic)
  449.             ui = e * (ui + mx)
  450.             vi = e * (vi + my)
  451.             uj = e * (uj + mx)
  452.             vj = e * (vj + my)
  453.  
  454.             '** move to new bounced position
  455.  
  456.             xi = xi - t * ui
  457.             yi = yi - t * vi
  458.             xj = xj - t * uj
  459.             yj = yj - t * vj
  460.  
  461.             '** set object velocities
  462.  
  463.             Object(H1%).Xvel = ui
  464.             Object(H1%).Yvel = vi
  465.  
  466.             '** set 2nd object velocities and position if allowed to respond to first object
  467.  
  468.             IF NOT Object(H2%).Fixed THEN
  469.                 Object(H2%).Xvel = uj
  470.                 Object(H2%).Yvel = vj
  471.                 Object(H2%).Xpos = xj
  472.                 Object(H2%).Ypos = yj
  473.             END IF
  474.  
  475.             '** set object position
  476.  
  477.             x = xi
  478.             y = yi
  479.         END IF
  480.  
  481.         '** attrack/repel the two objects to/against each other
  482.  
  483.         IF (Object(H1%).Attract <> 0) AND (Object(H1%).AttractedTo = H2%) THEN
  484.             xm = Object(H2%).Xpos - x
  485.             ym = Object(H2%).Ypos - y
  486.             dist = xm ^ 2 + ym ^ 2
  487.             dist = MAX(dist, Object(H1%).Radius ^ 2)
  488.             Object(H1%).Xvel = Object(H1%).Attract * xm / dist + Object(H1%).Xvel
  489.             Object(H1%).Yvel = Object(H1%).Attract * ym / dist + Object(H1%).Yvel
  490.             Object(H2%).Xvel = Object(H1%).Attract * xm / dist + Object(H2%).Xvel
  491.             Object(H2%).Yvel = -Object(H1%).Attract * ym / dist + Object(H2%).Yvel
  492.         END IF
  493.  
  494.         '** save position of object
  495.  
  496.         Object(H1%).Xpos = x
  497.         Object(H1%).Ypos = y
  498.  
  499.     END IF
  500. NEXT H2%
  501.  
  502.  
  503. '------------------------------------------------------------------------------
  504.  
  505. FUNCTION MIN (Num1!, Num2!)
  506.  
  507. '**
  508. '** returns the smallest number passed in
  509. '**
  510.  
  511. IF Num1! < Num2! THEN
  512.     MIN = Num1!
  513.     MIN = Num2!
  514.  
  515.  
  516. '------------------------------------------------------------------------------
  517.  
  518. FUNCTION MAX (Num1!, Num2!)
  519.  
  520. '**
  521. '** returns the largest number passed in
  522. '**
  523.  
  524. IF Num1! > Num2! THEN
  525.     MAX = Num1!
  526.     MAX = Num2!
  527.  
  528.  

Here is a simplified version of it with the source of the idea cited in the code.

Code: QB64: [Select]
  1. 'Most of the math in this code was realized from the following source:
  2. 'http://smallbasic.com/program/?PMT149
  3.  
  4. CONST FALSE = 0, TRUE = NOT FALSE
  5. CONST SWIDTH = 800, SHEIGHT = 600
  6. CONST GRAVITY = 0 '   puck feels the affect of gravity. Higher numbers equal more gravity
  7. CONST FRICTION = 0 '  puck had added friction. Use small increments of .1
  8. CONST FOLLOW = 0
  9. CONST ATTRACT = 0 '   puck is attracted to paddle. Higher numbers equal more attraction
  10. CONST TIMESTEP = 1
  11. CONST SHAPE = 0
  12. CONST ELASTIC = 1
  13.  
  14. TYPE OBJECT
  15.     Xpos AS SINGLE
  16.     Ypos AS SINGLE
  17.     Xvel AS SINGLE
  18.     Yvel AS SINGLE
  19.     Radius AS INTEGER
  20.  
  21. DIM Puck AS OBJECT
  22. DIM Paddle AS OBJECT
  23. DIM OldXpos!
  24. DIM OldYpos!
  25.  
  26. SCREEN _NEWIMAGE(SWIDTH, SHEIGHT, 32)
  27. Puck.Xpos = SWIDTH \ 2 - 1
  28. Puck.Ypos = SHEIGHT \ 2 - 1
  29. Puck.Xvel = 0
  30. Puck.Yvel = 0
  31. Puck.Radius = 20
  32. Paddle.Xpos = SWIDTH \ 2 - 1
  33. Paddle.Ypos = SHEIGHT - SHEIGHT \ 4
  34. Paddle.Xvel = 0
  35. Paddle.Yvel = 0
  36. Paddle.Radius = 40
  37. _MOUSEMOVE Paddle.Xpos, Paddle.Ypos
  38.  
  39. diam = Paddle.Radius + Puck.Radius
  40.  
  41.     _LIMIT 60
  42.     CLS
  43.  
  44.     '** get paddle position based on mouse position
  45.  
  46.     Paddle.Xpos = _MOUSEX
  47.     Paddle.Ypos = _MOUSEY
  48.  
  49.     '** calculate paddle velocities based on movement from last position
  50.  
  51.     Paddle.Xvel = Paddle.Xpos - OldXpos!
  52.     Paddle.Yvel = Paddle.Ypos - OldYpos!
  53.     OldXpos! = Paddle.Xpos
  54.     OldYpos! = Paddle.Ypos
  55.  
  56.     '** update puck position
  57.  
  58.     u = MIN(100, MAX(Puck.Xvel, -100))
  59.     v = MIN(100, MAX(Puck.Yvel, -100))
  60.     x = Puck.Xpos + TIMESTEP * u
  61.     y = Puck.Ypos + TIMESTEP * v
  62.     IF x < Puck.Radius THEN
  63.         Puck.Xvel = -Puck.Xvel
  64.         x = Puck.Radius
  65.     END IF
  66.  
  67.     '** check for edge bounces
  68.  
  69.     IF x > SWIDTH - Puck.Radius THEN
  70.         Puck.Xvel = -Puck.Xvel
  71.         x = SWIDTH - Puck.Radius
  72.     END IF
  73.     IF y < Puck.Radius THEN
  74.         Puck.Yvel = -Puck.Yvel
  75.         y = Puck.Radius
  76.     END IF
  77.     IF y > SHEIGHT - Puck.Radius THEN
  78.         Puck.Yvel = -Puck.Yvel
  79.         y = SHEIGHT - Puck.Radius
  80.     END IF
  81.  
  82.     ' ** Gravity, Friction and Follow paddle
  83.  
  84.     xm = Paddle.Xpos - x
  85.     ym = Paddle.Ypos - y
  86.     dist = xm ^ 2 + ym ^ 2
  87.     dist = MAX(dist, Puck.Radius * Puck.Radius)
  88.     'dist = dist * SQR(dist)
  89.     u = Puck.Xvel
  90.     v = Puck.Yvel
  91.     fricscale = 1 - FRICTION / SQR(1 + u ^ 2 + v ^ 2)
  92.     Puck.Xvel = FOLLOW * xm / dist + fricscale * u
  93.     Puck.Yvel = FOLLOW * ym / dist + fricscale * v + GRAVITY
  94.  
  95.     '** check for collision
  96.  
  97.     xi = x
  98.     yi = y
  99.     xj = Paddle.Xpos
  100.     yj = Paddle.Ypos
  101.     dx = xi - xj
  102.     dy = yi - yj
  103.     dist = SQR(dx ^ 2 + dy ^ 2)
  104.     IF dist < diam THEN
  105.         iscollision = TRUE
  106.  
  107.         '** get puck vectors
  108.  
  109.         ui = Puck.Xvel
  110.         vi = Puck.Yvel
  111.         uj = Paddle.Xvel
  112.         vj = Paddle.Yvel
  113.  
  114.         '** move backwards (forwards if TIMESTEP < 0) in time until puck and paddle are just touching
  115.  
  116.         coefa = (ui - uj) ^ 2 + (vi - vj) ^ 2
  117.         coefb = 2 * ((ui - uj) * (xi - xj) + (vi - vj) * (yi - yj))
  118.         coefc = (xi - xj) ^ 2 + (yi - yj) ^ 2 - diam ^ 2
  119.         IF coefa = 0 THEN
  120.             t = -coefc / coefb
  121.         ELSE
  122.             IF TIMESTEP >= 0 THEN
  123.                 t = (-coefb - SQR(coefb ^ 2 - 4 * coefa * coefc)) / (2 * coefa)
  124.             ELSE
  125.                 t = (-coefb + SQR(coefb ^ 2 - 4 * coefa * coefc)) / (2 * coefa)
  126.             END IF
  127.         END IF
  128.         xi = xi + t * ui
  129.         yi = yi + t * vi
  130.         xj = xj + t * uj
  131.         yj = yj + t * vj
  132.  
  133.         '** center of momentum coordinates
  134.  
  135.         mx = (ui + uj) / 2
  136.         my = (vi + vj) / 2
  137.         ui = ui - mx
  138.         vi = vi - my
  139.         uj = uj - mx
  140.         vj = vj - my
  141.  
  142.         '** new center to center line
  143.  
  144.         dx = xi - xj
  145.         dy = yi - yj
  146.         dist = SQR(dx ^ 2 + dy ^ 2)
  147.         dx = dx / dist
  148.         dy = dy / dist
  149.  
  150.         '** reflect puck veolcity vectors in center to center line
  151.  
  152.         OB = -(dx * ui + dy * vi)
  153.         ui = ui + 2 * OB * dx
  154.         vi = vi + 2 * OB * dy
  155.         OB = -(dx * uj + dy * vj)
  156.         uj = uj + 2 * OB * dx
  157.         vj = vj + 2 * OB * dy
  158.  
  159.         '** back to moving coordinates with elastic velocity change
  160.  
  161.         e = SQR(ELASTIC)
  162.         ui = e * (ui + mx)
  163.         vi = e * (vi + my)
  164.         uj = e * (uj + mx)
  165.         vj = e * (vj + my)
  166.  
  167.         '** move to new bounced position
  168.  
  169.         xi = xi - t * ui
  170.         yi = yi - t * vi
  171.         xj = xj - t * uj
  172.         yj = yj - t * vj
  173.  
  174.         '** set puck velocities
  175.  
  176.         Puck.Xvel = ui
  177.         Puck.Yvel = vi
  178.  
  179.         '** set paddle velocities and position if allowed to respond to puck
  180.  
  181.         'Paddle.Xvel = uj
  182.         'Paddle.Yvel = vj
  183.         'Paddle.Xpos = xj
  184.         'Paddle.Ypos = yj
  185.  
  186.         '** set puck position
  187.  
  188.         x = xi
  189.         y = yi
  190.     END IF
  191.  
  192.     '** attrack/repel puck and paddle to each other
  193.  
  194.     IF ATTRACT <> 0 THEN
  195.         xm = Paddle.Xpos - x
  196.         ym = Paddle.Ypos - y
  197.         dist = xm ^ 2 + ym ^ 2
  198.         dist = MAX(dist, Puck.Radius ^ 2) ' *******  may be wrong?
  199.         'dist = dist * SQR(dist)
  200.         Puck.Xvel = ATTRACT * xm / dist + Puck.Xvel
  201.         Puck.Yvel = ATTRACT * ym / dist + Puck.Yvel
  202.         Paddle.Xvel = ATTRACT * xm / dist + Paddle.Xvel
  203.         Paddle.Yvel = -ATTRACT * ym / dist + Paddle.Yvel
  204.     END IF
  205.  
  206.     '** save position of puck
  207.  
  208.     Puck.Xpos = x
  209.     Puck.Ypos = y
  210.  
  211.     '** draw puck and paddle
  212.  
  213.     CIRCLE (x, y), Puck.Radius, _RGB32(127, 127, 127)
  214.     CIRCLE (Paddle.Xpos, Paddle.Ypos), Paddle.Radius, _RGB32(255, 255, 255)
  215.  
  216.     '** draw right angle between puck and paddle
  217.  
  218.     'LINE (Paddle.Xpos, Paddle.Ypos)-(Puck.Xpos, Puck.Ypos), _RGB32(64, 64, 64)
  219.     'LINE -(Puck.Xpos, Paddle.Ypos), _RGB32(64, 64, 64)
  220.     'LINE -(Paddle.Xpos, Paddle.Ypos), _RGB32(64, 64, 64)
  221.     'LINE (Puck.Xpos, Paddle.Ypos)-(Puck.Xpos + (SGN(Paddle.Xpos - Puck.Xpos) * 10), Paddle.Ypos + (SGN(Puck.Ypos - Paddle.Ypos) * 10)), _RGB32(64, 64, 64), B
  222.  
  223.     '** play collision sound
  224.  
  225.     'IF iscollision THEN
  226.     'play sound here
  227.     'END IF
  228.  
  229.     '** update the display with changes
  230.  
  231.     _DISPLAY
  232.  
  233.  
  234. '------------------------------------------------------------------------------
  235.  
  236. FUNCTION MIN (Num1!, Num2!)
  237.  
  238. IF Num1! < Num2! THEN
  239.     MIN = Num1!
  240.     MIN = Num2!
  241.  
  242.  
  243. '------------------------------------------------------------------------------
  244.  
  245. FUNCTION MAX (Num1!, Num2!)
  246.  
  247. IF Num1! > Num2! THEN
  248.     MAX = Num1!
  249.     MAX = Num2!
  250.  
  251.  
« Last Edit: August 21, 2018, 03:27:11 am by TerryRitchie »
In order to understand recursion, one must first understand recursion.

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Physics Engine
« Reply #1 on: August 21, 2018, 04:47:14 am »
Very nicely done indeed... Cool.
Logic is the beginning of wisdom.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Physics Engine
« Reply #2 on: August 21, 2018, 12:28:45 pm »
Perfect!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Physics Engine
« Reply #3 on: August 21, 2018, 12:58:23 pm »
Holly Son of the Universal Machine!

That might just be what I needed to finish my Pool Game!

          :-) )  yea!

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Physics Engine
« Reply #4 on: August 21, 2018, 07:47:04 pm »
Pool? Did some just say, "Pool"?
Logic is the beginning of wisdom.

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Physics Engine
« Reply #5 on: August 22, 2018, 04:29:24 am »
Hi
interesting and fine...
Programming isn't difficult, only it's  consuming time and coffee

Offline Qwerkey

  • Forum Resident
  • Posts: 755
    • View Profile
Re: Physics Engine
« Reply #6 on: August 22, 2018, 05:45:59 am »
Terry, I tried substituting ROUND with SQUARE for object type but everything remained as circles.  Did I miss something or is it to do with "'** defines an object (very basic, not finished yet)" ie you haven't put it anything to do with squares yet?  Richard

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
    • View Profile
Re: Physics Engine
« Reply #7 on: September 03, 2018, 08:36:31 am »
I would have to study the code to even tell if it's over my head, but....

That was fun! :D

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Physics Engine
« Reply #8 on: September 03, 2018, 11:26:54 am »
Math is not my strong suit. I understand it but putting it to practical use for things such as 3D visualization has always eluded me. In the second code listing I cite the source for inspiration.
In order to understand recursion, one must first understand recursion.

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Physics Engine
« Reply #9 on: September 06, 2018, 02:28:07 am »
Holly Son of the Universal Machine!

That might just be what I needed to finish my Pool Game!

          :-) )  yea!

LOL, I missed this post. I hope you can use/modify the code to your needs. Seems perfect for pool!

My original thought was to somehow include this code in my sprite library, giving sprites the ability to interact much like the 2D engine in Angry Birds.
« Last Edit: September 06, 2018, 02:30:36 am by TerryRitchie »
In order to understand recursion, one must first understand recursion.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Physics Engine
« Reply #10 on: September 06, 2018, 08:58:45 am »
Yes, pool will likely be revisited, my own 2D collisions did OK with bouncing balls but complete disaster with pool.

Terry have you played with Boids? maybe that's what Angry Birds are?

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Physics Engine
« Reply #11 on: September 06, 2018, 01:09:12 pm »
Box2D is the engine used by Angry Birds. I've never heard of Boids and from research it appears to be an artificial life program, generating paths for flocks of birds for instance.
In order to understand recursion, one must first understand recursion.

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Physics Engine
« Reply #12 on: September 06, 2018, 05:50:55 pm »
This may be a stupid question.... Box2D and "this" Physics Engine did not just 'appear'. I would like to know 'how' those 'physical models' (for want of a better phrase)  were converted into QB64 etc? Reason: If I wanted to 'add' another feature I would either have to suggest it and wait for someone to make it or someone could show me how it's done and I could do it myself... (I am not saying that I have anything to 'add', it's just a 'what if' kind of thing...)

J
Logic is the beginning of wisdom.

Offline TerryRitchie

  • Seasoned Forum Regular
  • Posts: 495
  • Semper Fidelis
    • View Profile
Re: Physics Engine
« Reply #13 on: September 06, 2018, 08:42:16 pm »
In the case of my engine I used the source code of the program I cited in the second listing. Even though the original source is written in another language I can usually get the main gist of the code enough to rewrite it in QB64. Once I have an idea of what is going on math-wise, I then play around with the code to achieve my desired result.

The entire source of Box2D is available at their web site, however it's written in C++, a language I very poorly comprehend when dealing with code as involved as a 2D physics engine. C++'s constructs are my weak point.

Many graphics engines come into being because of a need. The Unreal engine due to Epic creating the Unreal game back in the 90's. Box2D came about from a group of programmers getting together at a gaming conference and wanting to build something better. The Doom engine, Half-life Engine, Quake Engine, Unity, etc.. all had a specific need to fill. I feel QB64 needs a 2D (or even 3D) engine (library) however I won't be able to deliver that given my weak math skills. We have the talent here to pull it off, but first there must be a defined need for it, a driving force if you will.

Unfortunately, people that are skilled enough in math to write something as complex as a physics engine are going to apply their talent for a much larger audience than we have here.

It can be done though. Check out this code by Galleon done years ago with QB64. It's a Portals clone!
* Portals.zip (Filesize: 15.86 MB, Downloads: 246)
« Last Edit: September 06, 2018, 08:49:34 pm by TerryRitchie »
In order to understand recursion, one must first understand recursion.

FellippeHeitor

  • Guest
Re: Physics Engine
« Reply #14 on: September 06, 2018, 10:11:30 pm »
Very entertaining physics demo with the bouncing balls, Terry.

The Portals clone by Galleon is amazing, I hadn't seen it before.

It requires _MOUSEMOVEMENTX and _MOUSEMOVEMENTY which haven't yet gotten fixed since the switch to OpenGL, so here's a fixed version that can be compiled with the latest version of QB64:
Code: QB64: [Select]
  1. 'CONTROLS:
  2. 'Left Mouse Button: Fire a blue portal
  3. 'Right Mouse Button: Fire an orange portal
  4. 'Mouse Movement: Look around
  5. 'W,A,S,D: Move forward, left, back and right
  6. 'Space: Jump
  7.  
  8. DEFDBL A-Z
  9.  
  10. DIM SHARED ScreenX AS LONG
  11. DIM SHARED ScreenY AS LONG
  12.  
  13. 'Note: Unplayable at higher resolutions! (Try it at 160x120 for realtime speed)
  14. ScreenX = 320
  15. ScreenY = 240
  16.  
  17.  
  18. _TITLE "PORTALS QB64"
  19.  
  20.  
  21. DIM SHARED portal(1 TO 2) AS INTEGER
  22. 'indexes to currently open portals (if any!)
  23.  
  24. '[8](256) standard textures in standard orientations
  25. '[10](1024) special references/modifiers
  26.  
  27. TYPE SpecialType
  28.     Effect AS INTEGER
  29.     '"this" box
  30.     X AS LONG
  31.     Y AS LONG
  32.     Z AS LONG
  33.     '"this" side/vector
  34.     dX AS LONG '1,0,-1
  35.     dY AS LONG '1,0,-1
  36.     dZ AS LONG '1,0,-1
  37.     '"reference" box
  38.     X2 AS INTEGER
  39.     Y2 AS INTEGER
  40.     Z2 AS INTEGER
  41.     '"reference" side/vector
  42.     dX2 AS INTEGER '1,0,-1
  43.     dY2 AS INTEGER '1,0,-1
  44.     dZ2 AS INTEGER '1,0,-1
  45. DIM SHARED Special(1023) AS SpecialType
  46.  
  47.  
  48.  
  49.  
  50. DIM SHARED vax, vay
  51.  
  52.  
  53. DIM SHARED KeyDown(255) AS LONG
  54.  
  55. DIM SHARED LastTime
  56. DIM SHARED ElapsedTime 'how many seconds have elapsed since the last main loop
  57.  
  58. TYPE ObjectType
  59.     X AS DOUBLE
  60.     Y AS DOUBLE
  61.     Z AS DOUBLE
  62.     Height AS DOUBLE
  63.     dX AS DOUBLE
  64.     dY AS DOUBLE
  65.     dZ AS DOUBLE
  66.  
  67. DIM Plr AS ObjectType
  68. Plr.X = 50
  69. Plr.Y = 50
  70. Plr.Z = 50
  71. Plr.Height = 0.85
  72.  
  73.  
  74. DIM SHARED UX AS LONG, UY AS LONG, UZ AS LONG 'start of ray
  75. DIM SHARED UdX AS LONG, UdY AS LONG, UdZ AS LONG 'vector to scan
  76. DIM SHARED USGNdX AS LONG, USGNdY AS LONG, USGNdZ AS LONG '0=negative, 1=zero or positive
  77. DIM SHARED USpeedX AS LONG, USpeedY AS LONG, USpeedZ AS LONG, UMinSpeed AS LONG
  78. DIM SHARED UABSdX AS LONG, UABSdY AS LONG, UABSdZ AS LONG '0=negative, 1=zero or positive
  79. DIM SHARED UCrossed AS LONG
  80. DIM SHARED URayDepth AS LONG, UMaxDepth AS LONG
  81. DIM SHARED UBoxType AS LONG
  82. UMaxDepth = 8
  83. DIM SHARED Ulr AS LONG, Udu AS LONG
  84. DIM SHARED UdX2 AS LONG, UdY2 AS LONG, UdZ2 AS LONG
  85. DIM SHARED UdX3 AS LONG, UdY3 AS LONG, UdZ3 AS LONG
  86.  
  87.  
  88.  
  89.  
  90.  
  91. DIM SHARED MapLimit AS LONG
  92. MapLimit = 100
  93. DIM SHARED Map(0 TO MapLimit, 0 TO MapLimit, 0 TO MapLimit) AS _UNSIGNED INTEGER
  94.  
  95. SCREEN _NEWIMAGE(ScreenX, ScreenY, 32)
  96. DIM ScrBuf(-1 TO ScreenX * ScreenY - 1) AS LONG
  97. GET (0, 0)-(ScreenX - 1, ScreenY - 1), ScrBuf()
  98.  
  99.  
  100.  
  101.  
  102.  
  103. FOR i = 1 TO 5
  104.     texi = _LOADIMAGE(".\portals\cube" + LTRIM$(STR$(i)) + ".bmp", 32)
  105.     _SOURCE texi
  106.     TexX = _WIDTH(texi) - 1
  107.     TexY = _HEIGHT(texi) - 1
  108.  
  109.     UTexX& = TexX
  110.     UTexY& = TexY
  111.  
  112.     IF i = 1 THEN DIM Tex(TexX, TexY, 1 TO 5) AS LONG
  113.  
  114.     FOR y = 0 TO TexY
  115.         FOR x = 0 TO TexX
  116.             Tex(x, y, i) = POINT(x, y)
  117.         NEXT
  118.     NEXT
  119.     _FREEIMAGE texi
  120.  
  121.  
  122.  
  123. FOR i = 1 TO 5
  124.     texi = _LOADIMAGE(".\portals\wall" + LTRIM$(STR$(i)) + ".bmp", 32)
  125.     _SOURCE texi
  126.     TexX = _WIDTH(texi) - 1
  127.     TexY = _HEIGHT(texi) - 1
  128.  
  129.     UTexX& = TexX
  130.     UTexY& = TexY
  131.  
  132.     IF i = 1 THEN DIM Tex2(TexX, TexY, 1 TO 5) AS LONG
  133.     FOR y = 0 TO TexY: FOR x = 0 TO TexX: Tex2(x, y, i) = POINT(x, y): NEXT: NEXT
  134.     _FREEIMAGE texi
  135.  
  136.  
  137. FOR i = 1 TO 5
  138.     texi = _LOADIMAGE(".\portals\but" + LTRIM$(STR$(i)) + ".bmp", 32)
  139.     _SOURCE texi
  140.     TexX = _WIDTH(texi) - 1
  141.     TexY = _HEIGHT(texi) - 1
  142.  
  143.     UTexX& = TexX
  144.     UTexY& = TexY
  145.  
  146.     IF i = 1 THEN DIM Tex3(TexX, TexY, 1 TO 5) AS LONG
  147.  
  148.     FOR y = 0 TO TexY
  149.         FOR x = 0 TO TexX
  150.             Tex3(x, y, i) = POINT(x, y)
  151.         NEXT
  152.     NEXT
  153.     _FREEIMAGE texi
  154.  
  155.  
  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162. texi = _LOADIMAGE(".\portals\p_floor.bmp", 32): _SOURCE texi: TexX = _WIDTH(texi) - 1: TexY = _HEIGHT(texi) - 1: UTexX& = TexX: UTexY& = TexY
  163. DIM t_floor(TexX, TexY, 1 TO 1) AS LONG
  164. FOR y = 0 TO TexY: FOR x = 0 TO TexX: t_floor(x, y, 1) = POINT(x, y): NEXT: NEXT
  165.  
  166. texi = _LOADIMAGE(".\portals\p_walla.bmp", 32): _SOURCE texi: TexX = _WIDTH(texi) - 1: TexY = _HEIGHT(texi) - 1: UTexX& = TexX: UTexY& = TexY
  167. DIM t_walla(TexX, TexY, 1 TO 1) AS LONG
  168. FOR y = 0 TO TexY: FOR x = 0 TO TexX: t_walla(x, y, 1) = POINT(x, y): NEXT: NEXT
  169.  
  170. texi = _LOADIMAGE(".\portals\p_wallb.bmp", 32): _SOURCE texi: TexX = _WIDTH(texi) - 1: TexY = _HEIGHT(texi) - 1: UTexX& = TexX: UTexY& = TexY
  171. DIM t_wallb(TexX, TexY, 1 TO 1) AS LONG
  172. FOR y = 0 TO TexY: FOR x = 0 TO TexX: t_wallb(x, y, 1) = POINT(x, y): NEXT: NEXT
  173.  
  174. texi = _LOADIMAGE(".\portals\p_roof.bmp", 32): _SOURCE texi: TexX = _WIDTH(texi) - 1: TexY = _HEIGHT(texi) - 1: UTexX& = TexX: UTexY& = TexY
  175. DIM t_roof(TexX, TexY, 1 TO 1) AS LONG
  176. FOR y = 0 TO TexY: FOR x = 0 TO TexX: t_roof(x, y, 1) = POINT(x, y): NEXT: NEXT
  177.  
  178. texi = _LOADIMAGE(".\portals\p_buta.bmp", 32): _SOURCE texi: TexX = _WIDTH(texi) - 1: TexY = _HEIGHT(texi) - 1: UTexX& = TexX: UTexY& = TexY
  179. DIM t_buta(TexX, TexY, 1 TO 1) AS LONG
  180. FOR y = 0 TO TexY: FOR x = 0 TO TexX: t_buta(x, y, 1) = POINT(x, y): NEXT: NEXT
  181.  
  182. texi = _LOADIMAGE(".\portals\p_butb.bmp", 32): _SOURCE texi: TexX = _WIDTH(texi) - 1: TexY = _HEIGHT(texi) - 1: UTexX& = TexX: UTexY& = TexY
  183. DIM t_butb(TexX, TexY, 1 TO 1) AS LONG
  184. FOR y = 0 TO TexY: FOR x = 0 TO TexX: t_butb(x, y, 1) = POINT(x, y): NEXT: NEXT
  185.  
  186.  
  187. texi = _LOADIMAGE(".\portals\p_s_box.bmp", 32): _SOURCE texi: TexX = _WIDTH(texi) - 1: TexY = _HEIGHT(texi) - 1: UTexX& = TexX: UTexY& = TexY
  188. DIM t_s_box(TexX, TexY, 1 TO 1) AS LONG
  189. FOR y = 0 TO TexY: FOR x = 0 TO TexX: t_s_box(x, y, 1) = POINT(x, y): NEXT: NEXT
  190.  
  191.  
  192.  
  193.  
  194. FovX = 75
  195. FovY = ScreenY / ScreenX * FovX
  196.  
  197.  
  198. DIM PixSinX(ScreenX - 1)
  199. DIM PixSinY(ScreenY - 1)
  200.  
  201. DIM PixX(ScreenX * ScreenY - 1) AS LONG
  202. DIM PixY(ScreenX * ScreenY - 1) AS LONG
  203. DIM PixZ(ScreenX * ScreenY - 1) AS LONG
  204.  
  205. deg2rad = 3.151592654 / 180
  206.  
  207. ay = -FovY / 2
  208. ayi = FovY / ScreenY
  209. FOR sy = ScreenY - 1 TO 0 STEP -1
  210.     a2 = ay * deg2rad
  211.     PixSinY(sy) = SIN(a2)
  212.     ay = ay + ayi
  213.  
  214. ax = -FovX / 2
  215. axi = FovX / ScreenX
  216. FOR sx = 0 TO ScreenX - 1
  217.     a1 = ax * deg2rad
  218.     PixSinX(sx) = SIN(a1)
  219.     ax = ax + axi
  220.  
  221. FOR sy = ScreenY - 1 TO 0 STEP -1
  222.     FOR sx = 0 TO ScreenX - 1
  223.         x = PixSinX(sx)
  224.         y = PixSinY(sy)
  225.         z = 1
  226.         l = SQR(x * x + y * y + z * z)
  227.         x = x / l
  228.         y = y / l
  229.         z = z / l
  230.         PixX(sy * ScreenX + sx) = x * 16384#
  231.         PixY(sy * ScreenX + sx) = y * 16384#
  232.         PixZ(sy * ScreenX + sx) = z * 16384#
  233.     NEXT
  234.  
  235.  
  236.  
  237. 'lets try a 2d test to see if we are getting anywhere with this, then a proper 3d test
  238. 'to test anything we need a map
  239.  
  240.  
  241. 'FOR x = -10 TO 10
  242. 'Map(x + 50, 50, -10 + 50) = 1
  243. 'Map(x + 50, 50, 10 + 50) = 1
  244. 'NEXT
  245. 'FOR z = -10 TO 10
  246. 'Map(-10 + 50, 50, z + 50) = 1
  247. 'Map(10 + 50, 50, z + 50) = 1
  248. 'NEXT
  249.  
  250.  
  251. 'floor n roof
  252. 'FOR x = 0 TO MapLimit
  253. 'FOR z = 0 TO MapLimit
  254. '  Map(x, 49, z) = 1
  255. 'Map(x, 60, z) = 1
  256. 'NEXT
  257. 'NEXT
  258.  
  259. FOR x = 0 TO MapLimit
  260.     FOR y = 0 TO MapLimit
  261.         FOR z = 0 TO MapLimit
  262.             Map(x, y, z) = 1
  263.             'IF y = 49 AND RND * 10 < 1 THEN Map(x, y, z) = 3
  264.             '      IF RND * 20 < 1 THEN Map(x, y, z) = 4
  265.         NEXT
  266.     NEXT
  267.  
  268.  
  269. FOR x = 0 TO MapLimit: FOR z = 0 TO MapLimit
  270.         Map(x, 49, z) = 10
  271.         IF RND * 50 < 1 THEN Map(x, 49, z) = 14
  272. FOR x = 0 TO MapLimit: FOR z = 0 TO MapLimit
  273.         Map(x, 50, z) = 11
  274. FOR x = 0 TO MapLimit: FOR z = 0 TO MapLimit
  275.         Map(x, 51, z) = 12
  276.         IF RND * 20 < 1 THEN Map(x, 51, z) = 15
  277.  
  278. FOR x = 0 TO MapLimit: FOR z = 0 TO MapLimit
  279.         Map(x, 52, z) = 11
  280. FOR x = 0 TO MapLimit: FOR z = 0 TO MapLimit
  281.         Map(x, 53, z) = 12
  282. FOR x = 0 TO MapLimit: FOR z = 0 TO MapLimit
  283.         Map(x, 54, z) = 13
  284.  
  285.  
  286.  
  287. FOR x = -5 TO 5
  288.     FOR y = 0 TO 3
  289.         FOR z = -5 TO 5
  290.             Map(50 + x, 50 + y, 50 + z) = 0
  291.         NEXT
  292.     NEXT
  293.  
  294. Map(50 - 6, 50, 50) = 2
  295.  
  296.  
  297. 'Map(50, 50 + 0, 50 - 6) = 2 + 1024
  298.  
  299. 'Special(1).dX = 0
  300. 'Special(1).dY = 0
  301. 'Special(1).dZ = 1
  302. 'Special(1).X = 50
  303. 'Special(1).Y = 52
  304. 'Special(1).Z = 50 - 4
  305.  
  306.  
  307.  
  308.  
  309.  
  310. 'FOR i = 1 TO 250
  311. '  xx = RND * 10
  312. 'yy = RND * 10
  313. 'zz = RND * 10
  314. 'Map(46 + xx, 50 + yy, 48 + zz) = 1
  315. 'NEXT
  316.  
  317. FOR i = 1 TO 50
  318.     xx = rnd2(4)
  319.     yy = INT(RND * 5)
  320.     zz = rnd2(4)
  321.  
  322.     IF Map(50 + xx, 50 + yy - 1, 50 + zz) THEN Map(50 + xx, 50 + yy, 50 + zz) = 2
  323.  
  324.  
  325.  
  326. 'Map(46, 50, 48) = 4
  327.  
  328. 'Map(46, 50, 52) = 4
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337. vax = 0
  338. vay = 0
  339.  
  340.  
  341.  
  342.  
  343.  
  344.  
  345. starttime = TIMER(0.001)
  346.  
  347. LastTime = TIMER(0.001)
  348.     _LIMIT 60
  349.  
  350.     Uvaxs& = SIN(vax * deg2rad) * 16384&: Uvaxc& = COS(vax * deg2rad) * 16384&
  351.     Uvays& = SIN(vay * deg2rad) * 16384&: Uvayc& = COS(vay * deg2rad) * 16384&
  352.  
  353.     DIM SHARED PixOff AS LONG
  354.  
  355.  
  356.     ay = -FovY / 2
  357.     ayi = FovY / ScreenY
  358.  
  359.  
  360.  
  361.  
  362.     Upx1& = Plr.X * 16384#
  363.     Upy1& = (Plr.Y + Plr.Height) * 16384#
  364.     Upz1& = Plr.Z * 16384#
  365.  
  366.     '$CHECKING:OFF
  367.  
  368.     FOR sY = ScreenY - 1 TO 0 STEP -1
  369.         siny = PixSinY(sY)
  370.  
  371.         PixOff = sY * ScreenX
  372.         FOR sX = 0 TO ScreenX - 1
  373.  
  374.             x& = PixX(PixOff)
  375.             y& = PixY(PixOff)
  376.             z& = PixZ(PixOff)
  377.  
  378.  
  379.  
  380.             UdY& = (Uvays& * z&) \ 16384 + (Uvayc& * y&) \ 16384
  381.             z& = (Uvayc& * z&) \ 16384 - (Uvays& * y&) \ 16384
  382.  
  383.             UdX& = (Uvaxs& * z&) \ 16384 + (Uvaxc& * x&) \ 16384
  384.             UdZ& = (Uvaxc& * z&) \ 16384 - (Uvaxs& * x&) \ 16384
  385.  
  386.             UX& = Upx1&
  387.             UY& = Upy1&
  388.             UZ& = Upz1&
  389.  
  390.  
  391.  
  392.             'copy from here
  393.  
  394.             IF UdX& >= 0 THEN USGNdX = 1 ELSE USGNdX = 0
  395.             IF UdY& >= 0 THEN USGNdY = 1 ELSE USGNdY = 0
  396.             IF UdZ& >= 0 THEN USGNdZ = 1 ELSE USGNdZ = 0
  397.  
  398.             UABSdX& = ABS(UdX&)
  399.             UABSdY& = ABS(UdY&)
  400.             UABSdZ& = ABS(UdZ&)
  401.  
  402.             UDis& = 0
  403.  
  404.             URayDepth = 0
  405.  
  406.             main_1: 'remove this line when possible
  407.  
  408.             DO
  409.  
  410.                 'calculate x,y,z distance to next 'cube'
  411.                 IF USGNdX THEN
  412.                     UDistx& = 16384 - (UX& AND 16383)
  413.                     IF UDistx& = 0 THEN UDistx& = 16384
  414.                 ELSE
  415.                     UDistx& = (UX& AND 16383) + 1
  416.                 END IF
  417.                 IF USGNdY THEN
  418.                     UDisty& = 16384 - (UY& AND 16383)
  419.                     IF UDisty& = 0 THEN UDisty& = 16384
  420.                 ELSE
  421.                     UDisty& = (UY& AND 16383) + 1
  422.                 END IF
  423.                 IF USGNdZ THEN
  424.                     UDistz& = 16384 - (UZ& AND 16383)
  425.                     IF UDistz& = 0 THEN UDistz& = 16384
  426.                 ELSE
  427.                     UDistz& = (UZ& AND 16383) + 1
  428.                 END IF
  429.  
  430.                 IF UABSdX& <> 0 THEN USpeedX& = (UDistx& * 16384) \ UABSdX& ELSE USpeedX& = 2147483647
  431.                 IF UABSdY& <> 0 THEN USpeedY& = (UDisty& * 16384) \ UABSdY& ELSE USpeedY& = 2147483647
  432.                 IF UABSdZ& <> 0 THEN USpeedZ& = (UDistz& * 16384) \ UABSdZ& ELSE USpeedZ& = 2147483647
  433.  
  434.                 'advance minimal speed + microstep(to cater for floating point errors only)
  435.                 UCrossed& = 1
  436.                 UMinSpeed& = USpeedX&
  437.                 IF USpeedY& < UMinSpeed& THEN UMinSpeed& = USpeedY&: UCrossed& = 2
  438.                 IF USpeedZ& < UMinSpeed& THEN UMinSpeed& = USpeedZ&: UCrossed& = 3
  439.                 UMinSpeed& = UMinSpeed& + 1
  440.                 UDis& = UDis& + UMinSpeed&
  441.  
  442.                 UX& = UX& + (UdX& * UMinSpeed&) \ 16384
  443.                 UY& = UY& + (UdY& * UMinSpeed&) \ 16384
  444.                 UZ& = UZ& + (UdZ& * UMinSpeed&) \ 16384
  445.  
  446.                 UBoxType& = Map(UX& \ 16384, UY& \ 16384, UZ& \ 16384)
  447.             LOOP UNTIL UBoxType&
  448.  
  449.  
  450.             IF UBoxType > 255 THEN
  451.  
  452.                 URayDepth = URayDepth + 1
  453.                 IF URayDepth > UMaxDepth THEN
  454.                     ScrBuf(PixOff) = 0
  455.                     GOTO 3
  456.                 END IF
  457.  
  458.                 Ui = UBoxType \ 256
  459.  
  460.  
  461.                 IF UCrossed = 1 THEN
  462.                     IF USGNdX THEN
  463.                         Ulr = 16383 - (UZ& AND 16383): Udu = UY& AND 16383
  464.                         UdX2 = -UdZ: UdY2 = UdY: UdZ2 = UdX
  465.                     ELSE
  466.                         Ulr = UZ& AND 16383: Udu = UY& AND 16383
  467.                         UdX2 = UdZ: UdY2 = UdY: UdZ2 = -UdX
  468.                     END IF
  469.                 END IF
  470.  
  471.                 IF UCrossed = 2 THEN
  472.                     IF USGNdY THEN
  473.                         Ulr = UX& AND 16383: Udu = 16383 - (UZ& AND 16383)
  474.                         UdX2 = UdX: UdY2 = -UdZ: UdZ2 = UdY
  475.                     ELSE
  476.                         Ulr = UX& AND 16383: Udu = UZ& AND 16383
  477.                         UdX2 = UdX: UdY2 = UdZ: UdZ2 = -UdY
  478.                     END IF
  479.                 END IF
  480.  
  481.  
  482.                 IF UCrossed = 3 THEN
  483.                     IF USGNdZ THEN
  484.                         Ulr = UX& AND 16383: Udu = UY& AND 16383
  485.                         UdX2 = UdX: UdY2 = UdY: UdZ2 = UdZ
  486.                     ELSE
  487.                         Ulr = 16383 - (UX& AND 16383): Udu = UY& AND 16383
  488.                         UdX2 = -UdX: UdY2 = UdY: UdZ2 = -UdZ
  489.                     END IF
  490.                 END IF
  491.  
  492.                 x = (Ulr / 16384) - 0.5
  493.                 y = (Udu / 16384) - 0.5
  494.                 ll = x * x + y * y
  495.  
  496.                 IF ll > .25 THEN UBoxType = UBoxType AND 255: GOTO 77
  497.  
  498.  
  499.                 IF ll > .23 THEN 'ring
  500.                     IF Ui = 1 THEN c& = _RGB(64, 128, 255) ELSE c& = _RGB(255, 128, 64)
  501.                     GOTO 770
  502.                 END IF
  503.  
  504.                 IF Ui = 1 THEN
  505.                     IF portal(2) = 0 THEN
  506.                         c& = _RGB(32, 64, 128)
  507.                         GOTO 770
  508.                     ELSE
  509.  
  510.                     END IF
  511.                 END IF
  512.  
  513.                 IF Ui = 2 THEN
  514.                     IF portal(1) = 0 THEN
  515.                         c& = _RGB(128, 64, 32)
  516.                         GOTO 770
  517.                     ELSE
  518.  
  519.                     END IF
  520.                 END IF
  521.  
  522.  
  523.                 IF Ui = 1 THEN Ui = 2 ELSE Ui = 1
  524.                 '      LOCATE 1, 1
  525.                 '       PRINT UdX, UdY, UdZ
  526.  
  527.                 '        PRINT UdX2, UdY2, UdZ2
  528.                 '        UDisPLAY
  529.                 '        SLEEP
  530.  
  531.                 'assume top down vantage
  532.  
  533.  
  534.                 '        UDisPLAY
  535.                 '       SLEEP
  536.  
  537.  
  538.  
  539.  
  540.  
  541.                 UX = Special(Ui).X
  542.                 UZ = Special(Ui).Z
  543.                 UY = Special(Ui).Y
  544.  
  545.                 UdX3 = Special(Ui).dX
  546.                 UdY3 = Special(Ui).dY
  547.                 UdZ3 = Special(Ui).dZ
  548.  
  549.                 IF UdX3 THEN
  550.                     IF UdX3 >= 0 THEN
  551.                         UX = UX + 16383
  552.                         UZ = UZ + 16383 - Ulr
  553.                         UY = UY + Udu
  554.                         UdX = UdZ2
  555.                         UdY = UdY2
  556.                         UdZ = -UdX2
  557.                     ELSE
  558.                         UX = UX
  559.                         UZ = UZ + Ulr
  560.                         UY = UY + Udu
  561.                         UdX = -UdZ2
  562.                         UdY = UdY2
  563.                         UdZ = UdX2
  564.                     END IF
  565.                 END IF
  566.  
  567.  
  568.  
  569.                 IF UdZ3 THEN
  570.                     IF UdZ3 >= 0 THEN
  571.                         UX = UX + Ulr
  572.                         UZ = UZ + 16383
  573.                         UY = UY + Udu
  574.                         UdX = UdX2
  575.                         UdY = UdY2
  576.                         UdZ = UdZ2
  577.                     ELSE
  578.                         UX = UX + 16383 - Ulr
  579.                         UZ = UZ
  580.                         UY = UY + Udu
  581.                         UdX = -UdX2
  582.                         UdY = UdY2
  583.                         UdZ = -UdZ2
  584.                     END IF
  585.                 END IF
  586.  
  587.  
  588.  
  589.  
  590.                 '        UX& = Special(Ui).X * 16384# + Ulr
  591.                 '        UZ& = Special(Ui).Z * 16384# + Udu
  592.                 '        UY& = Special(Ui).Y * 16384#
  593.  
  594.  
  595.                 '        UdX = UdX2
  596.                 '        UdZ = UdY2
  597.                 '        UdY = -UdZ2
  598.  
  599.  
  600.                 IF UdY3 THEN
  601.                     IF UdY3 >= 0 THEN
  602.                         UX = UX + Ulr
  603.                         UZ = UZ + 16383 - Udu
  604.                         UY = UY + 16383
  605.                         UdX = UdX2
  606.                         UdY = UdZ2
  607.                         UdZ = -UdY2
  608.                     ELSE
  609.                         UX = UX + Ulr
  610.                         UZ = UZ + Udu
  611.                         UY = UY
  612.                         UdX = UdX2
  613.                         UdY = -UdZ2
  614.                         UdZ = UdY2
  615.                     END IF
  616.                 END IF
  617.  
  618.  
  619.  
  620.  
  621.                 IF UdY& >= 0 THEN USGNdY = 1 ELSE USGNdY = 0
  622.                 IF UdX& >= 0 THEN USGNdX = 1 ELSE USGNdX = 0
  623.                 IF UdZ& >= 0 THEN USGNdZ = 1 ELSE USGNdZ = 0
  624.                 UABSdX& = ABS(UdX&)
  625.                 UABSdY& = ABS(UdY&)
  626.                 UABSdZ& = ABS(UdZ&)
  627.                 UDis& = 0
  628.                 GOTO main_1
  629.  
  630.  
  631.  
  632.             END IF
  633.  
  634.  
  635.  
  636.             'renderer specific code follows
  637.            77
  638.  
  639.  
  640.  
  641.  
  642.             IF UBoxType& = 4 THEN
  643.                 URayDepth = URayDepth + 1
  644.  
  645.                 IF URayDepth > UMaxDepth THEN
  646.                     ScrBuf(PixOff) = 0
  647.                     GOTO 3
  648.                 END IF
  649.  
  650.  
  651.                 IF UCrossed = 2 THEN
  652.  
  653.                     UdY& = -UdY&
  654.                     IF UdY& >= 0 THEN USGNdY = 1 ELSE USGNdY = 0
  655.                     UDis& = 0
  656.                     GOTO main_1
  657.                 END IF
  658.  
  659.  
  660.                 IF UCrossed = 1 THEN
  661.  
  662.                     UdX& = -UdX&
  663.                     IF UdX& >= 0 THEN USGNdX = 1 ELSE USGNdX = 0
  664.                     UDis& = 0
  665.                     GOTO main_1
  666.                 END IF
  667.  
  668.                 IF UCrossed = 3 THEN
  669.  
  670.                     UdZ& = -UdZ&
  671.                     IF UdZ& >= 0 THEN USGNdZ = 1 ELSE USGNdZ = 0
  672.                     UDis& = 0
  673.                     GOTO main_1
  674.                 END IF
  675.  
  676.             END IF
  677.  
  678.  
  679.             DIM SHARED tx AS LONG, ty AS LONG
  680.  
  681.             DIM SHARED disx1 AS LONG
  682.             DIM SHARED disx2 AS LONG
  683.             DIM SHARED disy1 AS LONG
  684.             DIM SHARED disy2 AS LONG
  685.             DIM SHARED disz1 AS LONG
  686.             DIM SHARED disz2 AS LONG
  687.  
  688.  
  689.  
  690.  
  691.  
  692.  
  693.  
  694.  
  695.  
  696.             IF UCrossed = 1 THEN 'x
  697.                 IF USGNdX THEN
  698.                     'hit lhs
  699.                     disz2 = 16384 - (UZ& AND 16383)
  700.                     tx = disz2
  701.                     disy1 = UY& AND 16383
  702.                     ty = disy1
  703.                 ELSE
  704.                     'hit rhs
  705.                     disz1 = UZ& AND 16383
  706.                     tx = disz1
  707.                     disy1 = UY& AND 16383
  708.                     ty = disy1
  709.                 END IF
  710.             END IF
  711.  
  712.             IF UCrossed = 3 THEN 'z
  713.                 IF USGNdZ THEN
  714.                     'hit bottom
  715.                     disx1 = UX& AND 16383
  716.                     tx = disx1
  717.                     disy1 = UY& AND 16383
  718.                     ty = disy1
  719.                 ELSE
  720.                     'hit top
  721.                     disx2 = 16384 - (UX& AND 16383)
  722.                     tx = disx2
  723.                     disy1 = UY& AND 16383
  724.                     ty = disy1
  725.                 END IF
  726.             END IF
  727.  
  728.             IF UCrossed = 2 THEN
  729.  
  730.                 disx1 = UX& AND 16383
  731.                 disz1 = UZ& AND 16383
  732.                 tx = disx1
  733.                 ty = disz1
  734.  
  735.                 '        tx = 16384
  736.                 '       ty = 16384
  737.  
  738.                 '        IF USGNdY THEN
  739.                 '          tx = px - INT(px)
  740.                 '          ty = pz - INT(pz)
  741.                 '        ELSE
  742.                 '          tx = px - INT(px)
  743.                 '          ty = pz - INT(pz)
  744.                 '        END IF
  745.             END IF
  746.  
  747.  
  748.  
  749.  
  750.             m& = (UDis& \ 16384) + 1 '(for low res)
  751.             ''''m& = (UDis& \ 65536) + 1 '(for high res)
  752.             IF m& > 5 THEN m& = 5
  753.  
  754.  
  755.             '      c& = Tex(tx * TexX, ty * Texy, m&)
  756.             '      PRINT ty
  757.             '      SLEEP
  758.  
  759.  
  760.  
  761.             IF UBoxType& = 2 THEN c& = Tex((tx * UTexX&) \ 16384, (ty * UTexY&) \ 16384, m&)
  762.             IF UBoxType& = 1 THEN c& = Tex2((tx * UTexX&) \ 16384, (ty * UTexY&) \ 16384, m&)
  763.             IF UBoxType& = 3 THEN c& = Tex3((tx * UTexX&) \ 16384, (ty * UTexY&) \ 16384, m&)
  764.  
  765.             IF UBoxType& = 10 THEN c& = t_floor((tx * UTexX&) \ 16384, (ty * UTexY&) \ 16384, 1)
  766.             IF UBoxType& = 11 THEN c& = t_walla((tx * UTexX&) \ 16384, (ty * UTexY&) \ 16384, 1)
  767.             IF UBoxType& = 12 THEN c& = t_wallb((tx * UTexX&) \ 16384, (ty * UTexY&) \ 16384, 1)
  768.             IF UBoxType& = 13 THEN c& = t_roof((tx * UTexX&) \ 16384, (ty * UTexY&) \ 16384, 1)
  769.             IF UBoxType& = 14 THEN
  770.                 IF TIMER AND 1 THEN
  771.                     c& = t_buta((tx * UTexX&) \ 16384, (ty * UTexY&) \ 16384, 1)
  772.                 ELSE
  773.                     c& = t_butb((tx * UTexX&) \ 16384, (ty * UTexY&) \ 16384, 1)
  774.                 END IF
  775.  
  776.             END IF
  777.             IF UBoxType& = 15 THEN c& = t_s_box((tx * UTexX&) \ 16384, (ty * UTexY&) \ 16384, 1)
  778.  
  779.  
  780.             'lighting algorithm under development
  781.  
  782.             c& = c& AND &HFFFFFF
  783.             r& = (c& \ 65536) AND 255
  784.             g& = (c& \ 256) AND 255
  785.             b& = c& AND 255
  786.  
  787.             '     IF URayDepth <> 0 THEN b& = b& + URayDepth * 32: IF b& > 255 THEN b& = 255
  788.  
  789.             l& = 16383 - (UDis& \ 30)
  790.             '      IF l& < 0 THEN l& = 0
  791.  
  792.             '      '      l = 1 - (UDis& / 16384) / 10
  793.  
  794.             c& = ((r& * l&) \ 16384) * 65536 + ((g& * l&) \ 16384) * 256 + ((b& * l&) \ 16384) + &HFF000000
  795.             '      c& = _RGB32(r& * l& \ 16384, g& * l& \ 16384, b& * l& \ 16384)
  796.  
  797.  
  798.             770
  799.             ScrBuf(PixOff) = c&
  800.  
  801.             3
  802.             PixOff = PixOff + 1
  803.         NEXT
  804.     NEXT
  805.  
  806.     '$CHECKING:ON
  807.  
  808.  
  809.  
  810.     PUT (0, 0), ScrBuf()
  811.     '  PSET (_MOUSEX, _MOUSEY), _RGB(255, 255, 255)
  812.     'LOCATE 1, 1
  813.     'PRINT CINT(frames / (TIMER(0.001) - starttime))
  814.  
  815.     PSET (ScreenX \ 2, ScreenY \ 2), _RGB(255, 255, 255)
  816.  
  817.     FOR x& = 1 TO 10
  818.         i& = INP(&H60)
  819.         IF (i& AND 128) THEN KeyDown(i& XOR 128) = 0
  820.         IF (i& AND 128) = 0 THEN KeyDown(i&) = -1
  821.     NEXT
  822.     'PRINT i&
  823.  
  824.     'PRINT vax
  825.     _DISPLAY
  826.     CLS
  827.  
  828.  
  829.     v = TIMER(0.001)
  830.     ElapsedTime = v - LastTime
  831.     LastTime = v
  832.  
  833.         mx = _MOUSEX
  834.         mouseMovementX = mx - oldMX
  835.         oldMX = mx
  836.         my = _MOUSEY
  837.         mouseMovementY = my - oldMY
  838.         oldMY = my
  839.  
  840.         vax = vax + (ABS(mouseMovementX / 4) ^ 1.2) * SGN(mouseMovementX)
  841.         vay = vay - (ABS(mouseMovementY / 4) ^ 1.2) * SGN(mouseMovementY)
  842.         IF vay > 90 THEN vay = 90
  843.         IF vay < -90 THEN vay = -90
  844.  
  845.         FOR p = 1 TO 2
  846.             IF _MOUSEBUTTON(p) THEN
  847.  
  848.                 UX = Plr.X * 16384#
  849.                 UY = (Plr.Y + Plr.Height) * 16384#
  850.                 UZ = Plr.Z * 16384#
  851.                 x& = 0
  852.                 y& = 0
  853.                 z& = 1 * 16384#
  854.                 Uvaxs& = SIN(vax * deg2rad) * 16384&: Uvaxc& = COS(vax * deg2rad) * 16384&
  855.                 Uvays& = SIN(vay * deg2rad) * 16384&: Uvayc& = COS(vay * deg2rad) * 16384&
  856.                 UdY& = (Uvays& * z&) \ 16384 + (Uvayc& * y&) \ 16384
  857.                 z& = (Uvayc& * z&) \ 16384 - (Uvays& * y&) \ 16384
  858.                 UdX& = (Uvaxs& * z&) \ 16384 + (Uvaxc& * x&) \ 16384
  859.                 UdZ& = (Uvaxc& * z&) \ 16384 - (Uvaxs& * x&) \ 16384
  860.                 RayCheck
  861.  
  862.                 IF UBoxType& <> 2 THEN
  863.  
  864.                     'remove previous portal?
  865.                     IF portal(p) THEN
  866.  
  867.                         Ui = portal(p)
  868.                         UX2 = Special(Ui).X \ 16384: UY2 = Special(Ui).Y \ 16384: UZ2 = Special(Ui).Z \ 16384
  869.  
  870.                         Map(UX2, UY2, UZ2) = Map(UX2, UY2, UZ2) AND 255
  871.  
  872.  
  873.                     END IF
  874.  
  875.                     Ui = p
  876.  
  877.                     Map(UX \ 16384, UY \ 16384, UZ \ 16384) = UBoxType + Ui * 256
  878.  
  879.                     Special(Ui).Effect = Ui
  880.  
  881.                     'store box position
  882.                     Special(Ui).X = (UX \ 16384) * 16384
  883.                     Special(Ui).Y = (UY \ 16384) * 16384
  884.                     Special(Ui).Z = (UZ \ 16384) * 16384
  885.                     'store side vector containing effect
  886.                     dx = 0: dy = 0: dz = 0
  887.                     IF UCrossed = 1 THEN IF USGNdX THEN dx = -1 ELSE dx = 1
  888.                     IF UCrossed = 2 THEN IF USGNdY THEN dy = -1 ELSE dy = 1
  889.                     IF UCrossed = 3 THEN IF USGNdZ THEN dz = -1 ELSE dz = 1
  890.                     Special(Ui).dX = dx: Special(Ui).dY = dy: Special(Ui).dZ = dz
  891.  
  892.                     portal(p) = Ui
  893.  
  894.                 END IF
  895.  
  896.  
  897.  
  898.  
  899.  
  900.  
  901.             END IF
  902.         NEXT
  903.  
  904.  
  905.  
  906.     LOOP
  907.  
  908.  
  909.  
  910.  
  911.     '  vay = vay - (_MOUSEY - ScreenY \ 2) \ 20
  912.     '  IF vay > 90 THEN vay = 90
  913.     '  IF vay < -90 THEN vay = -90
  914.     '  vax = vax + (_MOUSEX - ScreenX \ 2) \ 10
  915.  
  916.     'x = _MOUSEX - ScreenX \ 2
  917.     'vax = x * 2
  918.  
  919.     'y = (_MOUSEY - ScreenY \ 2) / (ScreenY / 2)
  920.     'y = y * 90
  921.     'vay = -y
  922.  
  923.  
  924.     k$ = INKEY$
  925.  
  926.  
  927.     'DO: LOOP UNTIL INKEY$ = ""
  928.  
  929.  
  930.  
  931.     et = TIMER(0.001) - LastTime
  932.     IF et > 1 THEN et = 1
  933.     LastTime = TIMER(0.001)
  934.  
  935.  
  936.     '  CLS
  937.     IF k$ = "6" THEN vax = vax + 20
  938.     IF k$ = "4" THEN vax = vax - 20
  939.  
  940.  
  941.     '  DEF SEG = 0
  942.     '  sh& = PEEK(&H417)
  943.  
  944.     x = Plr.X: y = Plr.Y: z = Plr.Z
  945.     dx = 0: dy = -1: dz = 0
  946.     UdX = dx * 16384#: UdY = dy * 16384#: UdZ = dz * 16384#: UX = x * 16384#: UY = y * 16384#: UZ = z * 16384#
  947.     RayCheck
  948.     height = UDis / 16384#
  949.  
  950.  
  951.  
  952.  
  953.     move = 0
  954.     x = 0: y = 0: z = 0
  955.     IF KeyDown(17) OR KeyDown(72) THEN move = 1: z = 1
  956.     IF KeyDown(31) OR KeyDown(80) THEN move = 1: z = -1
  957.     IF KeyDown(30) OR KeyDown(75) THEN move = 1: x = -1
  958.     IF KeyDown(32) OR KeyDown(77) THEN move = 1: x = 1
  959.  
  960.  
  961.     IF move THEN
  962.  
  963.         '    x = 0: y = 0: z = 1 'forward vector
  964.         '    IF k$ = "s" THEN z = -1
  965.  
  966.         a1 = vax * deg2rad: a2 = vay * deg2rad
  967.         x1 = SIN(a1) * z + COS(a1) * x
  968.         z1 = COS(a1) * z - SIN(a1) * x
  969.         x = x1: z = z1
  970.  
  971.         x = x * ElapsedTime * 15 'est 0.1 * ???
  972.         z = z * ElapsedTime * 15
  973.  
  974.  
  975.  
  976.         cs = SQR(Plr.dX * Plr.dX + Plr.dZ * Plr.dZ)
  977.         '1. add new vector
  978.         Plr.dX = Plr.dX + x
  979.         Plr.dZ = Plr.dZ + z
  980.         ns = SQR(Plr.dX * Plr.dX + Plr.dZ * Plr.dZ)
  981.  
  982.         '2. limit as necessary
  983.         IF ns > 3 AND ns > cs THEN
  984.             Plr.dX = (Plr.dX / ns) * 3
  985.             Plr.dZ = (Plr.dZ / ns) * 3
  986.         END IF
  987.  
  988.  
  989.         '    odx = Plr.dX
  990.         '    odz = Plr.dZ
  991.         '    cs = SQR(Plr.dX * Plr.dX + Plr.dZ * Plr.dZ)
  992.         '    Plr.dX = Plr.dX + x
  993.         '    Plr.dZ = Plr.dZ + z
  994.         ''    ns = SQR(Plr.dX * Plr.dX + Plr.dZ * Plr.dZ)
  995.         '   IF ns > cs AND ns > 3 THEN 'still doesn;t work (try qtr turn)
  996.         '     Plr.dX = odx
  997.         '   Plr.dZ = odz
  998.         ' END IF
  999.  
  1000.  
  1001.     ELSE
  1002.  
  1003.         'trying to stop friction
  1004.         IF height < 0.05 THEN
  1005.             Plr.dX = Plr.dX / (1 + ElapsedTime * 10)
  1006.             Plr.dZ = Plr.dZ / (1 + ElapsedTime * 10)
  1007.         END IF
  1008.  
  1009.     END IF
  1010.  
  1011.  
  1012.  
  1013.  
  1014.  
  1015.  
  1016.  
  1017.     'move player
  1018.  
  1019.     'add gravity to player vector
  1020.  
  1021.  
  1022.  
  1023.  
  1024.  
  1025.  
  1026.  
  1027.  
  1028.  
  1029.  
  1030.  
  1031.     IF KeyDown(57) THEN
  1032.         IF height < 0.05 THEN
  1033.             Plr.dY = 1.75
  1034.         END IF
  1035.     END IF
  1036.  
  1037.     '  IF height > 0.01 THEN
  1038.     y = Plr.dY
  1039.     ApplyGravity y
  1040.     Plr.dY = y
  1041.     '  END IF
  1042.  
  1043.  
  1044.     'portal transition checking
  1045.  
  1046.     ElapsedTimeold = ElapsedTime
  1047.     ElapsedTime = ElapsedTime / 100
  1048.     FOR ggg = 1 TO 100
  1049.  
  1050.  
  1051.         x = Plr.X: y = Plr.Y: z = Plr.Z
  1052.         l = SQR(Plr.dX * Plr.dX + Plr.dY * Plr.dY + Plr.dZ * Plr.dZ)
  1053.         IF l THEN
  1054.             dx = Plr.dX / l: dy = Plr.dY / l: dz = Plr.dZ / l
  1055.             UdX = dx * 16384#: UdY = dy * 16384#: UdZ = dz * 16384#
  1056.             UX = x * 16384#: UY = y * 16384#: UZ = z * 16384#
  1057.             RayCheck
  1058.             IF UBoxType > 255 THEN 'portal
  1059.                 length = UDis / 16384#
  1060.                 l = l * ElapsedTime
  1061.                 IF l > length - 0.01 THEN
  1062.                     'replace plane isolated vector with real movement vector
  1063.                     l = SQR(Plr.dX * Plr.dX + Plr.dY * Plr.dY + Plr.dZ * Plr.dZ)
  1064.                     dx = Plr.dX / l: dy = Plr.dY / l: dz = Plr.dZ / l
  1065.                     UdX = dx * 16384#: UdY = dy * 16384#: UdZ = dz * 16384#
  1066.                     IF RayFunnel THEN
  1067.                         x = UX / 16384#: y = UY / 16384#: z = UZ / 16384#
  1068.                         dx = UdX / 16384#: dy = UdY / 16384#: dz = UdZ / 16384#
  1069.                         Plr.X = x: Plr.Y = y: Plr.Z = z
  1070.                         Plr.dX = dx * l: Plr.dY = dy * l: Plr.dZ = dz * l
  1071.                     END IF
  1072.                     GOTO skip_movement
  1073.                 END IF
  1074.             END IF
  1075.         END IF
  1076.  
  1077.         IF Plr.dX THEN
  1078.             x = Plr.X: y = Plr.Y: z = Plr.Z
  1079.             dx = SGN(Plr.dX): dy = 0: dz = 0
  1080.             UdX = dx * 16384#: UdY = dy * 16384#: UdZ = dz * 16384#
  1081.             UX = x * 16384#: UY = y * 16384#: UZ = z * 16384#
  1082.             RayCheck
  1083.  
  1084.             length = UDis / 16384#
  1085.             x = ABS(Plr.dX * ElapsedTime)
  1086.             IF x > length - 0.01 THEN
  1087.  
  1088.                 IF UBoxType > 255 THEN 'portal
  1089.                     'replace plane isolated vector with real movement vector
  1090.                     l = SQR(Plr.dX * Plr.dX + Plr.dY * Plr.dY + Plr.dZ * Plr.dZ)
  1091.                     dx = Plr.dX / l: dy = Plr.dY / l: dz = Plr.dZ / l
  1092.                     UdX = dx * 16384#: UdY = dy * 16384#: UdZ = dz * 16384#
  1093.                     IF RayFunnel THEN
  1094.                         x = UX / 16384#: y = UY / 16384#: z = UZ / 16384#
  1095.                         dx = UdX / 16384#: dy = UdY / 16384#: dz = UdZ / 16384#
  1096.                         Plr.X = x: Plr.Y = y: Plr.Z = z
  1097.                         Plr.dX = dx * l: Plr.dY = dy * l: Plr.dZ = dz * l
  1098.                     END IF
  1099.                     GOTO skip_movement
  1100.                 END IF
  1101.  
  1102.                 x = length - 0.01
  1103.                 IF x < 0 THEN x = 0
  1104.             END IF
  1105.             Plr.X = Plr.X + x * SGN(Plr.dX)
  1106.         END IF
  1107.  
  1108.         IF Plr.dZ THEN
  1109.             x = Plr.X: y = Plr.Y: z = Plr.Z
  1110.             dx = 0: dy = 0: dz = SGN(Plr.dZ)
  1111.             UdX = dx * 16384#: UdY = dy * 16384#: UdZ = dz * 16384#
  1112.             UX = x * 16384#: UY = y * 16384#: UZ = z * 16384#
  1113.             RayCheck
  1114.             length = UDis / 16384#
  1115.             z = ABS(Plr.dZ * ElapsedTime)
  1116.             IF z > length - 0.01 THEN
  1117.  
  1118.                 IF UBoxType > 255 THEN 'portal
  1119.                     'replace plane isolated vector with real movement vector
  1120.                     l = SQR(Plr.dX * Plr.dX + Plr.dY * Plr.dY + Plr.dZ * Plr.dZ)
  1121.                     dx = Plr.dX / l: dy = Plr.dY / l: dz = Plr.dZ / l
  1122.                     UdX = dx * 16384#: UdY = dy * 16384#: UdZ = dz * 16384#
  1123.                     IF RayFunnel THEN
  1124.                         x = UX / 16384#: y = UY / 16384#: z = UZ / 16384#
  1125.                         dx = UdX / 16384#: dy = UdY / 16384#: dz = UdZ / 16384#
  1126.                         Plr.X = x: Plr.Y = y: Plr.Z = z
  1127.                         Plr.dX = dx * l: Plr.dY = dy * l: Plr.dZ = dz * l
  1128.                     END IF
  1129.                     GOTO skip_movement
  1130.                 END IF
  1131.  
  1132.                 z = length - 0.01
  1133.                 IF z < 0 THEN z = 0
  1134.             END IF
  1135.             Plr.Z = Plr.Z + z * SGN(Plr.dZ)
  1136.         END IF
  1137.  
  1138.  
  1139.         IF Plr.dY THEN
  1140.             x = Plr.X: y = Plr.Y: z = Plr.Z
  1141.             dx = 0: dy = SGN(Plr.dY): dz = 0
  1142.             UdX = dx * 16384#: UdY = dy * 16384#: UdZ = dz * 16384#
  1143.             UX = x * 16384#: UY = y * 16384#: UZ = z * 16384#
  1144.             RayCheck
  1145.             length = UDis / 16384#
  1146.             y = ABS(Plr.dY * ElapsedTime)
  1147.  
  1148.             IF y > length - 0.01 THEN
  1149.  
  1150.                 IF UBoxType > 255 THEN 'portal
  1151.                     'replace plane isolated vector with real movement vector
  1152.                     l = SQR(Plr.dX * Plr.dX + Plr.dY * Plr.dY + Plr.dZ * Plr.dZ)
  1153.                     dx = Plr.dX / l: dy = Plr.dY / l: dz = Plr.dZ / l
  1154.                     UdX = dx * 16384#: UdY = dy * 16384#: UdZ = dz * 16384#
  1155.                     IF RayFunnel THEN
  1156.                         x = UX / 16384#: y = UY / 16384#: z = UZ / 16384#
  1157.                         dx = UdX / 16384#: dy = UdY / 16384#: dz = UdZ / 16384#
  1158.                         Plr.X = x: Plr.Y = y: Plr.Z = z
  1159.                         Plr.dX = dx * l: Plr.dY = dy * l: Plr.dZ = dz * l
  1160.                     END IF
  1161.                     GOTO skip_movement
  1162.                 END IF
  1163.  
  1164.                 y = length - 0.01
  1165.                 IF y < 0 THEN y = 0
  1166.             END IF
  1167.             IF y = 0 THEN Plr.dY = 0
  1168.             Plr.Y = Plr.Y + y * SGN(Plr.dY)
  1169.         END IF
  1170.  
  1171.         skip_movement:
  1172.  
  1173.     NEXT
  1174.     ElapsedTime = ElapsedTime * 100
  1175.  
  1176.     11112
  1177.  
  1178.     GOTO shit
  1179.  
  1180.  
  1181.  
  1182.  
  1183.     l = SQR(Plr.dX * Plr.dX + Plr.dY * Plr.dY + Plr.dZ * Plr.dZ)
  1184.     IF l > 0 THEN 'only if moving
  1185.         dx = Plr.dX / l: dy = Plr.dY / l: dz = Plr.dZ / l
  1186.         x = Plr.X: y = Plr.Y: z = Plr.Z
  1187.         UdX = dx * 16384#: UdY = dy * 16384#: UdZ = dz * 16384#
  1188.         UX = x * 16384#: UY = y * 16384#: UZ = z * 16384#
  1189.         RayCheck
  1190.         l2 = UDis / 16384#
  1191.  
  1192.         l = l * ElapsedTime
  1193.  
  1194.         IF l >= l2 + 0.1 THEN
  1195.  
  1196.             l2 = l2 - 0.1
  1197.             IF l2 < 0.1 THEN GOTO 8
  1198.             '      x = x * l2
  1199.             '      y = y * l2
  1200.             '      z = z * l2
  1201.  
  1202.             '     Plr.X = Plr.X + x
  1203.             '     Plr.Y = Plr.Y + y
  1204.             '     Plr.Z = Plr.Z + z
  1205.  
  1206.             8
  1207.         ELSE
  1208.  
  1209.             Plr.X = Plr.X + Plr.dX * ElapsedTime
  1210.             Plr.Y = Plr.Y + Plr.dY * ElapsedTime
  1211.             Plr.Z = Plr.Z + Plr.dZ * ElapsedTime
  1212.  
  1213.         END IF
  1214.  
  1215.     END IF
  1216.  
  1217.  
  1218.  
  1219.     'IF k$ = " " THEN
  1220.     '   PlrY = PlrY + 1.3
  1221.     'END IF
  1222.  
  1223.     '  GOTO 11
  1224.     'freefall
  1225.     '  x = 0: y = -1: z = 0 'fall vector
  1226.     '  'cast a test ray
  1227.     '  Upx1& = PlrX * 16384#
  1228.     '  Upy1& = PlrY * 16384#
  1229.     '  Upz1& = PlrZ * 16384#
  1230.     '  UdX& = x * 16384#
  1231.     '  UdY& = y * 16384#
  1232.     '  UdZ& = z * 16384#
  1233.     '  testray& = 1
  1234.     '  GOSUB testray_entry
  1235.     '  s = 3
  1236.     '  mydis& = s * et * 16384#
  1237.     '  IF UDis& > mydis& THEN
  1238.     '    PlrX = PlrX + x * s * et
  1239.     '    PlrY = PlrY + y * s * et
  1240.     '    PlrZ = PlrZ + z * s * et
  1241.     '  END IF
  1242.  
  1243.     ' 11
  1244.  
  1245.  
  1246.  
  1247.     shit:
  1248.  
  1249.     '    PosZ = PosZ - 0.1
  1250.  
  1251.  
  1252.     frames = frames + 1
  1253.  
  1254.     IF k$ = "f" THEN
  1255.         starttime = TIMER(0.001)
  1256.         frames = 0
  1257.     END IF
  1258.  
  1259.  
  1260.  
  1261.  
  1262.  
  1263. FUNCTION rnd2& (limit&)
  1264.     rnd2& = INT(RND * (limit& * 2 + 1)) - limit&
  1265.  
  1266. SUB ApplyGravity (y)
  1267.     'quote:
  1268.     'http://en.wikipedia.org/wiki/Gravitation
  1269.     'The strength of the gravitational field is numerically equal to the acceleration of objects under its influence, and its value at the Earth's surface, denoted g, is approximately expressed below as the standard average.
  1270.     'g = 9.81 m/s2 = 32.2 ft/s2
  1271.     'This means that, ignoring air resistance, an object falling freely near the Earth's surface increases its velocity with 9.81 m/s (32.2 ft/s or 22 mph) for each second of its descent.
  1272.  
  1273.     y = y - (9.81 / 2) * ElapsedTime
  1274.  
  1275.     'With air resistance acting upon an object that has been dropped,
  1276.     'the object will eventually reach a terminal velocity,
  1277.     'around 56 m/s (200 km/h or 120 mph) for a human body.
  1278.     IF y < -(56 / 2) THEN y = -(56 / 2)
  1279.  
  1280.  
  1281. SUB MoveObject (o AS ObjectType)
  1282.     o.X = o.X + o.dX
  1283.     o.Y = o.Y + o.dY
  1284.     o.Z = o.Z + o.dZ
  1285.  
  1286. SUB RayCheck
  1287.  
  1288.     IF UdX& >= 0 THEN USGNdX = 1 ELSE USGNdX = 0
  1289.     IF UdY& >= 0 THEN USGNdY = 1 ELSE USGNdY = 0
  1290.     IF UdZ& >= 0 THEN USGNdZ = 1 ELSE USGNdZ = 0
  1291.  
  1292.     UABSdX& = ABS(UdX&)
  1293.     UABSdY& = ABS(UdY&)
  1294.     UABSdZ& = ABS(UdZ&)
  1295.  
  1296.     UDis& = 0
  1297.  
  1298.     URayDepth = 0
  1299.  
  1300.     'main_1: 'remove this line when possible
  1301.  
  1302.     DO
  1303.  
  1304.         'calculate x,y,z distance to next 'cube'
  1305.         IF USGNdX THEN
  1306.             UDistx& = 16384 - (UX& AND 16383)
  1307.             IF UDistx& = 0 THEN UDistx& = 16384
  1308.         ELSE
  1309.             UDistx& = (UX& AND 16383) + 1
  1310.         END IF
  1311.         IF USGNdY THEN
  1312.             UDisty& = 16384 - (UY& AND 16383)
  1313.             IF UDisty& = 0 THEN UDisty& = 16384
  1314.         ELSE
  1315.             UDisty& = (UY& AND 16383) + 1
  1316.         END IF
  1317.         IF USGNdZ THEN
  1318.             UDistz& = 16384 - (UZ& AND 16383)
  1319.             IF UDistz& = 0 THEN UDistz& = 16384
  1320.         ELSE
  1321.             UDistz& = (UZ& AND 16383) + 1
  1322.         END IF
  1323.  
  1324.         IF UABSdX& <> 0 THEN USpeedX& = (UDistx& * 16384) \ UABSdX& ELSE USpeedX& = 2147483647
  1325.         IF UABSdY& <> 0 THEN USpeedY& = (UDisty& * 16384) \ UABSdY& ELSE USpeedY& = 2147483647
  1326.         IF UABSdZ& <> 0 THEN USpeedZ& = (UDistz& * 16384) \ UABSdZ& ELSE USpeedZ& = 2147483647
  1327.  
  1328.         'advance minimal speed + microstep(to cater for floating point errors only)
  1329.         UCrossed& = 1
  1330.         UMinSpeed& = USpeedX&
  1331.         IF USpeedY& < UMinSpeed& THEN UMinSpeed& = USpeedY&: UCrossed& = 2
  1332.         IF USpeedZ& < UMinSpeed& THEN UMinSpeed& = USpeedZ&: UCrossed& = 3
  1333.         UMinSpeed& = UMinSpeed& + 1
  1334.         UDis& = UDis& + UMinSpeed&
  1335.  
  1336.         UX& = UX& + (UdX& * UMinSpeed&) \ 16384
  1337.         UY& = UY& + (UdY& * UMinSpeed&) \ 16384
  1338.         UZ& = UZ& + (UdZ& * UMinSpeed&) \ 16384
  1339.  
  1340.         UBoxType& = Map(UX& \ 16384, UY& \ 16384, UZ& \ 16384)
  1341.  
  1342.     LOOP UNTIL UBoxType&
  1343.  
  1344.  
  1345.  
  1346. FUNCTION scankey% (scancode%)
  1347.     i% = INP(&H60)
  1348.     IF (i% AND 128) THEN keyflags%(i% XOR 128) = 0
  1349.     IF (i% AND 128) = 0 THEN keyflags%(i%) = -1
  1350.     scankey% = keyflags%(scancode%)
  1351.  
  1352.  
  1353. FUNCTION RayFunnel&
  1354.  
  1355.     Ui = UBoxType \ 256
  1356.  
  1357.     vax2 = vax
  1358.     vay2 = vay
  1359.  
  1360.     IF UCrossed = 1 THEN
  1361.         IF USGNdX THEN
  1362.             Ulr = 16383 - (UZ& AND 16383): Udu = UY& AND 16383
  1363.             UdX2 = -UdZ: UdY2 = UdY: UdZ2 = UdX
  1364.             vax2 = vax2 - 90
  1365.         ELSE
  1366.             Ulr = UZ& AND 16383: Udu = UY& AND 16383
  1367.             UdX2 = UdZ: UdY2 = UdY: UdZ2 = -UdX
  1368.             vax2 = vax2 + 90
  1369.         END IF
  1370.     END IF
  1371.     IF UCrossed = 2 THEN
  1372.         IF USGNdY THEN
  1373.             Ulr = UX& AND 16383: Udu = 16383 - (UZ& AND 16383)
  1374.             UdX2 = UdX: UdY2 = -UdZ: UdZ2 = UdY
  1375.         ELSE
  1376.             Ulr = UX& AND 16383: Udu = UZ& AND 16383
  1377.             UdX2 = UdX: UdY2 = UdZ: UdZ2 = -UdY
  1378.         END IF
  1379.     END IF
  1380.     IF UCrossed = 3 THEN
  1381.         IF USGNdZ THEN
  1382.             Ulr = UX& AND 16383: Udu = UY& AND 16383
  1383.             UdX2 = UdX: UdY2 = UdY: UdZ2 = UdZ
  1384.             vax2 = vax2
  1385.         ELSE
  1386.             Ulr = 16383 - (UX& AND 16383): Udu = UY& AND 16383
  1387.             UdX2 = -UdX: UdY2 = UdY: UdZ2 = -UdZ
  1388.             vax2 = vax2 - 180
  1389.         END IF
  1390.     END IF
  1391.  
  1392.     IF Ui = 1 THEN
  1393.         IF portal(2) = 0 THEN
  1394.             EXIT FUNCTION
  1395.         END IF
  1396.     END IF
  1397.  
  1398.     IF Ui = 2 THEN
  1399.         IF portal(1) = 0 THEN
  1400.             EXIT FUNCTION
  1401.         END IF
  1402.     END IF
  1403.  
  1404.     IF Ui = 1 THEN Ui = 2 ELSE Ui = 1
  1405.  
  1406.     UX = Special(Ui).X
  1407.     UZ = Special(Ui).Z
  1408.     UY = Special(Ui).Y
  1409.     UdX3 = Special(Ui).dX
  1410.     UdY3 = Special(Ui).dY
  1411.     UdZ3 = Special(Ui).dZ
  1412.  
  1413.     IF UdX3 THEN
  1414.         IF UdX3 >= 0 THEN
  1415.             UX = UX + 16384
  1416.             UZ = UZ + 16383 - Ulr
  1417.             UY = UY + Udu
  1418.             UdX = UdZ2
  1419.             UdY = UdY2
  1420.             UdZ = -UdX2
  1421.             vax = vax2 + 90
  1422.             IF UCrossed = 2 THEN vax = 90
  1423.         ELSE
  1424.             UX = UX - 1
  1425.             UZ = UZ + Ulr
  1426.             UY = UY + Udu
  1427.             UdX = -UdZ2
  1428.             UdY = UdY2
  1429.             UdZ = UdX2
  1430.             vax = vax2 - 90
  1431.             IF UCrossed = 2 THEN vax = -90
  1432.         END IF
  1433.     END IF
  1434.     IF UdZ3 THEN
  1435.         IF UdZ3 >= 0 THEN
  1436.             UX = UX + Ulr
  1437.             UZ = UZ + 16384
  1438.             UY = UY + Udu
  1439.             UdX = UdX2
  1440.             UdY = UdY2
  1441.             UdZ = UdZ2
  1442.             vax = vax2
  1443.             IF UCrossed = 2 THEN vax = 0
  1444.         ELSE
  1445.             UX = UX + 16383 - Ulr
  1446.             UZ = UZ - 1
  1447.             UY = UY + Udu
  1448.             UdX = -UdX2
  1449.             UdY = UdY2
  1450.             UdZ = -UdZ2
  1451.             vax = vax2 + 180
  1452.             IF UCrossed = 2 THEN vax = 180
  1453.         END IF
  1454.     END IF
  1455.     IF UdY3 THEN
  1456.         IF UdY3 >= 0 THEN
  1457.             UX = UX + Ulr
  1458.             UZ = UZ + 16383 - Udu
  1459.             UY = UY + 16384
  1460.             UdX = UdX2
  1461.             UdY = UdZ2
  1462.             UdZ = -UdY2
  1463.         ELSE
  1464.             UX = UX + Ulr
  1465.             UZ = UZ + Udu
  1466.             UY = UY - 1
  1467.             UdX = UdX2
  1468.             UdY = -UdZ2
  1469.             UdZ = UdY2
  1470.         END IF
  1471.     END IF
  1472.  
  1473.     IF UdY& >= 0 THEN USGNdY = 1 ELSE USGNdY = 0
  1474.     IF UdX& >= 0 THEN USGNdX = 1 ELSE USGNdX = 0
  1475.     IF UdZ& >= 0 THEN USGNdZ = 1 ELSE USGNdZ = 0
  1476.     UABSdX& = ABS(UdX&)
  1477.     UABSdY& = ABS(UdY&)
  1478.     UABSdZ& = ABS(UdZ&)
  1479.  
  1480.     RayFunnel = 1
« Last Edit: September 06, 2018, 10:14:32 pm by FellippeHeitor »