@WLGfx,
I played around with things some more. I found that if I'm moving in an absolute left direction, I need to update the zero point... if I'm moving diagonally... I update the last point and allow it to shift in. Very strange behavior, but I coded for it.
I stuck to the original perlin for now because I wasn't sure if the tiling/wrapping I want would work correctly with simplex. You'll notice that I use your normalizing function in this code - it works like a charm.
Here's the code for the whole thing. Please excuse any commented out references to functions that don't exist. You'll notice real and integer values for the same thing... I was originally thinking that I was losing precision using integers and that would be the cause of the problem... that did not pan out, and I haven't removed the code yet.
Hold down the 2,3 or 4 key change the view of the camera. The 4 key moves the camera to the area on the matrix where I believe the problem starts.
Numpad 8 rotates you to zero degress, 4 to 270, 2 to 180 and 6 to 90.. so you can look at absolute direction. Arrow keys control direction.
RANDOMIZE TIMER()
Set Display Mode 800 , 600 , 32
sync on : sync rate 120 : color backdrop 0
TYPE MatrixData
`How many NxN blocks exist in this world's map?
iBlocksCount AS INTEGER
`The number of points across the axis of the matrix.
iSegPoints AS INTEGER
`The length of the segment BETWEEN 2 points... this is the space between (0,0) and (0,1) for instance
iSegLength AS INTEGER
`The acutual length of the axis of the matrix... the whole side
iAxisLength AS INTEGER
`Marker for the center point of the matrix object
iAxisCenter AS INTEGER
`How far do we travel with each step
fStepDistance# AS FLOAT
`The max point (and inverse min) point where the map should wrap
iMaxPoint AS INTEGER
fPosX# AS FLOAT : fPosZ# AS FLOAT
fPosY# AS FLOAT
`These hold the OLD X,Z position before stepping to the new position
fOPosX# AS FLOAT : fOPosZ# AS FLOAT
`These are both here to check any differences between using real/integer values
`Changed from float to integer - looks to be ok - this is like locking to a grid
fMatPosX# AS FLOAT : fMatPosZ# AS FLOAT
`When the matrix moves, the 0,0 point of the matrix sits at these coordinates
iMatPosX AS INTEGER : iMatPosZ AS INTEGER
`Matrix shifting values
fSHX# AS FLOAT : fSHZ# AS FLOAT
`Direction Controls
dirUp AS INTEGER : dirDown AS INTEGER : dirLeft AS INTEGER : dirRight AS INTEGER
`Latent Shift controller - may wind up being removed
iLS AS INTEGER
ic AS INTEGER
ENDTYPE
`NOISE SET PARAMS 0, 5, .0039, .00045, 1, 0
NOISE SET PARAMS 0, 5, .339, .240, 1, 0
`Type data does not need to be an array
oMD AS MatrixData
oMD.iBlocksCount = 4
oMD.fStepDistance# = 2
oMD.iSegPoints = 128
oMD.iAxisLength = 1024
oMD.iAxisCenter = (oMD.iAxisLength/2)
oMD.fPosX# = oMD.iAxisCenter
oMD.fPosZ# = oMD.iAxisCenter
oMD.iSegLength = (oMD.iAxisLength / oMD.iSegPoints)
oMD.iMaxPoint = (oMD.iSegPoints * oMD.iBlocksCount)
oMD.ic = 0
oMD.iLS = 0
`#########################################################
`These are for the debugging code I wrote
DIM iDFC(0)
iDFC(0) = 32
`We will start all our counts at 1
`Structure:
` arrDebugFiles(x,0) = fileid
` arrDebugFiles(x,1) = filename
` arrDebugFiles(x,2) = is file open CURRENTLY
DIM arrDebugFiles$(iDFC(0),2)
`#########################################################
`OBJECT ID CONSTANTS
#CONSTANT iCHARACTERID 1
#CONSTANT iCAMID 1
#CONSTANT iMATRIXID 1
`OBJECT ID CONSTANTS
`######## GENERATE THE MATRIX
`oMD.iSegPoints = 256 oMD.iAxisLength = 256
MAKE MATRIX iMATRIXID,oMD.iAxisLength,oMD.iAxisLength,oMD.iSegPoints,oMD.iSegPoints
position matrix iMATRIXID,0,0,0
`######## GENERATE THE MATRIX
`#### MAKE CAMERA
`oMD.iAxisCenter
make camera iCAMID
POSITION CAMERA iCAMID,oMD.iAxisCenter,50.0,oMD.iAxisCenter-50
XROTATE CAMERA iCAMID,30
`SET CAMERA RANGE iCAMID,1, iCamDrawDist(0)
`#### MAKE CAMERA
`######## MAKE A CHARACTER OBJECT
make object sphere iCHARACTERID,5
color object iCHARACTERID,rgb(0,0,255)
position object iCHARACTERID,oMD.iAxisCenter,5,oMD.iAxisCenter
`######## MAKE A CHARACTER OBJECT
set matrix 1,0,0,1,2,1,1,1
set matrix trim 1,0.004,0.004
`backgroundcolor=RGB(136,164,200)
`color backdrop backgroundcolor
set ambient light 60
set directional light 0,7,-3,0
color light 0,200,200,200
`set light range 0,100000
`fog on
`fog distance iMatrixLengthXZ(0)*0.7
`fog color backgroundcolor
`Update our matrix before we actually start our game loop so that it picks up our heights
`for the viewable area
UpdateMatrix()
Yrotate object iCHARACTERID,355
DO
`Set our old variables
oMD.fOPosX# = oMD.fPosX#
oMD.fOPosZ# = oMD.fPosZ#
oMD.fPosY# = get ground height(iMATRIXID,oMD.fPosX#,oMD.fPosZ#)
`Handle the wrapping of the map values here
`WRAP( Current Value, Min Value, Max Value)
`oMD(0).fMapX# = WRAP((oMSD(0).x# / oMD.iAxisLength),oMSD(0).iMinX#,oMSD(0).iMaxX#)
`oMSD(0).fMapZ# = WRAP((oMSD(0).z# / oMD.iAxisLength),oMSD(0).iMinZ#,oMSD(0).iMaxZ#)
`#################################################################################################
`DEBUG STATEMENTS FOR DISPLAY DURING RUNTIME
ink RGB(255,0,0), RGB(0,0,0)
SET CURSOR 0,0
print "FPS:";screen fps()
print "CHAR ANGLE Y: ";iCharAngleY#
print "Segment Length: " + str$(oMD.iSegLength)
print "X:";str$(oMD.fPosX#);" Y: ";str$(oMD.fPosY#);" Z: ";str$(oMD.fPosZ#)
print "fSHX:";str$(oMD.fSHX#);" fSHZ: ";str$(oMD.fSHZ#)
print "Up: " + str$(oMD.dirUp) + " Down: " + str$(oMD.dirDown) + " Left: " + str$(oMD.dirLeft) + " Right: " + str$(oMD.dirRight)
print "MatPosX: " + str$(oMD.iMatPosX) + " MatPosZ: " + str$(oMD.iMatPosZ)
print "MatPosX: " + str$(oMD.fMatPosX#) + " MatPosZ: " + str$(oMD.fMatPosZ#)
`#################################################################################################
`IF isMoving > 0 THEN print "CHARACTER MOVING"
isMoving = 0 `Is the character moving?
If Upkey()=1 then isMoving = 1
if Downkey() = 1 then isMoving = 2
`Control roatation quickly
IF KEYSTATE(72) = 1 : Yrotate object iCHARACTERID,0 : ENDIF
IF KEYSTATE(80) = 1 : Yrotate object iCHARACTERID,180 : ENDIF
IF KEYSTATE(75) = 1 : Yrotate object iCHARACTERID,270 : ENDIF
IF KEYSTATE(77) = 1 : Yrotate object iCHARACTERID,90 : ENDIF
s#=0 `This is involved with stepping movement
if isMoving = 1 and s# < oMD.fStepDistance# then s# = s# + oMD.fStepDistance#
if isMoving = 2 and s# > -1.0*oMD.fStepDistance# then s# = s# - oMD.fStepDistance#
`######
`this is our movement/stepping bit of code - newvalue gets the location of the next s# sized step
`fPosX# AS FLOAT : fPosY# AS FLOAT : fPosZ# AS FLOAT
oMD.fPosX# = newxvalue(oMD.fPosX#,iCharAngleY#,s#)
oMD.fPosZ# = newzvalue(oMD.fPosZ#,iCharAngleY#,s#)
oMD.fPosY# = get ground height(iMATRIXID,oMD.fPosX#,oMD.fPosZ#)
`######
`If the character is moving, setup the calculations for moving the map matrix
` and fire the controlMatrix() function
if isMoving > 0
oMD.fSHX# = oMD.fSHX# + (oMD.fPosX# - oMD.fOPosX#)
oMD.fSHZ# = oMD.fSHZ# + (oMD.fPosZ# - oMD.fOPosZ#)
controlMatrix()
endif
`Get the angle (direction) on the Y axis that the character is facing
` We use this to power the compass eventually!
iCharAngleY# = OBJECT ANGLE Y(iCHARACTERID)
`######## CONTROL THE SCENE
If Leftkey()=1 then Yrotate object iCHARACTERID,Wrapvalue(iCharAngleY#-2)
yrotate camera iCAMID,Wrapvalue(iCharAngleY#-2)
If Rightkey()=1 then Yrotate object iCHARACTERID,Wrapvalue(iCharAngleY#+2)
yrotate camera iCAMID,Wrapvalue(iCharAngleY#+2)
theheight# = GET GROUND HEIGHT(iMATRIXID,oMD.iAxisCenter,oMD.iAxisCenter)
`position object iCHARACTERID,oMD.iAxisCenter,theheight#,oMD.iAxisCenter
position object iCHARACTERID,oMD.fPosX#,theheight#,oMD.fPosZ#
`IF WE HIT THE 2 KEY, SWITCH TO VIEW 2
IF KEYSTATE(3) = 1
print "View 2"
POSITION CAMERA iCAMID,oMD.fPosX#,400.0,oMD.fPosZ#
`POSITION CAMERA iCAMID,0,999.0,0
`Camera 2 has a downward pointing view
XROTATE CAMERA iCAMID,40
ELSE
print "View 1"
`POSITION CAMERA iCAMID,oMD.iAxisCenter,100,(oMD.iAxisCenter)-50
POSITION CAMERA iCAMID,oMD.fPosX#,theheight#+20,oMD.fPosZ# -50
`POSITION CAMERA iCAMID,0,400.0,0
`Camera 2 has a downward pointing view
XROTATE CAMERA iCAMID,30
ENDIF
`######## CONTROL THE SCENE
IF KEYSTATE(4) = 1
print "View 3"
POSITION CAMERA iCAMID,camera position x(iCAMID),1000.0,camera position z(iCAMID)
`POSITION CAMERA iCAMID,0,999.0,0
`Camera 2 has a downward pointing view
XROTATE CAMERA iCAMID,90
ENDIF
IF KEYSTATE(5) = 1
print "View 4"
camx = oMD.fPosX# - 400
camz = oMD.fPosZ# + 400
POSITION CAMERA iCAMID,camx,200,camz
`POSITION CAMERA iCAMID,0,999.0,0
`Camera 2 has a downward pointing view
XROTATE CAMERA iCAMID,80
ENDIF
` cya#=wrapvalue(cya#+(mousemovex()/3.0))
` cxa#=cxa#+(mousemovey()/3.0)
` if cxa#<-45.0 then cxa#=-45.0
` if cxa#>45.0 then cxa#=45.0
`
` rem smooth camera rotation
` cx#=curveangle(cxa#,cx#,1.0)
` cy#=curveangle(cya#,cy#,4.0)
`
` rotate camera cx#,cy#,0
` rotate#=cy#
`position camera x#,h#+1500,z#
sync
LOOP
`##############################################################################################################
`##############################################################################################################
`##############################################################################################################
function controlMatrix()
oMD.dirUp = 0 : oMD.dirDown = 0 : oMD.dirLeft = 0 : oMD.dirRight = 0
freq# = 0 : ampl# = 0 : prevh# = 0
iTiles = oMD.iBlocksCount * oMD.iSegPoints
`Did I already shift once?
iShifted = 0
IF oMD.fPosX# < oMD.fOPosX#
iShifted = 1
ENDIF
IF oMD.fPosX# > oMD.fOPosX#
iShifted = 2
ENDIF
IF oMD.iLS = 0
`Movement up
IF oMD.fSHZ# >= oMD.iSegLength
oMD.fSHZ# = 0
oMD.dirUp = 1
ENDIF
`Movement Down
IF oMD.fSHZ# <= (0.0 - oMD.iSegLength)
oMD.fSHZ# = 0
oMD.dirDown = 1
ENDIF
IF oMD.dirUp = 1 OR oMD.dirDown = 1
oMD.iLS = 1
ELSE
`Movement Right
IF oMD.fSHX# >= oMD.iSegLength
oMD.fSHX# = 0
oMD.dirRight = 1
ENDIF
`Movement Left
IF oMD.fSHX# <= (0.0 - oMD.iSegLength)
oMD.fSHX# = 0
oMD.dirLeft = 1
ENDIF
ENDIF
ELSE
oMD.iLS = 0
`Movement Right
IF oMD.fSHX# >= oMD.iSegLength
oMD.fSHX# = 0
oMD.dirRight = 1
ENDIF
`Movement Left
IF oMD.fSHX# <= (0.0 - oMD.iSegLength)
oMD.fSHX# = 0
oMD.dirLeft = 1
ENDIF
ENDIF
remstart
`Uncomment this code to remove the latent shifting code
` The latent shift code came from the example code I found on the boards.
` I am not sure if the latent shift helps or not... it doesn't seem to
`Movement up
IF oMD.fSHZ# >= oMD.iSegLength
oMD.fSHZ# = 0
oMD.dirUp = 1
ENDIF
`Movement Down
IF oMD.fSHZ# <= (0.0 - oMD.iSegLength)
oMD.fSHZ# = 0
oMD.dirDown = 1
ENDIF
`Movement Right
IF oMD.fSHX# >= oMD.iSegLength
oMD.fSHX# = 0
oMD.dirRight = 1
ENDIF
`Movement Left
IF oMD.fSHX# <= (0.0 - oMD.iSegLength)
oMD.fSHX# = 0
oMD.dirLeft = 1
ENDIF
remend
`######## PLAYER MOVEMENT UP ########
IF oMD.dirUp = 1
controlMatrixHeights("up",iShifted)
`Perform the matrix shift
SHIFT MATRIX DOWN iMATRIXID
WL MATRIX NORMALISE iMATRIXID
`iShifted = 1
ENDIF `IF oMD(0).dirUp = 1
`######## PLAYER MOVEMENT UP ########
`######## PLAYER MOVEMENT DOWN ########
IF oMD.dirDown = 1
controlMatrixHeights("down",iShifted)
`Perform the matrix shift
SHIFT MATRIX UP iMATRIXID
WL MATRIX NORMALISE iMATRIXID
`iShifted = 2
ENDIF `IF oMD(0).dirDown = 1
`######## PLAYER MOVEMENT DOWN ########
`######## PLAYER MOVEMENT LEFT ########
IF oMD.dirLeft = 1
controlMatrixHeights("left",iShifted)
`Perform the matrix shift
SHIFT MATRIX RIGHT iMATRIXID
WL MATRIX NORMALISE iMATRIXID
ENDIF `IF oMD(0).dirDown = 1
`######## PLAYER MOVEMENT LEFT ########
`######## PLAYER MOVEMENT RIGHT ########
IF oMD.dirRight = 1
controlMatrixHeights("right",iShifted)
`Perform the matrix shift
SHIFT MATRIX LEFT iMATRIXID
WL MATRIX NORMALISE iMATRIXID
ENDIF `IF oMD(0).dirDown = 1
`######## PLAYER MOVEMENT RIGHT ########
rem reposition matrix
oMD.fMatPosX# = (oMD.fPosX# - oMD.iAxisCenter) - oMD.fSHX#
oMD.fMatPosZ# = (oMD.fPosZ# - oMD.iAxisCenter) - oMD.fSHZ#
`position matrix iMATRIXID,oMD.fMatPosX#,0,oMD.fMatPosZ#
`Converted to integer values for a more gridlike approach
`This number in essence moves by the size of iSegLength
oMD.iMatPosX = ((oMD.fPosX# - oMD.iAxisCenter) - oMD.fSHX#)
oMD.iMatPosZ = ((oMD.fPosZ# - oMD.iAxisCenter) - oMD.fSHZ#)
`show message oMD.iMatPosX
position matrix iMATRIXID,oMD.iMatPosX,0,oMD.iMatPosZ
ENDFUNCTION
`##############################################################################################################
FUNCTION controlMatrixHeights(sDir$,iShifted)
`iShifted: 1 = UP -- 2 = DOWN
iTiles = oMD.iBlocksCount * oMD.iSegPoints
`There can be shifting in 2 directions at any given time that this function is fired
`Need to account for that in the noisex and noisez variables to ensure that the correct height
` values are grabbed
SELECT sDir$
CASE "up":
FOR iSeg = 0 TO oMD.iSegPoints
`These are the points on the MATRIX that actually get affected by the update
x = iSeg : z = oMD.iSegPoints
`When the matrix is created, the heights are set with the entire world in mind
` So iTiles = oMD.iBlocksCount * oMD.iSegPoints
`As the matrix moves around, the 0,0 location of the matrix moves around the map
` and is held in the oMD.iMatPosX and oMD.iMatPosZ values
` - it's these values that become the 0,0 for the matrix
noisez = WRAP(((oMD.iMatPosZ / oMD.iSegLength) + oMD.iSegPoints + 1 ),0,iTiles)
noisex = WRAP(((oMD.iMatPosX / oMD.iSegLength) + iSeg),0,iTiles)
`noisez = WRAP(((oMD.fMatPosZ# / oMD.iSegLength) + oMD.iSegPoints +1 ),0,iTiles)
`noisex = WRAP(((oMD.fMatPosX# / oMD.iSegLength) + iSeg),0,iTiles)
newh# = NOISE GET HEIGHT TILED(0,noisex,noisez,iTiles,iTiles) * 255
set matrix height iMATRIXID,x,z,newh#
`set matrix height iMATRIXID,x,0,newh#
`strdebug$ = "UP x: " + str$(noisex) + " z: " + str$(noisez)+ " H: " + str$(newh#)
`strdebug$ = strdebug$ + " Applied to: " + str$(x) + "," + str$(z)
`debugit("move-up.txt",strdebug$,0)
NEXT iSeg
ENDCASE
CASE "down":
FOR iSeg = 0 TO oMD.iSegPoints
x = iSeg : z = 0
noisez = WRAP(((oMD.iMatPosZ / oMD.iSegLength) - 1),0,iTiles)
noisex = WRAP(((oMD.iMatPosX / oMD.iSegLength) + iSeg),0,iTiles)
`noisez = WRAP(((oMD.fMatPosZ# / oMD.iSegLength)-1),0,iTiles)
`noisex = WRAP(((oMD.fMatPosX# / oMD.iSegLength) + iSeg),0,iTiles)
newh# = NOISE GET HEIGHT TILED(0,noisex,noisez,iTiles,iTiles) * 255
`debugit("noisex.txt","x: " + str$(noisex) + " z: " + str$(noisez)+ " H: " + str$(newh#),0)
set matrix height iMATRIXID,x,z,newh#
`set matrix height iMATRIXID,x,oMD.iSegPoints,newh#
NEXT iSeg
ENDCASE
`Unless we are dead on moving left (270deg) we are either shifting DOWN (up) or UP (down) BEFORE this
`movement occurs
CASE "left":
FOR iSeg = 0 TO oMD.iSegPoints
x = 0 : z = iSeg
SELECT iShifted
CASE 0: `Moving straight on at 270
`This works - don't change anything
noisez = WRAP(((oMD.iMatPosZ / oMD.iSegLength) + iSeg),0,iTiles)
noisex = WRAP((((oMD.iMatPosX / oMD.iSegLength) + oMD.iSegPoints)-1),0,iTiles)
`noisez = WRAP(((oMD.fMatPosZ# / oMD.iSegLength) + iSeg),0,iTiles)
`noisex = WRAP(((oMD.fMatPosX# / oMD.iSegLength) -1),0,iTiles)
ENDCASE
CASE 1: `Moving with an up angle
noisez = WRAP(((oMD.iMatPosZ / oMD.iSegLength) + iSeg),0,iTiles)
noisex = WRAP(((oMD.iMatPosX / oMD.iSegLength) ) ,0,iTiles)
`noisez = WRAP(((FLOOR(oMD.fMatPosZ#) / oMD.iSegLength) + iSeg),0,iTiles)
`noisex = WRAP(((FLOOR(oMD.fMatPosX#) / oMD.iSegLength))-1,0,iTiles)
`The update has already occurred on the first x point, now subtract one again
`and let the shifting action bring it into view
x = WRAP(x-1,0,oMD.iSegPoints)
`z = WRAP(z+2,0,oMD.iSegPoints)
ENDCASE
`CASE 2: `Moving with a down angle - not implemented yet
` noisez = WRAP(((oMD.iMatPosZ / oMD.iSegLength) + iSeg),0,iTiles)
` noisex = WRAP(((oMD.iMatPosX / oMD.iSegLength) -1),0,iTiles)
` `noisez = WRAP(((oMD.fMatPosZ# / oMD.iSegLength) + iSeg),0,iTiles)
` `noisex = WRAP(((oMD.fMatPosX# / oMD.iSegLength)),0,iTiles)
`ENDCASE
ENDSELECT
newh# = NOISE GET HEIGHT TILED(0,noisex,noisez,iTiles,iTiles) * 255
strdebug$ = "LEFT x: " + str$(noisex) + " z: " + str$(noisez)+ " H: " + str$(newh#)
strdebug$ = strdebug$ + " Applied to: " + str$(x) + "," + str$(z)
strdebug$ = strdebug$ + " Mat Posx:" + str$(oMD.iMatPosX) + " Mat PosZ:" + str$(oMD.iMatPosZ)
debugit("movement.txt",strdebug$,0)
set matrix height iMATRIXID,x,z,newh#
`set matrix height iMATRIXID,oMD.iSegPoints,z,newh#
NEXT iSeg
ENDCASE
CASE "right":
`IF iShifted = 1 : iShifter = 1 : ENDIF
`IF iShifted = 2 : iShifter = -1 : ENDIF
FOR iSeg = 0 TO oMD.iSegPoints
x = oMD.iSegPoints : z = iSeg
noisez = WRAP(((oMD.iMatPosZ / oMD.iSegLength) + iSeg),0,iTiles)
noisex = WRAP(((oMD.iMatPosX / oMD.iSegLength) +1),0,iTiles)
`noisez = WRAP(((oMD.fMatPosZ# / oMD.iSegLength) + iSeg),0,iTiles)
`noisex = WRAP(((oMD.fMatPosX# / oMD.iSegLength) +1),0,iTiles)
newh# = NOISE GET HEIGHT TILED(0,noisex,noisez,iTiles,iTiles) * 255
`debugit("noisex.txt","x: " + str$(noisex) + " z: " + str$(noisez)+ " H: " + str$(newh#),0)
set matrix height iMATRIXID,x,z,newh#
`set matrix height iMATRIXID,0,z,newh#
NEXT iSeg
ENDCASE
ENDSELECT
ENDFUNCTION
`##############################################################################################################
`This is the function that actually generates the terriain data
function UpdateMatrix()
`Generates a texture from a gradient image
`generateTextureFromGradient()
`img = generateTextureFromGradient()
`PREPARE MATRIX TEXTURE Matrix Number, Image Number, Across, Down
`PREPARE MATRIX TEXTURE iMATRIXID, img, 16,16
iTiles = oMD.iBlocksCount * oMD.iSegPoints
`iTiles = oMD.iSegPoints
set matrix wireframe off iMATRIXID
for x = 0 to oMD.iSegPoints
for z = 0 to oMD.iSegPoints
hgt# = NOISE GET HEIGHT TILED(0,x,z,iTiles,iTiles) * 255
`hgt# = NOISE GET HEIGHT(0,x,z) * 255
set matrix height iMATRIXID,x,z,hgt#
`DebugIt("TestFilesize.txt",STR$(x) + "," + str$(z) + ": " + STR$(hgt),0)
`DebugIt("JustHeight.txt",STR$(hgt),0)
NEXT z
NEXT x
WL MATRIX NORMALISE iMATRIXID
UPDATE MATRIX iMATRIXID
ENDFUNCTION
EDIT:
@WLGfx,
I tested on a 128x128 set of perlin values from the original dll, and never once got a value outside of the range. I saved the values as a text file if you'd like me to upload it?
I also updated the code again. I had some values reversed.. but that didn't change things.