/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
richardMood: "sleeping",
lastFed: 0
});
/****
* Classes
****/
// Fish (food)
var Fish = Container.expand(function () {
var self = Container.call(this);
self.fishNode = self.attachAsset('fish', {
anchorX: 0.5,
anchorY: 0.5
});
self.plateNode = self.attachAsset('plate', {
anchorX: 0.5,
anchorY: 0.5,
y: 60
});
self.x = 0;
self.y = 0;
self.isDragging = false;
// Drag logic
self.down = function (x, y, obj) {
self.isDragging = true;
dragNode = self;
self.offsetX = self.x - x;
self.offsetY = self.y - y;
};
self.up = function (x, y, obj) {
self.isDragging = false;
dragNode = null;
};
return self;
});
// Richard the Falcon
var Richard = Container.expand(function () {
var self = Container.call(this);
// State: 'sleeping', 'awake', 'eating', 'happy', 'grumpy'
self.state = storage.richardMood || 'sleeping';
self.lastFed = storage.lastFed || 0;
self.lastStateChange = LK.ticks;
self.isInteracting = false;
// Asset nodes
self.richardNode = null;
self.zzzNode = null;
// Dialogue
self.dialogue = new Text2('', {
size: 80,
fill: "#fff",
font: "Tahoma"
});
self.dialogue.anchor.set(0.5, 0);
self.dialogue.x = 0;
self.dialogue.y = 270;
self.addChild(self.dialogue);
// Helper: Set Richard's visual state
self.setState = function (state) {
if (self.richardNode) {
self.removeChild(self.richardNode);
self.richardNode.destroy();
self.richardNode = null;
}
if (self.zzzNode) {
self.removeChild(self.zzzNode);
self.zzzNode.destroy();
self.zzzNode = null;
}
self.state = state;
storage.richardMood = state;
if (state === 'sleeping') {
self.richardNode = self.attachAsset('richard_sleep', {
anchorX: 0.5,
anchorY: 0.5
});
self.zzzNode = self.attachAsset('zzz', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: -180,
scaleX: 1.2,
scaleY: 1.2
});
self.dialogue.setText("Zzz... (Tap to wake Richard)");
} else if (state === 'awake') {
self.richardNode = self.attachAsset('richard_awake', {
anchorX: 0.5,
anchorY: 0.5
});
self.dialogue.setText("What? I'm up. Where's my breakfast?");
} else if (state === 'eating') {
self.richardNode = self.attachAsset('richard_eat', {
anchorX: 0.5,
anchorY: 0.5
});
self.dialogue.setText("Mmm... Fish. Not bad.");
} else if (state === 'happy') {
self.richardNode = self.attachAsset('richard_happy', {
anchorX: 0.5,
anchorY: 0.5
});
self.dialogue.setText("Fine, I'm happy. For now.");
} else if (state === 'grumpy') {
self.richardNode = self.attachAsset('richard_grumpy', {
anchorX: 0.5,
anchorY: 0.5
});
self.dialogue.setText("Hmph! You call this care?");
}
};
// Helper: Animate Richard (e.g. bounce)
self.bounce = function () {
tween(self, {
y: self.y - 60
}, {
duration: 120,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 60
}, {
duration: 180,
easing: tween.bounceIn
});
}
});
};
// Interactions
self.down = function (x, y, obj) {
if (self.isInteracting) return;
if (self.state === 'sleeping') {
self.isInteracting = true;
LK.getSound('wake').play();
self.setState('awake');
self.bounce();
LK.setTimeout(function () {
self.isInteracting = false;
}, 400);
} else if (self.state === 'awake') {
// Poke Richard
self.isInteracting = true;
LK.getSound('poke').play();
self.setState('grumpy');
self.bounce();
LK.setTimeout(function () {
self.setState('awake');
self.isInteracting = false;
}, 1200);
} else if (self.state === 'happy') {
// Pet Richard
self.isInteracting = true;
LK.getSound('happy').play();
self.dialogue.setText("Heh. Don't get used to this.");
self.bounce();
LK.setTimeout(function () {
self.setState('awake');
self.isInteracting = false;
}, 1200);
} else if (self.state === 'grumpy') {
// Poke again
self.isInteracting = true;
LK.getSound('grumpy').play();
self.dialogue.setText("Stop poking me!");
self.bounce();
LK.setTimeout(function () {
self.setState('awake');
self.isInteracting = false;
}, 1200);
}
};
// Called when fed
self.feed = function () {
if (self.isInteracting) return;
if (self.state === 'awake' || self.state === 'grumpy') {
self.isInteracting = true;
LK.getSound('eat').play();
self.setState('eating');
self.lastFed = LK.ticks;
storage.lastFed = self.lastFed;
LK.setTimeout(function () {
self.setState('happy');
self.isInteracting = false;
}, 1200);
}
};
// Update: handle mood decay
self.update = function () {
// If awake for a while and not fed, get grumpy
if (self.state === 'awake' && LK.ticks - self.lastFed > 600 && !self.isInteracting) {
self.setState('grumpy');
}
// If happy for a while, return to awake
if (self.state === 'happy' && LK.ticks - self.lastFed > 300 && !self.isInteracting) {
self.setState('awake');
}
// If grumpy for a while, fall asleep
if (self.state === 'grumpy' && LK.ticks - self.lastFed > 1200 && !self.isInteracting) {
self.setState('sleeping');
}
};
// Initialize
self.setState(self.state);
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Light blue sky
});
/****
* Game Code
****/
// Sound effects (placeholders)
// Richard the Falcon (main character)
// Center positions
var centerX = 2048 / 2;
var centerY = 2732 / 2 + 100;
// Add Richard
var richard = new Richard();
richard.x = centerX;
richard.y = centerY - 200;
game.addChild(richard);
// Add Fish (food)
var fish = new Fish();
fish.x = centerX;
fish.y = centerY + 400;
game.addChild(fish);
// Score text: "Richard's Mood"
var moodTxt = new Text2("Mood: Sleeping", {
size: 90,
fill: "#fff"
});
moodTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(moodTxt);
// Helper: Update mood text
function updateMoodText() {
var mood = richard.state;
var moodStr = "Mood: ";
if (mood === 'sleeping') moodStr += "Sleeping";else if (mood === 'awake') moodStr += "Hungry";else if (mood === 'eating') moodStr += "Eating";else if (mood === 'happy') moodStr += "Happy";else if (mood === 'grumpy') moodStr += "Grumpy";
moodTxt.setText(moodStr);
}
// Drag logic
var dragNode = null;
function handleMove(x, y, obj) {
if (dragNode && dragNode.isDragging) {
dragNode.x = x + (dragNode.offsetX || 0);
dragNode.y = y + (dragNode.offsetY || 0);
}
}
game.move = handleMove;
// Down event: check if fish or Richard is pressed
game.down = function (x, y, obj) {
// Convert to local coordinates for fish and Richard
var fishLocal = fish.toLocal(game.toGlobal({
x: x,
y: y
}));
var richardLocal = richard.toLocal(game.toGlobal({
x: x,
y: y
}));
// Check if fish is pressed
if (fish.fishNode && fishLocal.x > -fish.fishNode.width / 2 && fishLocal.x < fish.fishNode.width / 2 && fishLocal.y > -fish.fishNode.height / 2 && fishLocal.y < fish.fishNode.height / 2) {
fish.down(x, y, obj);
return;
}
// Check if Richard is pressed
if (richard.richardNode && richardLocal.x > -richard.richardNode.width / 2 && richardLocal.x < richard.richardNode.width / 2 && richardLocal.y > -richard.richardNode.height / 2 && richardLocal.y < richard.richardNode.height / 2) {
richard.down(x, y, obj);
return;
}
};
// Up event: release drag
game.up = function (x, y, obj) {
if (dragNode && dragNode.isDragging) {
// Check if fish is dropped on Richard
var fishCenter = {
x: fish.x,
y: fish.y
};
var richardBounds = {
x: richard.x - 250,
y: richard.y - 250,
width: 500,
height: 500
};
if (fishCenter.x > richardBounds.x && fishCenter.x < richardBounds.x + richardBounds.width && fishCenter.y > richardBounds.y && fishCenter.y < richardBounds.y + richardBounds.height) {
// Feed Richard
richard.feed();
// Animate fish "disappear" and reset
tween(fish, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
fish.x = centerX;
fish.y = centerY + 400;
fish.alpha = 1;
}
});
} else {
// Snap back to plate
tween(fish, {
x: centerX,
y: centerY + 400
}, {
duration: 200
});
}
fish.up(x, y, obj);
}
dragNode = null;
};
// Main update loop
game.update = function () {
richard.update();
updateMoodText();
// If fish is not being dragged and not at plate, snap back
if (!fish.isDragging && (Math.abs(fish.x - centerX) > 10 || Math.abs(fish.y - (centerY + 400)) > 10)) {
tween(fish, {
x: centerX,
y: centerY + 400
}, {
duration: 200
});
}
};
// Initial mood text
updateMoodText(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
richardMood: "sleeping",
lastFed: 0
});
/****
* Classes
****/
// Fish (food)
var Fish = Container.expand(function () {
var self = Container.call(this);
self.fishNode = self.attachAsset('fish', {
anchorX: 0.5,
anchorY: 0.5
});
self.plateNode = self.attachAsset('plate', {
anchorX: 0.5,
anchorY: 0.5,
y: 60
});
self.x = 0;
self.y = 0;
self.isDragging = false;
// Drag logic
self.down = function (x, y, obj) {
self.isDragging = true;
dragNode = self;
self.offsetX = self.x - x;
self.offsetY = self.y - y;
};
self.up = function (x, y, obj) {
self.isDragging = false;
dragNode = null;
};
return self;
});
// Richard the Falcon
var Richard = Container.expand(function () {
var self = Container.call(this);
// State: 'sleeping', 'awake', 'eating', 'happy', 'grumpy'
self.state = storage.richardMood || 'sleeping';
self.lastFed = storage.lastFed || 0;
self.lastStateChange = LK.ticks;
self.isInteracting = false;
// Asset nodes
self.richardNode = null;
self.zzzNode = null;
// Dialogue
self.dialogue = new Text2('', {
size: 80,
fill: "#fff",
font: "Tahoma"
});
self.dialogue.anchor.set(0.5, 0);
self.dialogue.x = 0;
self.dialogue.y = 270;
self.addChild(self.dialogue);
// Helper: Set Richard's visual state
self.setState = function (state) {
if (self.richardNode) {
self.removeChild(self.richardNode);
self.richardNode.destroy();
self.richardNode = null;
}
if (self.zzzNode) {
self.removeChild(self.zzzNode);
self.zzzNode.destroy();
self.zzzNode = null;
}
self.state = state;
storage.richardMood = state;
if (state === 'sleeping') {
self.richardNode = self.attachAsset('richard_sleep', {
anchorX: 0.5,
anchorY: 0.5
});
self.zzzNode = self.attachAsset('zzz', {
anchorX: 0.5,
anchorY: 0.5,
x: 120,
y: -180,
scaleX: 1.2,
scaleY: 1.2
});
self.dialogue.setText("Zzz... (Tap to wake Richard)");
} else if (state === 'awake') {
self.richardNode = self.attachAsset('richard_awake', {
anchorX: 0.5,
anchorY: 0.5
});
self.dialogue.setText("What? I'm up. Where's my breakfast?");
} else if (state === 'eating') {
self.richardNode = self.attachAsset('richard_eat', {
anchorX: 0.5,
anchorY: 0.5
});
self.dialogue.setText("Mmm... Fish. Not bad.");
} else if (state === 'happy') {
self.richardNode = self.attachAsset('richard_happy', {
anchorX: 0.5,
anchorY: 0.5
});
self.dialogue.setText("Fine, I'm happy. For now.");
} else if (state === 'grumpy') {
self.richardNode = self.attachAsset('richard_grumpy', {
anchorX: 0.5,
anchorY: 0.5
});
self.dialogue.setText("Hmph! You call this care?");
}
};
// Helper: Animate Richard (e.g. bounce)
self.bounce = function () {
tween(self, {
y: self.y - 60
}, {
duration: 120,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 60
}, {
duration: 180,
easing: tween.bounceIn
});
}
});
};
// Interactions
self.down = function (x, y, obj) {
if (self.isInteracting) return;
if (self.state === 'sleeping') {
self.isInteracting = true;
LK.getSound('wake').play();
self.setState('awake');
self.bounce();
LK.setTimeout(function () {
self.isInteracting = false;
}, 400);
} else if (self.state === 'awake') {
// Poke Richard
self.isInteracting = true;
LK.getSound('poke').play();
self.setState('grumpy');
self.bounce();
LK.setTimeout(function () {
self.setState('awake');
self.isInteracting = false;
}, 1200);
} else if (self.state === 'happy') {
// Pet Richard
self.isInteracting = true;
LK.getSound('happy').play();
self.dialogue.setText("Heh. Don't get used to this.");
self.bounce();
LK.setTimeout(function () {
self.setState('awake');
self.isInteracting = false;
}, 1200);
} else if (self.state === 'grumpy') {
// Poke again
self.isInteracting = true;
LK.getSound('grumpy').play();
self.dialogue.setText("Stop poking me!");
self.bounce();
LK.setTimeout(function () {
self.setState('awake');
self.isInteracting = false;
}, 1200);
}
};
// Called when fed
self.feed = function () {
if (self.isInteracting) return;
if (self.state === 'awake' || self.state === 'grumpy') {
self.isInteracting = true;
LK.getSound('eat').play();
self.setState('eating');
self.lastFed = LK.ticks;
storage.lastFed = self.lastFed;
LK.setTimeout(function () {
self.setState('happy');
self.isInteracting = false;
}, 1200);
}
};
// Update: handle mood decay
self.update = function () {
// If awake for a while and not fed, get grumpy
if (self.state === 'awake' && LK.ticks - self.lastFed > 600 && !self.isInteracting) {
self.setState('grumpy');
}
// If happy for a while, return to awake
if (self.state === 'happy' && LK.ticks - self.lastFed > 300 && !self.isInteracting) {
self.setState('awake');
}
// If grumpy for a while, fall asleep
if (self.state === 'grumpy' && LK.ticks - self.lastFed > 1200 && !self.isInteracting) {
self.setState('sleeping');
}
};
// Initialize
self.setState(self.state);
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Light blue sky
});
/****
* Game Code
****/
// Sound effects (placeholders)
// Richard the Falcon (main character)
// Center positions
var centerX = 2048 / 2;
var centerY = 2732 / 2 + 100;
// Add Richard
var richard = new Richard();
richard.x = centerX;
richard.y = centerY - 200;
game.addChild(richard);
// Add Fish (food)
var fish = new Fish();
fish.x = centerX;
fish.y = centerY + 400;
game.addChild(fish);
// Score text: "Richard's Mood"
var moodTxt = new Text2("Mood: Sleeping", {
size: 90,
fill: "#fff"
});
moodTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(moodTxt);
// Helper: Update mood text
function updateMoodText() {
var mood = richard.state;
var moodStr = "Mood: ";
if (mood === 'sleeping') moodStr += "Sleeping";else if (mood === 'awake') moodStr += "Hungry";else if (mood === 'eating') moodStr += "Eating";else if (mood === 'happy') moodStr += "Happy";else if (mood === 'grumpy') moodStr += "Grumpy";
moodTxt.setText(moodStr);
}
// Drag logic
var dragNode = null;
function handleMove(x, y, obj) {
if (dragNode && dragNode.isDragging) {
dragNode.x = x + (dragNode.offsetX || 0);
dragNode.y = y + (dragNode.offsetY || 0);
}
}
game.move = handleMove;
// Down event: check if fish or Richard is pressed
game.down = function (x, y, obj) {
// Convert to local coordinates for fish and Richard
var fishLocal = fish.toLocal(game.toGlobal({
x: x,
y: y
}));
var richardLocal = richard.toLocal(game.toGlobal({
x: x,
y: y
}));
// Check if fish is pressed
if (fish.fishNode && fishLocal.x > -fish.fishNode.width / 2 && fishLocal.x < fish.fishNode.width / 2 && fishLocal.y > -fish.fishNode.height / 2 && fishLocal.y < fish.fishNode.height / 2) {
fish.down(x, y, obj);
return;
}
// Check if Richard is pressed
if (richard.richardNode && richardLocal.x > -richard.richardNode.width / 2 && richardLocal.x < richard.richardNode.width / 2 && richardLocal.y > -richard.richardNode.height / 2 && richardLocal.y < richard.richardNode.height / 2) {
richard.down(x, y, obj);
return;
}
};
// Up event: release drag
game.up = function (x, y, obj) {
if (dragNode && dragNode.isDragging) {
// Check if fish is dropped on Richard
var fishCenter = {
x: fish.x,
y: fish.y
};
var richardBounds = {
x: richard.x - 250,
y: richard.y - 250,
width: 500,
height: 500
};
if (fishCenter.x > richardBounds.x && fishCenter.x < richardBounds.x + richardBounds.width && fishCenter.y > richardBounds.y && fishCenter.y < richardBounds.y + richardBounds.height) {
// Feed Richard
richard.feed();
// Animate fish "disappear" and reset
tween(fish, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
fish.x = centerX;
fish.y = centerY + 400;
fish.alpha = 1;
}
});
} else {
// Snap back to plate
tween(fish, {
x: centerX,
y: centerY + 400
}, {
duration: 200
});
}
fish.up(x, y, obj);
}
dragNode = null;
};
// Main update loop
game.update = function () {
richard.update();
updateMoodText();
// If fish is not being dragged and not at plate, snap back
if (!fish.isDragging && (Math.abs(fish.x - centerX) > 10 || Math.abs(fish.y - (centerY + 400)) > 10)) {
tween(fish, {
x: centerX,
y: centerY + 400
}, {
duration: 200
});
}
};
// Initial mood text
updateMoodText();