Skip to content

Commit

Permalink
feat(trackscene): display instrument name + color instead track numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
domi7777 committed Dec 15, 2024
1 parent 273c2d5 commit e8a240a
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 127 deletions.
41 changes: 19 additions & 22 deletions src/scenes/EmptyScene.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,43 @@
import Phaser from 'phaser';

import {LoopTracksScene} from './LoopTracksScene.ts';
import {Colors, HexaColor, hexToColor} from '../utils/colors.ts';
import {Colors, colorToHex, PhaserColor, PhaserColors} from '../utils/colors.ts';
import {FontFamily, FontSize} from '../utils/fonts.ts';
import {DrumsScene} from './DrumsScene.ts';
import {GibberishScene} from './GiberishScene.ts';
import {SimpleSynthScene} from './SimpleSynthScene.ts';
import {EVENTS} from '../events.ts';
import {DaftSynthScene} from './DaftSynthScene.ts';

const colors = {
bg: Colors.black,
active: '#2b2d30',
text: Colors.white,
border: Colors.black,
} satisfies Record<string, HexaColor>

export class EmptyScene extends Phaser.Scene {
static key = 'EmptyScene';
private readonly rowNumber = 5;
private readonly colNumber = 5;
private instrumentButtons!: Phaser.GameObjects.Rectangle[][];
private trackIndex!: number;

public static sceneText = '+';
public static sceneTextColor: PhaserColor = PhaserColors.white;

constructor() {
super(EmptyScene.key);
}

activateButton({row, col, text, scene}: {
activateButton(
row: number,
col: number,
text: string,
scene: typeof Phaser.Scene | typeof SimpleSynthScene
}) {
sceneClass: typeof Phaser.Scene | typeof SimpleSynthScene,
color: PhaserColor
) {
const button = this.instrumentButtons[col][row];
const trackSceneKey = LoopTracksScene.getTrackSceneKey(this.trackIndex);
button.setData('text', this.addText(button, text))
.setFillStyle(hexToColor(colors.active).color, 0.5)
button.setData('text', this.addText(button, text, color))
.setStrokeStyle(1, PhaserColors.grey.color)
.setInteractive()
.on(Phaser.Input.Events.POINTER_DOWN, () => {
this.scene.setVisible(false);
this.scene.add(trackSceneKey, scene, true);
this.scene.add(trackSceneKey, sceneClass, true, {color, text});
})
}

Expand All @@ -51,16 +48,16 @@ export class EmptyScene extends Phaser.Scene {

this.cameras.main
.setOrigin(0, 0)
.setBackgroundColor(colors.bg);
.setBackgroundColor(Colors.black);

this.createButtonsTable();

this.activateButton({row: 0, col: 0, text: 'Synth', scene: SimpleSynthScene});
this.activateButton({row: 1, col: 0, text: 'Daft synth', scene: DaftSynthScene});
this.activateButton(0, 0, 'Synth', SimpleSynthScene, PhaserColors.blue);
this.activateButton(1, 0, 'Daft synth', DaftSynthScene, PhaserColors.purple);

this.activateButton({row: 0, col: 1, text: 'Drums', scene: DrumsScene});
this.activateButton(0, 1, 'Drums', DrumsScene, PhaserColors.red);

this.activateButton({row: 0, col: 2, text: 'Gibberish', scene: GibberishScene});
this.activateButton(0, 2, 'Gibberish', GibberishScene, PhaserColors.green);

window.addEventListener('resize', () => this.resizeScene());
this.resizeScene();
Expand All @@ -74,17 +71,17 @@ export class EmptyScene extends Phaser.Scene {
this.instrumentButtons[i].push(
this.add.rectangle()
.setOrigin(0, 0)
.setStrokeStyle(2, hexToColor(colors.border).color, 0.1)
.setInteractive()
);
}
}
}

private addText(button: Phaser.GameObjects.Rectangle, text: string) {
private addText(button: Phaser.GameObjects.Rectangle, text: string, color: PhaserColor) {
return this.add.text(button.x + button.width / 2, button.y + button.height / 2, text, {
fontSize: FontSize.tiny,
color: colors.text,
color: colorToHex(color.darken(20)),
resolution: 2,
fontFamily: FontFamily.Text,
}).setOrigin(0.5);
}
Expand Down
101 changes: 24 additions & 77 deletions src/scenes/GiberishScene.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import {logger} from '../utils/logger.ts';
import {PadsScene} from './PadsScene.ts';
import Phaser from 'phaser';
import {PhaserColors} from '../utils/colors.ts';
import {LoopTracksScene} from './LoopTracksScene.ts';
import {rotateArray} from '../utils/math.ts';
import {logger} from '../utils/logger.ts';
import {EVENTS} from '../events.ts';

type Pad = {
instrument: number,
button: Phaser.GameObjects.Rectangle,
}

declare const Freeverb: any, Bus2: any, Gibberish: any, Synth: any, Add: any, Sine: any, Sequencer: any;

Expand Down Expand Up @@ -59,82 +52,36 @@ const testNote = () => {
noteSeq.start();
}

export class GibberishScene extends Phaser.Scene {
export class GibberishScene extends PadsScene {

canRecord = false;
canPlay = false;
isGibberishLoaded = false;

constructor() {
super();
playSound(_index: number): void {
if (!this.isGibberishLoaded) {
this.isGibberishLoaded = true;
Gibberish.workletPath = './worklet.js';
logger.log('loading Gibberish 2...');
Gibberish.init().then(() => {
logger.log('Gibberish is ready!')
Gibberish.export(window)
testNote();
}).catch((e: unknown) => logger.error('oops', e));
} else {
testNote();
}
}

create() {
this.createPads(8);
this.game.events.emit(EVENTS.sceneChange)
constructor() {
super(1 , 1);
}

private createPads(numberOfPads: number) {
// change the order of the pads if needed, top to bottom and left to right
const pads: Pad[] = new Array(numberOfPads).fill(0).map((_, index) => {
return this.createPad(index);
});

const resizePads = () => {
// FIXME duplicates what's in PadsScene. Moreover they all play the same music
const isPortrait = window.innerWidth < window.innerHeight;
const colNumber = isPortrait ? 2 : 4;// FIXME should depend on numberOfPads
const rowNumber = isPortrait ? 4 : 2;
const width = isPortrait ? window.innerWidth / colNumber : (window.innerWidth - LoopTracksScene.sceneWidthHeight) / colNumber;
const height = isPortrait ? (window.innerHeight - LoopTracksScene.sceneWidthHeight) / rowNumber : window.innerHeight / rowNumber;

const currentPads = isPortrait ? rotateArray(pads, rowNumber, colNumber) : pads;

currentPads.forEach(({button}, index) => {
const x = (index % colNumber) * width;
const y = Math.floor(index / colNumber) * height;
const offsetX = isPortrait ? 0 : LoopTracksScene.sceneWidthHeight;
const offsetY = isPortrait ? LoopTracksScene.sceneWidthHeight : 0;
button.setSize(width, height).setPosition(offsetX + x, offsetY + y);
});
};

// Attach the event listener and initial call
window.addEventListener('resize', resizePads);
resizePads();
protected getPadColor(_numberOfPads: number, _index: number): Phaser.Display.Color {
return PhaserColors.black;
}

private createPad(index: number): Pad {
const padColor = Phaser.Display.Color.HSLToColor(index / 16, 1, 0.5)
const inactiveColor = padColor.darken(40).color;
const hitColor = padColor.brighten(4).color;
const button = this.add.rectangle()
.setFillStyle(inactiveColor)
.setStrokeStyle(2, PhaserColors.white.color, 0.8)
.setInteractive()
.setOrigin(0, 0);
button.on('pointerdown', (e: Phaser.Input.Pointer) => {
if (e.downElement?.tagName?.toLowerCase() !== 'canvas') {
return;
}
if (!this.isGibberishLoaded) {
this.isGibberishLoaded = true;
Gibberish.workletPath = './worklet.js';
logger.log('loading Gibberish 2...');
Gibberish.init().then(() => {
logger.log('Gibberish is ready!')
Gibberish.export(window)
testNote();
}).catch((e: unknown) => logger.error('oops', e));
} else {
testNote();
}
button.setFillStyle(hitColor);
// TODO send a call to the loop scene to play the instrument ? or an object
// this.scene.get(LoopTracksScene.key).events.emit(EVENTS.instrumentPlayed, {instrument, scene: this});
}).on('pointerup', () => button.setFillStyle(inactiveColor))
.on('pointerout', () => button.setFillStyle(inactiveColor));
return {
instrument: index,
button
};
protected getPadText(_index: number): { text: string; color: Phaser.Display.Color } {
return { text: 'Play Gibberish', color: PhaserColors.green };
}
}
59 changes: 34 additions & 25 deletions src/scenes/LoopTracksScene.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Phaser from 'phaser';
import {Colors, PhaserColors} from '../utils/colors.ts';
import {Colors, colorToHex, PhaserColors} from '../utils/colors.ts';
import {FontColor, FontFamily, FontSize} from '../utils/fonts.ts';
import {EmptyScene} from './EmptyScene.ts';
import {Loop} from '../Loop.ts';
Expand All @@ -22,10 +22,12 @@ const controlColors = {
type Track = {
button: Phaser.GameObjects.Rectangle;
buttonText: Phaser.GameObjects.Text;
// TODO remove?
buttonSelectedCircle: Phaser.GameObjects.Ellipse;
selected: boolean,
loop: Loop;
controlIcon: Phaser.GameObjects.Text;
// FIXME re-implement
loopProgressArc: Phaser.GameObjects.Graphics;
};

Expand Down Expand Up @@ -72,11 +74,6 @@ export class LoopTracksScene extends Phaser.Scene {
}

create() {
this.cameras.main
.setOrigin(0, 0)
.setPosition(0, 0)
.setViewport(0, 0, LoopTracksScene.sceneWidthHeight, window.innerHeight)
.setBackgroundColor('#963');// ugly color that should never be seen
this.createTracks();
this.game.events.on(EVENTS.sceneChange, () => {
this.updateControlsState();
Expand All @@ -94,8 +91,8 @@ export class LoopTracksScene extends Phaser.Scene {
}
}

public getTrackScene(index: number) {
return this.scene.get(LoopTracksScene.getTrackSceneKey(index));
public getTrackScene(index: number): PadsScene | undefined {
return this.scene.get(LoopTracksScene.getTrackSceneKey(index)) as PadsScene;
}

updateProgressArc(track: Track) {
Expand Down Expand Up @@ -127,12 +124,12 @@ export class LoopTracksScene extends Phaser.Scene {
loop: new Loop(index),
button: this.add.rectangle()
.setOrigin(0, 0)
.setStrokeStyle(2, PhaserColors.white.color, 0.8)
.setStrokeStyle(1, PhaserColors.darkGrey.color)
.setInteractive()
.on(Phaser.Input.Events.POINTER_DOWN, () => this.selectTrack(index)),
selected: false,
buttonSelectedCircle: this.add.ellipse(0, 0, 0, 0, PhaserColors.white.color),
buttonText: this.add.text(0, 0, `${index + 1}`, {
buttonSelectedCircle: this.add.ellipse(0, 0, 0, 0, PhaserColors.white.color, 0).setVisible(false),
buttonText: this.add.text(0, 0, '+', {
fontFamily: FontFamily.Text,
fontSize: FontSize.medium,
color: FontColor.white,
Expand Down Expand Up @@ -171,11 +168,11 @@ export class LoopTracksScene extends Phaser.Scene {
{
button,
buttonText,
buttonSelectedCircle,
// buttonSelectedCircle,
controlIcon,
}, index) => {
const x = isPortrait ? buttonWidth * index : 0;
const y = isPortrait ? -1 : buttonHeight * index;
const y = isPortrait ? 0 : buttonHeight * index;
button.setSize(buttonWidth, buttonHeight).setPosition(x, y);

const textX = isPortrait ? button.getCenter().x : button.getCenter().x - buttonWidth / 4;
Expand All @@ -186,10 +183,13 @@ export class LoopTracksScene extends Phaser.Scene {
.setSize(buttonWidth, buttonHeight)
.setFontSize(minWidthHeight / 4)
.setPosition(textX, textY)

buttonSelectedCircle
.setSize(minWidthHeight / 3, minWidthHeight / 3)
.setPosition(textX, textY)
.setWordWrapWidth(buttonWidth - 10, true)
.setRotation(isPortrait ? 0 : - Math.PI / 2);
//
// buttonSelectedCircle
// .setSize(minWidthHeight / 3, minWidthHeight / 3)
// .setPosition(textX, textY)
// .setVisible(false);

controlIcon
.setOrigin(isPortrait ? 0.5 : 1, isPortrait ? 1 : 0.5)
Expand Down Expand Up @@ -217,7 +217,8 @@ export class LoopTracksScene extends Phaser.Scene {
const trackScene = this.getTrackScene(index);
if (trackScene) {
trackScene.scene.bringToTop();
const settings = (trackScene as PadsScene).settings;
const settings = trackScene.settings;
track.buttonText.setColor(colorToHex(trackScene.sceneTextColor)).setText(trackScene.sceneText);
this.game.events.emit(EVENTS.sceneChange, settings);
} else {
this.game.scene.start(EmptyScene.key, {index});
Expand All @@ -226,24 +227,32 @@ export class LoopTracksScene extends Phaser.Scene {
track.loop.handleClick();
this.updateControlsState();
}
this.scene.bringToTop();
}

private updateControlsState() {
LoopTracksScene.tracks.forEach((track, index) => {
track.button.setFillStyle(PhaserColors.black.color);
const trackScene = this.getTrackScene(index);
const sceneTextColor = trackScene?.sceneTextColor.color ?? EmptyScene.sceneTextColor.color;
track.button
.setDepth(track.selected ? 0 : -1)
.setFillStyle(PhaserColors.black.color)
.setStrokeStyle(1, track.selected ? sceneTextColor : PhaserColors.darkGrey.color);
track.buttonText
.setColor(track.selected ? Colors.black : Colors.white);
.setText(trackScene?.sceneText ?? EmptyScene.sceneText)
.setColor(colorToHex(trackScene?.sceneTextColor ?? EmptyScene.sceneTextColor))
.setAlpha(track.selected ? 1 : 0.5);

track.buttonSelectedCircle
.setVisible(true)
.setVisible(false)
.setFillStyle(track.selected ? PhaserColors.white.color : PhaserColors.black.color);

const trackScene = this.getTrackScene(index);
const hasLoopControls = trackScene && trackScene instanceof PadsScene;
const hasLoopControls = trackScene?.canRecord || trackScene?.canPlay;
if (hasLoopControls) {
if (track.selected && (track.loop.isRecording() || track.loop.isReadyToRecord())) {
if (trackScene?.canRecord && track.selected && (track.loop.isRecording() || track.loop.isReadyToRecord())) {
track.controlIcon.setText(controlIcons.record)
.setColor(track.loop.isRecording() ? controlColors.recording : controlColors.idle)
} else if (track.loop.isPlaying() || track.loop.isReadyToPlay()) {
} else if (trackScene?.canPlay && (track.loop.isPlaying() || track.loop.isReadyToPlay())) {
track.controlIcon.setText(controlIcons.play)
.setColor(track.loop.isPlaying() ? controlColors.playing : controlColors.idle);
} else {
Expand Down
Loading

0 comments on commit e8a240a

Please sign in to comment.