openvibers/openvibe.games Commits
Surf maps go straight onto the ramp: no character select or customize screen, no hands, tool, vitals or hotbar; the run's clock sits top centre (compact on touch, no key hints) and the view starts looking at the drop (#193)
Changes
@@@ -20,7 +20,7 @@ import { MapLightLayer, mapDiff, staticWork, terrainWork } from './render/mapRunimport { createRapierWorld, loadRapier } from '@openvibe/physics/rapier'import { FixedTimestep } from '@openvibe/shared'import { Vector3 } from '@babylonjs/core/Maths/math.vector.js'--import type { Appearance } from '@openvibe/protocol'++import { defaultAppearance, type Appearance } from '@openvibe/protocol'import { Color3 } from '@babylonjs/core/Maths/math.color.js'import { Scene } from '@babylonjs/core/scene.js'import { WATER_LEVEL, getMapOverride, terrainHeight } from '@openvibe/content'@@@ -241,7 +241,12 @@ async function start(): Promise<void> {} catch {characters = []}-- const choice = await characterSelect(uiRoot, characters, Boolean(sso))++ // A surf map (OpenVibe.Surf's Ride) goes straight onto the ramp: your first character if you have one, else a surfer++ // with the default look under your saved name. Character select and the customize screen belong to the islands.++ const firstOwn = [...characters].sort((a, b) => a.slot - b.slot)[0] ?? null++ const choice = surfInfo++ ? { slot: firstOwn ? firstOwn.slot : 0, existing: firstOwn }++ : await characterSelect(uiRoot, characters, Boolean(sso))let name: stringlet appearance: Appearancelet releaseCamera: () => void@@@ -249,6 +254,10 @@ async function start(): Promise<void> {name = choice.existing.nameappearance = { ...choice.existing.appearance, height: 1, build: 1 }releaseCamera = () => {}++ } else if (surfInfo) {++ name = identity.name ?? 'Surfer'++ appearance = defaultAppearance()++ releaseCamera = () => {}} else {const created = await customizeScreen(scene, content, uiRoot, identity.name, !sso)name = created.name@@@ -269,6 +278,8 @@ async function start(): Promise<void> {const state = new ClientState()const connection = new Connection()const input = new InputTracker(canvas)++ // A surf map starts on a pad above its first ramp: look a little down, so the pad's edge (the drop) is in front.++ if (surfInfo) input.pitch = -0.2const view = new EntityView(scene, physics, content, state)const icons = new IconFactory(scene, content)const weaponSettings = new WeaponSettings()@@@ -455,6 +466,12 @@ async function start(): Promise<void> {environment.hazeFog = falsehud.setCrosshair(false)}++ // A surf run is the ramps and the clock: no hands or held tool, and no survival bars or hotbar (surfHud.css hides++ // those under .ovg-surf).++ if (surfInfo) {++ viewmodel.setEnabled(false)++ uiRoot.classList.add('ovg-surf')++ }// From above, a ring under each player (yours blue) shows who is where and which way each one faces.const markers = topDown ? new TopDownMarkers(scene, state, view, player) : nullconst beams = new BeamRenderer(scene)@@@ -1,9 +1,13 @@++/* The run's clock sits top centre, as in CS surf: clear of the OpenVibe menu pill (top left) and the phone's Restart++ button (top right). */.surf-hud {position: fixed;z-index: 12;-- top: max(1rem, env(safe-area-inset-top));-- left: max(1rem, env(safe-area-inset-left));-- width: min(18rem, calc(100vw - 2rem));++ top: max(0.75rem, env(safe-area-inset-top));++ left: 50%;++ translate: -50% 0;++ width: min(19rem, calc(100vw - 13rem));++ min-width: 13.5rem;padding: 0.8rem 0.95rem 0.9rem;border: 1px solid var(--border, #2a3340);border-left: 3px solid var(--g-accent, #f0b040);@@@ -116,3 +120,25 @@}.surf-watch { background: transparent !important; color: var(--text-primary, #e6e6e6) !important; }.surf-finish-actions button:disabled { opacity: 0.45; cursor: default; }++++/* A surf place has no survival: the vitals, the hotbar and the first-steps card are the islands'. */++.ovg-surf .vitals,++.ovg-surf .hotbar,++.ovg-surf .first-steps { display: none !important; }++++/* Touch: the keys mean nothing, the screen is small. A compact clock, the last two splits. */++@media (pointer: coarse), (max-width: 640px) {++ .surf-hud {++ width: auto;++ min-width: 0;++ max-width: calc(100vw - 11.5rem);++ padding: 0.5rem 0.7rem 0.55rem;++ border-radius: 0.7rem;++ font-size: 0.78rem;++ }++ .surf-title { display: none; }++ .surf-timer { font-size: 1.55rem; margin: 0; }++ .surf-hint { display: none; }++ .surf-meta { font-size: 0.68rem; }++ .surf-split:not(:nth-last-child(-n + 2)) { display: none; }++}
@@ -20,7 +20,7 @@ import { MapLightLayer, mapDiff, staticWork, terrainWork } from './render/mapRun
@@ -20,7 +20,7 @@ import { MapLightLayer, mapDiff, staticWork, terrainWork } from './render/mapRun
import { createRapierWorld, loadRapier } from '@openvibe/physics/rapier'
import { createRapierWorld, loadRapier } from '@openvibe/physics/rapier'
import { FixedTimestep } from '@openvibe/shared'
import { FixedTimestep } from '@openvibe/shared'
import { Vector3 } from '@babylonjs/core/Maths/math.vector.js'
import { Vector3 } from '@babylonjs/core/Maths/math.vector.js'
-import type { Appearance } from '@openvibe/protocol'
+import { defaultAppearance, type Appearance } from '@openvibe/protocol'
import { Color3 } from '@babylonjs/core/Maths/math.color.js'
import { Color3 } from '@babylonjs/core/Maths/math.color.js'
import { Scene } from '@babylonjs/core/scene.js'
import { Scene } from '@babylonjs/core/scene.js'
import { WATER_LEVEL, getMapOverride, terrainHeight } from '@openvibe/content'
import { WATER_LEVEL, getMapOverride, terrainHeight } from '@openvibe/content'
@@ -241,7 +241,12 @@ async function start(): Promise<void> {
@@ -241,7 +241,12 @@ async function start(): Promise<void> {
} catch {
} catch {
characters = []
characters = []
}
}
- const choice = await characterSelect(uiRoot, characters, Boolean(sso))
+ // A surf map (OpenVibe.Surf's Ride) goes straight onto the ramp: your first character if you have one, else a surfer
+ // with the default look under your saved name. Character select and the customize screen belong to the islands.
+ const firstOwn = [...characters].sort((a, b) => a.slot - b.slot)[0] ?? null
+ const choice = surfInfo
+ ? { slot: firstOwn ? firstOwn.slot : 0, existing: firstOwn }
+ : await characterSelect(uiRoot, characters, Boolean(sso))
let name: string
let name: string
let appearance: Appearance
let appearance: Appearance
let releaseCamera: () => void
let releaseCamera: () => void
@@ -249,6 +254,10 @@ async function start(): Promise<void> {
@@ -249,6 +254,10 @@ async function start(): Promise<void> {
name = choice.existing.name
name = choice.existing.name
appearance = { ...choice.existing.appearance, height: 1, build: 1 }
appearance = { ...choice.existing.appearance, height: 1, build: 1 }
releaseCamera = () => {}
releaseCamera = () => {}
+ } else if (surfInfo) {
+ name = identity.name ?? 'Surfer'
+ appearance = defaultAppearance()
+ releaseCamera = () => {}
} else {
} else {
const created = await customizeScreen(scene, content, uiRoot, identity.name, !sso)
const created = await customizeScreen(scene, content, uiRoot, identity.name, !sso)
name = created.name
name = created.name
@@ -269,6 +278,8 @@ async function start(): Promise<void> {
@@ -269,6 +278,8 @@ async function start(): Promise<void> {
const state = new ClientState()
const state = new ClientState()
const connection = new Connection()
const connection = new Connection()
const input = new InputTracker(canvas)
const input = new InputTracker(canvas)
+ // A surf map starts on a pad above its first ramp: look a little down, so the pad's edge (the drop) is in front.
+ if (surfInfo) input.pitch = -0.2
const view = new EntityView(scene, physics, content, state)
const view = new EntityView(scene, physics, content, state)
const icons = new IconFactory(scene, content)
const icons = new IconFactory(scene, content)
const weaponSettings = new WeaponSettings()
const weaponSettings = new WeaponSettings()
@@ -455,6 +466,12 @@ async function start(): Promise<void> {
@@ -455,6 +466,12 @@ async function start(): Promise<void> {
environment.hazeFog = false
environment.hazeFog = false
hud.setCrosshair(false)
hud.setCrosshair(false)
}
}
+ // A surf run is the ramps and the clock: no hands or held tool, and no survival bars or hotbar (surfHud.css hides
+ // those under .ovg-surf).
+ if (surfInfo) {
+ viewmodel.setEnabled(false)
+ uiRoot.classList.add('ovg-surf')
+ }
// From above, a ring under each player (yours blue) shows who is where and which way each one faces.
// From above, a ring under each player (yours blue) shows who is where and which way each one faces.
const markers = topDown ? new TopDownMarkers(scene, state, view, player) : null
const markers = topDown ? new TopDownMarkers(scene, state, view, player) : null
const beams = new BeamRenderer(scene)
const beams = new BeamRenderer(scene)
@@ -1,9 +1,13 @@
@@ -1,9 +1,13 @@
+/* The run's clock sits top centre, as in CS surf: clear of the OpenVibe menu pill (top left) and the phone's Restart
+ button (top right). */
.surf-hud {
.surf-hud {
position: fixed;
position: fixed;
z-index: 12;
z-index: 12;
- top: max(1rem, env(safe-area-inset-top));
- left: max(1rem, env(safe-area-inset-left));
- width: min(18rem, calc(100vw - 2rem));
+ top: max(0.75rem, env(safe-area-inset-top));
+ left: 50%;
+ translate: -50% 0;
+ width: min(19rem, calc(100vw - 13rem));
+ min-width: 13.5rem;
padding: 0.8rem 0.95rem 0.9rem;
padding: 0.8rem 0.95rem 0.9rem;
border: 1px solid var(--border, #2a3340);
border: 1px solid var(--border, #2a3340);
border-left: 3px solid var(--g-accent, #f0b040);
border-left: 3px solid var(--g-accent, #f0b040);
@@ -116,3 +120,25 @@
@@ -116,3 +120,25 @@
}
}
.surf-watch { background: transparent !important; color: var(--text-primary, #e6e6e6) !important; }
.surf-watch { background: transparent !important; color: var(--text-primary, #e6e6e6) !important; }
.surf-finish-actions button:disabled { opacity: 0.45; cursor: default; }
.surf-finish-actions button:disabled { opacity: 0.45; cursor: default; }
+
+/* A surf place has no survival: the vitals, the hotbar and the first-steps card are the islands'. */
+.ovg-surf .vitals,
+.ovg-surf .hotbar,
+.ovg-surf .first-steps { display: none !important; }
+
+/* Touch: the keys mean nothing, the screen is small. A compact clock, the last two splits. */
+@media (pointer: coarse), (max-width: 640px) {
+ .surf-hud {
+ width: auto;
+ min-width: 0;
+ max-width: calc(100vw - 11.5rem);
+ padding: 0.5rem 0.7rem 0.55rem;
+ border-radius: 0.7rem;
+ font-size: 0.78rem;
+ }
+ .surf-title { display: none; }
+ .surf-timer { font-size: 1.55rem; margin: 0; }
+ .surf-hint { display: none; }
+ .surf-meta { font-size: 0.68rem; }
+ .surf-split:not(:nth-last-child(-n + 2)) { display: none; }
+}