forked from MarseyWorld/MarseyWorld
204 lines
4.5 KiB
JavaScript
204 lines
4.5 KiB
JavaScript
const cursormarseyEl = document.getElementById("cursormarsey");
|
|
const heartEl = document.getElementById("cursormarsey-heart");
|
|
|
|
function getInitialPosition(max) {
|
|
return Math.max(32, Math.floor(Math.random() * max));
|
|
}
|
|
let cursormarseyPosX = getInitialPosition(screen.availWidth - 20);
|
|
let cursormarseyPosY = getInitialPosition(screen.availHeight - 50);
|
|
cursormarseyEl.style.left = `${cursormarseyPosX}px`;
|
|
cursormarseyEl.style.top = `${cursormarseyPosY}px`;
|
|
heartEl.style.left = `${cursormarseyPosX+16}px`;
|
|
heartEl.style.top = `${cursormarseyPosY-16}px`;
|
|
|
|
let mousePosX = cursormarseyPosX;
|
|
let mousePosY = cursormarseyPosY;
|
|
|
|
let frameCount = 0;
|
|
let idleTime = 0;
|
|
let idleAnimation = null;
|
|
let idleAnimationFrame = 0;
|
|
const cursormarseySpeed = 10;
|
|
const spriteSets = {
|
|
idle: [[-3, -3]],
|
|
alert: [[-7, -3]],
|
|
scratchSelf: [
|
|
[-5, 0],
|
|
[-6, 0],
|
|
[-7, 0],
|
|
],
|
|
scratchWallN: [
|
|
[0, 0],
|
|
[0, -1],
|
|
],
|
|
scratchWallS: [
|
|
[-7, -1],
|
|
[-6, -2],
|
|
],
|
|
scratchWallE: [
|
|
[-2, -2],
|
|
[-2, -3],
|
|
],
|
|
scratchWallW: [
|
|
[-4, 0],
|
|
[-4, -1],
|
|
],
|
|
tired: [[-3, -2]],
|
|
sleeping: [
|
|
[-2, 0],
|
|
[-2, -1],
|
|
],
|
|
N: [
|
|
[-1, -2],
|
|
[-1, -3],
|
|
],
|
|
NE: [
|
|
[0, -2],
|
|
[0, -3],
|
|
],
|
|
E: [
|
|
[-3, 0],
|
|
[-3, -1],
|
|
],
|
|
SE: [
|
|
[-5, -1],
|
|
[-5, -2],
|
|
],
|
|
S: [
|
|
[-6, -3],
|
|
[-7, -2],
|
|
],
|
|
SW: [
|
|
[-5, -3],
|
|
[-6, -1],
|
|
],
|
|
W: [
|
|
[-4, -2],
|
|
[-4, -3],
|
|
],
|
|
NW: [
|
|
[-1, 0],
|
|
[-1, -1],
|
|
],
|
|
};
|
|
|
|
function setSprite(name, frame) {
|
|
const sprite = spriteSets[name][frame % spriteSets[name].length];
|
|
cursormarseyEl.style.backgroundPosition = `${sprite[0] * 32}px ${sprite[1] * 32}px`;
|
|
}
|
|
|
|
function resetIdleAnimation() {
|
|
idleAnimation = null;
|
|
idleAnimationFrame = 0;
|
|
}
|
|
|
|
function idle() {
|
|
idleTime += 1;
|
|
|
|
// every ~ 20 seconds
|
|
if (idleTime > 10 && true && idleAnimation == null) {
|
|
let avalibleIdleAnimations = ["sleeping", "scratchSelf"];
|
|
if (cursormarseyPosX < 32) {
|
|
avalibleIdleAnimations.push("scratchWallW");
|
|
}
|
|
if (cursormarseyPosY < 32) {
|
|
avalibleIdleAnimations.push("scratchWallN");
|
|
}
|
|
if (cursormarseyPosX > innerWidth - 32) {
|
|
avalibleIdleAnimations.push("scratchWallE");
|
|
}
|
|
if (cursormarseyPosY > innerHeight - 32) {
|
|
avalibleIdleAnimations.push("scratchWallS");
|
|
}
|
|
idleAnimation =
|
|
avalibleIdleAnimations[
|
|
Math.floor(Math.random() * avalibleIdleAnimations.length)
|
|
];
|
|
}
|
|
|
|
switch (idleAnimation) {
|
|
case "sleeping":
|
|
if (idleAnimationFrame < 8) {
|
|
setSprite("tired", 0);
|
|
break;
|
|
}
|
|
setSprite("sleeping", Math.floor(idleAnimationFrame / 4));
|
|
if (idleAnimationFrame > 192) {
|
|
resetIdleAnimation();
|
|
}
|
|
break;
|
|
case "scratchWallN":
|
|
case "scratchWallS":
|
|
case "scratchWallE":
|
|
case "scratchWallW":
|
|
case "scratchSelf":
|
|
setSprite(idleAnimation, idleAnimationFrame);
|
|
if (idleAnimationFrame > 9) {
|
|
resetIdleAnimation();
|
|
}
|
|
break;
|
|
default:
|
|
setSprite("idle", 0);
|
|
return;
|
|
}
|
|
idleAnimationFrame += 1;
|
|
}
|
|
|
|
function frame() {
|
|
frameCount += 1;
|
|
const diffX = cursormarseyPosX - mousePosX;
|
|
const diffY = cursormarseyPosY - mousePosY;
|
|
const distance = Math.sqrt(diffX ** 2 + diffY ** 2);
|
|
|
|
if (distance < cursormarseySpeed || distance < 100) {
|
|
idle();
|
|
return;
|
|
}
|
|
|
|
idleAnimation = null;
|
|
idleAnimationFrame = 0;
|
|
|
|
if (idleTime > 1) {
|
|
setSprite("alert", 0);
|
|
// count down after being alerted before moving
|
|
idleTime = Math.min(idleTime, 7);
|
|
idleTime -= 1;
|
|
return;
|
|
}
|
|
|
|
direction = diffY / distance > 0.5 ? "N" : "";
|
|
direction += diffY / distance < -0.5 ? "S" : "";
|
|
direction += diffX / distance > 0.5 ? "W" : "";
|
|
direction += diffX / distance < -0.5 ? "E" : "";
|
|
setSprite(direction, frameCount);
|
|
|
|
cursormarseyPosX -= (diffX / distance) * cursormarseySpeed;
|
|
cursormarseyPosY -= (diffY / distance) * cursormarseySpeed;
|
|
|
|
cursormarseyPosX = Math.min(Math.max(16, cursormarseyPosX), innerWidth - 16);
|
|
cursormarseyPosY = Math.min(Math.max(16, cursormarseyPosY), innerHeight - 16);
|
|
|
|
cursormarseyEl.style.left = `${cursormarseyPosX}px`;
|
|
cursormarseyEl.style.top = `${cursormarseyPosY}px`;
|
|
heartEl.style.left = `${cursormarseyPosX+16}px`;
|
|
heartEl.style.top = `${cursormarseyPosY-16}px`;
|
|
}
|
|
|
|
document.onmousemove = (event) => {
|
|
mousePosX = event.clientX;
|
|
mousePosY = event.clientY;
|
|
};
|
|
window.marseykoInterval = setInterval(frame, 100);
|
|
|
|
document.addEventListener('click', (event) => {
|
|
cursormarseyEl.style.removeProperty("pointer-events");
|
|
let elementClicked = document.elementFromPoint(event.clientX,event.clientY);
|
|
if (elementClicked && elementClicked.id === cursormarseyEl.id) {
|
|
heartEl.classList.remove("d-none");
|
|
setTimeout(() => {
|
|
heartEl.classList.add("d-none");
|
|
}, 2000);
|
|
}
|
|
cursormarseyEl.style.pointerEvents = "none";
|
|
});
|