Author Topic: Something of interest : Pseudo 3D Tracks V2 - Parts 1, 2, 3, 4 and 5  (Read 18352 times)

• Guest
Something of interest : Pseudo 3D Tracks V2 - Parts 1, 2, 3, 4 and 5
« on: 2014-Jun-08 »
I'm converting Jakes Gorden Pseudo 3D track example programs to GLBasic.  This is the first part (just straight roads).

Having to convert from Javascript to a more readable text can be a bit of problem!

Here's the current code :

Code: (glbasic) [Select]
`// --------------------------------- //// Project: Test2// Start: Tuesday, April 01, 2014// IDE Version: 12.001CONSTANT PLAYER_STRAIGHT% = 0CONSTANT PLAYER_LEFT% = 1CONSTANT PLAYER_RIGHT% = 2CONSTANT PLAYER_UPHILL_STRAIGHT% = 3CONSTANT PLAYER_UPHILL_LEFT% = 4CONSTANT PLAYER_UPHILL_RIGHT% = 5TYPE tScreen scale x y wENDTYPETYPE tCamera x y zENDTYPETYPE tWorld x y zENDTYPETYPE tColour rumble% road% grass% lane%ENDTYPETYPE tPart world AS tWorld camera AS tCamera screen AS tScreenENDTYPETYPE tSegment index% colour AS tColour p1 AS tPart p2 AS tPartENDTYPETYPE TRoad segments[] AS tSegment 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 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 width%;height% keyLeftRight% trackLength% drawDistance% = 100 FUNCTION Initialise%: LOCAL tW%,tH% GETSCREENSIZE self.width%,self.height% DEBUG "H:"+self.height%+"\n" self.resetRoad() self.position=0.0 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.grass%=1092112 self.LIGHT.rumble%=5592405 self.LIGHT.lane%=13421772 self.DARK.road%=6908265 self.DARK.grass%=39424 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%) ENDFUNCTION FUNCTION resetRoad%: LOCAL segment AS tSegment DIM self.segments[0] FOR n%=0 TO 499 segment.index%=n segment.p1.world.x=0.0 segment.p1.world.y=0.0 segment.p1.world.z=n*self.segmentLength% //segment.p1.camera segment.p2.world.x=0.0 segment.p2.world.y=0.0 segment.p2.world.z=(n+1)*self.segmentLength% IF MOD(FLOOR(n%/self.rumbleLength%),2)=0 segment.colour=self.LIGHT ELSE segment.colour=self.DARK ENDIF //segment.colour=IIF(MOD(FLOOR(n%/self.rumbleLength%),2),self.LIGHT,self.DARK) DIMPUSH self.segments[],segment NEXT self.trackLength% = BOUNDS(self.segments[],0)*self.segmentLength% ENDFUNCTION FUNCTION findSegment AS tSegment:z RETURN self.segments[MOD(FLOOR(z/self.segmentLength%),BOUNDS(self.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 accelerate:v,accel,dt  RETURN v + (accel * dt)  ENDFUNCTION  FUNCTION limit:value, minV,maxV  RETURN MAX(minV,MIN(value,maxV))  ENDFUNCTION FUNCTION fog%:x%,y%,width%,height% ALPHAMODE -0.9 DRAWRECT x%,y%,width%,height%,RGB(64,64,64) ALPHAMODE -1.0 ENDFUNCTION FUNCTION update%:dt LOCAL dx DEBUG dt+"\n" DEBUG "Speed:"+self.speed+"\n" DEBUG (dt*self.speed)+"\n"      self.position = self.increase(self.position, dt * self.speed, self.trackLength)      dx = dt * 2 * (self.speed/self.maxSpeed); // at top speed, should be able to cross from left to right (-1 to 1) in 1 second IF KEY(203) DEC self.playerX,dx self.keyLeftRight%=-1 ELSEIF KEY(205) INC self.playerX,dx self.keyLeftRight%=1 ELSE self.keyLeftRight%=0 ENDIF IF KEY(200) self.speed=self.accelerate(self.speed,self.accel,dt) ELSEIF KEY(208) self.speed=self.accelerate(self.speed,self.breaking,dt) ELSE self.speed=self.accelerate(self.speed,self.decel,dt) ENDIF IF (self.playerX<-1.0 OR self.playerX>1.0) AND (self.speed>self.offRoadLimit) self.speed=self.accelerate(self.speed,self.offRoadDecel,dt) ENDIF self.playerX=self.limit(self.playerX,-2,2) self.speed=self.limit(self.speed,0.0,self.maxSpeed) ENDFUNCTION FUNCTION project%:p AS tPart, cameraX, cameraY, cameraZ, cameraDepth, width%, height%, roadWidth% p.camera.x=p.world.x - cameraX p.camera.y=p.world.y - cameraY p.camera.z=p.world.z - cameraZ p.screen.scale=self.cameraDepth/p.camera.z// DEBUG "Z : "+p.camera.z+" "+cameraZ+"\n"// DEBUG "Y : "+p.camera.y+" "+cameraY+"\n"// DEBUG "X : "+p.camera.x+" "+cameraX+"\n"// DEBUG "Camera depth : "+cameraDepth+" p.camera.z : "+p.camera.z+"\n"// DEBUG "Scale : "+p.screen.scale+"\n"// DEBUG "Width : "+width%+" Height : "+height%+"\n"// DEBUG "Road width : "+roadWidth%+"\n" p.screen.x=INTEGER((width%/2)+(p.screen.scale*p.camera.x*width%/2)) p.screen.y=INTEGER((height%/2)-(p.screen.scale*p.camera.y*height%/2)) p.screen.w=INTEGER(p.screen.scale*roadWidth%*width%/2)// DEBUG p.screen.x+" "+p.screen.y+" "+p.screen.w+"\n" //KEYWAIT ENDFUNCTION FUNCTION player%:width%, height%, resolution, roadWidth, sprites, speedPercent, scale, destX, destY, steer, updown LOCAL bounce LOCAL sprite% bounce=1.5*(RND(2)-1)*speedPercent*resolution 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" self.sprite(width%,height%,resolution,roadWidth,sprite%,scale,destX,destY+bounce,-0.5,-1) ENDFUNCTION FUNCTION sprite%:width%, height%, resolution, roadWidth, sprite%, scale, destX, destY, offsetX, offsetY, clipY=0.0 LOCAL destW,destH,clipH GETSPRITESIZE sprite%,destW,destH destW=destW*scale*(width%/2.0)*self.SPRITES_SCALE*roadWidth destH=destH*scale*(width%/2.0)*self.SPRITES_SCALE*roadWidth DEBUG "Scale : "+self.SPRITES_SCALE+" Width : "+roadWidth+"\n" DEBUG "W:"+destW+" "+destH+"\n" INC destX,destW*offsetX INC destY,destH*offsetY clipH=IIF(clipY,MAX(0,destY+destH-clipY),0) IF clipH<destH STRETCHSPRITE sprite%,destX,destY,destW,destH-clipH ENDIF ENDFUNCTION FUNCTION render%: LOCAL baseSegment AS tSegment LOCAL maxy%,n% LOCAL segment AS tSegment// DEBUG "H2:"+self.height%+"\n" maxy%=self.height%// DEBUG "maxy : "+maxy%+"\n" DEBUG "Position : "+self.position+"\n" baseSegment = self.findSegment(self.position) FOR n%=0 TO self.drawDistance%-1 segment=self.segments[MOD(baseSegment.index%+n%,BOUNDS(self.segments[],0))] self.project(segment.p1,self.playerX*self.roadWidth%,self.cameraHeight%,self.position%,self.cameraDepth,self.width%,self.height%,self.roadWidth%) self.project(segment.p2,self.playerX*self.roadWidth%,self.cameraHeight%,self.position%,self.cameraDepth,self.width%,self.height%,self.roadWidth%)// DEBUG "Segment 1 camera Z : "+segment.p1.camera.z+"\n"// DEBUG "Segment 2 screen Y : "+segment.p2.screen.y+"\n"// DEBUG "maxy : "+maxy%+"\n" IF segment.p1.camera.z<=self.cameraDepth OR segment.p2.screen.y>=maxy% CONTINUE ELSE self.segment(self.width%,self.lanes%, _ segment.p1.screen.x, _                   segment.p1.screen.y, _                     segment.p1.screen.w, _                     segment.p2.screen.x, _                     segment.p2.screen.y, _                     segment.p2.screen.w, _                     1.0, _                     segment.colour) ENDIF maxy%=segment.p2.screen.y% NEXT self.player(self.width%, self.height%, self.resolution, self.roadWidth% ,PLAYER_STRAIGHT%,self.speed/self.maxSpeed, _ self.cameraDepth/self.playerZ, _ self.width%/2, _ self.height, _ self.speed * SGN(self.keyLeftRight%), _ 0) //                    self.cameraDepth/self.playerZ, _  //                  self.width%/2, _    //                self.height, _      //              self.speed * 1, _ // (keyLeft ? -1 : keyRight ? 1 : 0),         //           0) ENDFUNCTION FUNCTION rumbleWidth:projectedRoadWidth%,lanes% RETURN projectedRoadWidth%/MAX(6,2*lanes%) ENDFUNCTION FUNCTION laneMarkerWidth:projectedRoadWidth%,lanes% RETURN projectedRoadWidth/MAX(32,8*lanes%) ENDFUNCTION FUNCTION polygon%:x1,y1,x2,y2,x3,y3,x4,y4,colour% STARTPOLY 99,0 POLYVECTOR x1,y1,x2,y2,colour% POLYVECTOR x2,y2,x3,y3,colour% POLYVECTOR x3,y3,x4,y4,colour% POLYVECTOR x4,y4,x1,y2,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 segment%:width%,lanes%,x1,y1,w1,x2,y2,w2,fog,colour AS tColour LOCAL r1,r2,l1,l2,lanew1,lanew2,lanex1,lanex2 r1=self.rumbleWidth(w1,lanes%) r2=self.rumbleWidth(w2,lanes%) l1=self.laneMarkerWidth(w1,lanes%) l2=self.laneMarkerWidth(w2,lanes%) //DEBUG "R1 : "+r1%+" R2 : "+r2%+" l1 : "+l1%+" l2 : "+l2%+"\n" ALPHAMODE -1.0 DRAWRECT 0,y2,width%,y1-y2,colour.grass%    self.polygon(x1-w1-r1, y1, x1-w1, y1, x2-w2, y2, x2-w2-r2, y2, colour.rumble)    self.polygon(x1+w1+r1, y1, x1+w1, y1, x2+w2, y2, x2+w2+r2, y2, colour.rumble)    self.polygon(x1-w1, y1, x1+w1, y1, x2+w2, y2, x2-w2, y2, colour.road)    IF colour.lane%    lanew1=w1*2.0/lanes%    lanew2=w2*2.0/lanes%    lanex1=x1-w1+lanew1    lanex2=x2-w2+lanew2    FOR lane%=1 TO lanes%-1    self.polygon(lanex1-l1/2.0,y1,lanex1+l1/2.0,y1,lanex2+l2/2.0,y2,lanex2-l2/2.0,y2,colour.lane%)    INC lanex1,lanew1    INC lanex2,lanew2        NEXT    ENDIF        //self.fog(0,y1,width%,y2-y1)    ENDFUNCTIONENDTYPELOCAL road AS TRoadLOCAL now,last,dt,gdt,stp=0.025LIMITFPS -1LOADSPRITE "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%road.Initialise()road.resetRoad()now=GETTIMERALL()last=GETTIMERALL()WHILE TRUE now=GETTIMERALL() DEBUG last+" "+now+"\n" dt=MIN(1.0,(now-last)/1000.0) INC gdt,dt WHILE gdt>stp DEC gdt,stp road.update(stp) WEND road.update(stp) SMOOTHSHADING FALSE road.render() SHOWSCREEN last = nowWEND`
« Last Edit: 2014-Jun-11 by MrTAToad »

Ian Price

• Prof. Inline
• Posts: 4158
• On the shoulders of giants.
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1
« Reply #1 on: 2014-Jun-08 »
Nice and fast - perhaps too fast!

I created a road system in Div many years ago (in fact it was going to be a remake of OutRun). It was my last ever Div program. Unfortunately it's all gone now due to numerous computer deaths and updates. I've probably got the source on a CD somewhere, but I just haven't got the time or the will to find it.

I do often think about creating a 2D racer, to harken back to the old days (especially since Foppy released a motorbike racer on OUYA that got rave reviews, despite it's limited 1 track game mode). But then I remember I might still have the code somewhere and think sod it!

Looking forward to seeing the next part(s).
I came. I saw. I played.

• Guest
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1
« Reply #2 on: 2014-Jun-08 »
And if by magic, the next part is here.

One problem I did have was working out an acceptable easing value as Javascript uses radians.

But after a bit of experimenting, I found an acceptable value, although it's not quite the same as the original.

It is probably way too fast still - will have to look at that later.

Code: (glbasic) [Select]
`// --------------------------------- //// Project: Test2// Start: Tuesday, April 01, 2014// IDE Version: 12.001CONSTANT PLAYER_STRAIGHT% = 0CONSTANT PLAYER_LEFT% = 1CONSTANT PLAYER_RIGHT% = 2CONSTANT PLAYER_UPHILL_STRAIGHT% = 3CONSTANT PLAYER_UPHILL_LEFT% = 4CONSTANT PLAYER_UPHILL_RIGHT% = 5CONSTANT ROAD_LENGTH_NONE% = 0CONSTANT ROAD_LENGTH_SHORT% = 25CONSTANT ROAD_LENGTH_MEDIUM% = 50CONSTANT ROAD_LENGTH_LONG% = 100CONSTANT ROAD_CURVE_NONE% = 0CONSTANT ROAD_CURVE_EASY% = 2CONSTANT ROAD_CURVE_MEDIUM% = 4CONSTANT ROAD_CURVE_HARD% = 6    CONSTANT PI = 3.14159TYPE tScreen scale x y wENDTYPETYPE tCamera x y zENDTYPETYPE tWorld x y zENDTYPETYPE tColour rumble% road% grass% lane%ENDTYPETYPE tPart world AS tWorld camera AS tCamera screen AS tScreenENDTYPETYPE tSegment index% colour AS tColour p1 AS tPart p2 AS tPart curveENDTYPETYPE TRoad segments[] AS tSegment 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 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 width%;height% keyLeftRight% trackLength% drawDistance% = 100 FUNCTION Initialise%: LOCAL tW%,tH% GETSCREENSIZE self.width%,self.height% DEBUG "H:"+self.height%+"\n" self.resetRoad() self.position=0.0 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.grass%=1092112 self.LIGHT.rumble%=5592405 self.LIGHT.lane%=13421772 self.DARK.road%=6908265 self.DARK.grass%=39424 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%) ENDFUNCTION FUNCTION addSegment%:curve LOCAL size% LOCAL segment AS tSegment size%=BOUNDS(self.segments[],0) // DEBUG "Curve : "+curve+"\n" segment.index%=size% segment.curve=curve segment.p1.world.x=0.0 segment.p1.world.y=0.0 segment.p1.world.z=size%*self.segmentLength% segment.p1.camera.x=0.0 segment.p1.camera.y=0.0 segment.p1.camera.z=0.0 segment.p1.screen.x=0.0 segment.p1.screen.y=0.0 segment.p1.screen.w=0.0 segment.p1.screen.scale=0.0 segment.p2.world.x=0.0 segment.p2.world.y=0.0 segment.p2.world.z=(size%+1)*self.segmentLength% segment.p2.camera.x=0.0 segment.p2.camera.y=0.0 segment.p2.camera.z=0.0 segment.p2.screen.x=0.0 segment.p2.screen.y=0.0 segment.p2.screen.w=0.0 segment.p2.screen.scale=0.0 IF FLOOR(MOD(size%/self.rumbleLength%,2)) segment.colour.road%=RGB(64,64,64) segment.colour.grass%=RGB(0,64,0) segment.colour.rumble%=RGB(128,128,128) ELSE segment.colour.road%=RGB(200,200,200) segment.colour.grass%=RGB(0,200,0) segment.colour.rumble%=RGB(220,220,220) ENDIF segment.colour.lane%=RGB(255,255,0) DIMPUSH self.segments[],segment ENDFUNCTION FUNCTION addRoad%:enter, hold, leave, curve LOCAL n% FOR n%=0 TO enter-1; self.addSegment(self.easeIn(0,curve,n%/enter)); NEXT FOR n%=0 TO hold-1; self.addSegment(curve); NEXT FOR n%=0 TO leave-1; self.addSegment(self.easeInOut(curve,0,n%/leave)); NEXT ENDFUNCTION     FUNCTION addStraight%:num=25 self.addRoad(num,num,num,0) ENDFUNCTION     FUNCTION addCurve%:num, curve    self.addRoad(num,num,num,curve)    ENDFUNCTION                   FUNCTION addSCurves%:      self.addRoad(ROAD_LENGTH_MEDIUM%, ROAD_LENGTH_MEDIUM%, ROAD_LENGTH_MEDIUM%, -ROAD_CURVE_EASY%)      self.addRoad(ROAD_LENGTH_MEDIUM%, ROAD_LENGTH_MEDIUM%, ROAD_LENGTH_MEDIUM%, ROAD_CURVE_MEDIUM%)//      self.addRoad(ROAD_LENGTH_MEDIUM%, ROAD_LENGTH_MEDIUM%, ROAD_LENGTH_MEDIUM%, ROAD_CURVE_EASY%)  //    self.addRoad(ROAD_LENGTH_MEDIUM%, ROAD_LENGTH_MEDIUM%, ROAD_LENGTH_MEDIUM%, -ROAD_CURVE_EASY%)    //  self.addRoad(ROAD_LENGTH_MEDIUM%, ROAD_LENGTH_MEDIUM%, ROAD_LENGTH_MEDIUM%, -ROAD_CURVE_MEDIUM%)    ENDFUNCTION    FUNCTION resetRoad%: LOCAL segment AS tSegment DIM self.segments[0] self.addStraight(ROAD_LENGTH_SHORT%/4.0)      self.addSCurves()      self.addStraight(ROAD_LENGTH_LONG%)      self.addCurve(ROAD_LENGTH_MEDIUM%, ROAD_CURVE_MEDIUM%)      self.addCurve(ROAD_LENGTH_LONG%, ROAD_CURVE_MEDIUM%)      self.addStraight()      self.addSCurves()      self.addCurve(ROAD_LENGTH_LONG%, -ROAD_CURVE_MEDIUM%)      self.addCurve(ROAD_LENGTH_LONG%, ROAD_CURVE_MEDIUM%)      self.addStraight()      self.addSCurves()      self.addCurve(ROAD_LENGTH_LONG%, -ROAD_CURVE_EASY%) segment=self.findSegment(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.trackLength% = BOUNDS(self.segments[],0)*self.segmentLength% ENDFUNCTION FUNCTION findSegment AS tSegment:z RETURN self.segments[MOD(FLOOR(z/self.segmentLength%),BOUNDS(self.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 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  RETURN a + (b-a)*((-COS(percent*180.0)/2.0) + 0.5)  ENDFUNCTION    FUNCTION percentageRemaining:n,total  RETURN MOD(n,total)/total  ENDFUNCTION  FUNCTION fog%:x%,y%,width%,height% ALPHAMODE -0.9 DRAWRECT x%,y%,width%,height%,RGB(64,64,64) ALPHAMODE -1.0 ENDFUNCTION FUNCTION update%:dt LOCAL dx// DEBUG dt+"\n"// DEBUG "Speed:"+self.speed+"\n"// DEBUG (dt*self.speed)+"\n"      self.position = self.increase(self.position, dt * self.speed, self.trackLength)      dx = dt * 2 * (self.speed/self.maxSpeed); // at top speed, should be able to cross from left to right (-1 to 1) in 1 second IF KEY(203) DEC self.playerX,dx self.keyLeftRight%=-1 ELSEIF KEY(205) INC self.playerX,dx self.keyLeftRight%=1 ELSE self.keyLeftRight%=0 ENDIF IF KEY(200) self.speed=self.accelerate(self.speed,self.accel,dt) ELSEIF KEY(208) self.speed=self.accelerate(self.speed,self.breaking,dt) ELSE self.speed=self.accelerate(self.speed,self.decel,dt) ENDIF IF (self.playerX<-1.0 OR self.playerX>1.0) AND (self.speed>self.offRoadLimit) self.speed=self.accelerate(self.speed,self.offRoadDecel,dt) ENDIF self.playerX=self.limit(self.playerX,-2,2) self.speed=self.limit(self.speed,0.0,self.maxSpeed) ENDFUNCTION FUNCTION project%:p AS tPart, cameraX, cameraY, cameraZ, cameraDepth, width%, height%, roadWidth% p.camera.x=p.world.x - cameraX p.camera.y=p.world.y - cameraY p.camera.z=p.world.z - cameraZ p.screen.scale=self.cameraDepth/p.camera.z// DEBUG "Z : "+p.camera.z+" "+cameraZ+"\n"// DEBUG "Y : "+p.camera.y+" "+cameraY+"\n"// DEBUG "X : "+p.camera.x+" "+cameraX+"\n"// DEBUG "Camera depth : "+cameraDepth+" p.camera.z : "+p.camera.z+"\n"// DEBUG "Scale : "+p.screen.scale+"\n"// DEBUG "Width : "+width%+" Height : "+height%+"\n"// DEBUG "Road width : "+roadWidth%+"\n" p.screen.x=INTEGER((width%/2)+(p.screen.scale*p.camera.x*width%/2)) p.screen.y=INTEGER((height%/2)-(p.screen.scale*p.camera.y*height%/2)) p.screen.w=INTEGER(p.screen.scale*roadWidth%*width%/2)// DEBUG p.screen.x+" "+p.screen.y+" "+p.screen.w+"\n" //KEYWAIT ENDFUNCTION FUNCTION player%:width%, height%, resolution, roadWidth, sprites, speedPercent, scale, destX, destY, steer, updown LOCAL bounce LOCAL sprite% bounce=1.5*(RND(2)-1)*speedPercent*resolution 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" self.sprite(width%,height%,resolution,roadWidth,sprite%,scale,destX,destY+bounce,-0.5,-1) ENDFUNCTION FUNCTION sprite%:width%, height%, resolution, roadWidth, sprite%, scale, destX, destY, offsetX, offsetY, clipY=0.0 LOCAL destW,destH,clipH GETSPRITESIZE sprite%,destW,destH destW=destW*scale*(width%/2.0)*self.SPRITES_SCALE*roadWidth destH=destH*scale*(width%/2.0)*self.SPRITES_SCALE*roadWidth DEBUG "Scale : "+self.SPRITES_SCALE+" Width : "+roadWidth+"\n" DEBUG "W:"+destW+" "+destH+"\n" INC destX,destW*offsetX INC destY,destH*offsetY clipH=IIF(clipY,MAX(0,destY+destH-clipY),0) IF clipH<destH STRETCHSPRITE sprite%,destX,destY,destW,destH-clipH ENDIF ENDFUNCTION FUNCTION render%: LOCAL baseSegment AS tSegment LOCAL basePercentage LOCAL maxy%,n% LOCAL segment AS tSegment LOCAL x,dx// DEBUG "H2:"+self.height%+"\n" maxy%=self.height%// DEBUG "maxy : "+maxy%+"\n" DEBUG "Position : "+self.position+"\n" baseSegment = self.findSegment(self.position) basePercentage=self.percentageRemaining(self.position,self.segmentLength%) x=0.0 dx=-(baseSegment.curve*basePercentage) PRINT FORMAT\$(4,4,dx),0,0 //DEBUG "Base Percentage : "+basePercentage+" DX : "+dx+"\n"// KEYWAIT FOR n%=0 TO self.drawDistance%-1 segment=self.segments[MOD(baseSegment.index%+n%,BOUNDS(self.segments[],0))] self.project(segment.p1,(self.playerX*self.roadWidth%*1.0)-x,self.cameraHeight%,self.position%,self.cameraDepth,self.width%,self.height%,self.roadWidth%) self.project(segment.p2,(self.playerX*self.roadWidth%*1.0)-x-dx,self.cameraHeight%,self.position%,self.cameraDepth,self.width%,self.height%,self.roadWidth%)// DEBUG "Segment 1 camera Z : "+segment.p1.camera.z+"\n"// DEBUG "Segment 2 screen Y : "+segment.p2.screen.y+"\n"// DEBUG "maxy : "+maxy%+"\n" INC x,dx INC dx,baseSegment.curve IF segment.p1.camera.z<=self.cameraDepth OR segment.p2.screen.y>=maxy% CONTINUE ELSE self.segment(self.width%,self.lanes%, _ segment.p1.screen.x, _                   segment.p1.screen.y, _                     segment.p1.screen.w, _                     segment.p2.screen.x, _                     segment.p2.screen.y, _                     segment.p2.screen.w, _                     1.0, _                     segment.colour) ENDIF maxy%=segment.p2.screen.y% NEXT self.player(self.width%, self.height%, self.resolution, self.roadWidth% ,PLAYER_STRAIGHT%,self.speed/self.maxSpeed, _ self.cameraDepth/self.playerZ, _ self.width%/2, _ self.height, _ self.speed * SGN(self.keyLeftRight%), _ 0) //                    self.cameraDepth/self.playerZ, _  //                  self.width%/2, _    //                self.height, _      //              self.speed * 1, _ // (keyLeft ? -1 : keyRight ? 1 : 0),         //           0) ENDFUNCTION FUNCTION rumbleWidth:projectedRoadWidth%,lanes% RETURN projectedRoadWidth%/MAX(6,2*lanes%) ENDFUNCTION FUNCTION laneMarkerWidth:projectedRoadWidth%,lanes% RETURN projectedRoadWidth/MAX(32,8*lanes%) ENDFUNCTION FUNCTION polygon%:x1,y1,x2,y2,x3,y3,x4,y4,colour% STARTPOLY 99,0 POLYVECTOR x1,y1,x2,y2,colour% POLYVECTOR x2,y2,x3,y3,colour% POLYVECTOR x3,y3,x4,y4,colour% POLYVECTOR x4,y4,x1,y2,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 segment%:width%,lanes%,x1,y1,w1,x2,y2,w2,fog,colour AS tColour LOCAL r1,r2,l1,l2,lanew1,lanew2,lanex1,lanex2 r1=self.rumbleWidth(w1,lanes%) r2=self.rumbleWidth(w2,lanes%) l1=self.laneMarkerWidth(w1,lanes%) l2=self.laneMarkerWidth(w2,lanes%) //DEBUG "R1 : "+r1%+" R2 : "+r2%+" l1 : "+l1%+" l2 : "+l2%+"\n" ALPHAMODE -1.0 DRAWRECT 0,y2,width%,y1-y2,colour.grass%    self.polygon(x1-w1-r1, y1, x1-w1, y1, x2-w2, y2, x2-w2-r2, y2, colour.rumble)    self.polygon(x1+w1+r1, y1, x1+w1, y1, x2+w2, y2, x2+w2+r2, y2, colour.rumble)    self.polygon(x1-w1, y1, x1+w1, y1, x2+w2, y2, x2-w2, y2, colour.road)    IF colour.lane%    lanew1=w1*2.0/lanes%    lanew2=w2*2.0/lanes%    lanex1=x1-w1+lanew1    lanex2=x2-w2+lanew2    FOR lane%=1 TO lanes%-1    self.polygon(lanex1-l1/2.0,y1,lanex1+l1/2.0,y1,lanex2+l2/2.0,y2,lanex2-l2/2.0,y2,colour.lane%)    INC lanex1,lanew1    INC lanex2,lanew2    NEXT    ENDIF    //self.fog(0,y1,width%,y2-y1)    ENDFUNCTIONENDTYPELOCAL road AS TRoadLOCAL now,last,dt,gdt,stp=0.025LIMITFPS -1LOADSPRITE "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%road.Initialise()road.resetRoad()now=GETTIMERALL()last=GETTIMERALL()WHILE TRUE now=GETTIMERALL() DEBUG last+" "+now+"\n" dt=MIN(1.0,(now-last)/1000.0) INC gdt,dt WHILE gdt>stp DEC gdt,stp road.update(stp) WEND road.update(stp) SMOOTHSHADING FALSE road.render() SHOWSCREEN last = nowWEND`
I've always wanted to do a game like Outrun/Lotus Esprit, but the main problem has been graphics...

mentalthink

• Prof. Inline
• Posts: 3372
• Integrated Brain
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1 & 2
« Reply #3 on: 2014-Jun-09 »
Very very cool, and very very usefull,... Thanks a lot for the code....

• Guest
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1 & 2
« Reply #4 on: 2014-Jun-09 »
No problem!

This is the third part : Hills & trough's.  I had to sort the easing calculation for this - and worked out why it wasn't working properly : I was multiplying the result of COS by 180/PI rather than the initial value

Code: (glbasic) [Select]
`// --------------------------------- //// Project: Test2// Start: Tuesday, April 01, 2014// IDE Version: 12.001CONSTANT PLAYER_STRAIGHT% = 0CONSTANT PLAYER_LEFT% = 1CONSTANT PLAYER_RIGHT% = 2CONSTANT PLAYER_UPHILL_STRAIGHT% = 3CONSTANT PLAYER_UPHILL_LEFT% = 4CONSTANT PLAYER_UPHILL_RIGHT% = 5CONSTANT ROAD_LENGTH_NONE% = 0CONSTANT ROAD_LENGTH_SHORT% = 25CONSTANT ROAD_LENGTH_MEDIUM% = 50CONSTANT ROAD_LENGTH_LONG% = 100CONSTANT ROAD_HILL_NONE% = 0CONSTANT ROAD_HILL_LOW% = 20CONSTANT ROAD_HILL_MEDIUM% = 40CONSTANT ROAD_HILL_HIGH% = 60CONSTANT ROAD_CURVE_NONE% = 0CONSTANT ROAD_CURVE_EASY% = 2CONSTANT ROAD_CURVE_MEDIUM% = 4CONSTANT ROAD_CURVE_HARD% = 6    CONSTANT PI = 3.14159CONSTANT COLOURS_SKY% = 7526382CONSTANT COLOURS_TREE% = 20744CONSTANT COLOURS_FOG% = 20744TYPE tScreen scale x y wENDTYPETYPE tCamera x y zENDTYPETYPE tWorld x y zENDTYPETYPE tColour rumble% road% grass% lane%ENDTYPETYPE tPart world AS tWorld camera AS tCamera screen AS tScreenENDTYPETYPE tSegment index% colour AS tColour p1 AS tPart p2 AS tPart curveENDTYPETYPE TRoad segments[] AS tSegment 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 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 width%;height% keyLeftRight% trackLength% drawDistance% = 100 FUNCTION Initialise%: LOCAL tW%,tH% GETSCREENSIZE self.width%,self.height% self.position=0.0 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.grass%=1092112 self.LIGHT.rumble%=5592405 self.LIGHT.lane%=13421772 self.DARK.road%=6908265 self.DARK.grass%=39424 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%) ENDFUNCTION FUNCTION addSegment%:curve,y LOCAL size% LOCAL segment AS tSegment size%=BOUNDS(self.segments[],0) // DEBUG "Curve : "+curve+"\n" segment.index%=size% segment.curve=curve segment.p1.world.x=0.0 segment.p1.world.y=self.lastY() segment.p1.world.z=size%*self.segmentLength% segment.p1.camera.x=0.0 segment.p1.camera.y=0.0 segment.p1.camera.z=0.0 segment.p1.screen.x=0.0 segment.p1.screen.y=0.0 segment.p1.screen.w=0.0 segment.p1.screen.scale=0.0 segment.p2.world.x=0.0 segment.p2.world.y=y segment.p2.world.z=(size%+1)*self.segmentLength% segment.p2.camera.x=0.0 segment.p2.camera.y=0.0 segment.p2.camera.z=0.0 segment.p2.screen.x=0.0 segment.p2.screen.y=0.0 segment.p2.screen.w=0.0 segment.p2.screen.scale=0.0 IF FLOOR(MOD(size%/self.rumbleLength%,2)) segment.colour=self.LIGHT ELSE segment.colour=self.DARK ENDIF segment.colour.lane%=RGB(255,255,0) // DEBUG "> : "+segment.p1.world.y+" "+segment.p2.world.y+"\n" DIMPUSH self.segments[],segment ENDFUNCTION FUNCTION addRoad%:enter, hold, leave, curve, y LOCAL startY,endY,total LOCAL n% startY=self.lastY() endY=startY+(INTEGER(y)*self.segmentLength%) total=enter+hold+leave // DEBUG "Start Y : "+startY+" endY : "+endY+"\n"// KEYWAIT FOR n%=0 TO enter-1; self.addSegment(self.easeIn(0,curve,n%/enter),easeInOut(startY,endY,n%/total)); NEXT// DEBUG "Holding ---\n" FOR n%=0 TO hold-1 self.addSegment(curve,self.easeInOut(startY,endY,(enter+n%)/total)); NEXT// DEBUG "---\n" FOR n%=0 TO leave-1 self.addSegment(self.easeInOut(curve,0,n%/leave),self.easeInOut(startY,endY,(enter+hold+n)/total)) NEXT ENDFUNCTION     FUNCTION addStraight%:num=25 self.addRoad(num,num,num,0,0) ENDFUNCTION FUNCTION addHill%:num,height self.addRoad(num,num,num,0,height) ENDFUNCTION     FUNCTION addCurve%:num, curve,height    self.addRoad(num,num,num,curve,height)    ENDFUNCTION        FUNCTION addLowRollingHills%:num,height    self.addRoad(num, num, num, 0, height/2)      self.addRoad(num, num, num, 0, -height)      self.addRoad(num, num, num, 0, height)      self.addRoad(num, num, num, 0, 0)      self.addRoad(num, num, num, 0, height/2)      self.addRoad(num, num, num, 0, 0)    ENDFUNCTION        FUNCTION addSCurves%:      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 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] self.addStraight(ROAD_LENGTH_SHORT/2)      self.addHill(ROAD_LENGTH_SHORT, ROAD_HILL_LOW%)      self.addLowRollingHills(ROAD_LENGTH_SHORT,ROAD_HILL_LOW%)      self.addCurve(ROAD_LENGTH_MEDIUM, ROAD_CURVE_MEDIUM, ROAD_HILL_LOW)      self.addLowRollingHills(ROAD_LENGTH_SHORT,ROAD_HILL_LOW%)      self.addCurve(ROAD_LENGTH_LONG, ROAD_CURVE_MEDIUM, ROAD_HILL_MEDIUM)      self.addStraight()      self.addCurve(ROAD_LENGTH_LONG, -ROAD_CURVE_MEDIUM, ROAD_HILL_MEDIUM)      self.addHill(ROAD_LENGTH_LONG, ROAD_HILL_HIGH)      self.addCurve(ROAD_LENGTH_LONG, ROAD_CURVE_MEDIUM, -ROAD_HILL_LOW)      self.addHill(ROAD_LENGTH_LONG, -ROAD_HILL_MEDIUM)      self.addStraight()      self.addDownhillToEnd() segment=self.findSegment(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.trackLength% = BOUNDS(self.segments[],0)*self.segmentLength% ENDFUNCTION FUNCTION lastY: LOCAL size% size%=BOUNDS(self.segments[],0) IF size%=0 RETURN 0 ELSE RETURN self.segments[size%-1].p2.world.y ENDIF ENDFUNCTION FUNCTION findSegment AS tSegment:z RETURN self.segments[MOD(FLOOR(z/self.segmentLength%),BOUNDS(self.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 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 MOD(n,total)/total  ENDFUNCTION    FUNCTION interpolate:a,b,percent  RETURN a+(b-a)*percent  ENDFUNCTION  FUNCTION fog%:x%,y%,width%,height% ALPHAMODE -0.9 DRAWRECT x%,y%,width%,height%,RGB(64,64,64) ALPHAMODE -1.0 ENDFUNCTION FUNCTION update%:dt LOCAL dx// DEBUG dt+"\n"// DEBUG "Speed:"+self.speed+"\n"// DEBUG (dt*self.speed)+"\n"      self.position = self.increase(self.position, dt * self.speed, self.trackLength)      dx = dt * 2 * (self.speed/self.maxSpeed); // at top speed, should be able to cross from left to right (-1 to 1) in 1 second IF KEY(203) DEC self.playerX,dx self.keyLeftRight%=-1 ELSEIF KEY(205) INC self.playerX,dx self.keyLeftRight%=1 ELSE self.keyLeftRight%=0 ENDIF IF KEY(200) self.speed=self.accelerate(self.speed,self.accel,dt) ELSEIF KEY(208) self.speed=self.accelerate(self.speed,self.breaking,dt) ELSE self.speed=self.accelerate(self.speed,self.decel,dt) ENDIF IF (self.playerX<-1.0 OR self.playerX>1.0) AND (self.speed>self.offRoadLimit) self.speed=self.accelerate(self.speed,self.offRoadDecel,dt) ENDIF self.playerX=self.limit(self.playerX,-2,2) self.speed=self.limit(self.speed,0.0,self.maxSpeed) ENDFUNCTION FUNCTION project%:p AS tPart, cameraX, cameraY, cameraZ, cameraDepth, width%, height%, roadWidth% p.camera.x=p.world.x - cameraX p.camera.y=p.world.y - cameraY p.camera.z=p.world.z - cameraZ p.screen.scale=self.cameraDepth/p.camera.z// DEBUG "Z : "+p.camera.z+" "+cameraZ+"\n"// DEBUG "Y : "+p.camera.y+" "+cameraY+"\n"// DEBUG "X : "+p.camera.x+" "+cameraX+"\n"// DEBUG "Camera depth : "+cameraDepth+" p.camera.z : "+p.camera.z+"\n"// DEBUG "Scale : "+p.screen.scale+"\n"// DEBUG "Width : "+width%+" Height : "+height%+"\n"// DEBUG "Road width : "+roadWidth%+"\n" p.screen.x=INTEGER((width%/2)+(p.screen.scale*p.camera.x*width%/2)) p.screen.y=INTEGER((height%/2)-(p.screen.scale*p.camera.y*height%/2)) p.screen.w=INTEGER(p.screen.scale*roadWidth%*width%/2)// DEBUG p.screen.x+" "+p.screen.y+" "+p.screen.w+"\n" //KEYWAIT ENDFUNCTION FUNCTION player%:width%, height%, resolution, roadWidth, sprites, speedPercent, scale, destX, destY, steer, updown LOCAL bounce LOCAL sprite% bounce=1.5*(RND(2)-1)*speedPercent*resolution 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" self.sprite(width%,height%,resolution,roadWidth,sprite%,scale,destX,destY+bounce,-0.5,-1) ENDFUNCTION FUNCTION sprite%:width%, height%, resolution, roadWidth, sprite%, scale, destX, destY, offsetX, offsetY, clipY=0.0 LOCAL destW,destH,clipH GETSPRITESIZE sprite%,destW,destH destW=destW*scale*(width%/2.0)*self.SPRITES_SCALE*roadWidth destH=destH*scale*(width%/2.0)*self.SPRITES_SCALE*roadWidth DEBUG "Scale : "+self.SPRITES_SCALE+" Width : "+roadWidth+"\n" DEBUG "W:"+destW+" "+destH+"\n" INC destX,destW*offsetX INC destY,destH*offsetY clipH=IIF(clipY,MAX(0,destY+destH-clipY),0) IF clipH<destH STRETCHSPRITE sprite%,destX,destY,destW,destH-clipH ENDIF ENDFUNCTION FUNCTION render%: LOCAL baseSegment AS tSegment,playerSegment AS tSegment LOCAL basePercentage,playerY,playerPercent LOCAL maxy%,n% LOCAL segment AS tSegment LOCAL x,dx// DEBUG "H2:"+self.height%+"\n" maxy%=self.height%// DEBUG "maxy : "+maxy%+"\n" DEBUG "Position : "+self.position+"\n" baseSegment = self.findSegment(self.position) playerSegment=self.findSegment(self.position+self.playerZ) basePercentage=self.percentageRemaining(self.position,self.segmentLength%) playerPercent=self.percentageRemaining(self.position+self.playerZ,self.segmentLength%) playerY= self.interpolate(playerSegment.p1.world.y, playerSegment.p2.world.y, playerPercent); x=0.0 dx=-(baseSegment.curve*basePercentage) PRINT FORMAT\$(4,4,dx),0,0 //DEBUG "Base Percentage : "+basePercentage+" DX : "+dx+"\n"// KEYWAIT FOR n%=0 TO self.drawDistance%-1 segment=self.segments[MOD(baseSegment.index%+n%,BOUNDS(self.segments[],0))] self.project(segment.p1,(self.playerX*self.roadWidth%*1.0)-x,playerY+self.cameraHeight%,self.position%,self.cameraDepth,self.width%,self.height%,self.roadWidth%) self.project(segment.p2,(self.playerX*self.roadWidth%*1.0)-x-dx,playerY+self.cameraHeight%,self.position%,self.cameraDepth,self.width%,self.height%,self.roadWidth%)// DEBUG "Segment 1 camera Z : "+segment.p1.camera.z+"\n"// DEBUG "Segment 2 screen Y : "+segment.p2.screen.y+"\n"// DEBUG "maxy : "+maxy%+"\n" INC x,dx INC dx,baseSegment.curve IF segment.p1.camera.z<=self.cameraDepth OR segment.p2.screen.y>=maxy% CONTINUE ELSE self.segment(self.width%,self.lanes%, _ segment.p1.screen.x, _                   segment.p1.screen.y, _                     segment.p1.screen.w, _                     segment.p2.screen.x, _                     segment.p2.screen.y, _                     segment.p2.screen.w, _                     1.0, _                     segment.colour) ENDIF maxy%=segment.p2.screen.y% NEXT self.player(self.width%, self.height%, self.resolution, self.roadWidth% ,PLAYER_STRAIGHT%,self.speed/self.maxSpeed, _ self.cameraDepth/self.playerZ, _ self.width%/2, _ self.height- (self.cameraDepth/self.playerZ * interpolate(playerSegment.p1.camera.y, playerSegment.p2.camera.y, playerPercent) * self.height/2.0), _ self.speed * SGN(self.keyLeftRight%), _ playerSegment.p2.world.y - playerSegment.p1.world.y) //                    self.cameraDepth/self.playerZ, _  //                  self.width%/2, _    //                self.height, _      //              self.speed * 1, _ // (keyLeft ? -1 : keyRight ? 1 : 0),         //           0) ENDFUNCTION FUNCTION rumbleWidth:projectedRoadWidth%,lanes% RETURN projectedRoadWidth%/MAX(6,2*lanes%) ENDFUNCTION FUNCTION laneMarkerWidth:projectedRoadWidth%,lanes% RETURN projectedRoadWidth/MAX(32,8*lanes%) ENDFUNCTION FUNCTION polygon%:x1,y1,x2,y2,x3,y3,x4,y4,colour% STARTPOLY 99,0 POLYVECTOR x1,y1,x2,y2,colour% POLYVECTOR x2,y2,x3,y3,colour% POLYVECTOR x3,y3,x4,y4,colour% POLYVECTOR x4,y4,x1,y2,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 segment%:width%,lanes%,x1,y1,w1,x2,y2,w2,fog,colour AS tColour LOCAL r1,r2,l1,l2,lanew1,lanew2,lanex1,lanex2 r1=self.rumbleWidth(w1,lanes%) r2=self.rumbleWidth(w2,lanes%) l1=self.laneMarkerWidth(w1,lanes%) l2=self.laneMarkerWidth(w2,lanes%) //DEBUG "R1 : "+r1%+" R2 : "+r2%+" l1 : "+l1%+" l2 : "+l2%+"\n" ALPHAMODE -1.0 DRAWRECT 0,y2,width%,y1-y2,colour.grass%    self.polygon(x1-w1-r1, y1, x1-w1, y1, x2-w2, y2, x2-w2-r2, y2, colour.rumble)    self.polygon(x1+w1+r1, y1, x1+w1, y1, x2+w2, y2, x2+w2+r2, y2, colour.rumble)    self.polygon(x1-w1, y1, x1+w1, y1, x2+w2, y2, x2-w2, y2, colour.road)    IF colour.lane%    lanew1=w1*2.0/lanes%    lanew2=w2*2.0/lanes%    lanex1=x1-w1+lanew1    lanex2=x2-w2+lanew2    FOR lane%=1 TO lanes%-1    self.polygon(lanex1-l1/2.0,y1,lanex1+l1/2.0,y1,lanex2+l2/2.0,y2,lanex2-l2/2.0,y2,colour.lane%)    INC lanex1,lanew1    INC lanex2,lanew2    NEXT    ENDIF    //self.fog(0,y1,width%,y2-y1)    ENDFUNCTIONENDTYPELOCAL road AS TRoadLOCAL now,last,dt,gdt,stp=0.025LIMITFPS -1LOADSPRITE "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%road.Initialise()road.resetRoad()now=GETTIMERALL()last=GETTIMERALL()WHILE TRUE now=GETTIMERALL() DEBUG last+" "+now+"\n" dt=MIN(1.0,(now-last)/1000.0) INC gdt,dt WHILE gdt>stp DEC gdt,stp road.update(stp) WEND road.update(stp) SMOOTHSHADING FALSE road.render() SHOWSCREEN last = nowWEND`
« Last Edit: 2014-Jun-09 by MrTAToad »

matchy

• Prof. Inline
• Posts: 1544
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1, 2 and 3
« Reply #5 on: 2014-Jun-09 »
Good stuff. For inspiration, check out:

Ian Price

• Prof. Inline
• Posts: 4158
• On the shoulders of giants.
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1, 2 and 3
« Reply #6 on: 2014-Jun-09 »
Excellent stuffage
I came. I saw. I played.

mentalthink

• Prof. Inline
• Posts: 3372
• Integrated Brain
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1, 2 and 3
« Reply #7 on: 2014-Jun-09 »
Thanks Mr-T just yesterday I want comment this point... I think whit this we can done a great game... Thanks a lot, very very usefully.

• Guest
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1, 2 and 3
« Reply #8 on: 2014-Jun-09 »
No problem!

• Guest
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1, 2 and 3
« Reply #9 on: 2014-Jun-09 »
A quick preview of the next part : Scenery (and I'll try and get the background graphics in as well later) :

Marmor

• Community Developer
• Prof. Inline
• Posts: 925
• 96A285CC
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1, 2 and 3
« Reply #10 on: 2014-Jun-09 »
great , i like this stuff !

• Guest
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1, 2, 3 and 4
« Reply #11 on: 2014-Jun-10 »
Good to hear

This is the next stage, and has road-side objects and a background.  The background warps unfortunately - must be mis-reading the Javascript code for that, and will have to look at it later.

What could be done in future is "rent" billboard space

spacefractal

• Community Developer
• Prof. Inline
• Posts: 3928
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1, 2, 3 and 4
« Reply #12 on: 2014-Jun-10 »
This screenshot looks nice. There is a cool "Outrun" game with named "Final Freeway" for iOS which could been get some inspiration from. That is a 2d Outrun style game. But scene here also looks nice.
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation and The beagle Jam.

• Guest
Re: Something of interest : Pseudo 3D Tracks V2 - Part 1, 2, 3 and 4
« Reply #13 on: 2014-Jun-11 »
I'm using the graphics that Code inComplete used for his example programs - for a proper game, you would need a decent/proper/professional artist.

The last part will have the vehicles in!
« Last Edit: 2014-Jun-11 by MrTAToad »

mentalthink

• Prof. Inline
• Posts: 3372
• Integrated Brain
Re: Something of interest : Pseudo 3D Tracks V2 - Parts 1, 2, 3 and 4
« Reply #14 on: 2014-Jun-11 »
Very impressive, I think from here can see the light some interesting projects, not it's necessary a car game.... somethink like F-Zero can be cool too!!!

Thanks MrT this stuff have a lot of quality..