原生js编写的一款三维赛车游戏

代码语言:html

所属分类:游戏

代码描述:原生js编写的一款三维赛车游戏,玩法:鼠标 = 转向,点击 = 刹车,双击 = 跳转,R = 重新启动,1 = 屏幕截图。道路是随机生成的,每次都不同。您从 20 秒开始,通过检查点再获得 10 秒。通过转向或跳过岩石和树木来避开它们。路在1000结束,祝你好运!

代码标签: 原生 js 编写 三维 赛车 游戏

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<html>
<!--/*
HUE JUMPER - By Frank Force
Low fi retro inspired endless runner in only 2 kilobytes!
Features
- Retro style 3D rendering engine in full HD
- Realistic driving physics and collisions
- Random level generation with increasing difficulty
- Gradient sky with sun and moon
- Procedurally generated mountain range
- Random trees and rocks
- Camera rumble and slow when off road
- Checkpoint system, road markers, and hue shift
- Time and distance display
*/-->
<title>Hue Jumper</title>
<meta charset="utf-8">
<body bgcolor=#000>
<canvas id=c style='touch-action:none;position:absolute;left:0px;top:0px;width:100%;height:100%'></canvas>
<a hidden id=downloadLink></a>
<script>
    
'use strict';                        // strict mode
    
// debug settings
const debug = 0;                     // enable debug features
const usePointerLock = 1;            // remove pointer lock for 2k build

// draw settings
const context = c.getContext('2d');  // canvas 2d context
const drawDistance = 800;            // how many road segments to draw in front of player
const cameraDepth = 1;               // FOV of camera (1 / Math.tan((fieldOfView/2) * Math.PI/180))
const roadSegmentLength = 100;       // length of each road segment
const roadWidth = 500;               // how wide is road
const warningTrackWidth = 150;       // with of road plus warning track
const dashLineWidth = 9;             // width of the dashed line in the road
const maxPlayerX = 2e3;              // player can not move this far from center of road
const mountainCount = 30;            // how many mountains are there
const timeDelta = 1/60;              // inverse frame rate

// player settings
const playerHeight = 150;            // how high is player above ground
const playerMaxSpeed = 300;          // limit max player speed
const playerAccel = 1;               // player acceleration
const playerBrake = -3;              // player acceleration when breaking
const playerTurnControl = .2;        // player turning rate
const playerJumpSpeed = 25;          // z speed added for jump
const playerSpringConstant = .01;    // spring players pitch
const playerCollisionSlow = .1;      // slow down from collisions
const pitchLerp = .1;                // speed that camera pitch changes
const pitchSpringDamping = .9;       // dampen the pitch spring
const elasticity = 1.2;              // bounce elasticity (2 is full bounce, 1 is none)
const centrifugal = .002;            // how much to pull player on turns
const forwardDamping = .999;         // dampen player z speed
const lateralDamping = .7;           // dampen player x speed
const offRoadDamping = .98;          // more damping when off road
const gravity = -1;                  // gravity to apply in y axis
const cameraHeadingScale = 2;        // scale of player turning to rotate camera
const worldRotateScale = .00005;     // how much to rotate world around turns
    
// level settings
const maxTime = 20;                  // time to start with
const checkPointTime = 10;           // how much time for getting to checkpoint
const checkPointDistance = 1e5;      // how far between checkpoints
const checkpointMaxDifficulty = 9;   // how many checkpoints before max difficulty
const roadEnd = 1e4;                 // how many sections until end of the road
    
// global game variables  
let playerPos;                  // player position 3d vector
let playerVelocity;             // player velocity 3d vector
let playerPitchSpring;          // spring for player pitch bounce
let playerPitchSpringVelocity;  // velocity of pitch spring
let playerPitchRoad;            // pitch of road, or 0 if player is in air
let playerAirFrame;             // how many frames player has been in air
let worldHeading;               // heading to turn skybox
let randomSeed;                 // random seed for level
let startRandomSeed;            // save the starting seed for active use
let nextCheckPoint;             // distance of next checkpoint
let hueShift;                   // current hue shift for all hsl colors
let road;                       // the list of road segments
let time;                       // time left before game over
let lastUpdate = 0;             // time of last update
let timeBuffer = 0;             // frame rate adjustment

function StartLevel()
{ 
    /////////////////////////////////////////////////////////////////////////////////////
    // build the road with procedural generation
    /////////////////////////////////////////////////////////////////////////////////////

    let roadGenSectionDistanceMax = 0;          // init end of section distance
    let roadGenWidth = roadWidth;               // starting road width
    let roadGenSectionDistance = 0;             // distance left for this section
    let roadGenTaper = 0;                       // length of taper
    let roadGenWaveFrequencyX = 0;              // X wave frequency 
    let roadGenWaveFrequencyY = 0;              // Y wave frequency
    let roadGenWaveScaleX = 0;                  // X wave amplitude (turn size)
    let roadGenWaveScaleY = 0;                  // Y wave amplitude (hill size)
    startRandomSeed = randomSeed = Date.now();  // set random seed
    road = [];                                  // clear list of road segments
    
    // generate the road
    for( let i = 0; i < roadEnd*2; ++i )                                      // build road past end
    {
        if (roadGenSectionDistance++ > roadGenSectionDistanceMax)             // check for end of section
        {
            // calculate difficulty percent
            const difficulty = Math.min(1, i*roadSegmentLength/checkPointDistance/checkpointMaxDifficulty); // difficulty
            
            // randomize road settings
            roadGenWidth = roadWidth*Random(1-difficulty*.7, 3-2*difficulty);        // road width
            roadGenWaveFrequencyX = Random(Lerp(difficulty, .01, .02));              // X frequency
            roadGenWaveFrequencyY = Random(Lerp(difficulty, .01, .03));              // Y frequency
            roadGenWaveScaleX = i > roadEnd ? 0 : Random(Lerp(difficulty, .2, .6));  // X scale
            roadGenWaveScaleY = Random(Lerp(difficulty, 1e3, 2e3));                  // Y scale
            
            // apply taper and move back
            roadGenTaper = Random(99, 1e3)|0;                           // randomize taper
            roadGenSectionDistanceMax = roadGenTaper + Random(99, 1e3); // randomize segment distance
            roadGenSectionDistance = 0;                                 // reset section distance
            i -= roadGenTaper;                                          // subtract taper
        }
        
        // make a wavy road
        const x = Math.sin(i*roadGenWaveFrequencyX) * roadGenWaveScaleX;      // road X
        const y = Math.sin(i*roadGenWaveFrequencyY) * roadGenWaveScaleY;      // road Y
        road[i] = road[i]? road[i] : {x:x, y:y, w:roadGenWidth};              // get or make road segment
        
        // apply taper from last section
        const p = Clamp(roadGenSectionDistance / roadGenTaper, 0, 1);         // get taper percent
        road[i].x = Lerp(p, road[i].x, x);                                    // X pos and taper
        road[i].y = Lerp(p, road[i].y, y);                                    // Y pos and taper
        road[i].w = i > roadEnd ? 0 : Lerp(p, road[i].w, roadGenWidth);       // check for road end, width and taper
        road[i].a = road[i-1] ? Math.atan2(road[i-1].y-road[i].y, roadSegmentLength) : 0; // road pitch angle
    }  
    
    /////////////////////////////////////////////////////////////////////////////////////
    // init game
    /////////////////////////////////////////////////////////////////////////////////////
     
    // reset everything
    playerVelocity = new Vector3
    ( 
        playerPitchSpring = 
        playerPitchSpringVelocity = 
        playerPitchRoad =  
        hueShift = 0
    );
    playerPos = new Vector3(0, playerHeight);   // set player pos
    worldHeading = randomSeed;                  // randomize world heading
    nextCheckPoint = checkPointDistance;        // init next checkpoint
    time = maxTime;                             // set the starting time
}
    
function Update()
{
    // time regulation, in case running faster then 60 fps, though it causes judder REMOVE FROM MINFIED
    const now = performance.now();
    if (lastUpdate)
    {
        // limit to 60 fps
        const delta = now - lastUpdate;
        if (timeBuffer + delta < 0)
        {
            // running fast
            requestAnimationFrame(Update);
            return;
        }
        
        // update time buffer
        timeBuffer += delta;
        timeBuffer -= timeDelta * 1e3;
        if (timeBuffer > timeDelta * 1e3)
            timeBuffer = 0; // if running too slow
    }
    lastUpdate = now;
    
    // start frame
    if (snapshot) {c.width|0} else                                  // DEBUG REMOVE FROM MINFIED
        c.width = window.innerWidth,c.height = window.innerHeight;  // clear the screen and set size
    
    if (!c.width) // REMOVE FROM MINFIED
    {
        // fix bug on itch, wait for canvas before updating
        requestAnimationFrame(Update);
        return;
    }
    
    if (usePointerLock && document.pointerLockElement !== c && !touchMode) // set mouse down if pointer lock released
        mouseDown = 1; 
    
    UpdateDebugPre(); // DEBUG REMOVE FROM MINFIED
    
    /////////////////////////////////////////////////////////////////////////////////////
    // update player - controls and physics
    /////////////////////////////////////////////////////////////////////////////////////
    
    // get player road segment
    const playerRoadSegment = playerPos.z/roadSegmentLength|0;         // current player road segment 
    const playerRoadSegmentPercent = playerPos.z/roadSegmentLength%1;  // how far player is along current segment
    
    // get lerped values between last and current road segment
    const playerRoadX = Lerp(playerRoadSegmentPercent, road[playerRoadSegment].x, road[playerRoadSegment+1].x);
    const playerRoadY = Lerp(playerRoadSegmentPercent, road[playerRoadSegment].y, road[playerRoadSegment+1].y) + playerHeight;
    const roadPitch = Lerp(playerRoadSegmentPercent, road[playerRoadSegment].a, road[playerRoadSegment+1].a);
    
    const playerVelocityLast = playerVelocity.Add(0);                      // save last velocity
    playerVelocity.y += gravity;                                           // gravity
    playerVelocity.x *= lateralDamping;                                    // apply lateral damping
    playerVelocity.z = Math.max(0, time ? forwardDamping*playerVelocity.z : 0); // apply damping, prevent moving backwards
    playerPos = playerPos.Add(playerVelocity);                             // add player velocity
    
    const playerTurnAmount = Lerp(playerVelocity.z/playerMaxSpeed, mouseX * playerTurnControl, 0); // turning
    playerVelocity.x +=                                          // update x velocity
        playerVelocity.z * playerTurnAmount -                    // apply turn
        playerVelocity.z ** 2 * centrifugal * playerRoadX;       // apply centrifugal force
    playerPos.x = Clamp(playerPos.x, -maxPlayerX, maxPlayerX);   // limit player x position
    
    // check if on ground
    if (playerPos.y < playerRoadY)
    {
        // bounce velocity against ground normal
        playerPos.y = playerRoadY;                                                                // match y to ground plane
        playerAirFrame = 0;                                                                       // reset air grace frames
        playerVelocity = new Vector3(0, Math.cos(roadPitch), Math.sin(roadPitch))                 // get ground normal
            .Multiply(-elasticity *                                                               // apply bounce
               (Math.cos(roadPitch) * playerVelocity.y + Math.sin(roadPitch) * playerVelocity.z)) // dot of road and velocity
            .Add(playerVelocity);                                                                 // add velocity

        playerVelocity.z += 
            mouseDown? playerBrake :                                                // apply brake              
            Lerp(playerVelocity.z/playerMaxSpeed, mouseWasPressed*playerAccel, 0);  // apply accel
        
        if (Math.abs(playerPos.x) > road[playerRoadSegment].w)                      // check if off road
        {
            playerVelocity.z *= offRoadDamping;                                     // slow down when off road
            playerPitchSpring += Math.sin(playerPos.z/99)**4/99;                    // bump when off road
        }
    }
  
    // update jump
    if (playerAirFrame++<6 && mouseDown && mouseUpFrames && mouseUpFrames<9 && time)  // check for jump
    {
        playerVelocity.y += playerJumpSpeed;                                          // apply jump velocity
        playerAirFrame = 9;                                                           // prevent jumping again
    }
    mouseUpFrames = mouseDown? 0 : mouseUpFrames+1;                                   // update mouse up frames for double click
    const airPercent = (playerPos.y-playerRoadY)/99;                                  // calculate above ground percent
    playerPitchSpringVelocity += Lerp(airPercent,0,playerVelocity.y/4e4);             // pitch down with vertical velocity
    
    // update player pitch
    playerPitchSpringVelocity += (playerVelocity.z - playerVelocityLast.z)/2e3;       // pitch down with forward accel
    playerPitchSpringVelocity -= playerPitchSpring * playerSpringConstant;            // apply pitch spring constant
    playerPitchSpringVelocity *= pitchSpringDamping;                                  // dampen pitch spring
    playerPitchSpring += playerPitchSpringVelocity;                                   // update pitch spring        
    playerPitchRoad = Lerp(pitchLerp, playerPitchRoad, Lerp(airPercent,-roadPitch,0));// match pitch to road
    const playerPitch = playerPitchSpring + playerPitchRoad;                          // update player pitch
    
    if (playerPos.z > nextCheckPoint)          // crossed checkpoint
    {
        time += checkPointTime;                // add more time
        nextCheckPoint += checkPointDistance;  // set next checkpoint
        hueShift += 36;                        // shift hue
    }
    
    /////////////////////////////////////////////////////////////////////////////////////
    // draw background - sky, sun/moon, mountains, and horizon
    /////////////////////////////////////////////////////////////////////////////////////
    
    // multi use local variables
    let x, y, w, i;

    randomSeed = startRandomSeed;                                                                 // set start seed
    worldHeading = ClampAngle(worldHeading + playerVelocity.z * playerRoadX * worldRotateScale);  // update world angle
    
    // pre calculate projection scale, flip y because y+ is down on canvas
    const projectScale = (new Vector3(1, -1, 1)).Multiply(c.width/2/cameraDepth);                 // get projection scale
    const cameraHeading = playerTurnAmount * cameraHeadingScale;                                  // turn camera with player 
    const cameraOffset = Math.sin(cameraHeading)/2;                                               // apply heading with offset
    
    // draw sky
    const lighting = Math.cos(worldHeading);                                    // brightness from sun
    const horizon = c.height/2 - Math.tan(playerPitch) * projectScale.y;        // get horizon line
    const g = context.createLinearGradient(0,horizon-c.height/2,0,horizon);     // linear gradient for sky
    g.addColorStop(0,LSHA(39+lighting*25,49+lighting*19,230-lighting*19));      // top sky color
    g.addColorStop(1,LSHA(5,79,250-lighting*9));                                // bottom sky color
    DrawPoly(c.width/2, 0, c.width/2, c.width/2, c.height, c.width/2, g);       // draw sky
    
    // draw sun and moon
    for( i = 2; i--; )                                                          // 0 is sun, 1 is moon
    {
        const g = context.createRadialGradient(                                 // radial gradient for sun
            x = c.width*(.5+Lerp(                                               // angle 0 is center
                (worldHeading/Math.PI/2+.5+i/2)%1,     .........完整代码请登录后点击上方下载按钮下载查看

网友评论0