Skip to content

Commit 3e39989

Browse files
feat: sortable shot data and improved player updates
1 parent f4167da commit 3e39989

18 files changed

Lines changed: 522 additions & 234 deletions

examples/courses/courses.ts

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,17 @@ import {
1616
UIStats,
1717
UILoadingScreen,
1818
VolumetricClouds,
19-
type PlayerStatus,
2019
generateSetupData,
20+
CoursePlayer,
2121
} from '@opengolfsim/fuse';
2222

23-
interface GameContext {
24-
timer: THREE.Timer,
23+
24+
const gameContext: {
2525
startPoint: THREE.Vector3,
2626
aimPoint: THREE.Vector3,
2727

2828
// Environment
29+
timer: THREE.Timer,
2930
world?: World;
3031
scene?: THREE.Scene;
3132
renderer?: THREE.WebGLRenderer,
@@ -34,7 +35,7 @@ interface GameContext {
3435
fog?: THREE.Fog,
3536
clouds?: VolumetricClouds,
3637

37-
// Data
38+
// Course Data
3839
setupData?: OpenGolfSim.SetupData,
3940
gameData?: OpenGolfSim.GameData,
4041
course?: CourseLoader,
@@ -56,9 +57,7 @@ interface GameContext {
5657
// State
5758
distanceToAim: number,
5859
heightToAim: number,
59-
}
60-
61-
const gameContext: GameContext = {
60+
} = {
6261
timer: new THREE.Timer(),
6362
startPoint: new THREE.Vector3(0, 0, 0),
6463
aimPoint: new THREE.Vector3(0, 0, 0),
@@ -85,8 +84,7 @@ function launchShot(shot: OpenGolfSim.Shot) {
8584
}
8685
}
8786

88-
function setupNextShot(playerStatus?: PlayerStatus) {
89-
console.log('Setup next shot with player', playerStatus);
87+
function setupNextShot() {
9088
if (!gameContext.game) return;
9189
gameContext.camera?.setTracking(false);
9290
gameContext.startPoint.copy(gameContext.game.startPoint());
@@ -101,7 +99,8 @@ function setupNextShot(playerStatus?: PlayerStatus) {
10199

102100
gameContext.courseMap?.updatePosition(gameContext.startPoint, gameContext.game.pinPoint());
103101
gameContext.courseMap?.updateHole(gameContext.game.activeHole);
104-
gameContext.playerMenu?.update(gameContext.game.currentPlayer());
102+
103+
gameContext.playerMenu?.update(gameContext.game.activePlayer);
105104
}
106105

107106
function setupRenderer() {
@@ -184,13 +183,6 @@ async function setupScene() {
184183
});
185184
gameContext.scene.add(gameContext.clouds.object);
186185

187-
gameContext.shotData = new UIShotData('#shot-data', { units: gameContext.setupData?.units });
188-
gameContext.rangeFinder = new UIRangeFinder('#top-center', { units: gameContext.setupData?.units });
189-
gameContext.playerMenu = new UIPlayerMenu('#top-left', { setupData: gameContext.setupData });
190-
gameContext.playerMenu.on('selectClub', club => {
191-
192-
});
193-
194186
}
195187

196188
/**
@@ -244,7 +236,7 @@ async function handleSetup(payload: any) {
244236
preLoad();
245237
}
246238

247-
async function setupFullCourse() {
239+
async function setupCourse() {
248240
if (!app.world) {
249241
throw new Error('Physics world does not exist');
250242
}
@@ -281,26 +273,52 @@ async function setupFullCourse() {
281273

282274
// setup course game controller
283275
gameContext.game = new CourseGame(gameContext.course, gameContext.golfBall, gameContext.setupData);
284-
gameContext.game?.on('nextShot', (status) => setupNextShot(status));
276+
gameContext.game?.on('nextShot', (player) => {
277+
console.log(`A new player (${player.name}) is up!`);
278+
setupNextShot();
279+
});
280+
281+
gameContext.shotData = new UIShotData('#shot-data', { units: gameContext.setupData?.units });
282+
gameContext.rangeFinder = new UIRangeFinder('#top-center', { units: gameContext.setupData?.units });
283+
gameContext.playerMenu = new UIPlayerMenu('#top-left', { players: gameContext.game?.players || [] });
284+
gameContext.playerMenu.on('selectPlayer', player => {
285+
// handle player changed
286+
console.log('select player', player);
287+
if (gameContext.game) {
288+
gameContext.game.selectPlayer(player);
289+
}
290+
});
291+
gameContext.playerMenu.on('selectClub', club => {
292+
console.log('select club', club);
293+
// handle club change
294+
if (gameContext.game) {
295+
gameContext.game.selectClub(club);
296+
gameContext.playerMenu?.update(gameContext.game.activePlayer);
297+
}
298+
});
285299

300+
286301
setupNextShot();
287302

288303
gameContext.courseMap?.on('updateAim', adjustAimPoint);
289304
gameContext.courseMap?.on('updateStart', adjustStartPoint);
290305

291306
}
292307

308+
/**
309+
* Sets up loading screen and kicks off loading of the course and building the scene
310+
*/
293311
function preLoad() {
294-
gameContext.loadingScreen = new UILoadingScreen(document.body);
312+
gameContext.loadingScreen = new UILoadingScreen(document.body, { loadingPrefix: 'Loading Course' });
295313
gameContext.loadingScreen.on('load', (error) => {
296314
console.log('POST LOAD', error);
297315
if (!error) {
298316
requestAnimationFrame(animate);
299317
}
300318
});
301-
gameContext.loadingScreen.load(setupFullCourse);
319+
gameContext.loadingScreen.load(setupCourse);
302320

303-
gameContext.stats = new UIStats('#render-stats', { hidden: false }); // start hidden (press S to toggle)
321+
gameContext.stats = new UIStats('#render-stats', { hidden: true }); // start hidden (press S to toggle)
304322
gameContext.timer.connect(document);
305323
}
306324

@@ -367,15 +385,13 @@ async function initializeDebug() {
367385
if (!courseUrl) {
368386
throw new Error('No courseUrl provided');
369387
}
370-
gameContext.setupData = generateSetupData();
388+
gameContext.setupData = generateSetupData(2);
371389
gameContext.gameData = { id: 'web', courseUrl, gameMode: 2 };
372390
if (courseUrl) {
373391
preLoad();
374392
}
375393
}
376394

377-
// -- Required setup --
378-
//
379395
// listen for setup event from OpenGolfSim app
380396
app.on('setup', handleSetup);
381397
// listen for shot event from OpenGolfSim app

examples/index.html

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import '../src/css/base.css';
77
</script>
88
<style>
9+
body {
10+
overflow: auto !important;
11+
}
912
header {
1013
display: block;
1114
/* background-color: var(--bg-color-solid); */
@@ -14,39 +17,93 @@
1417
}
1518
main {
1619
display: block;
17-
padding: 20px 40px;
20+
padding: 4rem;
21+
}
22+
footer {
23+
display: block;
24+
text-align: center;
25+
padding: 4rem;
26+
color: var(--text-disabled);
27+
font-size: 12px;
1828
}
1929
.container {
20-
max-width: 500px;
30+
max-width: 800px;
2131
margin: auto;
2232
}
2333
h3 {
24-
font-weight: 800;
34+
font-weight: 700;
2535
color: var(--text-disabled);
2636
border-bottom: 1px solid var(--bg-color);
2737
padding-bottom: 1rem;
2838
}
39+
.social {
40+
text-align: center;
41+
display: flex;
42+
flex-direction: row;
43+
justify-content: flex-end;
44+
gap: 1rem;
45+
margin-bottom: 2rem;
46+
}
47+
.social a:hover img {
48+
opacity: 1;
49+
}
50+
.social a:active img {
51+
opacity: 0.4;
52+
}
53+
.social img {
54+
opacity: 0.7;
55+
width: 2rem;
56+
height: auto;
57+
}
58+
.section {
59+
margin-bottom: 3rem;
60+
}
2961
</style>
3062
</head>
3163
<body>
3264
<header>
65+
<div class="social">
66+
<a href="https://github.com/OpenGolfSim/fuse" target="_blank">
67+
<img src="https://cdn.simpleicons.org/github/FFFFFF" width="50" />
68+
</a>
69+
<a href="https://help.opengolfsim.com/connect-with-us" target="_blank">
70+
<img src="https://cdn.simpleicons.org/discord/FFFFFF" width="50" />
71+
</a>
72+
</div>
73+
3374
<div class="container">
3475
<img src="images/fuse.png" style="width: 200px;" />
3576
</div>
3677
</header>
3778
<main>
3879
<div class="container">
80+
<div class="section">
81+
<p>
82+
<a href="https://github.com/OpenGolfSim/fuse/">FUSE</a> (Fast Universal Simulator Engine) is <a href="https://opengolfsim.com">OpenGolfSim</a>'s free, lightweight 3D golf simulation and physics engine.
83+
It provides components and utilities for building fully featured golf simulator experiences in any WebGL-capable browser or device.
84+
</p>
85+
</div>
86+
87+
<div class="section">
88+
<h3>Examples</h3>
89+
<ul>
90+
<li>
91+
<a href="range/">Driving Range</a>
92+
</li>
93+
<li>
94+
<a href="courses/?courseUrl=https%3A%2F%2Fcoursedata.opengolfsim.com%2Fwebgl%2Fcourses%2Fmountain-vista%2Fv1%2Fmountain-vista-v1.1.glb">Mountain Vista 9-hole Course</a>
95+
</li>
96+
</ul>
97+
</div>
3998

40-
<h3>Examples</h3>
41-
<ul>
42-
<li>
43-
<a href="range/">Driving Range</a>
44-
</li>
45-
<li>
46-
<a href="courses/?courseUrl=https%3A%2F%2Fcoursedata.opengolfsim.com%2Fwebgl%2Fcourses%2Fmountain-vista%2Fv1%2Fmountain-vista-v1.1.glb">Mountain Vista 9-hole Course</a>
47-
</li>
48-
</ul>
99+
<div class="section">
100+
<h3>Documentation</h3>
101+
<p style="color: #888">Coming soon!</p>
102+
</div>
49103
</div>
50104
</main>
105+
<footer>
106+
&copy; 2026 <a href="https://opengolfsim.com">OpenGolfSim LLC</a> All Rights Reserved
107+
</footer>
51108
</body>
52109
</html>

0 commit comments

Comments
 (0)