Advertisement
here2share

js_Outrun_game_clone

May 23rd, 2018
220
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <!DOCTYPE html>
  2.  
  3. <html>
  4. <head>
  5.   <title>Javascript Racer - v4 (final)</title>
  6.   <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  7.   <link href="common.css" rel="stylesheet" type="text/css" />
  8. </head>
  9.  
  10. <body>
  11.  
  12.   <table id="controls">
  13.     <tr>
  14.       <td colspan="2">
  15.         <a href='v1.straight.html'>straight</a> |
  16.         <a href='v2.curves.html'>curves</a>     |
  17.         <a href='v3.hills.html'>hills</a>       |
  18.         <a href='v4.final.html'>final</a>
  19.       </td>
  20.     </tr>
  21.     <tr><td id="fps" colspan="2" align="right"></td></tr>
  22.     <tr>
  23.       <th><label for="resolution">Resolution :</label></th>
  24.       <td>
  25.         <select id="resolution" style="width:100%">
  26.           <option value='fine'>Fine (1280x960)</option>
  27.           <option selected value='high'>High (1024x768)</option>
  28.           <option value='medium'>Medium (640x480)</option>
  29.           <option value='low'>Low (480x360)</option>
  30.         </select>
  31.       </td>
  32.     </tr>
  33.     <tr>
  34.       <th><label for="lanes">Lanes :</label></th>
  35.       <td>
  36.         <select id="lanes">
  37.           <option>1</option>
  38.           <option>2</option>
  39.           <option selected>3</option>
  40.           <option>4</option>
  41.         </select>
  42.       </td>
  43.     </tr>
  44.     <tr>
  45.       <th><label for="roadWidth">Road Width (<span id="currentRoadWidth"></span>) :</label></th>
  46.       <td><input id="roadWidth" type='range' min='500' max='3000' title="integer (500-3000)"></td>
  47.     </tr>
  48.     <tr>
  49.       <th><label for="cameraHeight">CameraHeight (<span id="currentCameraHeight"></span>) :</label></th>
  50.       <td><input id="cameraHeight" type='range' min='500' max='5000' title="integer (500-5000)"></td>
  51.     </tr>
  52.     <tr>
  53.       <th><label for="drawDistance">Draw Distance (<span id="currentDrawDistance"></span>) :</label></th>
  54.       <td><input id="drawDistance" type='range' min='100' max='500' title="integer (100-500)"></td>
  55.     </tr>
  56.     <tr>
  57.       <th><label for="fieldOfView">Field of View (<span id="currentFieldOfView"></span>) :</label></th>
  58.       <td><input id="fieldOfView" type='range' min='80' max='140' title="integer (80-140)"></td>
  59.     </tr>
  60.     <tr>
  61.       <th><label for="fogDensity">Fog Density (<span id="currentFogDensity"></span>) :</label></th>
  62.       <td><input id="fogDensity" type='range' min='0' max='50' title="integer (0-50)"></td>
  63.     </tr>
  64.   </table>
  65.  
  66.   <div id='instructions'>
  67.     <p>Use the <b>arrow keys</b> to drive the car.</p>
  68.   </div>
  69.  
  70.   <div id="racer">
  71.     <div id="hud">
  72.       <span id="speed"            class="hud"><span id="speed_value" class="value">0</span> mph</span>
  73.       <span id="current_lap_time" class="hud">Time: <span id="current_lap_time_value" class="value">0.0</span></span>
  74.       <span id="last_lap_time"    class="hud">Last Lap: <span id="last_lap_time_value" class="value">0.0</span></span>
  75.       <span id="fast_lap_time"    class="hud">Fastest Lap: <span id="fast_lap_time_value" class="value">0.0</span></span>
  76.     </div>
  77.     <canvas id="canvas">
  78.       Sorry, this example cannot be run because your browser does not support the &lt;canvas&gt; element
  79.     </canvas>
  80.     Loading...
  81.   </div>
  82.  
  83.   <audio id='music'>
  84.     <source src="music/racer.ogg">
  85.     <source src="music/racer.mp3">
  86.   </audio>
  87.   <span id="mute"></span>
  88.  
  89.   <script src="stats.js"></script>
  90.   <script src="common.js"></script>
  91.   <script>
  92.     var fps            = 60;                      // how many 'update' frames per second
  93.     var step           = 1/fps;                   // how long is each frame (in seconds)
  94.     var width          = 1024;                    // logical canvas width
  95.     var height         = 768;                     // logical canvas height
  96.     var centrifugal    = 0.3;                     // centrifugal force multiplier when going around curves
  97.     var offRoadDecel   = 0.99;                    // speed multiplier when off road (e.g. you lose 2% speed each update frame)
  98.     var skySpeed       = 0.001;                   // background sky layer scroll speed when going around curve (or up hill)
  99.     var hillSpeed      = 0.002;                   // background hill layer scroll speed when going around curve (or up hill)
  100.     var treeSpeed      = 0.003;                   // background tree layer scroll speed when going around curve (or up hill)
  101.     var skyOffset      = 0;                       // current sky scroll offset
  102.     var hillOffset     = 0;                       // current hill scroll offset
  103.     var treeOffset     = 0;                       // current tree scroll offset
  104.     var segments       = [];                      // array of road segments
  105.     var cars           = [];                      // array of cars on the road
  106.     var stats          = Game.stats('fps');       // mr.doobs FPS counter
  107.     var canvas         = Dom.get('canvas');       // our canvas...
  108.     var ctx            = canvas.getContext('2d'); // ...and its drawing context
  109.     var background     = null;                    // our background image (loaded below)
  110.     var sprites        = null;                    // our spritesheet (loaded below)
  111.     var resolution     = null;                    // scaling factor to provide resolution independence (computed)
  112.     var roadWidth      = 2000;                    // actually half the roads width, easier math if the road spans from -roadWidth to +roadWidth
  113.     var segmentLength  = 200;                     // length of a single segment
  114.     var rumbleLength   = 3;                       // number of segments per red/white rumble strip
  115.     var trackLength    = null;                    // z length of entire track (computed)
  116.     var lanes          = 3;                       // number of lanes
  117.     var fieldOfView    = 100;                     // angle (degrees) for field of view
  118.     var cameraHeight   = 1000;                    // z height of camera
  119.     var cameraDepth    = null;                    // z distance camera is from screen (computed)
  120.     var drawDistance   = 300;                     // number of segments to draw
  121.     var playerX        = 0;                       // player x offset from center of road (-1 to 1 to stay independent of roadWidth)
  122.     var playerZ        = null;                    // player relative z distance from camera (computed)
  123.     var fogDensity     = 5;                       // exponential fog density
  124.     var position       = 0;                       // current camera Z position (add playerZ to get player's absolute Z position)
  125.     var speed          = 0;                       // current speed
  126.     var maxSpeed       = segmentLength/step;      // top speed (ensure we can't move more than 1 segment in a single frame to make collision detection easier)
  127.     var accel          =  maxSpeed/5;             // acceleration rate - tuned until it 'felt' right
  128.     var breaking       = -maxSpeed;               // deceleration rate when braking
  129.     var decel          = -maxSpeed/5;             // 'natural' deceleration rate when neither accelerating, nor braking
  130.     var offRoadDecel   = -maxSpeed/2;             // off road deceleration is somewhere in between
  131.     var offRoadLimit   =  maxSpeed/4;             // limit when off road deceleration no longer applies (e.g. you can always go at least this speed even when off road)
  132.     var totalCars      = 200;                     // total number of cars on the road
  133.     var currentLapTime = 0;                       // current lap time
  134.     var lastLapTime    = null;                    // last lap time
  135.     var keyLeft        = false;
  136.     var keyRight       = false;
  137.     var keyFaster      = false;
  138.     var keySlower      = false;
  139.     var hud = {
  140.       speed:            { value: null, dom: Dom.get('speed_value')            },
  141.       current_lap_time: { value: null, dom: Dom.get('current_lap_time_value') },
  142.       last_lap_time:    { value: null, dom: Dom.get('last_lap_time_value')    },
  143.       fast_lap_time:    { value: null, dom: Dom.get('fast_lap_time_value')    }
  144.     }
  145.     //=========================================================================
  146.     // UPDATE THE GAME WORLD
  147.     //=========================================================================
  148.     function update(dt) {
  149.       var n, car, carW, sprite, spriteW;
  150.       var playerSegment = findSegment(position+playerZ);
  151.       var playerW       = SPRITES.PLAYER_STRAIGHT.w * SPRITES.SCALE;
  152.       var speedPercent  = speed/maxSpeed;
  153.       var dx            = dt * 2 * speedPercent; // at top speed, should be able to cross from left to right (-1 to 1) in 1 second
  154.       var startPosition = position;
  155.       updateCars(dt, playerSegment, playerW);
  156.       position = Util.increase(position, dt * speed, trackLength);
  157.       if (keyLeft)
  158.         playerX = playerX - dx;
  159.       else if (keyRight)
  160.         playerX = playerX + dx;
  161.       playerX = playerX - (dx * speedPercent * playerSegment.curve * centrifugal);
  162.       if (keyFaster)
  163.         speed = Util.accelerate(speed, accel, dt);
  164.       else if (keySlower)
  165.         speed = Util.accelerate(speed, breaking, dt);
  166.       else
  167.         speed = Util.accelerate(speed, decel, dt);
  168.       if ((playerX < -1) || (playerX > 1)) {
  169.         if (speed > offRoadLimit)
  170.           speed = Util.accelerate(speed, offRoadDecel, dt);
  171.         for(n = 0 ; n < playerSegment.sprites.length ; n++) {
  172.           sprite  = playerSegment.sprites[n];
  173.           spriteW = sprite.source.w * SPRITES.SCALE;
  174.           if (Util.overlap(playerX, playerW, sprite.offset + spriteW/2 * (sprite.offset > 0 ? 1 : -1), spriteW)) {
  175.             speed = maxSpeed/5;
  176.             position = Util.increase(playerSegment.p1.world.z, -playerZ, trackLength); // stop in front of sprite (at front of segment)
  177.             break;
  178.           }
  179.         }
  180.       }
  181.       for(n = 0 ; n < playerSegment.cars.length ; n++) {
  182.         car  = playerSegment.cars[n];
  183.         carW = car.sprite.w * SPRITES.SCALE;
  184.         if (speed > car.speed) {
  185.           if (Util.overlap(playerX, playerW, car.offset, carW, 0.8)) {
  186.             speed    = car.speed * (car.speed/speed);
  187.             position = Util.increase(car.z, -playerZ, trackLength);
  188.             break;
  189.           }
  190.         }
  191.       }
  192.       playerX = Util.limit(playerX, -3, 3);     // dont ever let it go too far out of bounds
  193.       speed   = Util.limit(speed, 0, maxSpeed); // or exceed maxSpeed
  194.       skyOffset  = Util.increase(skyOffset,  skySpeed  * playerSegment.curve * (position-startPosition)/segmentLength, 1);
  195.       hillOffset = Util.increase(hillOffset, hillSpeed * playerSegment.curve * (position-startPosition)/segmentLength, 1);
  196.       treeOffset = Util.increase(treeOffset, treeSpeed * playerSegment.curve * (position-startPosition)/segmentLength, 1);
  197.       if (position > playerZ) {
  198.         if (currentLapTime && (startPosition < playerZ)) {
  199.           lastLapTime    = currentLapTime;
  200.           currentLapTime = 0;
  201.           if (lastLapTime <= Util.toFloat(Dom.storage.fast_lap_time)) {
  202.             Dom.storage.fast_lap_time = lastLapTime;
  203.             updateHud('fast_lap_time', formatTime(lastLapTime));
  204.             Dom.addClassName('fast_lap_time', 'fastest');
  205.             Dom.addClassName('last_lap_time', 'fastest');
  206.           }
  207.           else {
  208.             Dom.removeClassName('fast_lap_time', 'fastest');
  209.             Dom.removeClassName('last_lap_time', 'fastest');
  210.           }
  211.           updateHud('last_lap_time', formatTime(lastLapTime));
  212.           Dom.show('last_lap_time');
  213.         }
  214.         else {
  215.           currentLapTime += dt;
  216.         }
  217.       }
  218.       updateHud('speed',            5 * Math.round(speed/500));
  219.       updateHud('current_lap_time', formatTime(currentLapTime));
  220.     }
  221.     //-------------------------------------------------------------------------
  222.     function updateCars(dt, playerSegment, playerW) {
  223.       var n, car, oldSegment, newSegment;
  224.       for(n = 0 ; n < cars.length ; n++) {
  225.         car         = cars[n];
  226.         oldSegment  = findSegment(car.z);
  227.         car.offset  = car.offset + updateCarOffset(car, oldSegment, playerSegment, playerW);
  228.         car.z       = Util.increase(car.z, dt * car.speed, trackLength);
  229.         car.percent = Util.percentRemaining(car.z, segmentLength); // useful for interpolation during rendering phase
  230.         newSegment  = findSegment(car.z);
  231.         if (oldSegment != newSegment) {
  232.           index = oldSegment.cars.indexOf(car);
  233.           oldSegment.cars.splice(index, 1);
  234.           newSegment.cars.push(car);
  235.         }
  236.       }
  237.     }
  238.     function updateCarOffset(car, carSegment, playerSegment, playerW) {
  239.       var i, j, dir, segment, otherCar, otherCarW, lookahead = 20, carW = car.sprite.w * SPRITES.SCALE;
  240.       // optimization, dont bother steering around other cars when 'out of sight' of the player
  241.       if ((carSegment.index - playerSegment.index) > drawDistance)
  242.         return 0;
  243.       for(i = 1 ; i < lookahead ; i++) {
  244.         segment = segments[(carSegment.index+i)%segments.length];
  245.         if ((segment === playerSegment) && (car.speed > speed) && (Util.overlap(playerX, playerW, car.offset, carW, 1.2))) {
  246.           if (playerX > 0.5)
  247.             dir = -1;
  248.           else if (playerX < -0.5)
  249.             dir = 1;
  250.           else
  251.             dir = (car.offset > playerX) ? 1 : -1;
  252.           return dir * 1/i * (car.speed-speed)/maxSpeed; // the closer the cars (smaller i) and the greated the speed ratio, the larger the offset
  253.         }
  254.         for(j = 0 ; j < segment.cars.length ; j++) {
  255.           otherCar  = segment.cars[j];
  256.           otherCarW = otherCar.sprite.w * SPRITES.SCALE;
  257.           if ((car.speed > otherCar.speed) && Util.overlap(car.offset, carW, otherCar.offset, otherCarW, 1.2)) {
  258.             if (otherCar.offset > 0.5)
  259.               dir = -1;
  260.             else if (otherCar.offset < -0.5)
  261.               dir = 1;
  262.             else
  263.               dir = (car.offset > otherCar.offset) ? 1 : -1;
  264.             return dir * 1/i * (car.speed-otherCar.speed)/maxSpeed;
  265.           }
  266.         }
  267.       }
  268.       // if no cars ahead, but I have somehow ended up off road, then steer back on
  269.       if (car.offset < -0.9)
  270.         return 0.1;
  271.       else if (car.offset > 0.9)
  272.         return -0.1;
  273.       else
  274.         return 0;
  275.     }
  276.     //-------------------------------------------------------------------------
  277.     function updateHud(key, value) { // accessing DOM can be slow, so only do it if value has changed
  278.       if (hud[key].value !== value) {
  279.         hud[key].value = value;
  280.         Dom.set(hud[key].dom, value);
  281.       }
  282.     }
  283.     function formatTime(dt) {
  284.       var minutes = Math.floor(dt/60);
  285.       var seconds = Math.floor(dt - (minutes * 60));
  286.       var tenths  = Math.floor(10 * (dt - Math.floor(dt)));
  287.       if (minutes > 0)
  288.         return minutes + "." + (seconds < 10 ? "0" : "") + seconds + "." + tenths;
  289.       else
  290.         return seconds + "." + tenths;
  291.     }
  292.     //=========================================================================
  293.     // RENDER THE GAME WORLD
  294.     //=========================================================================
  295.     function render() {
  296.       var baseSegment   = findSegment(position);
  297.       var basePercent   = Util.percentRemaining(position, segmentLength);
  298.       var playerSegment = findSegment(position+playerZ);
  299.       var playerPercent = Util.percentRemaining(position+playerZ, segmentLength);
  300.       var playerY       = Util.interpolate(playerSegment.p1.world.y, playerSegment.p2.world.y, playerPercent);
  301.       var maxy          = height;
  302.       var x  = 0;
  303.       var dx = - (baseSegment.curve * basePercent);
  304.       ctx.clearRect(0, 0, width, height);
  305.       Render.background(ctx, background, width, height, BACKGROUND.SKY,   skyOffset,  resolution * skySpeed  * playerY);
  306.       Render.background(ctx, background, width, height, BACKGROUND.HILLS, hillOffset, resolution * hillSpeed * playerY);
  307.       Render.background(ctx, background, width, height, BACKGROUND.TREES, treeOffset, resolution * treeSpeed * playerY);
  308.       var n, i, segment, car, sprite, spriteScale, spriteX, spriteY;
  309.       for(n = 0 ; n < drawDistance ; n++) {
  310.         segment        = segments[(baseSegment.index + n) % segments.length];
  311.         segment.looped = segment.index < baseSegment.index;
  312.         segment.fog    = Util.exponentialFog(n/drawDistance, fogDensity);
  313.         segment.clip   = maxy;
  314.         Util.project(segment.p1, (playerX * roadWidth) - x,      playerY + cameraHeight, position - (segment.looped ? trackLength : 0), cameraDepth, width, height, roadWidth);
  315.         Util.project(segment.p2, (playerX * roadWidth) - x - dx, playerY + cameraHeight, position - (segment.looped ? trackLength : 0), cameraDepth, width, height, roadWidth);
  316.         x  = x + dx;
  317.         dx = dx + segment.curve;
  318.         if ((segment.p1.camera.z <= cameraDepth)         || // behind us
  319.             (segment.p2.screen.y >= segment.p1.screen.y) || // back face cull
  320.             (segment.p2.screen.y >= maxy))                  // clip by (already rendered) hill
  321.           continue;
  322.         Render.segment(ctx, width, lanes,
  323.                        segment.p1.screen.x,
  324.                        segment.p1.screen.y,
  325.                        segment.p1.screen.w,
  326.                        segment.p2.screen.x,
  327.                        segment.p2.screen.y,
  328.                        segment.p2.screen.w,
  329.                        segment.fog,
  330.                        segment.color);
  331.         maxy = segment.p1.screen.y;
  332.       }
  333.       for(n = (drawDistance-1) ; n > 0 ; n--) {
  334.         segment = segments[(baseSegment.index + n) % segments.length];
  335.         for(i = 0 ; i < segment.cars.length ; i++) {
  336.           car         = segment.cars[i];
  337.           sprite      = car.sprite;
  338.           spriteScale = Util.interpolate(segment.p1.screen.scale, segment.p2.screen.scale, car.percent);
  339.           spriteX     = Util.interpolate(segment.p1.screen.x,     segment.p2.screen.x,     car.percent) + (spriteScale * car.offset * roadWidth * width/2);
  340.           spriteY     = Util.interpolate(segment.p1.screen.y,     segment.p2.screen.y,     car.percent);
  341.           Render.sprite(ctx, width, height, resolution, roadWidth, sprites, car.sprite, spriteScale, spriteX, spriteY, -0.5, -1, segment.clip);
  342.         }
  343.         for(i = 0 ; i < segment.sprites.length ; i++) {
  344.           sprite      = segment.sprites[i];
  345.           spriteScale = segment.p1.screen.scale;
  346.           spriteX     = segment.p1.screen.x + (spriteScale * sprite.offset * roadWidth * width/2);
  347.           spriteY     = segment.p1.screen.y;
  348.           Render.sprite(ctx, width, height, resolution, roadWidth, sprites, sprite.source, spriteScale, spriteX, spriteY, (sprite.offset < 0 ? -1 : 0), -1, segment.clip);
  349.         }
  350.         if (segment == playerSegment) {
  351.           Render.player(ctx, width, height, resolution, roadWidth, sprites, speed/maxSpeed,
  352.                         cameraDepth/playerZ,
  353.                         width/2,
  354.                         (height/2) - (cameraDepth/playerZ * Util.interpolate(playerSegment.p1.camera.y, playerSegment.p2.camera.y, playerPercent) * height/2),
  355.                         speed * (keyLeft ? -1 : keyRight ? 1 : 0),
  356.                         playerSegment.p2.world.y - playerSegment.p1.world.y);
  357.         }
  358.       }
  359.     }
  360.     function findSegment(z) {
  361.       return segments[Math.floor(z/segmentLength) % segments.length];
  362.     }
  363.     //=========================================================================
  364.     // BUILD ROAD GEOMETRY
  365.     //=========================================================================
  366.     function lastY() { return (segments.length == 0) ? 0 : segments[segments.length-1].p2.world.y; }
  367.     function addSegment(curve, y) {
  368.       var n = segments.length;
  369.       segments.push({
  370.           index: n,
  371.              p1: { world: { y: lastY(), z:  n   *segmentLength }, camera: {}, screen: {} },
  372.              p2: { world: { y: y,       z: (n+1)*segmentLength }, camera: {}, screen: {} },
  373.           curve: curve,
  374.         sprites: [],
  375.            cars: [],
  376.           color: Math.floor(n/rumbleLength)%2 ? COLORS.DARK : COLORS.LIGHT
  377.       });
  378.     }
  379.     function addSprite(n, sprite, offset) {
  380.       segments[n].sprites.push({ source: sprite, offset: offset });
  381.     }
  382.     function addRoad(enter, hold, leave, curve, y) {
  383.       var startY   = lastY();
  384.       var endY     = startY + (Util.toInt(y, 0) * segmentLength);
  385.       var n, total = enter + hold + leave;
  386.       for(n = 0 ; n < enter ; n++)
  387.         addSegment(Util.easeIn(0, curve, n/enter), Util.easeInOut(startY, endY, n/total));
  388.       for(n = 0 ; n < hold  ; n++)
  389.         addSegment(curve, Util.easeInOut(startY, endY, (enter+n)/total));
  390.       for(n = 0 ; n < leave ; n++)
  391.         addSegment(Util.easeInOut(curve, 0, n/leave), Util.easeInOut(startY, endY, (enter+hold+n)/total));
  392.     }
  393.     var ROAD = {
  394.       LENGTH: { NONE: 0, SHORT:  25, MEDIUM:   50, LONG:  100 },
  395.       HILL:   { NONE: 0, LOW:    20, MEDIUM:   40, HIGH:   60 },
  396.       CURVE:  { NONE: 0, EASY:    2, MEDIUM:    4, HARD:    6 }
  397.     };
  398.     function addStraight(num) {
  399.       num = num || ROAD.LENGTH.MEDIUM;
  400.       addRoad(num, num, num, 0, 0);
  401.     }
  402.     function addHill(num, height) {
  403.       num    = num    || ROAD.LENGTH.MEDIUM;
  404.       height = height || ROAD.HILL.MEDIUM;
  405.       addRoad(num, num, num, 0, height);
  406.     }
  407.     function addCurve(num, curve, height) {
  408.       num    = num    || ROAD.LENGTH.MEDIUM;
  409.       curve  = curve  || ROAD.CURVE.MEDIUM;
  410.       height = height || ROAD.HILL.NONE;
  411.       addRoad(num, num, num, curve, height);
  412.     }
  413.        
  414.     function addLowRollingHills(num, height) {
  415.       num    = num    || ROAD.LENGTH.SHORT;
  416.       height = height || ROAD.HILL.LOW;
  417.       addRoad(num, num, num,  0,                height/2);
  418.       addRoad(num, num, num,  0,               -height);
  419.       addRoad(num, num, num,  ROAD.CURVE.EASY,  height);
  420.       addRoad(num, num, num,  0,                0);
  421.       addRoad(num, num, num, -ROAD.CURVE.EASY,  height/2);
  422.       addRoad(num, num, num,  0,                0);
  423.     }
  424.     function addSCurves() {
  425.       addRoad(ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM,  -ROAD.CURVE.EASY,    ROAD.HILL.NONE);
  426.       addRoad(ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM,   ROAD.CURVE.MEDIUM,  ROAD.HILL.MEDIUM);
  427.       addRoad(ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM,   ROAD.CURVE.EASY,   -ROAD.HILL.LOW);
  428.       addRoad(ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM,  -ROAD.CURVE.EASY,    ROAD.HILL.MEDIUM);
  429.       addRoad(ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM, ROAD.LENGTH.MEDIUM,  -ROAD.CURVE.MEDIUM, -ROAD.HILL.MEDIUM);
  430.     }
  431.     function addBumps() {
  432.       addRoad(10, 10, 10, 0,  5);
  433.       addRoad(10, 10, 10, 0, -2);
  434.       addRoad(10, 10, 10, 0, -5);
  435.       addRoad(10, 10, 10, 0,  8);
  436.       addRoad(10, 10, 10, 0,  5);
  437.       addRoad(10, 10, 10, 0, -7);
  438.       addRoad(10, 10, 10, 0,  5);
  439.       addRoad(10, 10, 10, 0, -2);
  440.     }
  441.     function addDownhillToEnd(num) {
  442.       num = num || 200;
  443.       addRoad(num, num, num, -ROAD.CURVE.EASY, -lastY()/segmentLength);
  444.     }
  445.     function resetRoad() {
  446.       segments = [];
  447.       addStraight(ROAD.LENGTH.SHORT);
  448.       addLowRollingHills();
  449.       addSCurves();
  450.       addCurve(ROAD.LENGTH.MEDIUM, ROAD.CURVE.MEDIUM, ROAD.HILL.LOW);
  451.       addBumps();
  452.       addLowRollingHills();
  453.       addCurve(ROAD.LENGTH.LONG*2, ROAD.CURVE.MEDIUM, ROAD.HILL.MEDIUM);
  454.       addStraight();
  455.       addHill(ROAD.LENGTH.MEDIUM, ROAD.HILL.HIGH);
  456.       addSCurves();
  457.       addCurve(ROAD.LENGTH.LONG, -ROAD.CURVE.MEDIUM, ROAD.HILL.NONE);
  458.       addHill(ROAD.LENGTH.LONG, ROAD.HILL.HIGH);
  459.       addCurve(ROAD.LENGTH.LONG, ROAD.CURVE.MEDIUM, -ROAD.HILL.LOW);
  460.       addBumps();
  461.       addHill(ROAD.LENGTH.LONG, -ROAD.HILL.MEDIUM);
  462.       addStraight();
  463.       addSCurves();
  464.       addDownhillToEnd();
  465.       resetSprites();
  466.       resetCars();
  467.       segments[findSegment(playerZ).index + 2].color = COLORS.START;
  468.       segments[findSegment(playerZ).index + 3].color = COLORS.START;
  469.       for(var n = 0 ; n < rumbleLength ; n++)
  470.         segments[segments.length-1-n].color = COLORS.FINISH;
  471.       trackLength = segments.length * segmentLength;
  472.     }
  473.     function resetSprites() {
  474.       var n, i;
  475.       addSprite(20,  SPRITES.BILLBOARD07, -1);
  476.       addSprite(40,  SPRITES.BILLBOARD06, -1);
  477.       addSprite(60,  SPRITES.BILLBOARD08, -1);
  478.       addSprite(80,  SPRITES.BILLBOARD09, -1);
  479.       addSprite(100, SPRITES.BILLBOARD01, -1);
  480.       addSprite(120, SPRITES.BILLBOARD02, -1);
  481.       addSprite(140, SPRITES.BILLBOARD03, -1);
  482.       addSprite(160, SPRITES.BILLBOARD04, -1);
  483.       addSprite(180, SPRITES.BILLBOARD05, -1);
  484.       addSprite(240,                  SPRITES.BILLBOARD07, -1.2);
  485.       addSprite(240,                  SPRITES.BILLBOARD06,  1.2);
  486.       addSprite(segments.length - 25, SPRITES.BILLBOARD07, -1.2);
  487.       addSprite(segments.length - 25, SPRITES.BILLBOARD06,  1.2);
  488.       for(n = 10 ; n < 200 ; n += 4 + Math.floor(n/100)) {
  489.         addSprite(n, SPRITES.PALM_TREE, 0.5 + Math.random()*0.5);
  490.         addSprite(n, SPRITES.PALM_TREE,   1 + Math.random()*2);
  491.       }
  492.       for(n = 250 ; n < 1000 ; n += 5) {
  493.         addSprite(n,     SPRITES.COLUMN, 1.1);
  494.         addSprite(n + Util.randomInt(0,5), SPRITES.TREE1, -1 - (Math.random() * 2));
  495.         addSprite(n + Util.randomInt(0,5), SPRITES.TREE2, -1 - (Math.random() * 2));
  496.       }
  497.       for(n = 200 ; n < segments.length ; n += 3) {
  498.         addSprite(n, Util.randomChoice(SPRITES.PLANTS), Util.randomChoice([1,-1]) * (2 + Math.random() * 5));
  499.       }
  500.       var side, sprite, offset;
  501.       for(n = 1000 ; n < (segments.length-50) ; n += 100) {
  502.         side      = Util.randomChoice([1, -1]);
  503.         addSprite(n + Util.randomInt(0, 50), Util.randomChoice(SPRITES.BILLBOARDS), -side);
  504.         for(i = 0 ; i < 20 ; i++) {
  505.           sprite = Util.randomChoice(SPRITES.PLANTS);
  506.           offset = side * (1.5 + Math.random());
  507.           addSprite(n + Util.randomInt(0, 50), sprite, offset);
  508.         }
  509.          
  510.       }
  511.     }
  512.     function resetCars() {
  513.       cars = [];
  514.       var n, car, segment, offset, z, sprite, speed;
  515.       for (var n = 0 ; n < totalCars ; n++) {
  516.         offset = Math.random() * Util.randomChoice([-0.8, 0.8]);
  517.         z      = Math.floor(Math.random() * segments.length) * segmentLength;
  518.         sprite = Util.randomChoice(SPRITES.CARS);
  519.         speed  = maxSpeed/4 + Math.random() * maxSpeed/(sprite == SPRITES.SEMI ? 4 : 2);
  520.         car = { offset: offset, z: z, sprite: sprite, speed: speed };
  521.         segment = findSegment(car.z);
  522.         segment.cars.push(car);
  523.         cars.push(car);
  524.       }
  525.     }
  526.     //=========================================================================
  527.     // THE GAME LOOP
  528.     //=========================================================================
  529.     Game.run({
  530.       canvas: canvas, render: render, update: update, stats: stats, step: step,
  531.       images: ["background", "sprites"],
  532.       keys: [
  533.         { keys: [KEY.LEFT,  KEY.A], mode: 'down', action: function() { keyLeft   = true;  } },
  534.         { keys: [KEY.RIGHT, KEY.D], mode: 'down', action: function() { keyRight  = true;  } },
  535.         { keys: [KEY.UP,    KEY.W], mode: 'down', action: function() { keyFaster = true;  } },
  536.         { keys: [KEY.DOWN,  KEY.S], mode: 'down', action: function() { keySlower = true;  } },
  537.         { keys: [KEY.LEFT,  KEY.A], mode: 'up',   action: function() { keyLeft   = false; } },
  538.         { keys: [KEY.RIGHT, KEY.D], mode: 'up',   action: function() { keyRight  = false; } },
  539.         { keys: [KEY.UP,    KEY.W], mode: 'up',   action: function() { keyFaster = false; } },
  540.         { keys: [KEY.DOWN,  KEY.S], mode: 'up',   action: function() { keySlower = false; } }
  541.       ],
  542.       ready: function(images) {
  543.         background = images[0];
  544.         sprites    = images[1];
  545.         reset();
  546.         Dom.storage.fast_lap_time = Dom.storage.fast_lap_time || 180;
  547.         updateHud('fast_lap_time', formatTime(Util.toFloat(Dom.storage.fast_lap_time)));
  548.       }
  549.     });
  550.     function reset(options) {
  551.       options       = options || {};
  552.       canvas.width  = width  = Util.toInt(options.width,          width);
  553.       canvas.height = height = Util.toInt(options.height,         height);
  554.       lanes                  = Util.toInt(options.lanes,          lanes);
  555.       roadWidth              = Util.toInt(options.roadWidth,      roadWidth);
  556.       cameraHeight           = Util.toInt(options.cameraHeight,   cameraHeight);
  557.       drawDistance           = Util.toInt(options.drawDistance,   drawDistance);
  558.       fogDensity             = Util.toInt(options.fogDensity,     fogDensity);
  559.       fieldOfView            = Util.toInt(options.fieldOfView,    fieldOfView);
  560.       segmentLength          = Util.toInt(options.segmentLength,  segmentLength);
  561.       rumbleLength           = Util.toInt(options.rumbleLength,   rumbleLength);
  562.       cameraDepth            = 1 / Math.tan((fieldOfView/2) * Math.PI/180);
  563.       playerZ                = (cameraHeight * cameraDepth);
  564.       resolution             = height/480;
  565.       refreshTweakUI();
  566.       if ((segments.length==0) || (options.segmentLength) || (options.rumbleLength))
  567.         resetRoad(); // only rebuild road when necessary
  568.     }
  569.     //=========================================================================
  570.     // TWEAK UI HANDLERS
  571.     //=========================================================================
  572.     Dom.on('resolution', 'change', function(ev) {
  573.       var w, h, ratio;
  574.       switch(ev.target.options[ev.target.selectedIndex].value) {
  575.         case 'fine':   w = 1280; h = 960;  ratio=w/width; break;
  576.         case 'high':   w = 1024; h = 768;  ratio=w/width; break;
  577.         case 'medium': w = 640;  h = 480;  ratio=w/width; break;
  578.         case 'low':    w = 480;  h = 360;  ratio=w/width; break;
  579.       }
  580.       reset({ width: w, height: h })
  581.       Dom.blur(ev);
  582.     });
  583.     Dom.on('lanes',          'change', function(ev) { Dom.blur(ev); reset({ lanes:         ev.target.options[ev.target.selectedIndex].value }); });
  584.     Dom.on('roadWidth',      'change', function(ev) { Dom.blur(ev); reset({ roadWidth:     Util.limit(Util.toInt(ev.target.value), Util.toInt(ev.target.getAttribute('min')), Util.toInt(ev.target.getAttribute('max'))) }); });
  585.     Dom.on('cameraHeight',   'change', function(ev) { Dom.blur(ev); reset({ cameraHeight:  Util.limit(Util.toInt(ev.target.value), Util.toInt(ev.target.getAttribute('min')), Util.toInt(ev.target.getAttribute('max'))) }); });
  586.     Dom.on('drawDistance',   'change', function(ev) { Dom.blur(ev); reset({ drawDistance:  Util.limit(Util.toInt(ev.target.value), Util.toInt(ev.target.getAttribute('min')), Util.toInt(ev.target.getAttribute('max'))) }); });
  587.     Dom.on('fieldOfView',    'change', function(ev) { Dom.blur(ev); reset({ fieldOfView:   Util.limit(Util.toInt(ev.target.value), Util.toInt(ev.target.getAttribute('min')), Util.toInt(ev.target.getAttribute('max'))) }); });
  588.     Dom.on('fogDensity',     'change', function(ev) { Dom.blur(ev); reset({ fogDensity:    Util.limit(Util.toInt(ev.target.value), Util.toInt(ev.target.getAttribute('min')), Util.toInt(ev.target.getAttribute('max'))) }); });
  589.     function refreshTweakUI() {
  590.       Dom.get('lanes').selectedIndex = lanes-1;
  591.       Dom.get('currentRoadWidth').innerHTML      = Dom.get('roadWidth').value      = roadWidth;
  592.       Dom.get('currentCameraHeight').innerHTML   = Dom.get('cameraHeight').value   = cameraHeight;
  593.       Dom.get('currentDrawDistance').innerHTML   = Dom.get('drawDistance').value   = drawDistance;
  594.       Dom.get('currentFieldOfView').innerHTML    = Dom.get('fieldOfView').value    = fieldOfView;
  595.       Dom.get('currentFogDensity').innerHTML     = Dom.get('fogDensity').value     = fogDensity;
  596.     }
  597.     //=========================================================================
  598.   </script>
  599.  
  600. </body>
  601. </html
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement