Handling in satisfactory manner scoro messages
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useEffect, useContext } from 'react';
|
import { useEffect, useContext } from 'react';
|
||||||
|
import { Dimensions } from 'react-native';
|
||||||
import Phaser from 'phaser';
|
import Phaser from 'phaser';
|
||||||
import useColorScheme from '../../hooks/colorScheme';
|
import useColorScheme from '../../hooks/colorScheme';
|
||||||
import { RootState, useSelector } from '../../state/Store';
|
import { RootState, useSelector } from '../../state/Store';
|
||||||
@@ -22,6 +23,9 @@ const isValidSoundPlayer = (soundPlayer: SplendidGrandPiano | undefined) => {
|
|||||||
return soundPlayer && soundPlayer.loaded;
|
return soundPlayer && soundPlayer.loaded;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const min = (a: number, b: number) => (a < b ? a : b);
|
||||||
|
const max = (a: number, b: number) => (a > b ? a : b);
|
||||||
|
|
||||||
const myFindLast = <T,>(a: T[], p: (_: T, _2: number) => boolean) => {
|
const myFindLast = <T,>(a: T[], p: (_: T, _2: number) => boolean) => {
|
||||||
for (let i = a.length - 1; i >= 0; i--) {
|
for (let i = a.length - 1; i >= 0; i--) {
|
||||||
if (p(a[i]!, i)) {
|
if (p(a[i]!, i)) {
|
||||||
@@ -75,19 +79,17 @@ const getPianoScene = (
|
|||||||
this.cursor = this.add.rectangle(0, 0, 30, 350, 0x31ef8c, 0.5).setOrigin(0, 0);
|
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);
|
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
|
// 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', {
|
this.emitter = this.add.particles(0, 0, 'star', {
|
||||||
lifespan: 700,
|
lifespan: 700,
|
||||||
duration: 100,
|
duration: 100,
|
||||||
quantity: 2,
|
|
||||||
follow: this.cursor,
|
follow: this.cursor,
|
||||||
speed: { min: 10, max: 20 },
|
speed: { min: 10, max: 20 },
|
||||||
scale: { start: 0, end: 0.4 },
|
scale: { start: 0, end: 0.4 },
|
||||||
// rotate: { start: 0, end: 360 },
|
// rotate: { start: 0, end: 360 },
|
||||||
emitZone: { type: 'edge', source: this.cursor.getBounds(), quantity: 50 },
|
emitZone: { type: 'edge', source: this.cursor.getBounds(), quantity: 50 },
|
||||||
|
|
||||||
emitting: false
|
emitting: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -113,7 +115,7 @@ const getPianoScene = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (globalMessages.length > 0) {
|
if (globalMessages.length > 0) {
|
||||||
handlePianoGameMsg(globalMessages, this.emitter);
|
handlePianoGameMsg(globalMessages, this.emitter, undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -148,11 +150,7 @@ export type PhaserCanvasProps = {
|
|||||||
onResume: () => void;
|
onResume: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PhaserCanvas = ({
|
const PhaserCanvas = ({ partitionB64, cursorPositions, onEndReached }: PhaserCanvasProps) => {
|
||||||
partitionB64,
|
|
||||||
cursorPositions,
|
|
||||||
onEndReached,
|
|
||||||
}: PhaserCanvasProps) => {
|
|
||||||
const colorScheme = useColorScheme();
|
const colorScheme = useColorScheme();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const pianoCC = useContext(PianoCC);
|
const pianoCC = useContext(PianoCC);
|
||||||
@@ -185,13 +183,43 @@ const PhaserCanvas = ({
|
|||||||
soundPlayer,
|
soundPlayer,
|
||||||
colorScheme
|
colorScheme
|
||||||
);
|
);
|
||||||
|
const { width, height } = Dimensions.get('window');
|
||||||
|
|
||||||
|
class UIScene extends Phaser.Scene {
|
||||||
|
private statusTextValue: string;
|
||||||
|
private statusText!: Phaser.GameObjects.Text;
|
||||||
|
constructor() {
|
||||||
|
super({ key: 'UIScene', active: true });
|
||||||
|
|
||||||
|
this.statusTextValue = 'Score: 0 Streak: 0';
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
this.statusText = this.add.text(
|
||||||
|
this.cameras.main.width - 300,
|
||||||
|
10,
|
||||||
|
this.statusTextValue,
|
||||||
|
{
|
||||||
|
fontFamily: 'Arial',
|
||||||
|
fontSize: 25,
|
||||||
|
color: '#3A784B',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
override update() {
|
||||||
|
if (globalMessages.length > 0) {
|
||||||
|
handlePianoGameMsg(globalMessages, undefined, this.statusText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
type: Phaser.AUTO,
|
type: Phaser.AUTO,
|
||||||
parent: 'phaser-canvas',
|
parent: 'phaser-canvas',
|
||||||
width: 1000,
|
width: max(width * 0.7, 850),
|
||||||
height: 400,
|
height: min(max(height * 0.7, 400), 600),
|
||||||
scene: pianoScene,
|
scene: [pianoScene, UIScene],
|
||||||
scale: {
|
scale: {
|
||||||
mode: Phaser.Scale.FIT,
|
mode: Phaser.Scale.FIT,
|
||||||
autoCenter: Phaser.Scale.CENTER_HORIZONTALLY,
|
autoCenter: Phaser.Scale.CENTER_HORIZONTALLY,
|
||||||
|
|||||||
@@ -1,34 +1,60 @@
|
|||||||
import { NoteTiming, PianoCanvasMsg } from '../../models/PianoGame';
|
import { NoteTiming, PianoCanvasMsg, PianoScoreInfo } from '../../models/PianoGame';
|
||||||
|
|
||||||
const handleNoteTimingMsg = (
|
const handleNoteTimingMsg = (
|
||||||
noteTiming: NoteTiming,
|
noteTiming: NoteTiming,
|
||||||
emitter: Phaser.GameObjects.Particles.ParticleEmitter
|
emitter: Phaser.GameObjects.Particles.ParticleEmitter
|
||||||
) => {
|
) => {
|
||||||
if (noteTiming === NoteTiming.Perfect) {
|
if (noteTiming === NoteTiming.Perfect) {
|
||||||
emitter.particleTint = 0x00ff00;
|
// gold
|
||||||
emitter.start(10);
|
emitter.particleTint = 0xffd700;
|
||||||
|
emitter.start(20);
|
||||||
} else if (noteTiming === NoteTiming.Great) {
|
} else if (noteTiming === NoteTiming.Great) {
|
||||||
emitter.particleTint = 0x00ffff;
|
emitter.particleTint = 0x00ffff;
|
||||||
emitter.start(5);
|
emitter.start(10);
|
||||||
} else if (noteTiming === NoteTiming.Good) {
|
} else if (noteTiming === NoteTiming.Good) {
|
||||||
emitter.particleTint = 0xffff00;
|
// orange/brown
|
||||||
emitter.start(3);
|
emitter.particleTint = 0xffa500;
|
||||||
|
emitter.start(5);
|
||||||
} else if (noteTiming === NoteTiming.Missed) {
|
} else if (noteTiming === NoteTiming.Missed) {
|
||||||
emitter.particleTint = 0xff0000;
|
emitter.particleTint = 0xff0000;
|
||||||
emitter.start(1);
|
emitter.start(5);
|
||||||
} else if (noteTiming === NoteTiming.Wrong) {
|
} else if (noteTiming === NoteTiming.Wrong) {
|
||||||
// maybe add some other effect
|
// maybe add some other effect
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleScoreMsg = (score: PianoScoreInfo, statusText: Phaser.GameObjects.Text) => {
|
||||||
|
statusText.setText(`Score: ${score.score} Streak: ${score.streak}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const findAndRemove = <T>(arr: Array<T>, predicate: (el: T) => boolean): T | undefined => {
|
||||||
|
const idx = arr.findIndex(predicate);
|
||||||
|
if (idx === -1) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return arr.splice(idx, 1)[0];
|
||||||
|
};
|
||||||
|
|
||||||
export const handlePianoGameMsg = (
|
export const handlePianoGameMsg = (
|
||||||
msgs: Array<PianoCanvasMsg>,
|
msgs: Array<PianoCanvasMsg>,
|
||||||
emitter: Phaser.GameObjects.Particles.ParticleEmitter
|
emitter: Phaser.GameObjects.Particles.ParticleEmitter | undefined,
|
||||||
|
statusText: Phaser.GameObjects.Text | undefined
|
||||||
) => {
|
) => {
|
||||||
const msg = msgs.shift();
|
// this is temporary way of hanlding messages it works ok but is laggy when
|
||||||
|
// pressing a lot of keys in a short time I will be using phaser events in the future I think
|
||||||
|
const msg = findAndRemove(msgs, (msg) => {
|
||||||
|
if (emitter && msg.type === 'noteTiming') {
|
||||||
|
return true;
|
||||||
|
} else if (statusText && msg.type === 'scoreInfo') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
if (msg) {
|
if (msg) {
|
||||||
if (msg.type === 'noteTiming') {
|
if (msg.type === 'noteTiming') {
|
||||||
handleNoteTimingMsg(msg.data as NoteTiming, emitter);
|
handleNoteTimingMsg(msg.data as NoteTiming, emitter!);
|
||||||
|
} else if (msg.type === 'scoreInfo') {
|
||||||
|
handleScoreMsg(msg.data as PianoScoreInfo, statusText!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,6 +19,12 @@ export type UpdateInfo = {
|
|||||||
status: 'playing' | 'paused' | 'stopped';
|
status: 'playing' | 'paused' | 'stopped';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PianoScoreInfo = {
|
||||||
|
score: number;
|
||||||
|
streak: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export enum NoteTiming {
|
export enum NoteTiming {
|
||||||
Perfect = 'Perfect',
|
Perfect = 'Perfect',
|
||||||
Great = 'Great',
|
Great = 'Great',
|
||||||
@@ -28,8 +34,8 @@ export enum NoteTiming {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type PianoCanvasMsg = {
|
export type PianoCanvasMsg = {
|
||||||
type: 'noteTiming' | 'score' | 'gameUpdate';
|
type: 'noteTiming' | 'scoreInfo' | 'gameUpdate';
|
||||||
data: UpdateInfo | NoteTiming | number;
|
data: UpdateInfo | NoteTiming | PianoScoreInfo | number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PianoCanvasContext = {
|
export type PianoCanvasContext = {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import TextButton from '../components/TextButton';
|
|||||||
import { MIDIAccess, MIDIMessageEvent, requestMIDIAccess } from '@motiz88/react-native-midi';
|
import { MIDIAccess, MIDIMessageEvent, requestMIDIAccess } from '@motiz88/react-native-midi';
|
||||||
import * as Linking from 'expo-linking';
|
import * as Linking from 'expo-linking';
|
||||||
import url from 'url';
|
import url from 'url';
|
||||||
import { PianoCanvasContext, PianoCanvasMsg, NoteTiming } from '../models/PianoGame';
|
import { PianoCanvasContext, PianoCanvasMsg, NoteTiming, PianoScoreInfo } from '../models/PianoGame';
|
||||||
|
|
||||||
type PlayViewProps = {
|
type PlayViewProps = {
|
||||||
songId: number;
|
songId: number;
|
||||||
@@ -187,9 +187,18 @@ const PlayView = ({ songId, type, route }: RouteProps<PlayViewProps>) => {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentStreak = data.info.current_streak;
|
||||||
const points = data.info.score;
|
const points = data.info.score;
|
||||||
const maxPoints = data.info.max_score || 1;
|
const maxPoints = data.info.max_score || 1;
|
||||||
|
|
||||||
|
if (currentStreak && points) {
|
||||||
|
setPianoMsgs({
|
||||||
|
type: 'scoreInfo',
|
||||||
|
data: { streak: currentStreak, score: points },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setScore(Math.floor((Math.max(points, 0) * 100) / maxPoints));
|
setScore(Math.floor((Math.max(points, 0) * 100) / maxPoints));
|
||||||
|
|
||||||
let formattedMessage = '';
|
let formattedMessage = '';
|
||||||
|
|||||||
Reference in New Issue
Block a user