From 477c8c4deb7eb48f3428b8d2edbdf47c8063b02c Mon Sep 17 00:00:00 2001 From: Frank Force Date: Sun, 29 Sep 2024 13:27:03 -0500 Subject: [PATCH] tweaks and opt --- code/draw.js | 2 +- code/game.js | 20 ++--- code/generative.js | 2 +- code/input.js | 5 +- code/levels.js | 4 +- code/scene.js | 12 +-- code/sounds.js | 2 +- code/track.js | 184 ++++++++++++++++++++++++++++++++++++++++++--- code/trackGen.js | 166 ---------------------------------------- code/utilities.js | 8 +- code/vehicle.js | 38 +++++----- code/webgl.js | 8 +- index.html | 34 ++++----- 13 files changed, 240 insertions(+), 245 deletions(-) diff --git a/code/draw.js b/code/draw.js index 1221f61..8e590d5 100644 --- a/code/draw.js +++ b/code/draw.js @@ -395,7 +395,7 @@ class Mesh function pushGradient(pos, size, color, color2) { const mesh = quadMesh; - const points = mesh.points.map(p=>p.multiply(size).add(pos)); + const points = mesh.points.map(p=>p.multiply(size).addSelf(pos)); const colors = [color, color, color2, color2]; glPushColoredVerts(points, colors); } diff --git a/code/game.js b/code/game.js index cb68ace..ab48831 100644 --- a/code/game.js +++ b/code/game.js @@ -31,7 +31,7 @@ const drawDistance = 1e3; // how many track segments to draw const cameraPlayerOffset = vec3(0,680,1050); const checkpointTrackSegments = testQuick?1e3:4500; const checkpointDistance = checkpointTrackSegments*trackSegmentLength; -const startCheckpointTime = 50; +const startCheckpointTime = 45; const extraCheckpointTime = 40; const levelLerpRange = .1; const levelGoal = 10; @@ -129,13 +129,6 @@ function gameStart() function gameUpdateInternal() { - if (document.hasFocus()) - { - if (autoFullscreen && !isFullscreen()) - toggleFullscreen(); - autoFullscreen = 0; - } - if (titleScreenMode) { // update title screen @@ -242,7 +235,6 @@ function gameUpdateInternal() function gameUpdate(frameTimeMS=0) { - requestAnimationFrame(gameUpdate); if (!clampAspectRatios) mainCanvasSize = vec3(mainCanvas.width=innerWidth, mainCanvas.height=innerHeight); else @@ -361,6 +353,7 @@ function gameUpdate(frameTimeMS=0) touchGamepadRender(); drawHUD(); debugDraw(); + requestAnimationFrame(gameUpdate); } function enhancedModeUpdate() @@ -368,7 +361,14 @@ function enhancedModeUpdate() if (!enhancedMode) return; - if (autoPause && !document.hasFocus() && !titleScreenMode && !isTouchDevice) + if (document.hasFocus()) + { + if (autoFullscreen && !isFullscreen()) + toggleFullscreen(); + autoFullscreen = 0; + } + + if (!titleScreenMode && !isTouchDevice && autoPause && !document.hasFocus()) paused = 1; // pause when losing focus if (keyWasPressed('Home')) // dev mode diff --git a/code/generative.js b/code/generative.js index c44fb45..77ab6b1 100644 --- a/code/generative.js +++ b/code/generative.js @@ -437,7 +437,7 @@ function generateTetures() // road signs setupContext(0,5); // turn left { - drawSignBackground(.5,.5,WHITE,BLACK,.04,GRAY,.3,.3,1); + drawSignBackground(.5,.5,WHITE,BLACK,.05,GRAY,.3,.3,1); color(BLACK); triangle(.42,.5,.12,-PI/2) context.lineWidth=.09; diff --git a/code/input.js b/code/input.js index d1f9a17..a4b0172 100644 --- a/code/input.js +++ b/code/input.js @@ -15,7 +15,7 @@ const keyWasPressed = (key) => inputData[key] & 2 ? 1 : 0; const keyWasReleased = (key) => inputData[key] & 4 ? 1 : 0; const clearInput = () => inputData = []; -let mousePos; +let mousePos = vec3(); const mouseIsDown = keyIsDown; const mouseWasPressed = keyWasPressed; const mouseWasReleased = keyWasReleased; @@ -35,9 +35,6 @@ let inputData = []; // track what keys are down function inputInit() { - if (!js13kBuildLevel2) - mousePos = vec3(); - if (gamepadsEnable) { gamepadData = []; diff --git a/code/levels.js b/code/levels.js index 7ebf4bf..d74919f 100644 --- a/code/levels.js +++ b/code/levels.js @@ -17,7 +17,7 @@ function initLevelInfos() LI.horizonSpriteSize = .5; //LI.tunnel = spriteList.tunnel2; // test tunnel LI.billboardChance = .3 // more billboards at start - LI.trafficDensity = .7; // less traffic start + //LI.trafficDensity = .7; // less traffic start // mostly straight with few well defined turns or bumps LI.turnChance = .6; @@ -117,7 +117,7 @@ function initLevelInfos() LI.sunHeight = .7; LI.hazardType = spriteList.hazard_rocks; LI.hazardChance = .002; - LI.trafficDensity = js13kBuildLevel2 ? 1.5 : 1.2; // extra traffic through snow + LI.trafficDensity = 1.2; // extra traffic through snow // snowy mountains //LI.turnChance = .5; diff --git a/code/scene.js b/code/scene.js index 10545bf..07e3ad3 100644 --- a/code/scene.js +++ b/code/scene.js @@ -30,7 +30,7 @@ function drawSky() // top/bottom gradient const skyColorTop = levelInfoLast.skyColorTop.lerp(levelInfo.skyColorTop, levelLerpPercent); const skyColorBottom = levelInfoLast.skyColorBottom.lerp(levelInfo.skyColorBottom, levelLerpPercent); - pushGradient(cameraPos.add(vec3(0,skyH,skyZ)), vec3(skyW,skyH), skyColorTop, skyColorBottom); + pushGradient(vec3(0,skyH,skyZ).addSelf(cameraPos), vec3(skyW,skyH), skyColorTop, skyColorBottom); // light settings from sky glLightDirection = vec3(0,1,1).rotateY(worldHeading).normalize(); @@ -51,7 +51,7 @@ function drawSky() for(let i=0;i<1;i+=.05) { sunColor.a = i?(1-i)**7:1; - pushSprite(cameraPos.add(vec3( x*headingScale, sunHeight, skyZ)), vec3(sunSize*(1+i*30)), sunColor, i?dotSpriteTile:circleSpriteTile); + pushSprite(vec3( x*headingScale, sunHeight, skyZ).addSelf(cameraPos), vec3(sunSize*(1+i*30)), sunColor, i?dotSpriteTile:circleSpriteTile); } } @@ -68,7 +68,7 @@ function drawSky() x = mod(x,range) - range/2; const y = random.float(skyTop); const s = random.float(3e2,8e2); - pushSprite(cameraPos.add(vec3( x, y, skyZ)), vec3(s*cloudWidth,s*cloudHeight), cloudColor, dotSpriteTile) + pushSprite(vec3( x, y, skyZ).addSelf(cameraPos), vec3(s*cloudWidth,s*cloudHeight), cloudColor, dotSpriteTile) } // parallax @@ -83,7 +83,7 @@ function drawSky() const levelTransition = levelFloat<.5 || levelFloat > levelGoal-.5 ? 1 : levelPercent < ltt ? (levelPercent/ltt)**ltp : levelPercent > 1-ltt ? 1-((levelPercent-1)/ltt+1)**ltp : 1; - const parallax = lerp(p, 1.01, 1.07); + const parallax = lerp(p, 1.01, 1.1); const s = random.float(1e2,2e2)*horizonSpriteSize; const size = vec3(random.float(1,2)*(horizonSprite.canMirror ? s*random.sign() : s),s,s); const x = mod(worldHeading*headingScale/parallax + random.float(range),range) - range/2; @@ -97,7 +97,7 @@ function drawSky() } const y = lerp(levelTransition, -yMax*1.5, yMax); const c = horizonSprite.getRandomSpriteColor(); - pushSprite(cameraPos.add(vec3( x, y, skyZ)), size, c, horizonSpriteTile); + pushSprite(vec3( x, y, skyZ).addSelf(cameraPos), size, c, horizonSpriteTile); } { @@ -111,7 +111,7 @@ function drawSky() // horizon bottom const groundColor = levelInfoLast.groundColor.lerp(levelInfo.groundColor, levelLerpPercent).brighten(.1); - pushSprite(cameraPos.add(vec3(0,-skyH,skyZ)), vec3(skyW,skyH), groundColor); + pushSprite(vec3(0,-skyH,skyZ).addSelf(cameraPos), vec3(skyW,skyH), groundColor); } glRender(); diff --git a/code/sounds.js b/code/sounds.js index 8b58e28..61d700f 100644 --- a/code/sounds.js +++ b/code/sounds.js @@ -1,7 +1,7 @@ 'use strict'; const sound_beep = new Sound([,0,220,.01,.08,.05,,.5,,,,,,,,,.3,.9,.01,,-99]); // beep -const sound_engine = new Sound([,,40,.2,.4,.2,,,,,,,,300,,,,,,,-80]); // engine +const sound_engine = new Sound([,,40,.2,.5,.5,,,,,,,,300,,,,,,,-80]); // engine const sound_hit = new Sound([,.3,90,,,.2,,3,,,,,,9,,.3,,.3,.01]); // crash const sound_bump = new Sound([4,.2,400,.01,.01,.01,,.8,-60,-70,,,.03,.1,,,.1,.5,.01,.4,400]); // bump const sound_checkpoint = new Sound([.3,0,980,,,,,3,,,,,,,,.03,,,,,500]); // checkpoint diff --git a/code/track.js b/code/track.js index be0fd65..f4d129b 100644 --- a/code/track.js +++ b/code/track.js @@ -131,20 +131,20 @@ function drawTrackScenery() if (!trackSegment.sideStreet) // no sprites on side streets for(let k=3;k--;) { - const spriteListide = (segmentIndex+k)%2 ? 1 : -1; - if (spriteListide == levelInfo.waterSide) + const spriteSide = (segmentIndex+k)%2 ? 1 : -1; + if (spriteSide == levelInfo.waterSide) { // water const sprite = spriteList.water; const s = sprite.size*sprite.getRandomSpriteScale(); const o2 = w+random.float(12e3,8e4); - const o = spriteListide * o2; + const o = spriteSide * o2; // get taller in distance to cover horizon const h = .4; const wave = time-segmentIndex/70; - const p = trackSegment.pos.add(vec3(o+2e3*Math.sin(wave),0)); + const p = vec3(o+2e3*Math.sin(wave),0).addSelf(trackSegment.pos); const waveWind = 9*Math.cos(wave); // fake wind to make wave seam more alive - pushTrackObject(p, vec3(spriteListide*s,s*h,s), WHITE, sprite, waveWind); + pushTrackObject(p, vec3(spriteSide*s,s*h,s), WHITE, sprite, waveWind); } else { @@ -164,8 +164,8 @@ function drawTrackScenery() // push farther away if big collision const xm = w+sprite.size+6*sprite.collideScale*s; - const o = spriteListide * random.float(xm,3e4); - const p = trackSegment.pos.add(vec3(o,0)); + const o = spriteSide * random.float(xm,3e4); + const p = vec3(o,0).addSelf(trackSegment.pos); const wind = trackSegment.getWind(); const color = sprite.getRandomSpriteColor(); const scale = vec3(s); @@ -239,7 +239,7 @@ function pushTrackObject(pos, scale, color, sprite, trackWind) const w = segment1.width; const o =(segmentIndex%2?1:-1)*(random.float(5e4,1e5)) const r = vec3(0,-heading,0); - const p = segment1.pos.add(vec3(-o,0)); + const p = vec3(-o,0).addSelf(segment1.pos); const s = vec3(random.float(500,1e3),random.float(1e3,4e3),random.float(500,1e3)); //const s = vec3(500,random.float(2e3,2e4),500); @@ -248,4 +248,170 @@ function pushTrackObject(pos, scale, color, sprite, trackWind) cubeMesh.render(m4, c); } } -*/ \ No newline at end of file +*/ + +/////////////////////////////////////////////////////////////////////////////// + +// an instance of a sprite +class TrackObject +{ + constructor(trackSegment, sprite, offset, color=WHITE, sizeScale=1) + { + this.trackSegment = trackSegment; + this.sprite = sprite; + this.offset = offset; + this.color = color; + + const scale = sprite.size * sizeScale; + this.scale = vec3(scale); + const trackWidth = trackSegment.width; + const trackside = offset.x < trackWidth*2 && offset.x > -trackWidth*2; + if (trackside && sprite.trackFace) + this.scale.x *= sign(offset.x); + else if (sprite.canMirror && random.bool()) + this.scale.x *= -1; + this.collideSize = sprite.collideScale*abs(scale); + } + + draw() + { + const trackSegment = this.trackSegment; + const pos = trackSegment.pos.add(this.offset); + const wind = trackSegment.getWind(); + pushTrackObject(pos, this.scale, this.color, this.sprite, wind); + } +} + +class TrackSegment +{ + constructor(segmentIndex,offset,width) + { + if (segmentIndex >= levelGoal*checkpointTrackSegments) + width = 0; // no track after end + + this.offset = offset; + this.width = width; + this.pitch = 0; + this.normal = vec3(); + + this.trackObjects = []; + const levelFloat = segmentIndex/checkpointTrackSegments; + const level = this.level = testLevelInfo ? testLevelInfo.level : levelFloat|0; + const levelInfo = getLevelInfo(level); + const levelInfoNext = getLevelInfo(levelFloat+1); + const levelLerpPercent = percent(levelFloat%1, 1-levelLerpRange, 1); + + const checkpointLine = segmentIndex > 25 && segmentIndex < 30 + || segmentIndex%checkpointTrackSegments > checkpointTrackSegments-10; + const recordPoint = bestDistance/trackSegmentLength; + const recordPointLine = segmentIndex>>3 == recordPoint>>3; + this.sideStreet = levelInfo.sideStreets && ((segmentIndex%checkpointTrackSegments)%495<36); + + { + // setup colors + const groundColor = levelInfo.groundColor.lerp(levelInfoNext.groundColor,levelLerpPercent); + const lineColor = levelInfo.lineColor.lerp(levelInfoNext.lineColor,levelLerpPercent); + const roadColor = levelInfo.roadColor.lerp(levelInfoNext.roadColor,levelLerpPercent); + + const largeSegmentIndex = segmentIndex/9|0; + const stripe = largeSegmentIndex% 2 ? .1: 0; + this.colorGround = groundColor.brighten(Math.cos(segmentIndex*2/PI)/20); + this.colorRoad = roadColor.brighten(stripe&&.05); + if (recordPointLine) + this.colorRoad = hsl(0,.8,.5); + else if (checkpointLine) + this.colorRoad = WHITE; // starting line + this.colorLine = lineColor; + if (stripe) + this.colorLine.a = 0; + if (this.sideStreet) + this.colorLine = this.colorGround = this.colorRoad; + } + + // spawn track objects + if (debug && testGameSprite) + { + // test sprite + this.addSprite(testGameSprite,random.floatSign(width/2,1e4)); + } + else if (debug && testTrackBillboards) + { + // test billboard + const billboardSprite = random.fromList(spriteList.billboards); + this.addSprite(billboardSprite,random.floatSign(width/2,1e4)); + } + else if (segmentIndex == levelGoal*checkpointTrackSegments) + { + // goal! + this.addSprite(spriteList.sign_goal); + } + else if (segmentIndex%checkpointTrackSegments == 0) + { + // checkpoint + if (segmentIndex < levelGoal*checkpointTrackSegments) + { + this.addSprite(spriteList.sign_checkpoint1,-width+500); + this.addSprite(spriteList.sign_checkpoint2, width-500); + } + } + + if (segmentIndex == 30) + { + // starting area + this.addSprite(spriteList.sign_start); + + // left + const ol = -(width+100); + this.addSprite(spriteList.sign_opGames,ol,1450); + this.addSprite(spriteList.sign_zzfx,ol,850); + this.addSprite(spriteList.sign_avalanche,ol); + + // right + const or = width+100; + this.addSprite(spriteList.sign_frankForce,or,1500); + this.addSprite(spriteList.sign_github,or,350); + this.addSprite(spriteList.sign_js13k,or); + if (js13kBuild) + random.seed = 1055752394; // hack, reset seed for js13k + } + } + + getWind() + { + const offset = this.offset; + const noiseScale = .001; + return Math.sin(time+(offset.x+offset.z)*noiseScale)/2; + } + + addSprite(sprite,x=0,y=0,extraScale=1) + { + // add a sprite to the track as a new track object + const offset = vec3(x,y); + const sizeScale = extraScale*sprite.getRandomSpriteScale(); + const color = sprite.getRandomSpriteColor(); + const trackObject = new TrackObject(this, sprite, offset, color, sizeScale); + this.trackObjects.push(trackObject); + } +} + +// get lerped info about a track segment +class TrackSegmentInfo +{ + constructor(z) + { + const segment = this.segmentIndex = z/trackSegmentLength|0; + const percent = this.percent = z/trackSegmentLength%1; + if (track[segment] && track[segment+1]) + { + if (track[segment].pos && track[segment+1].pos) + this.pos = track[segment].pos.lerp(track[segment+1].pos, percent); + else + this.pos = vec3(0,0,z); + this.pitch = lerp(percent, track[segment].pitch, track[segment+1].pitch); + this.offset = track[segment].offset.lerp(track[segment+1].offset, percent); + this.width = lerp(percent, track[segment].width,track[segment+1].width); + } + else + this.offset = this.pos = vec3(this.pitch = this.width = 0,0,z); + } +} diff --git a/code/trackGen.js b/code/trackGen.js index 46d2133..d420e0b 100644 --- a/code/trackGen.js +++ b/code/trackGen.js @@ -2,172 +2,6 @@ const testTrackBillboards=0; -/////////////////////////////////////////////////////////////////////////////// - -// an instance of a sprite -class TrackObject -{ - constructor(trackSegment, sprite, offset, color=WHITE, sizeScale=1) - { - this.trackSegment = trackSegment; - this.sprite = sprite; - this.offset = offset; - this.color = color; - - const scale = sprite.size * sizeScale; - this.scale = vec3(scale); - const trackWidth = trackSegment.width; - const trackside = offset.x < trackWidth*2 && offset.x > -trackWidth*2; - if (trackside && sprite.trackFace) - this.scale.x *= sign(offset.x); - else if (sprite.canMirror && random.bool()) - this.scale.x *= -1; - this.collideSize = sprite.collideScale*abs(scale); - } - - draw() - { - const trackSegment = this.trackSegment; - const pos = trackSegment.pos.add(this.offset); - const wind = trackSegment.getWind(); - pushTrackObject(pos, this.scale, this.color, this.sprite, wind); - } -} - -class TrackSegment -{ - constructor(segmentIndex,offset,width) - { - if (segmentIndex >= levelGoal*checkpointTrackSegments) - width = 0; // no track after end - - this.offset = offset; - this.width = width; - this.pitch = 0; - this.normal = vec3(); - - this.trackObjects = []; - const levelFloat = segmentIndex/checkpointTrackSegments; - const level = this.level = testLevelInfo ? testLevelInfo.level : levelFloat|0; - const levelInfo = getLevelInfo(level); - const levelInfoNext = getLevelInfo(levelFloat+1); - const levelLerpPercent = percent(levelFloat%1, 1-levelLerpRange, 1); - - const checkpointLine = segmentIndex > 25 && segmentIndex < 30 - || segmentIndex%checkpointTrackSegments > checkpointTrackSegments-10; - const recordPoint = bestDistance/trackSegmentLength; - const recordPointLine = segmentIndex>>3 == recordPoint>>3; - this.sideStreet = levelInfo.sideStreets && ((segmentIndex%checkpointTrackSegments)%495<36); - - { - // setup colors - const groundColor = levelInfo.groundColor.lerp(levelInfoNext.groundColor,levelLerpPercent); - const lineColor = levelInfo.lineColor.lerp(levelInfoNext.lineColor,levelLerpPercent); - const roadColor = levelInfo.roadColor.lerp(levelInfoNext.roadColor,levelLerpPercent); - - const largeSegmentIndex = segmentIndex/9|0; - const stripe = largeSegmentIndex% 2 ? .1: 0; - this.colorGround = groundColor.brighten(Math.cos(segmentIndex*2/PI)/20); - this.colorRoad = roadColor.brighten(stripe&&.05); - if (recordPointLine) - this.colorRoad = hsl(0,.8,.5); - else if (checkpointLine) - this.colorRoad = WHITE; // starting line - this.colorLine = lineColor; - if (stripe) - this.colorLine.a = 0; - if (this.sideStreet) - this.colorLine = this.colorGround = this.colorRoad; - } - - // spawn track objects - if (debug && testGameSprite) - { - // test sprite - this.addSprite(testGameSprite,random.floatSign(width/2,1e4)); - } - else if (debug && testTrackBillboards) - { - // test billboard - const billboardSprite = random.fromList(spriteList.billboards); - this.addSprite(billboardSprite,random.floatSign(width/2,1e4)); - } - else if (segmentIndex == levelGoal*checkpointTrackSegments) - { - // goal! - this.addSprite(spriteList.sign_goal); - } - else if (segmentIndex%checkpointTrackSegments == 0) - { - // checkpoint - if (segmentIndex < levelGoal*checkpointTrackSegments) - { - this.addSprite(spriteList.sign_checkpoint1,-width+500); - this.addSprite(spriteList.sign_checkpoint2, width-500); - } - } - - if (segmentIndex == 30) - { - // starting area - this.addSprite(spriteList.sign_start); - - // left - const ol = -(width+100); - this.addSprite(spriteList.sign_opGames,ol,1450); - this.addSprite(spriteList.sign_zzfx,ol,850); - this.addSprite(spriteList.sign_avalanche,ol); - - // right - const or = width+100; - this.addSprite(spriteList.sign_frankForce,or,1500); - this.addSprite(spriteList.sign_github,or,350); - this.addSprite(spriteList.sign_js13k,or); - if (js13kBuild) - random.seed = 1055752394; // hack, reset seed for js13k - } - } - - getWind() - { - const offset = this.offset; - const noiseScale = .001; - return Math.sin(time+(offset.x+offset.z)*noiseScale)/2; - } - - addSprite(sprite,x=0,y=0,extraScale=1) - { - // add a sprite to the track as a new track object - const offset = vec3(x,y); - const sizeScale = extraScale*sprite.getRandomSpriteScale(); - const color = sprite.getRandomSpriteColor(); - const trackObject = new TrackObject(this, sprite, offset, color, sizeScale); - this.trackObjects.push(trackObject); - } -} - -// get lerped info about a track segment -class TrackSegmentInfo -{ - constructor(z) - { - const segment = this.segmentIndex = z/trackSegmentLength|0; - const percent = this.percent = z/trackSegmentLength%1; - if (track[segment] && track[segment+1]) - { - if (track[segment].pos && track[segment+1].pos) - this.pos = track[segment].pos.lerp(track[segment+1].pos, percent); - else - this.pos = vec3(0,0,z); - this.pitch = lerp(percent, track[segment].pitch, track[segment+1].pitch); - this.offset = track[segment].offset.lerp(track[segment+1].offset, percent); - this.width = lerp(percent, track[segment].width,track[segment+1].width); - } - else - this.offset = this.pos = vec3(this.pitch = this.width = 0,0,z); - } -} - // build the road with procedural generation function buildTrack() { diff --git a/code/utilities.js b/code/utilities.js index 20553aa..91f5c9f 100644 --- a/code/utilities.js +++ b/code/utilities.js @@ -66,8 +66,8 @@ class Vector3 this.x=x; this.y=y; this.z=z; } copy() { return vec3(this.x, this.y, this.z); } - abs() { return vec3(abs(this.x), abs(this.y), abs(this.z)); } add(v) { ASSERT_VEC3(v); return vec3(this.x + v.x, this.y + v.y, this.z + v.z); } + addSelf(v) { ASSERT_VEC3(v); this.x += v.x, this.y += v.y, this.z += v.z; return this } subtract(v) { ASSERT_VEC3(v); return vec3(this.x - v.x, this.y - v.y, this.z - v.z); } multiply(v) { ASSERT_VEC3(v); return vec3(this.x * v.x, this.y * v.y, this.z * v.z); } divide(v) { ASSERT_VEC3(v); return vec3(this.x / v.x, this.y / v.y, this.z / v.z); } @@ -80,13 +80,9 @@ class Vector3 clampLength(length=1) { const l = this.length(); return l > length ? this.scale(length/l) : this; } dot(v) { ASSERT_VEC3(v); return this.x*v.x + this.y*v.y + this.z*v.z; } angleBetween(v) { ASSERT_VEC3(v); return Math.acos(clamp(this.dot(v), -1, 1)); } - max(v) { ASSERT_VEC3(v); return vec3(max(this.x, v.x), max(this.y, v.y), max(this.z, v.z)); } - min(v) { ASSERT_VEC3(v); return vec3(min(this.x, v.x), min(this.y, v.y), min(this.z, v.z)); } - floor() { return vec3(floor(this.x), floor(this.y), floor(this.z)); } - round() { return vec3(Math.round(this.x), Math.round(this.y), Math.round(this.z)); } clamp(a, b) { return vec3(clamp(this.x, a, b), clamp(this.y, a, b), clamp(this.z, a, b)); } cross(v) { ASSERT_VEC3(v); return vec3(this.y*v.z-this.z*v.y, this.z*v.x-this.x*v.z, this.x*v.y-this.y*v.x); } - lerp(v, p) { ASSERT_VEC3(v); return this.add(v.subtract(this).scale(clamp(p))); } + lerp(v, p) { ASSERT_VEC3(v); return v.subtract(this).scale(clamp(p)).addSelf(this); } rotateX(a) { const c=Math.cos(a), s=Math.sin(a); diff --git a/code/vehicle.js b/code/vehicle.js index 7e9bdb6..580c7ae 100644 --- a/code/vehicle.js +++ b/code/vehicle.js @@ -10,7 +10,7 @@ function updateCars() { // spawn in more vehicles const playerIsSlow = titleScreenMode || playerVehicle.velocity.z < 20; - const trafficPosOffset = playerIsSlow? 0 : 18e4; // check in front/behind + const trafficPosOffset = playerIsSlow? 0 : 16e4; // check in front/behind const trafficLevel = (playerVehicle.pos.z+trafficPosOffset)/checkpointDistance; const trafficLevelInfo = getLevelInfo(trafficLevel); const trafficDensity = trafficLevelInfo.trafficDensity; @@ -130,10 +130,10 @@ class Vehicle { // slow down if behind if (v != this && v != playerVehicle) - if (this.pos.z < v.pos.z + (js13kBuildLevel2?0:500) && this.pos.z > v.pos.z - 2e3) + if (this.pos.z < v.pos.z + 500 && this.pos.z > v.pos.z - 2e3) if (abs(x-v.laneOffset) < 500) // lane space { - if (!js13kBuildLevel2 && this.pos.z >= v.pos.z) + if (this.pos.z >= v.pos.z) this.destroyed = 1; // get rid of overlaps this.velocity.z = min(this.velocity.z, v.velocity.z++); // clamp velocity & push this.isBraking = 20; @@ -195,7 +195,7 @@ class Vehicle glPolygonOffset(60); const lightOffset = vec3(0,0,-60).rotateY(worldHeading); const shadowColor = rgb(0,0,0,.5); - const shadowPosBase = vec3(p.x,trackInfo.pos.y,p.z).add(lightOffset); + const shadowPosBase = vec3(p.x,trackInfo.pos.y,p.z).addSelf(lightOffset); const shadowSize = vec3(-720,200,600); // why x negative? const m2 = buildMatrix(shadowPosBase, vec3(trackPitch,0)).multiply(mHeading); @@ -221,7 +221,7 @@ class Vehicle } glPolygonOffset(); // turn it off! - if (optimizedCulling && !js13kBuildLevel2) + if (optimizedCulling) { const distanceFromPlayer = this.pos.z - playerVehicle.pos.z; if (distanceFromPlayer > 4e4) @@ -374,14 +374,14 @@ class PlayerVehicle extends Vehicle if (!testDrive) for(const v of vehicles) { - const d = this.pos.subtract(v.pos).abs(); + const d = this.pos.subtract(v.pos); const s = this.collisionSize.add(v.collisionSize); - if (v != this && d.x < s.x && d.z < s.z) + if (v != this && abs(d.x) < s.x && abs(d.z) < s.z) { // collision this.velocity.z = v.velocity.z/2; v.velocity.z = max(v.velocity.z, this.velocity.z*1.5); // push other car - this.velocity.x = 99*sign(this.pos.x-v.pos.x); // push away from car + this.velocity.x = 99*sign(d.x); // push away from car playHitSound(); } } @@ -434,16 +434,16 @@ class PlayerVehicle extends Vehicle this.isBraking = playerInputBrake; const sound_velocity = max(40+playerInputGas*50,this.velocity.z); - this.engineTime += sound_velocity*sound_velocity/1e4; + this.engineTime += sound_velocity*sound_velocity/5e4; if (this.engineTime > 1) { --this.engineTime; const f = sound_velocity; - sound_engine.play(.1,f*f/5e3+rand(.1)); + sound_engine.play(.1,f*f/4e3+rand(.1)); } // player settings - const forwardDamping = .998; // dampen player z speed + const forwardDamping = .9978; // dampen player z speed const playerTurnControl = .4 // player turning rate const gravity = -3; // gravity to apply in y axis const lateralDamping = .5; // dampen player x speed @@ -455,7 +455,7 @@ class PlayerVehicle extends Vehicle // update physics this.velocity.y += gravity; this.velocity.x *= lateralDamping; - this.pos = this.pos.add(this.velocity); + this.pos.addSelf(this.velocity); const playerTrackInfo = new TrackSegmentInfo(this.pos.z); const playerTrackSegment = playerTrackInfo.segmentIndex; @@ -483,7 +483,7 @@ class PlayerVehicle extends Vehicle (Math.cos(trackPitch) * this.velocity.y + Math.sin(trackPitch) * this.velocity.z)); if (!gameOverTimer.isSet()) // dont roll in game over - this.velocity = this.velocity.add(reflectVelocity); + this.velocity.addSelf(reflectVelocity); if (!wasOnGround) { @@ -511,11 +511,14 @@ class PlayerVehicle extends Vehicle // apply acceleration in angle of road //const accelVec = vec3(0,0,accel).rotateX(trackSegment.pitch); - //this.velocity = this.velocity.add(accelVec); + //this.velocity.addSelf(accelVec); this.velocity.z += accel; } else if (this.velocity.z < 30) this.velocity.z *= .9; // slow to stop + + // dampen z velocity & clamp + this.velocity.z = max(0, this.velocity.z*forwardDamping); } else { @@ -524,10 +527,7 @@ class PlayerVehicle extends Vehicle this.onGround = 0; } - { - // dampen z velocity & clamp - this.velocity.z = max(0, this.velocity.z*forwardDamping); - + { // turning let desiredPlayerTurn = startCountdown > 0 ? 0 : playerInputTurn * playerTurnControl; if (testDrive) @@ -628,7 +628,7 @@ class PlayerVehicle extends Vehicle if (abs(dp.z) > 430 || abs(dp.x) > csx) continue; - //const cs = this.collisionSize.add(vec3(trackObject.collideSize,0,50)); + //const cs = vec3(trackObject.collideSize,0,50),addSelf(this.collisionSize); //if (abs(dp.z) > cs.z || abs(dp.x) > cs.x)// js13k hack // continue; diff --git a/code/webgl.js b/code/webgl.js index 785109a..f3f889e 100644 --- a/code/webgl.js +++ b/code/webgl.js @@ -214,6 +214,8 @@ function glCreateProjectionMatrix(fov=.5, near = 1, far = 1e4) /////////////////////////////////////////////////////////////////////////////// // drawing functions +const vectorOne = vec3(1); // no lighting/texture + // push a list of colored verts with optonal normals and uvs function glPushVerts(points, normals, color, uvs) { @@ -221,7 +223,7 @@ function glPushVerts(points, normals, color, uvs) if (!(count < gl_MAX_BATCH - glBatchCount)) glRender(); - const na = vec3(1); // no lighting/texture + const na = vectorOne; // no lighting/texture for(let i=count; i--;) glPushVert(points[i], normals ? normals[i] : na, uvs ? uvs[i] : na, color); } @@ -235,7 +237,7 @@ function glPushVertsCapped(points, normals, color, uvs) if (!(count+2 < gl_MAX_BATCH - glBatchCount)) glRender(); - const na = vec3(1); // no lighting/texture + const na = vectorOne; // no lighting/texture glPushVert(points[count-1], na, na, color); for(let i=count; i--;) glPushVert(points[i], normals ? normals[i] : na, uvs ? uvs[i] : na, color); @@ -250,7 +252,7 @@ function glPushColoredVerts(points, colors) if (!(count+2 < gl_MAX_BATCH - glBatchCount)) glRender(); - const na = vec3(1); // no lighting/texture + const na = vectorOne; // no lighting/texture glPushVert(points[count-1], na, na, colors[count-1]); for(let i=count; i--;) glPushVert(points[i], na, na, colors[i]); diff --git a/index.html b/index.html index 7029223..9085bc9 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ Dr1v3n Wild! 🚗🌴 - + @@ -27,19 +27,19 @@ document.body.style.backgroundColor = '#222'; } - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + \ No newline at end of file