I've converted Code Incomplete Pseudo 3D road routine to GLBasic, but have problems with hills, namely that the road "shakes" (moves up and down) as you move up (or down) the hill.
I had thought that it was due to using an integer instead of a float somewhere, but it appears not. The only other thing is that I have converted some code incorrectly somewhere, but have no idea what.
This is the code (rendering order isn't correct, but that is easy to solve) :
// --------------------------------- //
// Project: Test2
// Start: Tuesday, April 01, 2014
// IDE Version: 12.001
CONSTANT PLAYER_STRAIGHT% = 0
CONSTANT PLAYER_LEFT% = 1
CONSTANT PLAYER_RIGHT% = 2
CONSTANT PLAYER_UPHILL_STRAIGHT% = 3
CONSTANT PLAYER_UPHILL_LEFT% = 4
CONSTANT PLAYER_UPHILL_RIGHT% = 5
CONSTANT ROAD_LENGTH_NONE% = 0
CONSTANT ROAD_LENGTH_SHORT% = 25
CONSTANT ROAD_LENGTH_MEDIUM% = 50
CONSTANT ROAD_LENGTH_LONG% = 100
CONSTANT ROAD_HILL_NONE% = 0
CONSTANT ROAD_HILL_LOW% = 20
CONSTANT ROAD_HILL_MEDIUM% = 40
CONSTANT ROAD_HILL_HIGH% = 60
CONSTANT ROAD_CURVE_NONE% = 0
CONSTANT ROAD_CURVE_EASY% = 2
CONSTANT ROAD_CURVE_MEDIUM% = 4
CONSTANT ROAD_CURVE_HARD% = 6
CONSTANT PI = 3.14159
CONSTANT COLOURS_SKY% = 7526382
CONSTANT COLOURS_TREE% = 20744
CONSTANT COLOURS_FOG% = 20744
CONSTANT SPRITES_BILLBOARD_01% = 16
CONSTANT SPRITES_BILLBOARD_02% = 17
CONSTANT SPRITES_BILLBOARD_03% = 18
CONSTANT SPRITES_BILLBOARD_04% = 19
CONSTANT SPRITES_BILLBOARD_05% = 20
CONSTANT SPRITES_BILLBOARD_06% = 21
CONSTANT SPRITES_BILLBOARD_07% = 22
CONSTANT SPRITES_BILLBOARD_08% = 23
CONSTANT SPRITES_BILLBOARD_09% = 24
CONSTANT SPRITES_PALM_TREE% = 25
CONSTANT SPRITES_DEAD_TREE1% = 26
CONSTANT SPRITES_DEAD_TREE2% = 27
CONSTANT SPRITES_COLUMN% = 28
CONSTANT SPRITES_CATCUS% = 29
CONSTANT SPRITES_TREE1% = 30
CONSTANT SPRITES_TREE2% = 31
CONSTANT SPRITES_BUSH1% = 32
CONSTANT SPRITES_BUSH2% = 33
CONSTANT SPRITES_STUMP% = 34
CONSTANT SPRITES_BOULDER1% = 35
CONSTANT SPRITES_BOULDER2% = 36
CONSTANT SPRITES_BOULDER3% = 37
CONSTANT SPRITES_TUNNELWALL% = 38
CONSTANT SPRITES_TUNNELTOP% = 39
CONSTANT BACKGROUND_SKY% = 64
CONSTANT BACKGROUND_HILLS% = 65
CONSTANT BACKGROUND_TREES% = 66
CONSTANT CARS_CAR_01% = 70
CONSTANT CARS_CAR_02% = 71
CONSTANT CARS_CAR_03% = 72
CONSTANT CARS_CAR_04% = 73
CONSTANT CARS_SEMI% = 74
CONSTANT CARS_TRUCK% = 75
TYPE tGraphic
id% // Sprite index
index% // Car ID
roadIndex% // Which road the graphic is attached too
orgXSize%;orgYSize%;
currentXSize%;currentYSize%
xOffset
yOffset
z
speed
percent
moveSpeed // Movement speed - not used with static objects!
ENDTYPE
//TYPE tCar
// which%
// offset
// z
// id%
// speed
// percent
//ENDTYPE
//
//TYPE tSprite
// id%
// offset // Offset of road
// yOffset
//ENDTYPE
TYPE tScreen
scale
x
y
w
ENDTYPE
TYPE tCamera
x
y
z
ENDTYPE
TYPE tWorld
x
y
z
ENDTYPE
TYPE tRoadPos
index%
xPos
ENDTYPE
TYPE tColour
rumble% // Denotes area between the grass and road%
road% // Road colour
leftGrass% // Area before rumble bit
rightGrass% // Area after right rumble bit
lane% // Lane colour
ENDTYPE
TYPE tPart
world AS tWorld
camera AS tCamera
screen AS tScreen
rumbleWidth
ENDTYPE
// Each road can have its own width, number of lines and colours
TYPE tSegmentPart
numLanes% // Number of lanes
rumbleWidth% // Rumble width
roadWidth% // Width of road
colour AS tColour
graphics[] AS tGraphic
cars[] AS tGraphic
p1 AS tPart
p2 AS tPart
ENDTYPE
TYPE tSegment
index%
roads[] AS tSegmentPart
tunnel%
curve
clip
ENDTYPE
TYPE tPlayerInfo
graphic AS tGraphic
playerSegment AS tSegment
playerPercent
position
speed
segmentIndex%
cameraHeight
cameraDepth
cameraZ
fov
ENDTYPE
TYPE TRoad
segments[] AS tSegment
cars[] AS tGraphic
playerInfo AS tPlayerInfo
LIGHT AS tColour
DARK AS tColour
SPRITES_SCALE
fps = 75.0
fpsStep = 0.0
segmentLength% = 200 // Length of a single segment
rumbleLength% = 3 // Number of segments per red/white rumble strip
//roadWidth% = 2000 // Actually half the roads width, easier math if the road spans from -roadWidth to +roadWidth
//cameraHeight% = 1000 // Z height of camera
//cameraDepth = 0
centrifugal = 0.3
//position = 0.0 // Current camera Z position
// playerX = 0 // Player x offset from center of road (-1 to 1 to stay independent of roadWidth)
// playerZ = 0 // Player relative z distance from camera (computed)
//lanes% = 3 // Number of lanes
//fieldOfView% = 100 // angle (degrees) for field of view
// speed = 0.0 // current speed
maxSpeed = 0 // top speed (ensure we can't move more than 1 segment in a single frame to make collision detection easier)
accel = 0 // acceleration rate - tuned until it 'felt' right
breaking = 0 // deceleration rate when braking
decel = 0 // 'natural' deceleration rate when neither accelerating, nor braking
offRoadDecel = 0 // off road deceleration is somewhere in between
offRoadLimit = 0 // limit when off road deceleration no longer applies (e.g. you can always go at least t
resolution = 0.0
skyOffset = 0.0 // Current sky scroll offset
skySpeed = 0.001 // Background sky layer scroll speed when going around curve (or up hill)
hillOffset = 0.0 // current hill scroll offset
treeOffset = 0.0 // current tree scroll offset
hillSpeed = 0.002 // background hill layer scroll speed when going around curve (or up hill)
treeSpeed = 0.003 // background tree layer scroll speed when going around curve (or up hill)
totalCars% = 200 // total number of cars on the road
width%;height%
keyLeftRight%
trackLength%
drawDistance% = 500
FUNCTION Initialise%:
LOCAL tW%,tH%
GETSCREENSIZE self.width%,self.height%
SEEDRND GETTIMERALL()
//self.cameraDepth=1.0 / TAN((self.fieldOfView%/2)) // * 3.141592653/180.0)
//DEBUG "Camera depth : "+self.cameraDepth+" "+self.fieldOfView%+"\n"
self.LIGHT.road%=7039851
self.LIGHT.leftGrass%=1092112
self.LIGHT.rightGrass=RGB(127,127,127)
self.LIGHT.rumble%=5592405
self.LIGHT.lane%=13421772
self.DARK.road%=6908265
self.DARK.leftGrass%=39424
self.DARK.rightGrass%=RGB(255,255,0)
self.DARK.rumble%=12303291
self.DARK.lane%=0
self.fpsStep=1.0/self.fps
self.maxSpeed=self.segmentLength/self.fpsStep
self.accel = self.maxSpeed/5.0
self.breaking = -self.maxSpeed
self.decel = -self.maxSpeed/5.0
self.offRoadDecel = -self.maxSpeed/2.0
self.offRoadLimit = self.maxSpeed/4.0
// self.speed=0.0
// self.playerZ=self.cameraHeight * self.cameraDepth
self.resolution=self.height%/640.0
self.keyLeftRight%=0
GETSPRITESIZE PLAYER_STRAIGHT%,tW%,tH%
self.SPRITES_SCALE= 0.3 * (1.0/tW%)
self.playerInfo.graphic.id%=PLAYER_STRAIGHT%
GETSPRITESIZE self.playerInfo.graphic.id%,self.playerInfo.graphic.orgXSize%,self.playerInfo.graphic.orgYSize%
self.playerInfo.graphic.z=0.0
self.playerInfo.playerPercent=0.0
self.playerInfo.speed=0.0
self.playerInfo.segmentIndex%=0
self.playerInfo.cameraHeight=1500.0
self.playerInfo.fov=100.0
self.playerInfo.cameraDepth=1.0 / TAN((self.playerInfo.fov/2.0))
self.playerInfo.cameraZ=(self.playerInfo.cameraHeight * self.playerInfo.cameraDepth)
ENDFUNCTION
FUNCTION addSegment%:segments[] AS tSegment,curve,y,roadOffset
LOCAL size%
LOCAL segment AS tSegment
size%=BOUNDS(segments[],0)
DIM segment.roads[1]
segment.index%=size%
segment.curve=curve
FOR loop%=0 TO BOUNDS(segment.roads[],0)-1
DIM segment.roads[loop%].cars[0]
DIM segment.roads[loop%].graphics[0]
segment.roads[loop%].p1.world.x=IIF(loop%>0,2000*2*loop%,0)
segment.roads[loop%].p1.world.y=self.lastY(segments)
segment.roads[loop%].p1.world.z=size%*self.segmentLength%
segment.roads[loop%].p1.camera.x=0.0
segment.roads[loop%].p1.camera.y=0.0
segment.roads[loop%].p1.camera.z=0.0
segment.roads[loop%].p1.screen.x=0.0
segment.roads[loop%].p1.screen.y=0.0
segment.roads[loop%].p1.screen.w=0.0
segment.roads[loop%].p1.screen.scale=0.0
segment.roads[loop%].p2.world.x=IIF(loop%>0,2000*2*loop%,0)
segment.roads[loop%].p2.world.y=y
segment.roads[loop%].p2.world.z=(size%+1)*self.segmentLength%
segment.roads[loop%].p2.camera.x=0.0
segment.roads[loop%].p2.camera.y=0.0
segment.roads[loop%].p2.camera.z=0.0
segment.roads[loop%].p2.screen.x=0.0
segment.roads[loop%].p2.screen.y=0.0
segment.roads[loop%].p2.screen.w=0.0
segment.roads[loop%].p2.screen.scale=0.0
segment.roads[loop%].roadWidth%=2000
segment.roads[loop%].rumbleWidth%=2
segment.clip=0.0
segment.curve=curve
IF FLOOR(MOD(size%/self.rumbleLength%,2))
segment.roads[loop%].colour=self.LIGHT
segment.roads[loop%].colour.lane%=RGB(255,255,255)
segment.roads[loop%].numLanes%=4
ELSE
segment.roads[loop%].colour=self.DARK
segment.roads[loop%].colour.lane%=RGB(255,255,255)
segment.roads[loop%].numLanes%=0
ENDIF
NEXT
DIMPUSH segments[],segment
ENDFUNCTION
// Add static graphics (billboards, clouds, tunnels etc)
FUNCTION addGraphic%:isStatic%,z,roadIndex%,id%,xOffset,moveSpeed,yOffset=0.0
LOCAL graphic AS tGraphic
LOCAL index%
IF id%>=0
GETSPRITESIZE id%,graphic.orgXSize%,graphic.orgYSize%
ELSE
IF id%=-1
graphic.orgXSize%=64
graphic.orgYSize%=512
ELSE
graphic.orgXSize%=1000
graphic.orgYSize%=64
ENDIF
ENDIF
graphic.id%=id%
graphic.currentXSize%=graphic.orgXSize%
graphic.currentYSize%=graphic.orgYSize%
graphic.xOffset=xOffset
graphic.yOffset=yOffset
graphic.z=z
graphic.percent=0.0
graphic.roadIndex%=roadIndex%
index%=FMOD(FLOOR(graphic.z/self.segmentLength%),BOUNDS(self.segments[],0))
IF isStatic%=TRUE
graphic.index%=0
graphic.moveSpeed=0.0
DIMPUSH self.segments[index%].roads[roadIndex%].graphics[],graphic
ELSE
graphic.index%=BOUNDS(self.cars[],0)
graphic.moveSpeed=moveSpeed
DIMPUSH self.segments[index%].roads[roadIndex%].cars[],graphic
DIMPUSH self.cars[],graphic
ENDIF
// LOCAL dx%,dy%
//
// IF id%=0
// GETSPRITESIZE id%,dx%,dy%
// //IF dx%=0 OR dy%=0
// DEBUG id%+"\n"
//// KEYWAIT
// ENDIF
//
//
// spr.id%=id%
// spr.offset=offset
// spr.yOffset=yOffset
// DIMPUSH self.segments[n%].sprites[],spr
ENDFUNCTION
FUNCTION addRoad%:segments[] AS tSegment,enter, hold, leave, curve, y, offset
LOCAL startY,endY,total
LOCAL n%
startY=self.lastY(segments)
endY=startY+(y*self.segmentLength%)
total=enter+hold+leave
// DEBUG "Start Y : "+startY+" endY : "+endY+"\n"
// KEYWAIT
FOR n%=0 TO enter-1
self.addSegment(segments[],self.easeIn(0,curve,n%/enter),easeInOut(startY,endY,n%/total),offset)
NEXT
// DEBUG "Holding ---\n"
FOR n%=0 TO hold-1
self.addSegment(segments[],curve,self.easeInOut(startY,endY,(enter+n%)/total),offset)
NEXT
// DEBUG "---\n"
FOR n%=0 TO leave-1
self.addSegment(segments[],self.easeInOut(curve,0,n%/leave),self.easeInOut(startY,endY,(enter+hold+n)/total),offset)
NEXT
ENDFUNCTION
FUNCTION addStraight%:segments[] AS tSegment,num=25,offset%=0
self.addRoad(segments[],num,num,num,0,0,offset%)
ENDFUNCTION
FUNCTION addHill%:segments[] AS tSegment,num,height,offset%=0
self.addRoad(segments[],num,num,num,0,height,offset%)
ENDFUNCTION
FUNCTION addCurve%:segments[] AS tSegment,num, curve,height,offset%=0
self.addRoad(segments[],num,num,num,curve,height,offset)
ENDFUNCTION
FUNCTION addLowRollingHills%:segments[] AS tSegment,num,height,offset%=0
self.addRoad(segments[],num, num, num, 0, height/2,offset%)
self.addRoad(segments[],num, num, num, 0, -height,offset%)
self.addRoad(segments[],num, num, num, 0, height,offset%)
self.addRoad(segments[],num, num, num, 0, 0,offset%)
self.addRoad(segments[],num, num, num, 0, height/2,offset%)
self.addRoad(segments[],num, num, num, 0, 0,offset%)
ENDFUNCTION
FUNCTION addSCurves%:segments[] AS tSegment
// self.addRoad(ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, -ROAD_CURVE_EASY, ROAD_HILL_NONE)
// self.addRoad(ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_CURVE_MEDIUM, ROAD_HILL_MEDIUM)
// self.addRoad(ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_CURVE_EASY, -ROAD_HILL_LOW)
// self.addRoad(ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, -ROAD_CURVE_EASY, ROAD_HILL_MEDIUM)
// self.addRoad(ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, ROAD_LENGTH_MEDIUM, -ROAD_CURVE_MEDIUM, -ROAD_HILL_MEDIUM)
ENDFUNCTION
FUNCTION addBumps%:
// self.addRoad(10, 10, 10, 0, 5);
// self.addRoad(10, 10, 10, 0, -2);
// self.addRoad(10, 10, 10, 0, -5);
// self.addRoad(10, 10, 10, 0, 8);
// self.addRoad(10, 10, 10, 0, 5);
// self.addRoad(10, 10, 10, 0, -7);
// self.addRoad(10, 10, 10, 0, 5);
// self.addRoad(10, 10, 10, 0, -2);
ENDFUNCTION
FUNCTION addDownhillToEnd%:num=200
// self.addRoad(num, num, num, -ROAD_CURVE_EASY, -lastY()/self.segmentLength);
ENDFUNCTION
FUNCTION resetRoad%:
LOCAL segment AS tSegment
DIM self.segments[0]
DIM self.cars[0]
self.addStraight(self.segments[],ROAD_LENGTH_SHORT%,0)
self.addCurve(self.segments[],ROAD_LENGTH_SHORT%,-ROAD_CURVE_MEDIUM%,ROAD_HILL_HIGH%,0)
// self.addCurve(self.segments[],ROAD_LENGTH_SHORT,-ROAD_CURVE_MEDIUM%,ROAD_HILL_HIGH%,0)
// self.addCurve(self.segments[],ROAD_LENGTH_SHORT%,-ROAD_CURVE_MEDIUM%,-ROAD_HILL_HIGH%,0)
// self.addCurve(self.segments[],ROAD_LENGTH_LONG%,ROAD_CURVE_MEDIUM%,ROAD_HILL_NONE%,0)
// self.addStraight(self.segments[],ROAD_LENGTH_LONG%,0)
// self.addStraight(self.segments[],ROAD_LENGTH_LONG%,0)
// self.addStraight(self.segments[],ROAD_LENGTH_LONG%,0)
// self.addCurve(self.segments[],ROAD_LENGTH_LONG%,-ROAD_CURVE_MEDIUM%,ROAD_HILL_NONE%,0)
// self.addCurve(self.segments[],ROAD_LENGTH_SHORT%,ROAD_CURVE_MEDIUM%,ROAD_HILL_NONE%,0)
// self.addStraight(self.segments[],ROAD_LENGTH_LONG%,0)
// self.addCurve(self.segments[],ROAD_LENGTH_LONG%,-ROAD_CURVE_MEDIUM%,ROAD_HILL_NONE%,0)
self.addHill(self.segments[],ROAD_LENGTH_SHORT%,ROAD_HILL_HIGH%,0)
self.addHill(self.segments[],ROAD_LENGTH_MEDIUM%,-ROAD_HILL_HIGH%,0)
// self.addCurve(self.segments[],ROAD_LENGTH_MEDIUM%, ROAD_CURVE_MEDIUM%, -ROAD_HILL_HIGH%,0)
// self.addCurve(self.segments[],ROAD_LENGTH_LONG%, -ROAD_CURVE_EASY%, -ROAD_HILL_HIGH%,0)
// self.addHill(self.segments[],ROAD_LENGTH_LONG%,-ROAD_HILL_HIGH%,0)
// self.addHill(self.segments[],ROAD_LENGTH_SHORT%,-ROAD_HILL_HIGH%,0)
// self.addHill(self.segments[],ROAD_LENGTH_LONG%,-ROAD_HILL_HIGH%,0)
// self.addLowRollingHills(self.segments[],ROAD_LENGTH_SHORT%,ROAD_HILL_LOW%,0)
//// self.addSCurves(segments[])
// self.addCurve(self.segments[],ROAD_LENGTH_LONG%, ROAD_CURVE_NONE%, ROAD_HILL_HIGH%)
// self.addCurve(self.segments[],ROAD_LENGTH_MEDIUM%, ROAD_CURVE_MEDIUM%, ROAD_HILL_LOW)
// self.addBumps()
// self.addLowRollingHills(ROAD_LENGTH_SHORT%,ROAD_HILL_LOW%)
// self.addCurve(self.segments[],ROAD_LENGTH_LONG%*2, ROAD_CURVE_MEDIUM%, ROAD_HILL_MEDIUM%)
// self.addStraight()
// self.addHill(self.segments[],ROAD_LENGTH_MEDIUM%, ROAD_HILL_HIGH%)
// self.addSCurves()
// self.addCurve(self.segments[],ROAD_LENGTH_SHORT%, ROAD_CURVE_NONE%, -ROAD_HILL_HIGH%)
// self.addCurve(self.segments[],ROAD_LENGTH_LONG%, -ROAD_CURVE_MEDIUM%, ROAD_HILL_NONE%)
// self.addHill(self.segments[],ROAD_LENGTH_LONG%, -ROAD_HILL_HIGH%)
// self.addCurve(self.segments[],ROAD_LENGTH_LONG%, ROAD_CURVE_MEDIUM%, -ROAD_HILL_LOW%)
// self.addBumps()
// self.addHill(self.segments[],ROAD_LENGTH_LONG%, ROAD_HILL_MEDIUM%)
// self.addStraight()
// self.addSCurves()
// self.addDownhillToEnd()
self.resetSprites()
self.resetCars()
//segment=self.findSegment(self.segments[],self.playerZ)
// self.segments[segment.index% + 2].colour.road% = RGB(255,255,255)
// self.segments[segment.index% + 2].colour.lane% = RGB(255,255,255)
// self.segments[segment.index% + 3].colour.road% = RGB(255,255,255)
// self.segments[segment.index% + 3].colour.lane% = RGB(255,255,255)
//
// FOR n%=0 TO self.rumbleLength%-1
// self.segments[BOUNDS(self.segments[],0)-1-n%].colour.road% = RGB(255,255,255)
// self.segments[BOUNDS(self.segments[],0)-1-n%].colour.lane% = RGB(255,255,255)
// NEXT
// self.segments[30].tunnel%=1
// FOR n%=31 TO 501
// IF n%<501
// self.segments[n%].tunnel%=2
// ELSE
// self.segments[n%].tunnel%=3
// ENDIF
// NEXT
self.trackLength% = BOUNDS(self.segments[],0)*self.segmentLength%
ENDFUNCTION
FUNCTION RndFloat:
RETURN RND(1000)/1000.0
ENDFUNCTION
FUNCTION accelerate:v,accel,dt
RETURN v + (accel * dt)
ENDFUNCTION
FUNCTION limit:value, minV,maxV
RETURN MAX(minV,MIN(value,maxV))
ENDFUNCTION
FUNCTION easeIn:a,b,percent
RETURN a + (b-a)*POW(percent,2)
ENDFUNCTION
FUNCTION easeOut:a,b,percent
RETURN a + (b-a)*(1.0-POW(1-percent,2))
ENDFUNCTION
FUNCTION easeInOut:a,b,percent
LOCAL cosV,v
// DEBUG "A:"+a+" B:"+b+" Percent:"+percent+"\n"
cosV=(percent*PI)*(180.0/PI)
v=a + (b-a)*((-COS(cosV)/2.0) + 0.5)
// DEBUG "Value : "+v+"\n"
RETURN v
ENDFUNCTION
FUNCTION percentageRemaining:n,total
RETURN FMOD(n,total)/total
ENDFUNCTION
FUNCTION interpolate:a,b,percent
RETURN a+(b-a)*percent
ENDFUNCTION
FUNCTION resetSprites%:
LOCAL n%
self.addGraphic(TRUE,self.segmentLength%*20, 0,SPRITES_BILLBOARD_07%, -1,0.0)
self.addGraphic(TRUE,self.segmentLength%*40, 0,-1, -1.5,0.0); self.addGraphic(TRUE,self.segmentLength%*40, 0,-1, 1.5,0.0); self.addGraphic(TRUE,self.segmentLength%*40, 0,-2, -0.5,0.0,-3800)
self.addGraphic(TRUE,self.segmentLength%*60, 0,SPRITES_BILLBOARD_06%, -1,0.0)
self.addGraphic(TRUE,self.segmentLength%*80, 0,SPRITES_STUMP%, 0,0.0)
self.addGraphic(TRUE,self.segmentLength%*100, 0,SPRITES_STUMP%, -0.5,0.0);
self.addGraphic(TRUE,self.segmentLength%*120, 0,SPRITES_STUMP%, 0.5,0.0)
self.addGraphic(TRUE,self.segmentLength%*140, 0,SPRITES_BILLBOARD_08%, -1,0.0)
RETURN
// self.addSprite(80, SPRITES_BILLBOARD_09%, -1)
// self.addSprite(100, SPRITES_BILLBOARD_01%, -1)
// self.addSprite(120, SPRITES_BILLBOARD_02%, -1)
// self.addSprite(140, SPRITES_BILLBOARD_03%, -1)
// self.addSprite(160, SPRITES_BILLBOARD_04%, -1)
// self.addSprite(180, SPRITES_BILLBOARD_05%, -1)
//
// self.addSprite(240, SPRITES_BILLBOARD_07%, -1.2);
// self.addSprite(240, SPRITES_BILLBOARD_06%, 1.2);
// self.addSprite(BOUNDS(self.segments[],0) - 25, SPRITES_BILLBOARD_07%, -1.2);
// self.addSprite(BOUNDS(self.segments[],0) - 25, SPRITES_BILLBOARD_06%, 1.2);
//
// n%=10
// WHILE n%<200
// self.addSprite(n,SPRITES_PALM_TREE%,0.5+(self.RndFloat()*0.5))
// self.addSprite(n,SPRITES_PALM_TREE%,1+(self.RndFloat()*2))
// INC n%,4+FLOOR(n%/100)
// WEND
//
// FOR n%=250 TO 1000 STEP 5
// self.addSprite(n,SPRITES_COLUMN%,1.1)
// self.addSprite(n%+RND(5),SPRITES_DEAD_TREE1%,-1-(self.RndFloat()*2))
// self.addSprite(n%+RND(5),SPRITES_DEAD_TREE2%,-1-(self.RndFloat()*2))
// NEXT
//
// FOR n%=200 TO BOUNDS(self.segments[],0) STEP 3
// LOCAL index%,i%,v
//
// i%=RND(12)
//
// SELECT i%
// CASE 0
// index%=SPRITES_TREE1%
//
// CASE 1
// index%=SPRITES_TREE2%
//
// CASE 2
// index%=SPRITES_DEAD_TREE1%
//
// CASE 3
// index%=SPRITES_DEAD_TREE2%
//
// CASE 4
// index%=SPRITES_PALM_TREE%
//
// CASE 5
// index%=SPRITES_BUSH1%
//
// CASE 6
// index%=SPRITES_BUSH2%
//
// CASE 7
// index%=SPRITES_BUSH2%
//
// CASE 8
// index%=SPRITES_CATCUS%
//
// CASE 9
// index%=SPRITES_STUMP%
//
// CASE 10
// index%=SPRITES_BOULDER1%
//
// CASE 11
// index%=SPRITES_BOULDER2%
//
// CASE 12
// index%=SPRITES_BOULDER3%
//
// DEFAULT
// DEBUG "Ooops!"
// ENDSELECT
//
// IF RND(100)<50
// v=-1.0
// ELSE
// v=1
// ENDIF
//
// self.addSprite(n%,index%,v*(2+self.RndFloat()*5.0))
// NEXT
ENDFUNCTION
FUNCTION resetCars%:
LOCAL n%,id%,v%,div%
// LOCAL car AS tGraphic
// LOCAL index%,v%,div%
FOR n%=0 TO self.totalCars%
// car.offset=RndFloat()*((RND(16)-8)/10)
// car.z=
v%=RND(5)
SELECT v%
CASE 0
id%=CARS_CAR_01%
div%=2
CASE 1
id%=CARS_CAR_02%
div%=2
CASE 2
id%=CARS_CAR_03%
div%=2
CASE 3
id%=CARS_CAR_04%
div%=2
CASE 4
id%=CARS_SEMI%
div%=4
CASE 5
id%=CARS_TRUCK%
div%=2
ENDSELECT
self.addGraphic(FALSE,FLOOR(RndFloat()*BOUNDS(self.segments[],0))*self.segmentLength,0,id%,RndFloat()*((RND(16)-8)/10), _
self.maxSpeed/4.0+RndFloat()*self.maxSpeed/div%)
// car.speed=self.maxSpeed/4.0+RndFloat()*self.maxSpeed/div%
// car.percent=0.0
// car.which%=BOUNDS(self.cars[],0)
// DIMPUSH self.segments[MOD(FLOOR(car.z/self.segmentLength%),BOUNDS(self.segments[],0))].cars[],car
// DIMPUSH self.cars[],car
NEXT
ENDFUNCTION
FUNCTION lastY:segments[] AS tSegment
LOCAL size%
size%=BOUNDS(segments[],0)
IF size%=0
RETURN 0
ELSE
RETURN segments[size%-1].roads[0].p2.world.y
ENDIF
ENDFUNCTION
FUNCTION findSegment AS tSegment:segments[] AS tSegment,z
RETURN segments[MOD(FLOOR(z/self.segmentLength%),BOUNDS(segments[],0))]
ENDFUNCTION
FUNCTION increase: start,increment,maxV
LOCAL result
result=start+increment
WHILE result>=maxV
DEC result,maxV
WEND
WHILE result<0
INC result,maxV
WEND
RETURN result
ENDFUNCTION
FUNCTION fog%:x%,y%,width%,height%
ALPHAMODE -0.9
DRAWRECT x%,y%,width%,height%,RGB(64,64,64)
ALPHAMODE -1.0
ENDFUNCTION
FUNCTION updateCars%:dt,playerSegment AS tSegment,playerW
LOCAL n%
LOCAL oldSegment AS tSegment,newSegment AS tSegment
//LOCAL road AS TRoad
LOCAL oldIndex%,newIndex%
FOR n%=0 TO BOUNDS(self.cars[],0)-1
oldSegment=self.findSegment(self.segments[],self.cars[n%].z)
oldIndex%=FMOD(FLOOR(self.cars[n%].z/self.segmentLength%),BOUNDS(self.segments[],0))
INC self.cars[n%].xOffset,self.updateCarOffset(self.cars[n%],oldSegment,playerSegment,playerW)
self.cars[n%].z=self.increase(self.cars[n%].z,dt*self.cars[n%].moveSpeed,self.trackLength)
self.cars[n%].percent=self.percentageRemaining(self.cars[n%].z,self.segmentLength)
newSegment=self.findSegment(self.segments[],self.cars[n%].z)
newIndex%=FMOD(FLOOR(self.cars[n%].z/self.segmentLength%),BOUNDS(self.segments[],0))
//DEBUG "NZ:"+self.cars[n%].moveSpeed+"\n"
//DEBUG "Speed : "+self.cars[n%].speed+"\n"
// DEBUG "O:"+oldIndex%+" N:"+newIndex%+" "+self.cars[n%].percent+"\n"
IF oldIndex%<>newIndex%
// DEBUG "Here1\n"
// KEYWAIT
//FOREACH road IN self.segments[oldIndex%].roads[]
//DEBUG "Road index : "+self.cars[n%].index%
// DEBUG "Size : "+BOUNDS(self.segments[oldIndex].roads[self.cars[n%].roadIndex%].cars[],0)+"\n"
// DEBUG "OI:"+oldIndex%+" "+self.cars[n%].roadIndex%+"\n"
// KEYWAIT
FOR index%=0 TO BOUNDS(self.segments[oldIndex].roads[self.cars[n%].roadIndex%].cars[],0)-1
//DEBUG self.segments[oldIndex].roads[self.cars[n%].roadIndex%].cars[index%].index%+" "+self.cars[n%].index%+"\n"
IF self.segments[oldIndex].roads[self.cars[n%].roadIndex%].cars[index%].index%=self.cars[n%].index%
DIMDEL self.segments[oldIndex].roads[self.cars[n%].roadIndex%].cars[],index%
DIMPUSH self.segments[newIndex].roads[self.cars[n%].roadIndex%].cars[],self.cars[n%]
// DEBUG "Found\n"
// KEYWAIT
ENDIF
NEXT
// //KEYWAIT
ENDIF
NEXT
ENDFUNCTION
FUNCTION overlap:x1,w1,x2,w2,percent=1.0
LOCAL half,min1,min2,max1,max2
half = percent/2;
min1 = x1 - (w1*half)
max1 = x1 + (w1*half)
min2 = x2 - (w2*half)
max2 = x2 + (w2*half)
RETURN IIF(max1<min2 OR min1>max2,FALSE,TRUE)
ENDFUNCTION
FUNCTION updateCarOffset:car AS tGraphic,carSegment AS tSegment,playerSegment AS tSegment,playerW
LOCAL i%,j%
LOCAL carW,dir,otherCarW
LOCAL lookAhead%=30
LOCAL segment AS tSegment
LOCAL otherCar AS tGraphic
LOCAL segmentIndex%,playerIndex%
carW=car.orgXSize*self.SPRITES_SCALE
IF carSegment.index-playerSegment.index>self.drawDistance THEN RETURN 0.0
playerIndex%=FMOD(FLOOR(playerSegment.roads[0].p1.world.z/self.segmentLength%),BOUNDS(self.segments[],0))
FOR i%=1 TO lookAhead%-1
segmentIndex%=FMOD(FLOOR(carSegment.index+i%),BOUNDS(self.segments[],0))
IF segmentIndex%=playerIndex% AND car.moveSpeed>self.playerInfo.speed AND self.overlap(self.playerInfo.graphic.xOffset, playerW, car.xOffset, carW, 1.2)
IF self.playerInfo.graphic.xOffset>0.5
dir=-1.0
ELSEIF (self.playerInfo.graphic.xOffset<-0.5)
dir=1.0
ELSE
dir=IIF(car.xOffset>self.playerInfo.graphic.xOffset,1,-1)
ENDIF
RETURN dir*1/i*(car.moveSpeed-self.playerInfo.speed)/self.maxSpeed
ENDIF
FOR j%=0 TO BOUNDS(self.segments[segmentIndex%].roads[0].cars[],0)-1
otherCar=self.segments[segmentIndex%].roads[0].cars[j%]
otherCarW=otherCar.orgXSize*self.SPRITES_SCALE
//
IF car.speed>otherCar.moveSpeed AND self.overlap(car.xOffset, carW, otherCar.xOffset, otherCarW, 1.2)
IF otherCar.xOffset>0.5
dir=-1
ELSEIF otherCar.xOffset<-0.5
dir=1
ELSE
dir=IIF(car.xOffset>otherCar.xOffset,1,-1)
ENDIF
//
RETURN dir*1/i*(car.speed-otherCar.speed)/self.maxSpeed
ENDIF
NEXT
NEXT
IF car.xOffset<-0.9
RETURN 0.1
ELSEIF car.xOffset>0.9
RETURN -0.1
ELSE
RETURN 0.0
ENDIF
ENDFUNCTION
FUNCTION update%:dt
LOCAL dx
LOCAL playerSegment AS tSegment
LOCAL startPosition,speedPercentage
LOCAL playerW // ,tW%,tH%
// DEBUG dt+"\n"
// DEBUG "Speed:"+self.speed+"\n"
// DEBUG (dt*self.speed)+"\n"
playerW=self.playerInfo.graphic.orgXSize*self.SPRITES_SCALE
playerSegment=self.findSegment(self.segments[],self.playerInfo.graphic.z+self.playerInfo.cameraZ)
startPosition=self.playerInfo.graphic.z
speedPercentage=self.playerInfo.speed/self.maxSpeed
self.playerInfo.segmentIndex%=MOD(FLOOR(self.playerInfo.graphic.z/self.segmentLength%),BOUNDS(self.segments[],0))
self.playerInfo.playerPercent=self.percentageRemaining(self.playerInfo.graphic.z+self.playerInfo.cameraZ,self.segmentLength%)
self.playerInfo.graphic.z = self.increase(self.playerInfo.graphic.z, dt * self.playerInfo.speed, self.trackLength)
//DEBUG self.playerInfo.playerPercent+"\n"
//self.playerInfo.playerSegment= findSegment(self.segments[],self.playerInfo.graphic.z+self.playerInfo.graphic.z)
dx = dt * 2 * (self.playerInfo.speed/self.maxSpeed); // at top speed, should be able to cross from left to right (-1 to 1) in 1 second
self.updateCars(dt,playerSegment,playerW)
IF KEY(203)
DEC self.playerInfo.graphic.xOffset,dx
self.keyLeftRight%=-1
ELSEIF KEY(205)
INC self.playerInfo.graphic.xOffset,dx
self.keyLeftRight%=1
ELSE
self.keyLeftRight%=0
ENDIF
self.playerInfo.graphic.xOffset = self.playerInfo.graphic.xOffset - (dx * speedPercentage * playerSegment.curve * self.centrifugal)
IF KEY(200)
self.playerInfo.speed=self.accelerate(self.playerInfo.speed,self.accel,dt)
ELSEIF KEY(208)
self.playerInfo.speed=self.accelerate(self.playerInfo.speed,self.breaking,dt)
ELSE
self.playerInfo.speed=self.accelerate(self.playerInfo.speed,self.decel,dt)
ENDIF
IF self.playerInfo.graphic.xOffset<-1 OR self.playerInfo.graphic.yOffset>1
IF self.playerInfo.speed>self.offRoadLimit
self.playerInfo.speed=self.accelerate(self.playerInfo.speed,self.offRoadDecel,dt)
ENDIF
// FOR n%=0 TO BOUNDS(playerSegment.sprites[],0)-1
// LOCAL sprite AS tSprite
// LOCAL sW,sH,spriteW
//
// sprite=playerSegment.sprites[n%]
// GETSPRITESIZE sprite.id%,sW,sH // Need to calculate current size and not the original size
//
// spriteW=sW*self.SPRITES_SCALE
//
// IF self.overlap(self.playerX,playerW,sprite.offset+spriteW/2*IIF(sprite.offset>0,1,-1),spriteW)
// self.speed=self.maxSpeed/5.0
// self.position=increase(playerSegment.p1.world.z,-self.playerZ,self.trackLength)
// BREAK
// ENDIF
// NEXT
ENDIF
// FOR n%=0 TO BOUNDS(playerSegment.cars[],0)-1
// LOCAL car AS tCar
// LOCAL sW,sH,carW
//
// car=playerSegment.cars[n%]
// GETSPRITESIZE car.id%,sW,sH
// carW=sW*self.SPRITES_SCALE
//
// IF self.speed>car.speed
// IF self.overlap(self.playerX,playerW,car.offset,carW,0.8)
// self.speed=car.speed*(car.speed/self.speed)
// self.position=increase(car.z,-self.playerZ,self.trackLength)
// BREAK
// ENDIF
// ENDIF
// NEXT
//
self.playerInfo.graphic.xOffset=self.limit(self.playerInfo.graphic.xOffset,-3,3)
self.playerInfo.speed=self.limit(self.playerInfo.speed,0.0,self.maxSpeed)
self.skyOffset=self.increase(self.skyOffset, self.skySpeed * playerSegment.curve * (self.playerInfo.graphic.z-startPosition)/self.segmentLength, 1);
self.hillOffset = self.increase(self.hillOffset, self.hillSpeed * playerSegment.curve * (self.playerInfo.graphic.z-startPosition)/self.segmentLength, 1);
self.treeOffset = self.increase(self.treeOffset, self.treeSpeed * playerSegment.curve * (self.playerInfo.graphic.z-startPosition)/self.segmentLength, 1);
ENDFUNCTION
FUNCTION project%:p AS tPart, cameraX, cameraY, cameraZ, cameraDepth, swidth, sheight, roadWidth%, rumbleWidth%
p.camera.x=p.world.x - cameraX
p.camera.y=p.world.y - cameraY
p.camera.z=p.world.z - cameraZ
p.screen.scale=cameraDepth/p.camera.z
p.screen.x=((swidth/2.0)+(p.screen.scale*p.camera.x*swidth/2.0))
p.screen.y=((sheight/2.0)-(p.screen.scale*p.camera.y*sheight/2.0))
p.screen.w=(p.screen.scale*roadWidth%*swidth/2.0)
p.rumbleWidth=p.screen.w/rumbleWidth%
ENDFUNCTION
FUNCTION player%:width%, height%, resolution, roadWidth, graphic AS tGraphic, speedPercent, scale, destX, destY, steer, updown
LOCAL bounce
LOCAL sprite%
bounce=(1.5 *RndFloat() * speedPercent * resolution) * (RND(2)-1)
IF steer<0
sprite%=IIF(updown>0,PLAYER_UPHILL_LEFT%,PLAYER_LEFT%)
ELSEIF steer>0
sprite%=IIF(updown>0,PLAYER_UPHILL_RIGHT%,PLAYER_RIGHT%)
ELSE
sprite%=IIF(updown>0,PLAYER_UPHILL_STRAIGHT%,PLAYER_STRAIGHT%)
ENDIF
//DEBUG "SP:"+sprite%+"\n"
//DEBUG "Dest Y : "+destY+"\n"
self.sprite(width%,height%,resolution,roadWidth,graphic,scale,destX,destY+bounce,-0.5,-1)
ENDFUNCTION
FUNCTION sprite%:width%, height%, resolution, roadWidth, graphic AS tGraphic, scale, destX, destY, offsetX, offsetY, clipY=0.0
LOCAL clipH
graphic.currentXSize=(graphic.orgXSize*scale*width%/2.0)*(self.SPRITES_SCALE*roadWidth)
graphic.currentYSize=(graphic.orgYSize*scale*width%/2.0)*(self.SPRITES_SCALE*roadWidth)
INC destX,graphic.currentXSize*offsetX
INC destY,graphic.currentYSize*offsetY
clipH=IIF(clipY,MAX(0,destY+graphic.currentYSize-clipY),0)
// DEBUG destW+" "+(destH-clipH)+"\n"
// KEYWAIT
IF clipH<graphic.currentYSize
IF graphic.id%>=0
STRETCHSPRITE graphic.id%,destX,destY,graphic.currentXSize,graphic.currentYSize-clipH
ELSE
DRAWRECT destX,destY,graphic.currentXSize,graphic.currentYSize-clipH,RGB(255,255,255)
ENDIF
ENDIF
ENDFUNCTION
FUNCTION background%:spr%,width%,height%,layer%,rotation=0.0,offset=0.0
LOCAL w,h,imageW,imageH
LOCAL sourceX,sourceY,sourceW,sourceH
LOCAL destX,destY,destW,destH
GETSPRITESIZE spr%,w,h
imageW=w/2.0
imageH=h
sourceX=0.0+FLOOR(w*rotation)
sourceY=0.0
sourceW=MIN(imageW,0+w-sourceX)
sourceH=imageH
destX=FLOOR(w * rotation)
IF destX<=-0.0-width%
destX=width%
ELSEIF destX>=width%
destX=0.0-width%
ENDIF
destY=offset
destW=width% // FLOOR(width*(sourceW/imageW))
destH=height%
STRETCHSPRITE spr%,destX,destY,destW,destH
STRETCHSPRITE spr%,destX-width%,destY,destW,destH
STRETCHSPRITE spr%,destX+width%,destY,destW,destH
ENDFUNCTION
FUNCTION render%:
LOCAL baseSegment AS tSegment,playerSegment AS tSegment
//LOCAL basePercentage
LOCAL playerY,playerPercent
LOCAL maxy,n%,spriteID%,sIndex%,r%,index%
LOCAL graphic AS tGraphic
LOCAL graphicScale,graphicX,graphicY
LOCAL seg AS tSegment
LOCAL x,dx
LOCAL indexes[] AS tRoadPos
LOCAL indexLoop AS tRoadPos
maxy=self.height%
baseSegment = self.findSegment(self.segments[],self.playerInfo.graphic.z)
playerSegment=self.findSegment(self.segments[],self.playerInfo.graphic.z+self.playerInfo.cameraZ)
//playerPercent=self.percentageRemaining(self.playerInfo.position+self.playerInfo.graphic.z,self.segmentLength%)
playerY= self.interpolate(playerSegment.roads[0].p1.world.y, _
playerSegment.roads[0].p2.world.y, _
self.playerInfo.playerPercent)
x=0.0
dx=-(baseSegment.curve*self.percentageRemaining(self.playerInfo.graphic.z,self.segmentLength%))
self.background(BACKGROUND_SKY%, self.width%, self.height%, BACKGROUND_SKY%, self.skyOffset, self.resolution * self.skySpeed * playerY)
self.background(BACKGROUND_HILLS%, self.width%, self.height%, BACKGROUND_HILLS%, self.hillOffset, self.resolution * self.hillSpeed * playerY)
self.background(BACKGROUND_TREES%, self.width%, self.height%, BACKGROUND_TREES%, self.treeOffset, self.resolution * self.treeSpeed * playerY);
PRINT baseSegment.index%,0,16
// Part 1 - Calculate all segment positions for all roads
FOR n%=0 TO self.drawDistance%-1
sIndex%=MOD(baseSegment.index%+n%,BOUNDS(self.segments[],0))
// Calculate all segment positions and scaling values
self.segments[sIndex%].clip=maxy
FOR index%=0 TO BOUNDS(self.segments[sIndex%].roads[],0)-1
self.project(self.segments[sIndex%].roads[index%].p1, _
(self.playerInfo.graphic.xOffset*self.segments[sIndex%].roads[index%].roadWidth%)-x, _
playerY+self.playerInfo.cameraHeight, _
self.playerInfo.graphic.z, _
self.playerInfo.cameraDepth, self.width%,self.height%, _
self.segments[sIndex%].roads[index%].roadWidth%, _
self.segments[sIndex%].roads[index%].rumbleWidth%)
self.project(self.segments[sIndex%].roads[index%].p2, _
(self.playerInfo.graphic.xOffset*self.segments[sIndex%].roads[index%].roadWidth%)-x-dx, _
playerY+self.playerInfo.cameraHeight, _
self.playerInfo.graphic.z, _
self.playerInfo.cameraDepth, _
self.width%,self.height%, _
self.segments[sIndex%].roads[index%].roadWidth%,self.segments[sIndex%].roads[index%].rumbleWidth%)
NEXT
INC x,dx
INC dx,baseSegment.curve
FOR index%=0 TO 0
IF self.segments[sIndex%].roads[index%].p1.camera.z<=self.playerInfo.cameraDepth OR _
self.segments[sIndex%].roads[index%].p2.screen.y >= maxy
CONTINUE
ELSE
self.drawRoad(self.width%,self.segments[sIndex%].roads[index%])
ENDIF
NEXT
maxy=self.segments[sIndex%].roads[0].p1.screen.y
NEXT
// Part 2 - Make sure that not duplicate roads would be displayed
self.player(self.width%, self.height%, self.resolution, 4000 , _
self.playerInfo.graphic,self.playerInfo.speed/self.maxSpeed, _
self.playerInfo.cameraDepth/self.playerInfo.cameraZ, _
self.width%/2, _
(self.height/2.0)- (self.playerInfo.cameraDepth/self.playerInfo.cameraZ * self.interpolate(playerSegment.roads[0].p1.camera.y, playerSegment.roads[0].p2.camera.y, self.playerInfo.playerPercent) * self.height/2.0), _
self.playerInfo.speed * SGN(self.keyLeftRight%), _
self.segments[self.playerInfo.segmentIndex%].roads[0].p2.world.y - self.segments[self.playerInfo.segmentIndex%].roads[0].p1.world.y)
// IF playerSegment.tunnel%=2
// ALPHAMODE -0.3
// DRAWRECT 0,0,self.width,self.height%,RGB(1,1,1)
// ENDIF
ENDFUNCTION
FUNCTION laneMarkerWidth:projectedRoadWidth%,lanes%
RETURN projectedRoadWidth/MAX(32,8*lanes%)
ENDFUNCTION
FUNCTION polygon2%:x%,y%,width%,height%
STARTPOLY -1
POLYVECTOR width%,y%,0,0,RGB(0,255,0)
POLYVECTOR x%,y%,0,0,RGB(255,0,0)
POLYVECTOR x%,height%,0,0,RGB(0,255,0)
POLYVECTOR width%,height%,0,0,RGB(0,0,255)
ENDPOLY
ENDFUNCTION
FUNCTION polygon%:x1,y1,x2,y2,x3,y3,x4,y4,colour%
STARTPOLY -1,0
POLYVECTOR (x1),(y1),(x2),(y2),colour%
POLYVECTOR (x2),(y2),(x3),(y3),colour%
POLYVECTOR (x3),(y3),(x4),(y4),colour%
POLYVECTOR (x4),(y4),(x1),(y1),colour%
ENDPOLY
// DRAWRECT x1,y1,x2,y2,colour%
// DRAWRECT x3,y3,x4,y4,colour%
//DRAWLINE x1,y1,x2,y2,colour%
//DRAWLINE x3,y3,x4,y4,colour%
ENDFUNCTION
FUNCTION drawRoad%:width%,segment AS tSegmentPart
LOCAL r1,r2,l1,l2,lanew1,lanew2,lanex1,lanex2
// DRAWRECT 0,.p2.screen.y, _
// self.width%,self.segments[sIndex%].roads[0].p1.screen.y-self.segments[sIndex%].roads[0].p2.screen.y, _
// self.segments[sIndex%].roads[0].colour.rightGrass%
self.polygon(segment.p1.screen.x-segment.p1.screen.w, segment.p1.screen.y, _
segment.p1.screen.x+segment.p1.screen.w, segment.p1.screen.y, _
segment.p2.screen.x+segment.p2.screen.w, segment.p2.screen.y, _
segment.p2.screen.x-segment.p2.screen.w, segment.p2.screen.y, _
segment.colour.road)
IF segment.numLanes%>0
l1=self.laneMarkerWidth(segment.p1.screen.w,segment.numLanes%)
l2=self.laneMarkerWidth(segment.p2.screen.w,segment.numLanes%)
lanew1=segment.p1.screen.w*2.0/segment.numLanes%
lanew2=segment.p2.screen.w*2.0/segment.numLanes%
lanex1=segment.p1.screen.x-segment.p1.screen.w+lanew1
lanex2=segment.p2.screen.x-segment.p2.screen.w+lanew2
FOR lane%=1 TO segment.numLanes%-1
self.polygon(lanex1-l1/2.0,segment.p1.screen.y, _
lanex1+l1/2.0,segment.p1.screen.y, _
lanex2+l2/2.0,segment.p2.screen.y, _
lanex2-l2/2.0,segment.p2.screen.y, _
segment.colour.lane%)
INC lanex1,lanew1
INC lanex2,lanew2
NEXT
ENDIF
ENDFUNCTION
FUNCTION drawRumble%:roadPos AS tSegmentPart,dir%
IF dir%>0
self.polygon( roadPos.p1.screen.x+roadPos.p1.screen.w+roadPos.p1.rumbleWidth, roadPos.p1.screen.y, _
roadPos.p1.screen.x+roadPos.p1.screen.w, roadPos.p1.screen.y, _
roadPos.p2.screen.x+roadPos.p2.screen.w, roadPos.p2.screen.y, _
roadPos.p2.screen.x+roadPos.p2.screen.w+roadPos.p2.rumbleWidth, roadPos.p2.screen.y, _
roadPos.colour.rumble)
ELSEIF dir%<0
self.polygon( roadPos.p1.screen.x-roadPos.p1.screen.w-roadPos.p1.rumbleWidth, roadPos.p1.screen.y, _
roadPos.p1.screen.x-roadPos.p1.screen.w, roadPos.p1.screen.y, _
roadPos.p2.screen.x-roadPos.p2.screen.w, roadPos.p2.screen.y, _
roadPos.p2.screen.x-roadPos.p2.screen.w-roadPos.p2.rumbleWidth, roadPos.p2.screen.y, _
roadPos.colour.rumble)
ENDIF
ENDFUNCTION
FUNCTION drawGrass%:roadPos AS tSegmentPart,width%,dir%
IF dir%=TRUE
self.polygon(0, roadPos.p1.screen.y, _
roadPos.p1.screen.x-roadPos.p1.screen.w-roadPos.p1.rumbleWidth, roadPos.p1.screen.y, _
roadPos.p2.screen.x-roadPos.p2.screen.w-roadPos.p2.rumbleWidth, roadPos.p2.screen.y, _
0, roadPos.p2.screen.y, _
roadPos.colour.leftGrass%)
ELSE
self.polygon(width%, roadPos.p1.screen.y, _
roadPos.p1.screen.x+roadPos.p1.screen.w+roadPos.p1.rumbleWidth, roadPos.p1.screen.y, _
roadPos.p2.screen.x+roadPos.p2.screen.w+roadPos.p2.rumbleWidth, roadPos.p2.screen.y, _
width%, roadPos.p2.screen.y, _
roadPos.colour.rightGrass%)
ENDIF
ENDFUNCTION
ENDTYPE
LOCAL road AS TRoad
LOCAL now,last,dt=0.0,gdt=0.0,stp=1.0/75.0
SETSCREEN 640,480,FALSE
LIMITFPS -1
PLAYMUSIC "Media/arc_or2_mss.mp3",FALSE
LOADSPRITE "Media/player_straight.png",PLAYER_STRAIGHT%
LOADSPRITE "Media/player_left.png",PLAYER_LEFT%
LOADSPRITE "Media/player_right.png",PLAYER_RIGHT%
LOADSPRITE "Media/player_uphill_straight.png",PLAYER_UPHILL_STRAIGHT%
LOADSPRITE "Media/player_uphill_left.png",PLAYER_UPHILL_LEFT%
LOADSPRITE "Media/player_uphill_right.png",PLAYER_UPHILL_RIGHT%
LOADSPRITE "Media/billboard01.png",SPRITES_BILLBOARD_01%
LOADSPRITE "Media/billboard02.png",SPRITES_BILLBOARD_02%
LOADSPRITE "Media/billboard03.png",SPRITES_BILLBOARD_03%
LOADSPRITE "Media/billboard04.png",SPRITES_BILLBOARD_04%
LOADSPRITE "Media/billboard05.png",SPRITES_BILLBOARD_05%
LOADSPRITE "Media/billboard06.png",SPRITES_BILLBOARD_06%
LOADSPRITE "Media/billboard07.png",SPRITES_BILLBOARD_07%
LOADSPRITE "Media/billboard08.png",SPRITES_BILLBOARD_08%
LOADSPRITE "Media/billboard09.png",SPRITES_BILLBOARD_09%
LOADSPRITE "Media/palm_tree.png",SPRITES_PALM_TREE%
LOADSPRITE "Media/column.png",SPRITES_COLUMN%
LOADSPRITE "Media/dead_tree1.png",SPRITES_DEAD_TREE1%
LOADSPRITE "Media/dead_tree2.png",SPRITES_DEAD_TREE2%
LOADSPRITE "Media/cactus.png",SPRITES_CATCUS%
LOADSPRITE "Media/tree1.png",SPRITES_TREE1%
LOADSPRITE "Media/tree2.png",SPRITES_TREE2%
LOADSPRITE "Media/bush1.png",SPRITES_BUSH1%
LOADSPRITE "Media/bush2.png",SPRITES_BUSH2%
LOADSPRITE "Media/stump.png",SPRITES_STUMP%
LOADSPRITE "Media/boulder1.png",SPRITES_BOULDER1%
LOADSPRITE "Media/boulder2.png",SPRITES_BOULDER2%
LOADSPRITE "Media/boulder3.png",SPRITES_BOULDER3%
LOADSPRITE "Media/tunnelwall.png",SPRITES_TUNNELWALL%
LOADSPRITE "Media/tunneltop.png",SPRITES_TUNNELTOP%
LOADSPRITE "Media/sky.png",BACKGROUND_SKY%
LOADSPRITE "Media/hills.png",BACKGROUND_HILLS%
LOADSPRITE "Media/trees.png",BACKGROUND_TREES%
LOADSPRITE "Media/car01.png",CARS_CAR_01%
LOADSPRITE "Media/car02.png",CARS_CAR_02%
LOADSPRITE "Media/car03.png",CARS_CAR_03%
LOADSPRITE "Media/car04.png",CARS_CAR_04%
LOADSPRITE "Media/semi.png",CARS_SEMI%
LOADSPRITE "Media/truck.png",CARS_TRUCK%
road.Initialise()
road.resetRoad()
now=GETTIMERALL()
last=GETTIMERALL()
WHILE TRUE
SMOOTHSHADING FALSE
ALPHAMODE -1.0
road.render()
SHOWSCREEN
dt=MIN(1.0,(now-last)/1000.0)
INC gdt,dt
WHILE gdt>stp
DEC gdt,stp
road.update(stp)
WEND
//road.update(stp)
last = now
now=GETTIMERALL()
WEND
I've included a more complete version (although the rendering order is still incorrect). If anyone can find the problem, I would be grateful!