Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 82 additions & 7 deletions src/main/java/engine/components/AbstractComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,107 @@
* Abstract base class for all components in the scene graph.
*
* <p>This class provides a shared implementation of common functionality across all components,
* reducing boilerplate and centralizing shared logic for ease of maintenance.
* reducing boilerplate code and centralizing shared logic for ease of maintenance.
*
* <p>Components extending this class inherit basic lifecycle management, including activation state
* handling and owner node reference management. The {@link #update(float)} method includes a check
* for the active state, ensuring that inactive components are automatically skipped during the
* update cycle.
*/
public abstract class AbstractComponent implements Component {

/** Reference to the owning SceneNode */
/** Indicates whether the component is currently active. */
protected boolean active = true;

/** Reference to the owning {@link SceneNode}. */
protected SceneNode owner;

/**
* Sets the owner (parent node) of this component.
*
* <p>This is common logic provided by the abstract class to ensure consistency among all
* components.
* <p>This method is called when the component is added to a {@link SceneNode}. It stores a
* reference to the owning node, which can be used for interactions with other components or scene
* graph operations.
*
* @param owner The SceneNode that owns this component.
* @param owner The {@link SceneNode} that owns this component; must not be {@code null}.
*/
@Override
public void setOwner(SceneNode owner) {
this.owner = owner;
}

/**
* Retrieves the owning node for convenience.
* Retrieves the owning {@link SceneNode} of this component.
*
* @return The owning SceneNode instance.
* <p>This method provides convenient access to the parent node, allowing components to interact
* with the scene graph or access shared properties such as transformations or child nodes.
*
* @return The {@link SceneNode} instance that owns this component, or {@code null} if not set.
*/
@Override
public SceneNode getOwner() {
return owner;
}

/**
* Sets the active state of this component.
*
* <p>An active component participates in updates and other operations within the scene's
* lifecycle. Inactive components are effectively disabled and will not be processed during
* updates or rendering.
*
* @param active A boolean value where {@code true} sets the component as active, and {@code
* false} sets it as inactive.
*/
@Override
public void setActive(boolean active) {
this.active = active;
}

/**
* Returns the active state of this component.
*
* <p>If the component is active, it will be included in updates and other scene lifecycle
* processes. Inactive components are skipped to optimize performance.
*
* @return {@code true} if the component is active, {@code false} otherwise.
*/
@Override
public boolean isActive() {
return active;
}

/**
* Updates this component during the scene's update cycle.
*
* <p>This method checks if the component is active before invoking the {@link #onUpdate(float)}
* method. If the component is inactive, the update logic is skipped.
*
* @param tpf The time per frame in seconds (time delta) since the last update.
*/
@Override
public void update(float tpf) {
if (active) {
onUpdate(tpf);
}
}

/**
* Abstract method to be implemented by subclasses to define component-specific update logic.
*
* <p>This method is only called if the component is active. Subclasses should implement their
* frame-specific logic here, such as animations, physics calculations, or interactions with other
* components.
*
* <p>Example use cases include:
*
* <ul>
* <li>Animating properties of the node (e.g., position, rotation, scale)
* <li>Handling physics calculations for the node
* <li>Interacting with other components or systems
* </ul>
*
* @param tpf The time per frame in seconds (time delta) since the last update.
*/
public abstract void onUpdate(float tpf);
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public CinematicBlackBarsRenderer(float fadeSpeed, float targetBarHeight) {
* @param tpf Time per frame (time elapsed since the last frame in seconds).
*/
@Override
public void update(float tpf) {
public void onUpdate(float tpf) {
if (!isFading()) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public CircularAnimationComponent(float radius, float angularSpeed) {
* @param tpf Time per frame (time in seconds since the last frame).
*/
@Override
public void update(float tpf) {
public void onUpdate(float tpf) {
// Update the elapsed time based on the time per frame
timeElapsed += tpf;

Expand Down
95 changes: 81 additions & 14 deletions src/main/java/engine/components/Component.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,112 @@
* SceneNode} instances. They encapsulate logic, rendering, or other behaviors, following a
* component-based design pattern.
*
* <p>Each component should manage its lifecycle, with {@code onAttach()}, {@code update()}, and
* {@code onDetach()} methods, allowing nodes to manage their behavior lifecycle cleanly.
* <p>Each component should manage its lifecycle with {@code onAttach()}, {@code update(float)}, and
* {@code onDetach()} methods, allowing nodes to manage component behavior efficiently.
*/
public interface Component {

/**
* Sets the active state of this component.
*
* <p>An active component will participate in updates, rendering, or other operations during the
* scene's lifecycle. Inactive components are skipped in these processes, allowing for optimized
* performance and dynamic behavior control.
*
* @param active A boolean value where {@code true} sets the component as active, and {@code
* false} sets it as inactive.
*/
void setActive(boolean active);

/**
* Returns the active state of this component.
*
* <p>An active component participates in updates and other operations. If a component is
* inactive, it is effectively disabled and will not be updated or rendered by the owning {@link
* SceneNode}.
*
* @return {@code true} if the component is active, {@code false} otherwise.
*/
boolean isActive();

/**
* Returns the owning {@link SceneNode} of this component.
*
* <p>This method provides access to the {@link SceneNode} that owns this component, allowing the
* component to interact with its parent node and other components within the scene graph.
*
* <p>If the component has not been attached to a {@link SceneNode}, this method may return {@code
* null}.
*
* @return The {@link SceneNode} that owns this component, or {@code null} if not attached.
*/
SceneNode getOwner();

/**
* Sets the owning {@link SceneNode} for this component.
*
* <p>This is called when the component is added to a {@link SceneNode}. The owning node serves as
* the context within which this component operates, allowing it to interact with other components
* or node transformations.
* <p>This method is called when the component is added to a {@link SceneNode}. The owning node
* provides context and access to the scene graph, allowing the component to interact with other
* components, transformations, and scene properties.
*
* @param owner The {@link SceneNode} that owns this component; cannot be null.
* @param owner The {@link SceneNode} that owns this component; must not be {@code null}.
*/
void setOwner(SceneNode owner);

/**
* Updates the component's logic every frame.
* Updates the component during the scene's update cycle.
*
* <p>This method is responsible for invoking the component's update logic if it is active. It
* checks the component's active state and then calls {@link #onUpdate(float)} to perform any
* custom behavior defined by the component.
*
* <p>Called once per frame during the scene's update cycle. The time-per-frame (tpf) is passed in
* to allow for time-based animations or logic that depends on frame timing.
* <p>The {@link AbstractComponent} base class typically implements this method to handle active
* state checks, ensuring that {@link #onUpdate(float)} is only called when the component is
* enabled.
*
* @param tpf The time per frame in seconds (time delta) since the last update.
* <p>Subclasses should override {@link #onUpdate(float)} to define their specific update logic,
* rather than overriding this method directly.
*
* @param tpf The time per frame in seconds since the last update.
*/
void update(float tpf);

/**
* Called during the scene's update cycle to perform component-specific logic.
*
* <p>This method is intended to be overridden by components to define their unique behavior.
* Unlike {@code update(float)}, which is provided by the {@link AbstractComponent} base class,
* this method does not need to handle active state checks. It is only called if the component is
* active.
*
* <p>Implementations should ensure that the logic is efficient and avoids unnecessary
* computations to maintain performance.
*
* @param tpf The time per frame in seconds since the last update.
*/
void onUpdate(float tpf);

/**
* Called when the component is attached to a {@link SceneNode}.
*
* <p>This allows the component to set up necessary resources, state, or perform other preparatory
* work specific to being added to a node.
* <p>This method provides an opportunity to perform any initialization or setup required when the
* component becomes part of a node. It can be used to register listeners, allocate resources, or
* initialize state.
*
* <p>Components should avoid performing heavy computations in this method to minimize performance
* impact during scene setup.
*/
void onAttach();

/**
* Called when the component is detached from a {@link SceneNode}.
*
* <p>This ensures no memory is leaked, threads are terminated, or other resources are left
* hanging by cleaning up internal state and releasing references.
* <p>This method allows the component to clean up any resources, references, or listeners that
* were established during its lifecycle. It is essential to release resources here to avoid
* memory leaks or lingering state that could impact performance or stability.
*
* <p>Common tasks include unregistering listeners, stopping threads, or nullifying references to
* other objects in the scene.
*/
void onDetach();
}
2 changes: 1 addition & 1 deletion src/main/java/engine/components/ControlWASD.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public ControlWASD(Input input, float speed) {
* @param tpf Time per frame, used to ensure frame-rate-independent movement.
*/
@Override
public void update(float tpf) {
public void onUpdate(float tpf) {
SceneNode node = getOwner();
Vector3f velocity = handleInput();

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/engine/components/FlyByCameraControl.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public FlyByCameraControl(Input input, PerspectiveCamera camera) {
* @param tpf The time per frame (delta time) used for movement scaling.
*/
@Override
public void update(float tpf) {
public void onUpdate(float tpf) {
float mouseX = input.getMouseDeltaX() * mouseSensitivity * tpf;
float mouseY = input.getMouseDeltaY() * mouseSensitivity * tpf;

Expand Down
32 changes: 16 additions & 16 deletions src/main/java/engine/components/Geometry.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,21 +114,21 @@ public void debugRenderBounds(Graphics g) {
float maxZ = bounds.getMax().z;

// Draw lines for each edge of the bounding box
g.drawLine(minX, minY, minZ, maxX, minY, minZ);
g.drawLine(minX, minY, minZ, minX, maxY, minZ);
g.drawLine(minX, minY, minZ, minX, minY, maxZ);

g.drawLine(maxX, maxY, maxZ, minX, maxY, maxZ);
g.drawLine(maxX, maxY, maxZ, maxX, minY, maxZ);
g.drawLine(maxX, maxY, maxZ, maxX, maxY, minZ);

g.drawLine(minX, maxY, minZ, maxX, maxY, minZ);
g.drawLine(maxX, minY, minZ, maxX, maxY, minZ);
g.drawLine(maxX, minY, minZ, maxX, minY, maxZ);

g.drawLine(minX, maxY, maxZ, minX, minY, maxZ);
g.drawLine(maxX, minY, maxZ, minX, minY, maxZ);
g.drawLine(minX, maxY, maxZ, minX, maxY, minZ);
// g.drawLine(minX, minY, minZ, maxX, minY, minZ);
// g.drawLine(minX, minY, minZ, minX, maxY, minZ);
// g.drawLine(minX, minY, minZ, minX, minY, maxZ);
//
// g.drawLine(maxX, maxY, maxZ, minX, maxY, maxZ);
// g.drawLine(maxX, maxY, maxZ, maxX, minY, maxZ);
// g.drawLine(maxX, maxY, maxZ, maxX, maxY, minZ);
//
// g.drawLine(minX, maxY, minZ, maxX, maxY, minZ);
// g.drawLine(maxX, minY, minZ, maxX, maxY, minZ);
// g.drawLine(maxX, minY, minZ, maxX, minY, maxZ);
//
// g.drawLine(minX, maxY, maxZ, minX, minY, maxZ);
// g.drawLine(maxX, minY, maxZ, minX, minY, maxZ);
// g.drawLine(minX, maxY, maxZ, minX, maxY, minZ);
}

/**
Expand All @@ -138,7 +138,7 @@ public void debugRenderBounds(Graphics g) {
* @param tpf The time per frame used for the update (in seconds).
*/
@Override
public void update(float tpf) {
public void onUpdate(float tpf) {
// Placeholder for potential mesh state updates
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/engine/components/RotationComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public RotationComponent(Vector3f axis, float angularSpeed) {
* @param tpf Time per frame (in seconds since the last frame).
*/
@Override
public void update(float tpf) {
public void onUpdate(float tpf) {
SceneNode node = getOwner();
if (node == null) return;

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/engine/components/RoundReticle.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ private void renderCenteredOval(
* @param tpf time per frame, used for animations or updates.
*/
@Override
public void update(float tpf) {}
public void onUpdate(float tpf) {}

/** Called when the component is attached to a {@link engine.SceneNode}. */
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public SmoothFlyByCameraControl(Input input, PerspectiveCamera camera) {
* @param tpf Time per frame, used to adjust movement and smoothing.
*/
@Override
public void update(float tpf) {
public void onUpdate(float tpf) {
float rawMouseX = input.getMouseDeltaX() * mouseSensitivity * tpf;
float rawMouseY = input.getMouseDeltaY() * mouseSensitivity * tpf;

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/engine/components/StaticGeometry.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public void render(Graphics g) {
}

@Override
public void update(float tpf) {}
public void onUpdate(float tpf) {}

@Override
public void onAttach() {}
Expand Down
24 changes: 23 additions & 1 deletion src/main/java/engine/components/Transform.java
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,30 @@ public Vector3f getRight() {
return new Vector3f(-sinY, 0, cosY).normalizeLocal();
}

/**
* Sets the forward direction of this transform.
*
* <p>This method calculates the rotation angles (pitch and yaw) needed to make the object face
* the given forward direction and updates the rotation vector accordingly.
*
* @param forward The desired forward direction as a normalized vector.
*/
public void setForward(Vector3f forward) {
if (forward == null || forward.length() == 0) {
throw new IllegalArgumentException("Forward vector cannot be null or zero-length.");
}

// Calculate yaw (rotation around the Y-axis) and pitch (rotation around the X-axis)
float yaw = (float) Math.atan2(forward.z, forward.x);
float pitch =
(float) Math.atan2(forward.y, Math.sqrt(forward.x * forward.x + forward.z * forward.z));

// Update the rotation vector
this.rotation.set(pitch, yaw, 0);
}

@Override
public void update(float tpf) {}
public void onUpdate(float tpf) {}

@Override
public void onAttach() {}
Expand Down
Loading
Loading