/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var ControlButton = Container.expand(function (buttonType) {
var self = Container.call(this);
var graphics = self.attachAsset('recordButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.buttonType = buttonType;
var buttonText = new Text2(getButtonLabel(buttonType), {
size: 32,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
function getButtonLabel(type) {
switch (type) {
case 'record':
return isRecording ? 'STOP' : 'REC';
case 'play':
return 'PLAY';
case 'clear':
return 'CLEAR';
default:
return '';
}
}
self.updateLabel = function () {
buttonText.setText(getButtonLabel(self.buttonType));
};
self.down = function (x, y, obj) {
graphics.scaleX = graphics.scaleY = 0.9;
tween(graphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeOut
});
if (self.buttonType === 'record') {
toggleRecording();
} else if (self.buttonType === 'play') {
playRecording();
} else if (self.buttonType === 'clear') {
clearRecording();
}
};
return self;
});
var MusicalTile = Container.expand(function (tileType, soundId, noteIndex) {
var self = Container.call(this);
var assetName = tileType + 'Tile';
var graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.tileType = tileType;
self.soundId = soundId;
self.noteIndex = noteIndex;
self.originalScale = 1;
self.isPressed = false;
var noteText = new Text2(getNoteLabel(tileType, noteIndex), {
size: 40,
fill: 0xFFFFFF
});
noteText.anchor.set(0.5, 0.5);
self.addChild(noteText);
function getNoteLabel(type, index) {
if (type === 'piano') {
var notes = ['C', 'D', 'E', 'F', 'G', 'A', 'B', 'C2'];
return notes[index];
} else if (type === 'drum') {
var drums = ['Kick', 'Snare', 'Hi-Hat', 'Crash', 'Tom', 'Rim', 'Clap', 'Open'];
return drums[index];
} else if (type === 'synth') {
var synths = ['Bass', 'Lead', 'Pad', 'Arp', 'Pluck', 'Sweep', 'Bell', 'Choir'];
return synths[index];
} else if (type === 'nature') {
var nature = ['Rain', 'Wind', 'Birds', 'Water', 'Thunder', 'Ocean', 'Forest', 'Fire'];
return nature[index];
}
return '';
}
self.playSound = function () {
LK.getSound(self.soundId).play();
self.createParticles();
self.animateTile();
};
self.createParticles = function () {
for (var i = 0; i < 8; i++) {
var particle = new Particle();
particle.x = self.x + (Math.random() - 0.5) * 100;
particle.y = self.y + (Math.random() - 0.5) * 50;
particles.push(particle);
game.addChild(particle);
}
};
self.animateTile = function () {
self.isPressed = true;
graphics.scaleX = graphics.scaleY = 1.2;
graphics.tint = 0xFFFFFF;
tween(graphics, {
scaleX: self.originalScale,
scaleY: self.originalScale
}, {
duration: 200,
easing: tween.easeOut
});
tween(graphics, {
tint: getTileColor(self.tileType)
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isPressed = false;
}
});
};
function getTileColor(type) {
switch (type) {
case 'piano':
return 0x4A90E2;
case 'drum':
return 0xE94B3C;
case 'synth':
return 0x7B68EE;
case 'nature':
return 0x50C878;
default:
return 0xFFFFFF;
}
}
self.down = function (x, y, obj) {
self.playSound();
if (isRecording) {
recordedNotes.push({
soundId: self.soundId,
time: Date.now() - recordingStartTime,
tileType: self.tileType,
noteIndex: self.noteIndex
});
}
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = (Math.random() - 0.5) * 10;
self.speedY = -Math.random() * 8 - 2;
self.life = 60;
self.maxLife = 60;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.speedY += 0.2;
self.life--;
graphics.alpha = self.life / self.maxLife;
graphics.scaleX = graphics.scaleY = self.life / self.maxLife * 0.5 + 0.5;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2C3E50
});
/****
* Game Code
****/
var tiles = [];
var particles = [];
var controlButtons = [];
var recordedNotes = [];
var isRecording = false;
var isPlaying = false;
var recordingStartTime = 0;
var playbackStartTime = 0;
var currentPlaybackIndex = 0;
var instrumentTypes = ['piano', 'drum', 'synth', 'nature'];
var soundMaps = {
piano: ['piano_c', 'piano_d', 'piano_e', 'piano_f', 'piano_g', 'piano_a', 'piano_b', 'piano_c2'],
drum: ['drum_kick', 'drum_snare', 'drum_hihat', 'drum_crash', 'drum_tom', 'drum_rim', 'drum_clap', 'drum_openhat'],
synth: ['synth_bass', 'synth_lead', 'synth_pad', 'synth_arp', 'synth_pluck', 'synth_sweep', 'synth_bell', 'synth_choir'],
nature: ['nature_rain', 'nature_wind', 'nature_birds', 'nature_water', 'nature_thunder', 'nature_ocean', 'nature_forest', 'nature_fire']
};
// Create title
var titleText = new Text2('Melody Maker', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 100;
game.addChild(titleText);
var currentInstrument = 'piano';
// Create tiles grid
var startY = 350;
var tileSpacing = 320;
var tilesPerRow = 4;
var tileRows = 2;
for (var row = 0; row < tileRows; row++) {
for (var col = 0; col < tilesPerRow; col++) {
var tileIndex = row * tilesPerRow + col;
var soundId = soundMaps[currentInstrument][tileIndex];
var tile = new MusicalTile(currentInstrument, soundId, tileIndex);
var x = (col - 1.5) * tileSpacing + 2048 / 2;
var y = startY + row * 200;
tile.x = x;
tile.y = y;
tiles.push(tile);
game.addChild(tile);
}
}
// Create control buttons
var recordButton = new ControlButton('record');
recordButton.x = 2048 / 2 - 250;
recordButton.y = 2400;
controlButtons.push(recordButton);
game.addChild(recordButton);
var playButton = new ControlButton('play');
playButton.x = 2048 / 2;
playButton.y = 2400;
controlButtons.push(playButton);
game.addChild(playButton);
var clearButton = new ControlButton('clear');
clearButton.x = 2048 / 2 + 250;
clearButton.y = 2400;
controlButtons.push(clearButton);
game.addChild(clearButton);
// Create status text
var statusText = new Text2('Tap tiles to create music!', {
size: 40,
fill: 0xBDC3C7
});
statusText.anchor.set(0.5, 0.5);
statusText.x = 2048 / 2;
statusText.y = 2550;
game.addChild(statusText);
function getTileColorForType(type) {
switch (type) {
case 'piano':
return 0x4A90E2;
case 'drum':
return 0xE94B3C;
case 'synth':
return 0x7B68EE;
case 'nature':
return 0x50C878;
default:
return 0xFFFFFF;
}
}
function toggleRecording() {
if (isRecording) {
// Stop recording
isRecording = false;
statusText.setText('Recording stopped. ' + recordedNotes.length + ' notes recorded.');
} else {
// Start recording
isRecording = true;
recordingStartTime = Date.now();
recordedNotes = [];
statusText.setText('Recording... Tap tiles to record your melody!');
}
// Update button labels
for (var i = 0; i < controlButtons.length; i++) {
controlButtons[i].updateLabel();
}
}
function playRecording() {
if (recordedNotes.length === 0) {
statusText.setText('No recording to play. Record some notes first!');
return;
}
if (isPlaying) {
return;
}
isPlaying = true;
playbackStartTime = Date.now();
currentPlaybackIndex = 0;
statusText.setText('Playing back your melody...');
}
function clearRecording() {
recordedNotes = [];
isRecording = false;
isPlaying = false;
currentPlaybackIndex = 0;
statusText.setText('Recording cleared. Start creating a new melody!');
// Update button labels
for (var i = 0; i < controlButtons.length; i++) {
controlButtons[i].updateLabel();
}
}
game.update = function () {
// Update particles
for (var i = particles.length - 1; i >= 0; i--) {
var particle = particles[i];
if (particle.life <= 0) {
particle.destroy();
particles.splice(i, 1);
}
}
// Handle playback
if (isPlaying && recordedNotes.length > 0) {
var currentTime = Date.now() - playbackStartTime;
while (currentPlaybackIndex < recordedNotes.length) {
var note = recordedNotes[currentPlaybackIndex];
if (currentTime >= note.time) {
LK.getSound(note.soundId).play();
// Find and animate the corresponding tile
for (var j = 0; j < tiles.length; j++) {
var tile = tiles[j];
if (tile.soundId === note.soundId) {
tile.createParticles();
tile.animateTile();
break;
}
}
currentPlaybackIndex++;
} else {
break;
}
}
// Check if playback is complete
if (currentPlaybackIndex >= recordedNotes.length) {
var lastNoteTime = recordedNotes[recordedNotes.length - 1].time;
if (currentTime >= lastNoteTime + 1000) {
isPlaying = false;
statusText.setText('Playback complete! Record new notes or play again.');
}
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var ControlButton = Container.expand(function (buttonType) {
var self = Container.call(this);
var graphics = self.attachAsset('recordButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.buttonType = buttonType;
var buttonText = new Text2(getButtonLabel(buttonType), {
size: 32,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
self.addChild(buttonText);
function getButtonLabel(type) {
switch (type) {
case 'record':
return isRecording ? 'STOP' : 'REC';
case 'play':
return 'PLAY';
case 'clear':
return 'CLEAR';
default:
return '';
}
}
self.updateLabel = function () {
buttonText.setText(getButtonLabel(self.buttonType));
};
self.down = function (x, y, obj) {
graphics.scaleX = graphics.scaleY = 0.9;
tween(graphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeOut
});
if (self.buttonType === 'record') {
toggleRecording();
} else if (self.buttonType === 'play') {
playRecording();
} else if (self.buttonType === 'clear') {
clearRecording();
}
};
return self;
});
var MusicalTile = Container.expand(function (tileType, soundId, noteIndex) {
var self = Container.call(this);
var assetName = tileType + 'Tile';
var graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.tileType = tileType;
self.soundId = soundId;
self.noteIndex = noteIndex;
self.originalScale = 1;
self.isPressed = false;
var noteText = new Text2(getNoteLabel(tileType, noteIndex), {
size: 40,
fill: 0xFFFFFF
});
noteText.anchor.set(0.5, 0.5);
self.addChild(noteText);
function getNoteLabel(type, index) {
if (type === 'piano') {
var notes = ['C', 'D', 'E', 'F', 'G', 'A', 'B', 'C2'];
return notes[index];
} else if (type === 'drum') {
var drums = ['Kick', 'Snare', 'Hi-Hat', 'Crash', 'Tom', 'Rim', 'Clap', 'Open'];
return drums[index];
} else if (type === 'synth') {
var synths = ['Bass', 'Lead', 'Pad', 'Arp', 'Pluck', 'Sweep', 'Bell', 'Choir'];
return synths[index];
} else if (type === 'nature') {
var nature = ['Rain', 'Wind', 'Birds', 'Water', 'Thunder', 'Ocean', 'Forest', 'Fire'];
return nature[index];
}
return '';
}
self.playSound = function () {
LK.getSound(self.soundId).play();
self.createParticles();
self.animateTile();
};
self.createParticles = function () {
for (var i = 0; i < 8; i++) {
var particle = new Particle();
particle.x = self.x + (Math.random() - 0.5) * 100;
particle.y = self.y + (Math.random() - 0.5) * 50;
particles.push(particle);
game.addChild(particle);
}
};
self.animateTile = function () {
self.isPressed = true;
graphics.scaleX = graphics.scaleY = 1.2;
graphics.tint = 0xFFFFFF;
tween(graphics, {
scaleX: self.originalScale,
scaleY: self.originalScale
}, {
duration: 200,
easing: tween.easeOut
});
tween(graphics, {
tint: getTileColor(self.tileType)
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isPressed = false;
}
});
};
function getTileColor(type) {
switch (type) {
case 'piano':
return 0x4A90E2;
case 'drum':
return 0xE94B3C;
case 'synth':
return 0x7B68EE;
case 'nature':
return 0x50C878;
default:
return 0xFFFFFF;
}
}
self.down = function (x, y, obj) {
self.playSound();
if (isRecording) {
recordedNotes.push({
soundId: self.soundId,
time: Date.now() - recordingStartTime,
tileType: self.tileType,
noteIndex: self.noteIndex
});
}
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
self.speedX = (Math.random() - 0.5) * 10;
self.speedY = -Math.random() * 8 - 2;
self.life = 60;
self.maxLife = 60;
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.speedY += 0.2;
self.life--;
graphics.alpha = self.life / self.maxLife;
graphics.scaleX = graphics.scaleY = self.life / self.maxLife * 0.5 + 0.5;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2C3E50
});
/****
* Game Code
****/
var tiles = [];
var particles = [];
var controlButtons = [];
var recordedNotes = [];
var isRecording = false;
var isPlaying = false;
var recordingStartTime = 0;
var playbackStartTime = 0;
var currentPlaybackIndex = 0;
var instrumentTypes = ['piano', 'drum', 'synth', 'nature'];
var soundMaps = {
piano: ['piano_c', 'piano_d', 'piano_e', 'piano_f', 'piano_g', 'piano_a', 'piano_b', 'piano_c2'],
drum: ['drum_kick', 'drum_snare', 'drum_hihat', 'drum_crash', 'drum_tom', 'drum_rim', 'drum_clap', 'drum_openhat'],
synth: ['synth_bass', 'synth_lead', 'synth_pad', 'synth_arp', 'synth_pluck', 'synth_sweep', 'synth_bell', 'synth_choir'],
nature: ['nature_rain', 'nature_wind', 'nature_birds', 'nature_water', 'nature_thunder', 'nature_ocean', 'nature_forest', 'nature_fire']
};
// Create title
var titleText = new Text2('Melody Maker', {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 100;
game.addChild(titleText);
var currentInstrument = 'piano';
// Create tiles grid
var startY = 350;
var tileSpacing = 320;
var tilesPerRow = 4;
var tileRows = 2;
for (var row = 0; row < tileRows; row++) {
for (var col = 0; col < tilesPerRow; col++) {
var tileIndex = row * tilesPerRow + col;
var soundId = soundMaps[currentInstrument][tileIndex];
var tile = new MusicalTile(currentInstrument, soundId, tileIndex);
var x = (col - 1.5) * tileSpacing + 2048 / 2;
var y = startY + row * 200;
tile.x = x;
tile.y = y;
tiles.push(tile);
game.addChild(tile);
}
}
// Create control buttons
var recordButton = new ControlButton('record');
recordButton.x = 2048 / 2 - 250;
recordButton.y = 2400;
controlButtons.push(recordButton);
game.addChild(recordButton);
var playButton = new ControlButton('play');
playButton.x = 2048 / 2;
playButton.y = 2400;
controlButtons.push(playButton);
game.addChild(playButton);
var clearButton = new ControlButton('clear');
clearButton.x = 2048 / 2 + 250;
clearButton.y = 2400;
controlButtons.push(clearButton);
game.addChild(clearButton);
// Create status text
var statusText = new Text2('Tap tiles to create music!', {
size: 40,
fill: 0xBDC3C7
});
statusText.anchor.set(0.5, 0.5);
statusText.x = 2048 / 2;
statusText.y = 2550;
game.addChild(statusText);
function getTileColorForType(type) {
switch (type) {
case 'piano':
return 0x4A90E2;
case 'drum':
return 0xE94B3C;
case 'synth':
return 0x7B68EE;
case 'nature':
return 0x50C878;
default:
return 0xFFFFFF;
}
}
function toggleRecording() {
if (isRecording) {
// Stop recording
isRecording = false;
statusText.setText('Recording stopped. ' + recordedNotes.length + ' notes recorded.');
} else {
// Start recording
isRecording = true;
recordingStartTime = Date.now();
recordedNotes = [];
statusText.setText('Recording... Tap tiles to record your melody!');
}
// Update button labels
for (var i = 0; i < controlButtons.length; i++) {
controlButtons[i].updateLabel();
}
}
function playRecording() {
if (recordedNotes.length === 0) {
statusText.setText('No recording to play. Record some notes first!');
return;
}
if (isPlaying) {
return;
}
isPlaying = true;
playbackStartTime = Date.now();
currentPlaybackIndex = 0;
statusText.setText('Playing back your melody...');
}
function clearRecording() {
recordedNotes = [];
isRecording = false;
isPlaying = false;
currentPlaybackIndex = 0;
statusText.setText('Recording cleared. Start creating a new melody!');
// Update button labels
for (var i = 0; i < controlButtons.length; i++) {
controlButtons[i].updateLabel();
}
}
game.update = function () {
// Update particles
for (var i = particles.length - 1; i >= 0; i--) {
var particle = particles[i];
if (particle.life <= 0) {
particle.destroy();
particles.splice(i, 1);
}
}
// Handle playback
if (isPlaying && recordedNotes.length > 0) {
var currentTime = Date.now() - playbackStartTime;
while (currentPlaybackIndex < recordedNotes.length) {
var note = recordedNotes[currentPlaybackIndex];
if (currentTime >= note.time) {
LK.getSound(note.soundId).play();
// Find and animate the corresponding tile
for (var j = 0; j < tiles.length; j++) {
var tile = tiles[j];
if (tile.soundId === note.soundId) {
tile.createParticles();
tile.animateTile();
break;
}
}
currentPlaybackIndex++;
} else {
break;
}
}
// Check if playback is complete
if (currentPlaybackIndex >= recordedNotes.length) {
var lastNoteTime = recordedNotes[recordedNotes.length - 1].time;
if (currentTime >= lastNoteTime + 1000) {
isPlaying = false;
statusText.setText('Playback complete! Record new notes or play again.');
}
}
}
};