Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - FutureCow

#31
I'll put some images in to show what I mean.

Assume this is the initial landscape (it's not, I stole my image from another thread :D ) - also assume they are just textures and not flat colours. The landscape is a solid mesh where each vertex (tile corner) is (currently) an offset into a texture image that has images of snow, grass, mud etc textures.


Then you change only some of the tiles textures (again, assume the tile has a texture and not a flat colour). Note that not all the ones that were light blue have changed to purple, only one. Also one that was red is now purple.


Does that make it clearer?
#32
Thanks for the replies.
Metalthink - I can't split it up into sections easily. I have a camera that can rotate/zoom in any direction so depending on how you rotate and zoom the camera, you could have just 1 of the smaller meshes on the screen, or some of them, or all of them. The landscape is mountains, where parts of it can hide other parts of the landscape, so working out which meshes are on the screen would be a nightmare.

Matchy, I think I understand what you're saying but unfortunately that's a bit different to what I'm trying to do. To use the technique I think you're suggesting I need to be able to update the texture offset of each vertext. I can't find any command that allows me to do that which is what the problem is.

Just to clarify : My idea is that at the start all 128x128 tiles on my landscape are, for example, grass. A short while later, I might have to set, for example, 1352 of those squares to mud, 15 to snow, 823 to sand. Then a short while later, some of the snow might become ice, other snow ones may become grass again, some that were mud are now grass again, some previously untouched grass ones have become swampy etc. Being able to change the texture of each individual 3D tile is what I need to do.
#33
I have a 3D terrain object that is currently made up of lots of joined together squares (ie. it's drawn as one 3D object by my code). Currently I set my texture then draw the land object once per game loop.
Originally all the squares have the same texture, but over time I want to change some of them (eg. make some squares muddy).
Any idea what the best way to accomplish changing part of the texture of a 3D object is?

The only way I've come up with that would work : My terrain is currently 128x128 squares (ie. 32768 triangles) and I'm using x_collisionray to determine which grid location is under the cursor. I could draw each grid square as a separate 3D object and texture them separately but that's a lot of 3D objects draw every frame, and 32768 x_collisionray calls per frame (or even once a second) I'm guessing would make the program really slow.

A bit of googling initially led me to think that a vertex shader is what I'm after but now I'm not so sure - besides which I've got no idea how to write/implement one (assuming that IS what I'm looking for!)

If anyone has any great ideas I'd love to hear them!!!
#34
It would be great to have good database integration as part of the language if you have the time to improve it!
#35
Sorry I'm in a rush so don't have time to write much about this now, but if may be more efficient to use bitwise operations. Eg. A standard character is made up of 8 bits = 2 x 4 lines. Get the first line by bitwise anding the number with 11110000 and the lower by anding with 00001111. Therefore 2 lines per ascii character, that's 2 ascii characters to store each block. 7 blocks worth of shapes can be stored in 14 alphanumeric characters.
Depending on how much programming experience you've had it might be a bit hard to get your head around / bug fix bitwise operations though. Also, although it's very efficient storage, it's often much wiser to compromise efficiency. Nowadays computers have cpu cycles and memory to burn. I'm not saying you should intentionally waste resources, but your "time" resource to write and bug fix "efficient" code to save a couple of CPU cycles and a few KB of RAM may be effort better spent elsewhere.
Bitwise calculations on each line of blocks will allow you to quickly determine which lines are full and which have holes in them, whether a block can fit in a hole etc.
I wouldn't necessarily recommend you head this way, it's just an idea.

Another thought is to store your data as a 1D array. The first 4 bits of data are the first line, the next 4 the second line etc. It only takes a for loop or addition statement to find the right bit of data.

In regards to kanonet's post, my personal preference is to err on the side of caution and explicitly set arrays and variables to known values (in that case, 0). That way you future-proof your code in case, for example, the language changes and all variables get whatever random value is in that section of memory at the time of creation until it's set otherwise. It also guarantees you know exactly what everything's set to at that point in the code in case you accidently reset the variable to another value somewhere else.
#36
Off Topic / Re: Raspberry Pi
2012-Jun-06
Great stuff Minion (and Gernot!)
#37
Okay, I think I've figured it out!!!  I have no idea what the maths are doing, but I had a crazy idea (based on a number minus a negative does an addition instead of a subtraction) and swapped some of the operations around. After a few attempts to work out which operations to swap, now pitch, roll and yaw seem to work as they should!  :enc:

For yaw, swap the two sides of the minus operation as below
Code (glbasic) Select

//        qLook.x = cam.lx - cam.x
//        qLook.y = cam.ly - cam.y
//        qLook.z = cam.lz - cam.z

// Fixes yaw inversion problem
        qLook.x = cam.x - cam.lx
        qLook.y = cam.y - cam.ly
        qLook.z = cam.z - cam.lz


For roll swap as below
Code (glbasic) Select
//        qUp.x = cam.ux - cam.x
//        qUp.y = cam.uy - cam.y
//        qUp.z = cam.uz - cam.z

// Fixes roll inversion problem
        qUp.x = cam.x - cam.ux
        qUp.y = cam.y - cam.uy
        qUp.z = cam.z - cam.uz


And for pitch you have to swap two sets of operations
Code (glbasic) Select

        qUp.w = 0
//        qUp.x = cam.ux - cam.x
//        qUp.y = cam.uy - cam.y
//        qUp.z = cam.uz - cam.z

// Fixes pitch inversion problem
        qUp.x = cam.x - cam.ux
        qUp.y = cam.y - cam.uy
        qUp.z = cam.z - cam.uz

        LOCAL qLook AS Tquaternion
        qLook.w = 0
//        qLook.x = cam.lx - cam.x
//        qLook.y = cam.ly - cam.y
//        qLook.z = cam.lz - cam.z

// Fixes pitch inversion problem
        qLook.x = cam.x - cam.lx
        qLook.y = cam.y - cam.ly
        qLook.z = cam.z - cam.lz


I've got to test the other functions are all working as they should (at some point that's not this late at night), and that it works when you start at some point other than (0,0,0) but it's fixed based on the starting position in the demo code!

If anyone would like me to fix their code by trying vague theories without understanding what their code's doing, let me know.  =D
#38
That's how I've done it in the past and it worked fine for me.
#39
I had posted in that thread, but seeing the post is stickied and old, I thought people would overlook the post so moved it here.

I'm not sure what's going on but I seem to have big issues with this code and GLBasic 10.283. Hopefully someone will have some ideas! (I don't understand the maths too well so I don't know where to start sorry!!!!)

If I use camera_roll,pitch or yaw, every alternate call seems to give me a result 180 degrees out (based on how it shows on the screen) from where it should be. For example, assuming each call to "camera_roll" rotates 1 degree, my first run through the code would be 0 degrees roll, rollowed by 181 degrees, followed by 2 degrees, followed by 183 degrees, followed by 4 degrees etc.

My only change to the original code to show the problem easily is to modify the showscreen section of the main loop to say :
Code (glbasic) Select

SHOWSCREEN
MOUSEWAIT
camera_roll(cam1,2)


but I can change that "2" value to anything I like and still appear to get the same results.

Here's the full combined code from the post about the library (http://www.glbasic.com/forum/index.php?topic=3851.0) with my little change to make it easy for someone to paste straight into a project. Run it, and click the mouse multiple times and you'll see the issue.

Code (glbasic) Select
// --------------------------------- //
// Project: 6DOFCam_lib
// Start: Thursday, November 19, 2009
// IDE Version: 7.177
//

main()

TYPE Tquaternion
    w#
    x#
    y#
    z#
ENDTYPE

TYPE Tcamera
    //position
    x#
    y#
    z#

    //look vector
    lx#
    ly#
    lz#

    //up vector
    ux#
    uy#
    uz#

    //right vector
    rx#
    ry#
    rz#

    FOV#
    aspect#
    nearClip#
    farClip#
ENDTYPE


FUNCTION quaternion_normalize AS Tquaternion: tmpQ AS Tquaternion
LOCAL mag# = SQR(tmpQ.w*tmpQ.w+tmpQ.x*tmpQ.x+tmpQ.y*tmpQ.y+tmpQ.z*tmpQ.z)
LOCAL q AS Tquaternion
q.w = tmpQ.w / mag
q.x = tmpQ.x / mag
q.y = tmpQ.y / mag
q.z = tmpQ.z / mag
RETURN q
ENDFUNCTION


FUNCTION quaternion_conj AS Tquaternion: tmpQ AS Tquaternion
LOCAL q AS Tquaternion
q.w = -tmpQ.w
q.x = -tmpQ.x
q.y = -tmpQ.y
q.z = -tmpQ.z
    RETURN q
ENDFUNCTION


FUNCTION quaternion_mult AS Tquaternion: lhs AS Tquaternion, rhs AS Tquaternion
LOCAL q AS Tquaternion
    q.w = lhs.w * rhs.w - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z
    q.x = lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y
    q.y = lhs.w * rhs.y - lhs.x * rhs.z + lhs.y * rhs.w + lhs.z * rhs.x
    q.z = lhs.w * rhs.z + lhs.x * rhs.y - lhs.y * rhs.x + lhs.z * rhs.w
RETURN q
ENDFUNCTION


FUNCTION camera_advance: cam AS Tcamera, d#
        LOCAL xt#, yt#, zt#
        xt = (cam.lx - cam.x) * d
        yt = (cam.ly - cam.y) * d
        zt = (cam.lz - cam.z) * d
        cam.x = cam.x + xt
        cam.y = cam.y + yt
        cam.z = cam.z + zt
        cam.ux =cam.ux + xt
        cam.uy =cam.uy + yt
        cam.uz =cam.uz + zt
        cam.rx =cam.rx + xt
        cam.ry =cam.ry + yt
        cam.rz =cam.rz + zt
        cam.lx =cam.lx + xt
        cam.ly =cam.ly + yt
        cam.lz =cam.lz + zt
ENDFUNCTION


FUNCTION camera_strafe: cam AS Tcamera, d#
        LOCAL xt#, yt#, zt#
        xt = (cam.rx - cam.x) * d
        yt = (cam.ry - cam.y) * d
        zt = (cam.rz - cam.z) * d
        cam.x = cam.x + xt
        cam.y = cam.y + yt
        cam.z = cam.z + zt
        cam.ux = cam.ux + xt
        cam.uy = cam.uy + yt
        cam.uz = cam.uz + zt
        cam.rx = cam.rx + xt
        cam.ry = cam.ry + yt
        cam.rz = cam.rz + zt
        cam.lx = cam.lx + xt
        cam.ly = cam.ly + yt
        cam.lz = cam.lz + zt
ENDFUNCTION


FUNCTION camera_rise: cam AS Tcamera, d#
        LOCAL xt#, yt#, zt#
        xt = (cam.ux - cam.x) * d
        yt = (cam.uy - cam.y) * d
        zt = (cam.uz - cam.z) * d
        cam.x = cam.x + xt
        cam.y = cam.y + yt
        cam.z = cam.z + zt
        cam.ux = cam.ux + xt
        cam.uy = cam.uy + yt
        cam.uz = cam.uz + zt
        cam.rx = cam.rx + xt
        cam.ry = cam.ry + yt
        cam.rz = cam.rz + zt
        cam.lx = cam.lx + xt
        cam.ly = cam.ly + yt
        cam.lz = cam.lz + zt
ENDFUNCTION


FUNCTION camera_roll: cam AS Tcamera, a#
        LOCAL qUp AS Tquaternion
        qUp.w = 0
        qUp.x = cam.ux - cam.x
        qUp.y = cam.uy - cam.y
        qUp.z = cam.uz - cam.z

        LOCAL qRight AS Tquaternion
        qRight.w = 0
        qRight.x = cam.rx - cam.x
        qRight.y = cam.ry - cam.y
        qRight.z = cam.rz - cam.z

        LOCAL qRot AS Tquaternion
        qRot.w = COS(a * rad/2)
        qRot.x = (cam.lx - cam.x) * SIN(a * rad/2)
        qRot.y = (cam.ly - cam.y) * SIN(a * rad/2)
        qRot.z = (cam.lz - cam.z) * SIN(a * rad/2)

        LOCAL W AS Tquaternion,W1 AS Tquaternion,W2 AS Tquaternion
        W1 = quaternion_mult(qRot,qUp)
        W2 = quaternion_conj(qRot)
        W = quaternion_mult(W2,W1)
        W = quaternion_normalize(W)
            cam.ux = W.x + cam.x
            cam.uy = W.y + cam.y
            cam.uz = W.z + cam.z
//        W = quaternion_mult(quaternion_mult(qRot,qRight), quaternion_conj(qRot)) <<< This does not work?!?!
        W1 = quaternion_mult(qRot,qRight)
        W2 = quaternion_conj(qRot)
        W = quaternion_mult(W2,W1)
        W = quaternion_normalize(W)
            cam.rx = W.x + cam.x
            cam.ry = W.y + cam.y
            cam.rz = W.z + cam.z
ENDFUNCTION

FUNCTION camera_pitch: cam AS Tcamera, a#
        LOCAL qUp AS Tquaternion
        qUp.w = 0
        qUp.x = cam.ux - cam.x
        qUp.y = cam.uy - cam.y
        qUp.z = cam.uz - cam.z

        LOCAL qLook AS Tquaternion
        qLook.w = 0
        qLook.x = cam.lx - cam.x
        qLook.y = cam.ly - cam.y
        qLook.z = cam.lz - cam.z

        LOCAL qRot AS Tquaternion
        qRot.w = COS(a * rad/2)
        qRot.x = (cam.rx - cam.x) * SIN(a * rad/2)
        qRot.y = (cam.ry - cam.y) * SIN(a * rad/2)
        qRot.z = (cam.rz - cam.z) * SIN(a * rad/2)

        LOCAL W AS Tquaternion,W1 AS Tquaternion,W2 AS Tquaternion
        W1 = quaternion_mult(qRot,qUp)
        W2 = quaternion_conj(qRot)
        W = quaternion_mult(W2,W1)
        W = quaternion_normalize(W)
            cam.ux = W.x + cam.x
            cam.uy = W.y + cam.y
            cam.uz = W.z + cam.z
        W1 = quaternion_mult(qRot,qLook)
        W2 = quaternion_conj(qRot)
        W = quaternion_mult(W2,W1)
        W = quaternion_normalize(W)
            cam.lx = W.x + cam.x
            cam.ly = W.y + cam.y
            cam.lz = W.z + cam.z
ENDFUNCTION


FUNCTION camera_yaw: cam AS Tcamera, a#
        LOCAL qRight AS Tquaternion
        qRight.w = 0
        qRight.x = cam.rx - cam.x
        qRight.y = cam.ry - cam.y
        qRight.z = cam.rz - cam.z

        LOCAL qLook AS Tquaternion
        qLook.w = 0
        qLook.x = cam.lx - cam.x
        qLook.y = cam.ly - cam.y
        qLook.z = cam.lz - cam.z

        LOCAL qRot AS Tquaternion
        qRot.w = COS(a * rad/2)
        qRot.x = (cam.ux - cam.x) * SIN(a * rad/2)
        qRot.y = (cam.uy - cam.y) * SIN(a * rad/2)
        qRot.z = (cam.uz - cam.z) * SIN(a * rad/2)

        LOCAL W AS Tquaternion,W1 AS Tquaternion,W2 AS Tquaternion
        W1 = quaternion_mult(qRot,qRight)
        W2 = quaternion_conj(qRot)
        W = quaternion_mult(W2,W1)
        W = quaternion_normalize(W)
            cam.rx = W.x + cam.x
            cam.ry = W.y + cam.y
            cam.rz = W.z + cam.z
        W1 = quaternion_mult(qRot,qLook)
        W2 = quaternion_conj(qRot)
        W = quaternion_mult(W2,W1)
        W = quaternion_normalize(W)
            cam.lx = W.x + cam.x
            cam.ly = W.y + cam.y
            cam.lz = W.z + cam.z
ENDFUNCTION


FUNCTION X_6DOFCAMERA: cam AS Tcamera
X_MAKE3D cam.nearClip, cam.farClip, cam.FOV
X_CAMERAUP cam.x - cam.ux, cam.y - cam.uy, cam.z - cam.uz
DEBUG cam.x+","+cam.ux+","+cam.y+","+cam.uy+","+cam.z+","+cam.uz+"\n"
X_CAMERA cam.x, cam.y, cam.z, cam.lx, cam.ly, cam.lz
ENDFUNCTION



FUNCTION main:


// --------------------------------- //
// Project: 6DOFCam_test
// Start: Thursday, November 19, 2009
// IDE Version: 7.177

LOCAL cam1 AS Tcamera

LOCAL speed# = .01
LOCAL xv#, yv#, zv#, p#=0, r#=0, y#=0
LOCAL mx%, my%, mw%, mba%, mbb%
CONSTANT rad = 3.1415926535/180

cam1.x# = 0
cam1.y = 0
cam1.z = 0

cam1.lx = 0
cam1.ly = 0
cam1.lz = -1

cam1.ux# = 0
cam1.uy# = 1
cam1.uz# = 0

cam1.rx = 1
cam1.ry = 0
cam1.rz = 0

cam1.FOV = 45
cam1.aspect = 1024/768
cam1.nearClip = .01
cam1.farClip = 5000

WHILE TRUE


MOUSESTATE mx, my, mba, mbb
mx = MOUSEAXIS(0)/10
my = -MOUSEAXIS(1)/10

X_6DOFCAMERA(cam1)

    //Linear Velocity Dampening (SPACE)
    IF KEY(57)
        xv = xv * .95
        yv = yv * .95
        zv = zv * .95
    ENDIF

    //Angular Velocity Dampening (CTRL)
    IF KEY(29)
        r = r * .95
        p = p * .95
        y = y * .95
    ENDIF

    //Accelerate Forward (W)
    IF KEY(17)
        xv = xv + (cam1.lx - cam1.x) * speed
        yv = yv + (cam1.ly - cam1.y) * speed
        zv = zv + (cam1.lz - cam1.z) * speed
    ENDIF
    //Accelerate Backward (S)
    IF KEY(31)
        xv = xv - (cam1.lx - cam1.x) * speed
        yv = yv - (cam1.ly - cam1.y) * speed
        zv = zv - (cam1.lz - cam1.z) * speed
    ENDIF
    //Accelerate Left (A)
    IF KEY(30)
        xv = xv + (cam1.rx - cam1.x) * speed
        yv = yv + (cam1.ry - cam1.y) * speed
        zv = zv + (cam1.rz - cam1.z) * speed
    ENDIF
    //Accelerate Right (D)
    IF KEY(32)
        xv = xv - (cam1.rx - cam1.x) * speed
        yv = yv - (cam1.ry - cam1.y) * speed
        zv = zv - (cam1.rz - cam1.z) * speed
    ENDIF
    //Accelerate Down (F)
    IF KEY(33)
        xv = xv + (cam1.ux - cam1.x) * speed
        yv = yv + (cam1.uy - cam1.y) * speed
        zv = zv + (cam1.uz - cam1.z) * speed
    ENDIF
    //Accelerate Up (R)
    IF KEY(19)
        xv = xv - (cam1.ux - cam1.x) * speed
        yv = yv - (cam1.uy - cam1.y) * speed
        zv = zv - (cam1.uz - cam1.z) * speed
    ENDIF

    // change IF the left mouse button is pressed
    IF mba = 1
        //Pitch mouse up AND
        p = p + my
        //Yaw
        y = y + mx
    ELSEIF mbb = 1
        //Roll with right mouse button
        r = r + mx
    ENDIF

    cam1.x = cam1.x + xv
    cam1.y = cam1.y + yv
    cam1.z = cam1.z + zv
    cam1.lx = cam1.lx + xv
    cam1.ly = cam1.ly + yv
    cam1.lz = cam1.lz + zv
    cam1.rx = cam1.rx + xv
    cam1.ry = cam1.ry + yv
    cam1.rz = cam1.rz + zv
    cam1.ux = cam1.ux + xv
    cam1.uy = cam1.uy + yv
    cam1.uz = cam1.uz + zv

    debug_view(0,0,0,100,RGB(255,255,0),RGB(255,0,255),RGB(0,255,255))

  camera_roll(cam1,r)
  camera_pitch(cam1,p)
  camera_yaw(cam1,y)

X_MAKE2D
PRINT "Cam Pitch = "+p,10,10
PRINT "Cam Yaw = "+y,10,20
PRINT "Cam Roll = "+r,10,30
SETPIXEL mx,my,RGB(255,255,255)
SHOWSCREEN
MOUSEWAIT
camera_roll(cam1,0.1)
WEND
ENDFUNCTION


FUNCTION debug_view: x, y, z, crad, rgb1, rgb2, rgb3
LOCAL rad, x1, y1, j, x2, y2
y1=SIN(0)*crad
x1=COS(0)*crad
FOR j=4 TO 360 STEP 4
    y2=SIN(j)*crad
    x2=COS(j)*crad
    X_LINE x+x1,y+y1,z  , x+x2,y+y2,z,0.1,rgb1
    X_LINE x+x1,y+0,y1+z, x+x2,y+0,y2+z,1,rgb2
    X_LINE x+0,y+x1,y1+z, x+0,y+x2,y2+z,1,rgb3
    x1=x2
    y1=y2
NEXT
X_DOT x,y,z,10,rgb1
X_DRAWAXES x+crad,y,z
    X_DRAWAXES x-crad,y,z
    X_DRAWAXES x,y+crad,z
    X_DRAWAXES x,y-crad,z
    X_DRAWAXES x,y,crad+z
    X_DRAWAXES x,y,-crad+z
    X_PRINT "RIGHT X+",x+crad,y,z,0
    X_PRINT "LEFT X-",x-crad,y,z,0
    X_PRINT "UP Y+",x,y+crad,z,0
    X_PRINT "DOWN Y-",x,y-crad,z,0
    X_PRINT "OUT Z+",x,y,crad+z,0
    X_PRINT "IN Z-",x,y,-crad+z,0
    X_SETTEXTURE -1, -1
ENDFUNCTION


I know the entity system is an alternative, but I found it a bit clunky and buggy when I used it in the past so at this point I'd rather stick with the camera library. Also, I might not understand the maths in the camera library, but at least I wouldn't have to rewrite my project if someone can identify how to fix it.

Any help is appreciated!
#40
I'm not seeing quite the same behaviour, I'm seeing that MOUSEAXIS is 99% broken, almost always returning 0. I'm calling before x_make3d.
#41
It is definitely the line containing X_COLLISIONRAY that crashes the program as I ran the following test and the program still crashes when not in debug mode.

Code (glbasic) Select
IF X_COLLISIONRAY(M_Hill, 0, x, y, z, x2-x, y2-y, z2-z)<>0
                END
ELSE
                END
ENDIF

#42
No, the command crashes.
#43
So am I correct about the way to use this? :

If I have rotated my camera and then move it, after moving it I run a X_getcameramatrix and store the value in an array (eg. "cam[]")
The next frame I run
Code (glbasic) Select
x_cameraup cam[4],cam[5],cam[6]
x_camera cam[12],cam[13],cam[14],cam[8],cam[9],cam[10]


Assuming that's correct, how do I then align the camera with the x-axis returned earlier so that I can then move the camera relative to the new orientation? I can't see that x_movement works with the camera, it looks like I've got to use x_camera and it uses absolute coordinates.
I'm guessing I have to do some sort of matrix calculation to multiply/add this matrix against another???
#44
My program will crash when it hits the X_COLLISIONRAY line in the following section of code - but only when debug is disabled

Code (glbasic) Select

LOCAL x,y,z, x2,y2,z2
X_SCREEN2WORLD MouseX, MouseY,  0, x, y, z
X_SCREEN2WORLD MouseX, MouseY, -1, x2,y2,z2
// DEBUG M_Hill+","+x+","+y+","+z+","+x2+","+y2+","+z2
// END
IF X_COLLISIONRAY(M_Hill, 0, x, y, z, x2-x, y2-y, z2-z)<>0
MouseCollisionFace=X_GETCOLLISIONFACE() // div by 3 for x_getcollisionface bug, then divide by 2 to get the right triangle
X_GETFACE M_Hill, 0, MouseCollisionFace, Face[]
DEBUG "Collision = "+MouseCollisionFace+",X="+Face[0][0]+",Y="+Face[0][1]+",Z="+Face[0][2]+",nx="+Face[0][6]+",ny="+Face[0][7]+",nz="+Face[0][8]+"\n"
ELSE
MouseCollisionFace=-1
ENDIF


If I turn debug on, there's no crash. By uncommenting the two commented lines I can see I have valid variables to pass to the command :
Code (glbasic) Select
Injection started

7,-6.900289536,1.999999642,3.900290012,-6.900289536,1.999999642,3.900290012

By putting "END" commands straight after the "IF" and "ELSE" lines, I can prove it's the X_COLLISIONRAY on the first execution of the code that crashes the program.

My setup is Windows XP, GLBasic 10.283
#45
 :good: Great work MrTAToad!!!!