This is a new typescript project template intended for VirtEx
Modules / Features
Vite as bundler
Vitest for unit testing
Typedoc for documentation
Learnings from the Phase I Project
Avoid "any" type, for example see how to cast json into a class with baseutil methods
Clean service for database access. The service should have no knowledge of the database json structure.
Types of Files and Naming Conventions
Files contain code for different purposes. Here are a few conventions
utils are files that have only or mostly static functions. Examples navbarUtils.ts with class NavbarUtils
services are files that contain classes that need to be instantiated. Examples are firebaseService.ts with class FirebaseService
models are files that contain strongly typed models reflecting the database. Examples are playerModel.ts with PlayerModel
handlers are files containing class that manipulate models. Example playerHandler.ts with class PlayerHandler
html are html files and can are clearly identified by their extensions
test are typescript files that do unit test for typescript classes (in particular handlers). Example playerHandler.test.ts
Folder Structure
The folder structure should offer a "meaningfull" way to organize all files.
One good rule for "meaningful" can be that a developer can find files without knowing berforehand where they are.
Here are some guiding princles for this approach:
Keep related files close together Examples for related files can be:
The player model is only used in playerhandler; the files should be next to each other
The unit test for the playerhandler should be next to the the playerhandler
Keep utils and services at the closest folder where they are used
Servcices like firebase or s3 should be in a folder services
Utilities like baseUtils should be in a folder utils.
Angular like components Establish a habit of grouping angular like components together. An example is the placement component.
placement.ts is the typescript code for the component. It is invoked by the parent and the parent holds a handle to the component. The parent can supply a callback if necessary.
placement.html contains the html for this component. It is injected into the dom by the constructor of the placement.ts class.
placement.css contains any specific css for this component. It is injected by the placement.ts class.
The main entry points:
index.html with index.ts (in src)
app.ts has the logic to administer the game
Some Selected Topics
Player Management
The application manages two types of players:
Local Player:
Represents the player controlled by your keyboard inputs.
Only one local player exists per instance of the application.
Remote Players:
Represent players instantiated and controlled by other users.
Multiple remote players can exist in the scene.
Visible and animated based on data synchronized from Firebase.
Both player types are rendered in the same scene and must be visible to all users for real-time interaction. However, only the local player responds to keyboard inputs.
Player Classes
The management of players is divided into the following classes:
BasePlayer:
Contains shared functionality for all players, such as loading the 3D model (mesh) and extracting animation groups. It serves as the foundation for LocalPlayer and RemotePlayer.
LocalPlayer:
Represents the player controlled by the user via keyboard input. This class extends BasePlayer and adds functionality for local input handling and movement.
RemotePlayer:
Represents players controlled by other users. This class extends BasePlayer and updates its state based on real-time data received from Firebase.
Data Synchronization
Player data is synchronized between users using Firebase. To optimize performance, the data is divided into three types:
PlayerStaticData:
Contains information that rarely changes, such as:
Mesh file name (e.g., .glb file)
Player name
Role or other metadata
This data is uploaded to Firebase when the player is instantiated and updated infrequently.
PlayerDynamicData:
Contains frequently updated data for real-time synchronization, such as:
Position (x, y, z)
Orientation (quaternion or Euler angles)
Current state (e.g., idle, walking, falling)
PlayerLocalData:
Stores data needed only locally, such as:
References to the 3D mesh
Animation groups (e.g., walking, idle)
Other runtime-only information that does not need to be synchronized with Firebase.
Synchronization Management
The class FBPlayerSync handles the synchronization of player data across all users via Firebase. Key responsibilities include:
Listening for updates to PlayerDynamicData and PlayerStaticData in the Firebase database.
Propagating local changes (e.g., player movement or state changes) to Firebase for real-time synchronization with other users.
Instantiating or updating RemotePlayer instances when new players join or update their data.
This structure ensures seamless integration of multiple players in a real-time 3D environment, leveraging Firebase for efficient data sharing while minimizing unnecessary network traffic.