Added first effect of particules

This commit is contained in:
Clément Le Bihan
2023-09-12 18:18:09 +02:00
parent 13d0be4586
commit 607c35b621
3 changed files with 62 additions and 6 deletions

View File

@@ -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();
}}

View File

@@ -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)) {

View File

@@ -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 />}