Added first effect of particules
This commit is contained in:
@@ -12,6 +12,7 @@ type PartitionCoordProps = {
|
||||
onPause: () => void;
|
||||
// Timestamp of the play session, in milisecond
|
||||
timestamp: number;
|
||||
pressedKeys: Map<number, number>;
|
||||
};
|
||||
|
||||
const PartitionCoord = ({
|
||||
@@ -21,6 +22,7 @@ const PartitionCoord = ({
|
||||
onPause,
|
||||
onResume,
|
||||
timestamp,
|
||||
pressedKeys,
|
||||
}: PartitionCoordProps) => {
|
||||
const [partitionData, setPartitionData] = React.useState<
|
||||
[string, PianoCursorPosition[]] | null
|
||||
@@ -48,6 +50,7 @@ const PartitionCoord = ({
|
||||
timestamp={timestamp}
|
||||
onPause={onPause}
|
||||
onResume={onResume}
|
||||
pressedKeys={pressedKeys}
|
||||
onEndReached={() => {
|
||||
onEndReached();
|
||||
}}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { SplendidGrandPiano, CacheStorage } from 'smplr';
|
||||
import { Note } from 'opensheetmusicdisplay';
|
||||
|
||||
let globalTimestamp = 0;
|
||||
let globalPressedKeys: Map<number, number> = new Map();
|
||||
const globalStatus: 'playing' | 'paused' | 'stopped' = 'playing';
|
||||
|
||||
const isValidSoundPlayer = (soundPlayer: SplendidGrandPiano | undefined) => {
|
||||
@@ -48,17 +49,42 @@ const getPianoScene = (
|
||||
private cursorPositionsIdx = -1;
|
||||
private partition!: Phaser.GameObjects.Image;
|
||||
private cursor!: Phaser.GameObjects.Rectangle;
|
||||
private emitter!: Phaser.GameObjects.Particles.ParticleEmitter;
|
||||
private emitzone!: Phaser.GameObjects.Particles.Zones.EdgeZone;
|
||||
private nbTextureTolad!: number;
|
||||
create() {
|
||||
this.textures.addBase64(
|
||||
'star',
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEQAAAApCAYAAACMeY82AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjYyNzNEOEU4NzUxMzExRTRCN0ZCODQ1QUJCREFFQzA4IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjYyNzNEOEU5NzUxMzExRTRCN0ZCODQ1QUJCREFFQzA4Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NjI3M0Q4RTY3NTEzMTFFNEI3RkI4NDVBQkJEQUVDMDgiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NjI3M0Q4RTc3NTEzMTFFNEI3RkI4NDVBQkJEQUVDMDgiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4vDiTDAAAB4UlEQVR42uxagY2DMAw0VRdghayQFVghs3SF/1XaEdoVGIGswAj5OK0rkwfalx5wiY2smAik+OrYFxcAAWLABFQJazmAykCOEhZRx0sBYdLHS0VFk6omVU2qOwRktS1jwYY5QKSAslqEtNBWM0lVt4xUQERUmdrWSV+VZi27xVYZU1OimYyOmJTRDB58VVyE5BUJQYhJGZYGYzMH87nuqwuoRSRVdLyB5hcoWIZxjs9P2buT3LkI0PP+BKcQriEp2jjnwO0XjDFwUDFRouNXF5HoQlK0iwKDVw10/GzPdzBIoo1zBApF1prb57iUw/zQxkdkpY1rwNhoOQMDkhpt62wqw+ZisMTiOwNQqLu2VMWpxhggOcBbe/zwlTvKqTfZxDyJYyAAfEyPTTF2/1AcWj8Ye39fU98+geHlebBuvv4xX8Zal5WoCEGnvn1y/na5JQdz55aOkM3knRyS5xwpbcZ/BSG//2uVWTrB6uFOAjHjoT9GzIojZzlYdJaRQNcPW0cMby3OtRl32w950PbU2yAAiGPk22qL0rp4hOSlEkFAfvGi6RwenCXsLkLGfuUcDGKf/J2tIkTGv/9t/xaQxQDCzyPFJdU1AYns5kO3jKAPZhQQPctohHweIJK+D/kRYAAaWClvtE6otAAAAABJRU5ErkJggg=='
|
||||
);
|
||||
this.textures.addBase64('partition', partitionB64);
|
||||
this.cursorPositionsIdx = -1;
|
||||
this.nbTextureTolad = 2;
|
||||
|
||||
this.cameras.main.setBackgroundColor(colorScheme === 'light' ? '#FFFFFF' : '#000000');
|
||||
this.textures.on('onload', () => {
|
||||
this.nbTextureTolad--;
|
||||
if (this.nbTextureTolad > 0) return;
|
||||
this.partition = this.add.image(0, 0, 'partition').setOrigin(0, 0);
|
||||
this.cameras.main.setBounds(0, 0, this.partition.width, this.partition.height);
|
||||
|
||||
this.cursor = this.add.rectangle(0, 0, 30, 350, 0x31ef8c, 0.5).setOrigin(0, 0);
|
||||
this.cameras.main.startFollow(this.cursor, true, 0.05, 0.05);
|
||||
|
||||
|
||||
// create an emitter the once called later will spawn 15 particules all around the sprite that it is attached to
|
||||
this.emitter = this.add.particles(0, 0, 'star', {
|
||||
lifespan: 700,
|
||||
duration: 100,
|
||||
quantity: 2,
|
||||
follow: this.cursor,
|
||||
speed: { min: 10, max: 20 },
|
||||
scale: { start: 0, end: 0.4 },
|
||||
// rotate: { start: 0, end: 360 },
|
||||
emitZone: { type: 'edge', source: this.cursor.getBounds(), quantity: 50 },
|
||||
|
||||
emitting: false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -76,6 +102,14 @@ const getPianoScene = (
|
||||
this.cursorPositionsIdx = idx;
|
||||
return true;
|
||||
}
|
||||
if (globalPressedKeys.size > 0) {
|
||||
// add particles at the position of the cursor
|
||||
this.emitter.start(1);
|
||||
this.cursor.fillAlpha = 0.9;
|
||||
} else if (this.cursor) {
|
||||
this.cursor.fillAlpha = 0.5;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
if (cP) {
|
||||
@@ -127,6 +161,7 @@ export type PhaserCanvasProps = {
|
||||
onResume: () => void;
|
||||
// Timestamp of the play session, in milisecond
|
||||
timestamp: number;
|
||||
pressedKeys: Map<number, number>;
|
||||
};
|
||||
|
||||
const PhaserCanvas = ({
|
||||
@@ -134,6 +169,7 @@ const PhaserCanvas = ({
|
||||
cursorPositions,
|
||||
onEndReached,
|
||||
timestamp,
|
||||
pressedKeys,
|
||||
}: PhaserCanvasProps) => {
|
||||
const colorScheme = useColorScheme();
|
||||
const dispatch = useDispatch();
|
||||
@@ -141,6 +177,7 @@ const PhaserCanvas = ({
|
||||
const [game, setGame] = React.useState<Phaser.Game | null>(null);
|
||||
|
||||
globalTimestamp = timestamp;
|
||||
globalPressedKeys = pressedKeys;
|
||||
|
||||
useEffect(() => {
|
||||
if (isValidSoundPlayer(soundPlayer)) {
|
||||
|
||||
@@ -87,6 +87,8 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
);
|
||||
const getElapsedTime = () => stopwatch.getElapsedRunningTime() - 3000;
|
||||
const [midiKeyboardFound, setMidiKeyboardFound] = useState<boolean>();
|
||||
// first number is the note, the other is the time when pressed on release the key is removed
|
||||
const [pressedKeys, setPressedKeys] = useState<Map<number, number>>(new Map()); // [note, time]
|
||||
|
||||
const onPause = () => {
|
||||
stopwatch.pause();
|
||||
@@ -210,17 +212,30 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
}
|
||||
};
|
||||
inputs.forEach((input) => {
|
||||
if (inputIndex != 0) {
|
||||
return;
|
||||
}
|
||||
// if (inputIndex != 0) {
|
||||
|
||||
// return;
|
||||
// }
|
||||
input.onmidimessage = (message) => {
|
||||
const { command } = parseMidiMessage(message);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { command, channel, note, velocity } = parseMidiMessage(message);
|
||||
const keyIsPressed = command == 9;
|
||||
const keyCode = message.data[1];
|
||||
if (keyIsPressed) {
|
||||
setPressedKeys((prev) => {
|
||||
prev.set(note, getElapsedTime());
|
||||
return prev;
|
||||
});
|
||||
} else {
|
||||
setPressedKeys((prev) => {
|
||||
prev.delete(note);
|
||||
return prev;
|
||||
});
|
||||
}
|
||||
|
||||
webSocket.current?.send(
|
||||
JSON.stringify({
|
||||
type: keyIsPressed ? 'note_on' : 'note_off',
|
||||
note: keyCode,
|
||||
note: note,
|
||||
id: song.data!.id,
|
||||
time: getElapsedTime(),
|
||||
})
|
||||
@@ -293,6 +308,7 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
||||
onEndReached={onEnd}
|
||||
onPause={onPause}
|
||||
onResume={onResume}
|
||||
pressedKeys={pressedKeys}
|
||||
onPartitionReady={() => setPartitionRendered(true)}
|
||||
/>
|
||||
{!partitionRendered && <LoadingComponent />}
|
||||
|
||||
Reference in New Issue
Block a user