Skip to content

Commit

Permalink
feat: add sinusoidal wave motion to the emitter (#941)
Browse files Browse the repository at this point in the history
* feat: add sinusoidal wave motion to the emitter

* chore: fix formatting issues
  • Loading branch information
VmMad authored Jan 9, 2024
1 parent e2e832e commit e87ee9f
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 13 deletions.
56 changes: 44 additions & 12 deletions client/src/features/visualizer-threejs/Emitter.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/* eslint-disable react/no-unknown-property */
import { useFrame, useThree } from "@react-three/fiber";
import React, { RefObject, Dispatch, SetStateAction, useEffect } from "react";
import React, { RefObject, Dispatch, SetStateAction, useEffect, useRef, useState } from "react";
import * as THREE from "three";
import { useBorderPositions } from "./hooks/useBorderPositions";
import { useConfigStore, useTangleStore } from "./store";
import { useRenderTangle } from "./useRenderTangle";
import { EMITTER_DEPTH, EMITTER_HEIGHT, EMITTER_WIDTH } from './constants';
import { EMITTER_DEPTH, EMITTER_HEIGHT, EMITTER_WIDTH, MAX_AMPLITUDE, AMPLITUDE_ACCUMULATOR, HALF_WAVE_PERIOD_SECONDS } from './constants';
import { getNewSinusoidalPosition } from './utils';

interface EmitterProps {
readonly setRunListeners: Dispatch<SetStateAction<boolean>>;
Expand All @@ -16,11 +17,17 @@ const Emitter: React.FC<EmitterProps> = ({
setRunListeners,
emitterRef
}: EmitterProps) => {
const isPlaying = useConfigStore(state => state.isPlaying);
const setZoom = useTangleStore(s => s.setZoom);
const get = useThree(state => state.get);
const currentZoom = useThree(state => state.camera.zoom);
const setZoom = useTangleStore(s => s.setZoom);
const { halfScreenWidth } = useBorderPositions();
const isPlaying = useConfigStore(state => state.isPlaying);

const [animationTime, setAnimationTime] = useState<number>(0)
const [currentAmplitude, setCurrentAmplitude] = useState<number>(AMPLITUDE_ACCUMULATOR);

const previousRealTime = useRef<number>(0);
const previousPeakTime = useRef<number>(0);

useEffect(() => {
setZoom(currentZoom);
Expand All @@ -41,24 +48,49 @@ const Emitter: React.FC<EmitterProps> = ({
}
});

function updateAnimationTime(realTimeDelta: number): void {
setAnimationTime(prev => prev + realTimeDelta);
}

function checkAndHandleNewPeak(): void {
const currentHalfWaveCount = Math.floor(animationTime / HALF_WAVE_PERIOD_SECONDS);
const lastPeakHalfWaveCount = Math.floor(previousPeakTime.current / HALF_WAVE_PERIOD_SECONDS);

if (currentHalfWaveCount > lastPeakHalfWaveCount) {
setCurrentAmplitude(prev => Math.min(prev + AMPLITUDE_ACCUMULATOR, MAX_AMPLITUDE));
previousPeakTime.current = animationTime;
}
}

/**
* Emitter shift
*/
useFrame((_, delta) => {
if (!isPlaying) {
return;
}
useFrame(({ clock }, delta) => {
const DELTA_MULTIPLIER = 80; // depends on this param we can manage speed of emitter

if (emitterRef?.current) {
const DELTA_MULTIPLIER = 80; // depends on this param we can manage speed of emitter
emitterRef.current.position.x += delta * DELTA_MULTIPLIER;
const currentRealTime = clock.getElapsedTime();
const realTimeDelta = currentRealTime - previousRealTime.current;
previousRealTime.current = currentRealTime;

if (isPlaying) {
updateAnimationTime(realTimeDelta);
checkAndHandleNewPeak();

if (emitterRef.current) {
const { x } = emitterRef.current.position;

const newXPos = x + (delta * DELTA_MULTIPLIER);
const newYPos = getNewSinusoidalPosition(animationTime, currentAmplitude);

emitterRef.current.position.y = newYPos;
emitterRef.current.position.x = newXPos;
}
}
});

// The Tangle rendering hook
useRenderTangle();


return (
<mesh
ref={emitterRef}
Expand Down
4 changes: 4 additions & 0 deletions client/src/features/visualizer-threejs/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,7 @@ export const VISUALIZER_BACKGROUND: Record<ThemeMode, string> = {
export const EMITTER_WIDTH = 30;
export const EMITTER_HEIGHT = 250;
export const EMITTER_DEPTH = 250;

export const MAX_AMPLITUDE = 200;
export const AMPLITUDE_ACCUMULATOR = 10;
export const HALF_WAVE_PERIOD_SECONDS = 4;
12 changes: 11 additions & 1 deletion client/src/features/visualizer-threejs/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { STEP_Y_PX, TIME_DIFF_COUNTER, SECOND } from "./constants";
import { STEP_Y_PX, TIME_DIFF_COUNTER, SECOND, HALF_WAVE_PERIOD_SECONDS } from "./constants";

/**
* Generates a random number within a specified range.
Expand Down Expand Up @@ -147,3 +147,13 @@ export const getGenerateY = ({ withRandom }: {withRandom?: boolean} = {}): (shif
return Y * STEP_Y_PX;
};
};

export function getNewSinusoidalPosition(time: number, amplitude: number): number {
const period = HALF_WAVE_PERIOD_SECONDS * 2;
const frequency = 1 / period;
const phase = (time % period) * frequency

const newY = amplitude * Math.sin(phase * 2 * Math.PI);

return newY;
}

0 comments on commit e87ee9f

Please sign in to comment.