catmause / index.html
0c0ps2619's picture
Add 2 files
262c147 verified
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kedi vs Fare</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap');
body {
font-family: 'Poppins', sans-serif;
overflow: hidden;
touch-action: none;
user-select: none;
-webkit-user-select: none;
margin: 0;
padding: 0;
background: linear-gradient(135deg, #1e3a8a, #3b82f6, #10b981, #f59e0b);
background-size: 400% 400%;
animation: gradientBG 15s ease infinite;
}
@keyframes gradientBG {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
#gameContainer {
position: relative;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.letter {
position: absolute;
font-weight: 900;
cursor: default;
color: white;
text-shadow: 0 0 10px rgba(0,0,0,0.5);
pointer-events: none;
z-index: 5;
display: flex;
justify-content: center;
align-items: center;
animation: float 3s ease-in-out infinite, colorChange 5s infinite alternate;
transform-origin: center;
font-size: 40px;
opacity: 0.9;
width: 40px;
height: 40px;
}
@keyframes float {
0%, 100% { transform: translateY(0) rotate(0deg) scale(1); }
50% { transform: translateY(-10px) rotate(5deg) scale(1.05); }
}
@keyframes colorChange {
0% { color: #f87171; }
25% { color: #60a5fa; }
50% { color: #34d399; }
75% { color: #fbbf24; }
100% { color: #a78bfa; }
}
#cat {
position: absolute;
width: 60px;
height: 60px;
background-image: url('https://cdn-icons-png.flaticon.com/512/616/616430.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
transition: transform 0.05s ease;
z-index: 10;
filter: drop-shadow(0 0 5px rgba(0,0,0,0.5));
animation: catBounce 0.5s infinite alternate;
}
@keyframes catBounce {
0% { transform: translateY(0) scale(1); }
100% { transform: translateY(-3px) scale(1.02); }
}
#mouse {
position: absolute;
width: 40px;
height: 40px;
z-index: 10;
filter: drop-shadow(0 0 5px rgba(0,0,0,0.5));
animation: mouseShake 0.3s infinite alternate;
}
@keyframes mouseShake {
0% { transform: rotate(-2deg); }
100% { transform: rotate(2deg); }
}
.mouse-body {
position: absolute;
width: 30px;
height: 20px;
background-color: #8B4513;
border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
top: 10px;
left: 5px;
}
.mouse-ear {
position: absolute;
width: 10px;
height: 10px;
background-color: #A0522D;
border-radius: 50%;
top: 5px;
}
.mouse-ear.left {
left: 5px;
}
.mouse-ear.right {
right: 5px;
}
.mouse-eye {
position: absolute;
width: 4px;
height: 4px;
background-color: black;
border-radius: 50%;
top: 10px;
}
.mouse-eye.left {
left: 8px;
}
.mouse-eye.right {
right: 8px;
}
.mouse-nose {
position: absolute;
width: 3px;
height: 3px;
background-color: pink;
border-radius: 50%;
top: 15px;
left: 13px;
}
.mouse-tail {
position: absolute;
width: 20px;
height: 3px;
background-color: #FFD700;
border-radius: 3px;
top: 15px;
left: -10px;
transform-origin: right center;
animation: tailWag 0.3s infinite alternate;
}
@keyframes tailWag {
0% { transform: rotate(-30deg); }
100% { transform: rotate(30deg); }
}
.joystick {
position: absolute;
width: 80px;
height: 80px;
background-color: rgba(255, 255, 255, 0.3);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
z-index: 20;
border: 2px solid rgba(255,255,255,0.5);
backdrop-filter: blur(5px);
}
.joystick-knob {
width: 30px;
height: 30px;
background-color: rgba(255, 255, 255, 0.7);
border-radius: 50%;
touch-action: none;
border: 2px solid rgba(255,255,255,0.9);
}
#joystick1 {
bottom: 60px;
left: 50%;
transform: translateX(-50%);
}
#joystick2 {
top: 60px;
left: 50%;
transform: translateX(-50%);
}
#startScreen, #gameOverScreen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.7);
color: white;
z-index: 30;
backdrop-filter: blur(5px);
}
#fullscreenBtn {
position: absolute;
top: 15px;
right: 15px;
background-color: rgba(255, 255, 255, 0.3);
border: none;
color: white;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
z-index: 20;
font-size: 1.2rem;
border: 2px solid rgba(255,255,255,0.5);
backdrop-filter: blur(5px);
transition: all 0.2s ease;
}
#fullscreenBtn:hover {
transform: scale(1.1);
background-color: rgba(255, 255, 255, 0.5);
}
.btn {
background: linear-gradient(45deg, #f97316, #ef4444);
color: white;
border: none;
padding: 12px 25px;
margin: 12px;
border-radius: 25px;
font-size: 1rem;
font-weight: bold;
cursor: pointer;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
transition: all 0.2s ease;
position: relative;
overflow: hidden;
}
.btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: 0.5s;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.4);
}
.btn:hover::before {
left: 100%;
}
.input-text {
padding: 12px 15px;
margin: 15px 0;
width: 80%;
max-width: 400px;
border: 2px solid #f97316;
border-radius: 25px;
font-size: 1rem;
text-align: center;
background-color: rgba(255, 255, 255, 0.9);
transition: all 0.2s ease;
box-shadow: 0 3px 8px rgba(0,0,0,0.1);
color: #1e3a8a;
font-weight: bold;
}
.input-text:focus {
outline: none;
border-color: #ef4444;
box-shadow: 0 0 10px rgba(239, 68, 68, 0.5);
}
.title {
font-size: 3rem;
font-weight: bold;
margin-bottom: 8px;
color: white;
text-shadow: 0 3px 10px rgba(0, 0, 0, 0.5);
background: linear-gradient(45deg, #f97316, #ef4444, #f59e0b);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: titleGlow 2s ease infinite alternate;
}
@keyframes titleGlow {
0% { text-shadow: 0 0 8px rgba(249, 115, 22, 0.5); }
100% { text-shadow: 0 0 15px rgba(239, 68, 68, 0.8); }
}
.subtitle {
font-size: 1.2rem;
margin-bottom: 15px;
text-align: center;
max-width: 80%;
color: white;
text-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
.timer {
position: absolute;
top: 10px;
left: 50%;
transform: translateX(-50%);
color: white;
font-size: 0.9rem;
z-index: 20;
background-color: rgba(0,0,0,0.5);
padding: 5px 10px;
border-radius: 15px;
backdrop-filter: blur(5px);
border: 1px solid rgba(255,255,255,0.2);
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
.countdown {
position: absolute;
top: 15px;
left: 50%;
transform: translateX(-50%);
font-size: 1.5rem;
color: white;
text-shadow: 0 0 10px rgba(255,255,255,0.7);
z-index: 40;
background-color: rgba(0,0,0,0.5);
padding: 8px 15px;
border-radius: 25px;
backdrop-filter: blur(5px);
border: 2px solid rgba(255,255,255,0.2);
box-shadow: 0 3px 10px rgba(0,0,0,0.2);
}
.game-mode-selector {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin: 15px 0;
width: 100%;
max-width: 500px;
}
.game-mode-btn {
margin: 8px;
padding: 10px 15px;
border-radius: 25px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s ease;
border: 2px solid transparent;
box-shadow: 0 3px 8px rgba(0,0,0,0.2);
font-size: 0.9rem;
min-width: 120px;
}
.game-mode-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 12px rgba(0,0,0,0.3);
}
.game-mode-btn.active {
transform: scale(1.05);
border-color: white;
box-shadow: 0 0 10px rgba(255,255,255,0.5);
}
.single-player {
background: linear-gradient(45deg, #3b82f6, #60a5fa);
color: white;
}
.multiplayer {
background: linear-gradient(45deg, #10b981, #34d399);
color: white;
}
.difficulty-selector {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin: 15px 0;
width: 100%;
max-width: 500px;
}
.difficulty-btn {
margin: 8px;
padding: 8px 15px;
border-radius: 25px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s ease;
border: 2px solid transparent;
box-shadow: 0 3px 8px rgba(0,0,0,0.2);
font-size: 0.8rem;
}
.difficulty-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 12px rgba(0,0,0,0.3);
}
.difficulty-btn.active {
transform: scale(1.05);
border-color: white;
box-shadow: 0 0 10px rgba(255,255,255,0.5);
}
.easy {
background: linear-gradient(45deg, #10b981, #34d399);
color: white;
}
.medium {
background: linear-gradient(45deg, #f59e0b, #f97316);
color: white;
}
.hard {
background: linear-gradient(45deg, #ef4444, #f87171);
color: white;
}
.extreme {
background: linear-gradient(45deg, #8b5cf6, #7c3aed);
color: white;
}
.role-selector {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin: 15px 0;
width: 100%;
max-width: 500px;
}
.role-btn {
margin: 8px;
padding: 10px 15px;
border-radius: 25px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s ease;
border: 2px solid transparent;
box-shadow: 0 3px 8px rgba(0,0,0,0.2);
font-size: 0.9rem;
min-width: 100px;
}
.role-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 12px rgba(0,0,0,0.3);
}
.role-btn.active {
transform: scale(1.05);
border-color: white;
box-shadow: 0 0 10px rgba(255,255,255,0.5);
}
.cat-role {
background: linear-gradient(45deg, #f97316, #ef4444);
color: white;
}
.mouse-role {
background: linear-gradient(45deg, #8B4513, #A0522D);
color: white;
}
.pulse {
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
.shake {
animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both;
}
@keyframes shake {
10%, 90% { transform: translateX(-1px); }
20%, 80% { transform: translateX(2px); }
30%, 50%, 70% { transform: translateX(-4px); }
40%, 60% { transform: translateX(4px); }
}
</style>
</head>
<body>
<div id="gameContainer">
<div id="cat"></div>
<div id="mouse">
<div class="mouse-ear left"></div>
<div class="mouse-ear right"></div>
<div class="mouse-body"></div>
<div class="mouse-eye left"></div>
<div class="mouse-eye right"></div>
<div class="mouse-nose"></div>
<div class="mouse-tail"></div>
</div>
<div id="joystick1" class="joystick">
<div id="joystickKnob1" class="joystick-knob"></div>
</div>
<div id="joystick2" class="joystick" style="display: none;">
<div id="joystickKnob2" class="joystick-knob"></div>
</div>
<button id="fullscreenBtn">
<i class="fas fa-expand"></i>
</button>
<div class="timer">
Kalan Süre: <span id="time">30</span>s
</div>
<div id="startScreen">
<h1 class="title">Kedi vs Fare</h1>
<p class="subtitle">Fareyi yakalamak için kediyi kontrol et veya fare olup kaçmayı dene!<br>Harfler hem kedi hem fare için engel olacak.</p>
<div class="game-mode-selector">
<button class="game-mode-btn single-player active" data-mode="single">TEK OYUNCU</button>
<button class="game-mode-btn multiplayer" data-mode="multi">ÇİFT OYUNCU</button>
</div>
<div id="roleSelection" class="role-selector">
<button class="role-btn cat-role active" data-role="cat">KEDİ OL</button>
<button class="role-btn mouse-role" data-role="mouse">FARE OL</button>
</div>
<div class="difficulty-selector">
<button class="difficulty-btn easy active" data-difficulty="easy">KOLAY</button>
<button class="difficulty-btn medium" data-difficulty="medium">ORTA</button>
<button class="difficulty-btn hard" data-difficulty="hard">ZOR</button>
<button class="difficulty-btn extreme" data-difficulty="extreme">ÇOK ZOR</button>
</div>
<input type="text" id="sentenceInput" class="input-text" placeholder="Bir cümle yazın (örnek: KEDİFARE)" maxlength="15">
<button id="startBtn" class="btn pulse">OYUNA BAŞLA</button>
</div>
<div id="gameOverScreen" style="display: none;">
<h1 class="title">Oyun Bitti!</h1>
<p class="subtitle" id="resultMessage">Fareyi yakaladın!<br>Geçen Süre: <span id="finalTime">0</span>s</p>
<button id="restartBtn" class="btn">TEKRAR OYNA</button>
</div>
</div>
<script>
// Game variables
let gameActive = false;
let letters = [];
let joystick1Active = false;
let joystick2Active = false;
let joystick1Angle = 0;
let joystick2Angle = 0;
let joystick1Distance = 0;
let joystick2Distance = 0;
let catSpeed = 15;
let mouseSpeed = 30; // Reduced mouse speed
let catPosition = { x: 0, y: 0 };
let mousePosition = { x: 0, y: 0 };
let joystick1Position = { x: 0, y: 0 };
let joystick2Position = { x: 0, y: 0 };
let joystick1KnobPosition = { x: 0, y: 0 };
let joystick2KnobPosition = { x: 0, y: 0 };
let joystickRadius = 40;
let gameWidth = window.innerWidth;
let gameHeight = window.innerHeight;
let gameTime = 30; // Increased to 30 seconds
let timerInterval;
let countdownInterval;
let mouseCaught = false;
let sentence = "";
let lastFrameTime = 0;
let deltaTime = 0;
let currentDifficulty = "easy";
let gameMode = "single";
let playerRole = "cat";
let multiplayer = false;
let player1ControlsCat = true;
// Enhanced difficulty settings
const difficultySettings = {
easy: {
catSpeed: 12,
mouseSpeed: 30, // Reduced mouse speed
mouseIntelligence: 0.3,
gameTime: 30, // Increased to 30 seconds
letterSpeed: 2,
letterCount: 5
},
medium: {
catSpeed: 18,
mouseSpeed: 45, // Reduced mouse speed
mouseIntelligence: 0.5,
gameTime: 30, // Increased to 30 seconds
letterSpeed: 3,
letterCount: 7
},
hard: {
catSpeed: 24,
mouseSpeed: 60, // Reduced mouse speed
mouseIntelligence: 0.7,
gameTime: 30, // Increased to 30 seconds
letterSpeed: 4,
letterCount: 10
},
extreme: {
catSpeed: 30,
mouseSpeed: 75, // Reduced mouse speed
mouseIntelligence: 0.9,
gameTime: 30, // Increased to 30 seconds
letterSpeed: 5,
letterCount: 12
}
};
// DOM elements cache
const gameContainer = document.getElementById('gameContainer');
const cat = document.getElementById('cat');
const mouse = document.getElementById('mouse');
const joystick1 = document.getElementById('joystick1');
const joystick2 = document.getElementById('joystick2');
const joystickKnob1 = document.getElementById('joystickKnob1');
const joystickKnob2 = document.getElementById('joystickKnob2');
const startScreen = document.getElementById('startScreen');
const gameOverScreen = document.getElementById('gameOverScreen');
const startBtn = document.getElementById('startBtn');
const restartBtn = document.getElementById('restartBtn');
const sentenceInput = document.getElementById('sentenceInput');
const timeDisplay = document.getElementById('time');
const finalTimeDisplay = document.getElementById('finalTime');
const resultMessage = document.getElementById('resultMessage');
const fullscreenBtn = document.getElementById('fullscreenBtn');
const difficultyBtns = document.querySelectorAll('.difficulty-btn');
const gameModeBtns = document.querySelectorAll('.game-mode-btn');
const roleBtns = document.querySelectorAll('.role-btn');
const roleSelection = document.getElementById('roleSelection');
const mouseTail = document.querySelector('.mouse-tail');
// Initialize game
function initGame() {
// Reset game state
mouseCaught = false;
gameTime = difficultySettings[currentDifficulty].gameTime;
timeDisplay.textContent = gameTime;
// Set speeds based on difficulty
catSpeed = difficultySettings[currentDifficulty].catSpeed;
mouseSpeed = difficultySettings[currentDifficulty].mouseSpeed;
// Set initial positions
catPosition = {
x: gameWidth / 2 - 30,
y: gameHeight / 2 - 30
};
mousePosition = {
x: Math.random() * (gameWidth - 40),
y: Math.random() * (gameHeight - 40)
};
// Joystick positions (one at bottom, one at top)
joystick1Position = {
x: gameWidth / 2,
y: gameHeight - 60 - 40
};
joystick2Position = {
x: gameWidth / 2,
y: 60 + 40
};
joystick1KnobPosition = {
x: joystick1Position.x,
y: joystick1Position.y
};
joystick2KnobPosition = {
x: joystick2Position.x,
y: joystick2Position.y
};
// Update DOM elements
updateCatPosition();
updateMousePosition();
updateJoystickPositions();
// Create letters from sentence
createLetters();
// Start countdown
startCountdown();
}
// Start countdown before game begins
function startCountdown() {
let count = 3;
const countdownElement = document.createElement('div');
countdownElement.className = 'countdown';
countdownElement.textContent = count;
gameContainer.appendChild(countdownElement);
countdownInterval = setInterval(() => {
count--;
if (count > 0) {
countdownElement.textContent = count;
} else {
clearInterval(countdownInterval);
countdownElement.textContent = 'BAŞLA!';
setTimeout(() => {
gameContainer.removeChild(countdownElement);
startGame();
}, 500);
}
}, 1000);
}
// Start the actual game
function startGame() {
// Start timer
timerInterval = setInterval(updateTimer, 1000);
// Start game loop with timestamp
gameActive = true;
lastFrameTime = performance.now();
requestAnimationFrame(gameLoop);
}
// Update timer
function updateTimer() {
if (gameActive) {
gameTime--;
timeDisplay.textContent = gameTime;
if (gameTime <= 0) {
// Time's up - mouse wins
gameOver(false);
}
}
}
// Create letters from the input sentence
function createLetters() {
// Clear existing letters
letters.forEach(letter => {
if (letter.element && letter.element.parentNode) {
gameContainer.removeChild(letter.element);
}
});
letters = [];
// Create new letters
const chars = sentence.split('');
const maxLetters = Math.min(chars.length, difficultySettings[currentDifficulty].letterCount);
for (let i = 0; i < maxLetters; i++) {
const char = chars[i % chars.length];
if (char.trim() === '') continue;
const letter = {
char: char,
element: document.createElement('div'),
x: Math.random() * (gameWidth - 40),
y: Math.random() * (gameHeight - 40),
size: 40,
speedX: (Math.random() - 0.5) * difficultySettings[currentDifficulty].letterSpeed * 2,
speedY: (Math.random() - 0.5) * difficultySettings[currentDifficulty].letterSpeed * 2,
rotation: Math.random() * 360,
rotationSpeed: (Math.random() - 0.5) * 4
};
letter.element.className = 'letter';
letter.element.textContent = char;
letter.element.style.fontSize = `40px`;
letter.element.style.left = `${letter.x}px`;
letter.element.style.top = `${letter.y}px`;
letter.element.style.transform = `rotate(${letter.rotation}deg)`;
letter.element.style.zIndex = '5';
gameContainer.appendChild(letter.element);
letters.push(letter);
}
}
// Optimized game loop with delta time
function gameLoop(timestamp) {
if (!gameActive) return;
// Calculate delta time for smooth movement
deltaTime = (timestamp - lastFrameTime) / 16.67; // Normalize to ~60fps
lastFrameTime = timestamp;
// Move cat based on joystick input
if (joystick1Active && (playerRole === "cat" || multiplayer)) {
const moveX = Math.cos(joystick1Angle) * catSpeed * (joystick1Distance / joystickRadius) * deltaTime;
const moveY = Math.sin(joystick1Angle) * catSpeed * (joystick1Distance / joystickRadius) * deltaTime;
// Check if cat can move to new position (avoid letters)
const newCatX = catPosition.x + moveX;
const newCatY = catPosition.y + moveY;
let canMove = true;
// Optimized collision check with letters
for (let i = 0; i < letters.length; i++) {
const letter = letters[i];
if (checkCollisionWithObject(newCatX, newCatY, 60, 60, letter.x, letter.y, letter.size, letter.size)) {
canMove = false;
break;
}
}
if (canMove) {
catPosition.x = newCatX;
catPosition.y = newCatY;
}
// Keep cat within bounds
catPosition.x = Math.max(0, Math.min(gameWidth - 60, catPosition.x));
catPosition.y = Math.max(0, Math.min(gameHeight - 60, catPosition.y));
}
// Move mouse based on joystick input (in multiplayer)
if (multiplayer && joystick2Active) {
const moveX = Math.cos(joystick2Angle) * mouseSpeed * (joystick2Distance / joystickRadius) * deltaTime;
const moveY = Math.sin(joystick2Angle) * mouseSpeed * (joystick2Distance / joystickRadius) * deltaTime;
// Check if mouse can move to new position (avoid letters)
const newMouseX = mousePosition.x + moveX;
const newMouseY = mousePosition.y + moveY;
let canMove = true;
for (let i = 0; i < letters.length; i++) {
const letter = letters[i];
if (checkCollisionWithObject(newMouseX, newMouseY, 40, 40, letter.x, letter.y, letter.size, letter.size)) {
canMove = false;
break;
}
}
if (canMove) {
mousePosition.x += moveX;
mousePosition.y += moveY;
}
// Keep mouse within bounds
mousePosition.x = Math.max(0, Math.min(gameWidth - 40, mousePosition.x));
mousePosition.y = Math.max(0, Math.min(gameHeight - 40, mousePosition.y));
} else if (!multiplayer && playerRole === "mouse") {
// Player controls mouse when in single player mouse mode
if (joystick1Active) {
const moveX = Math.cos(joystick1Angle) * mouseSpeed * (joystick1Distance / joystickRadius) * deltaTime;
const moveY = Math.sin(joystick1Angle) * mouseSpeed * (joystick1Distance / joystickRadius) * deltaTime;
// Check if mouse can move to new position (avoid letters)
const newMouseX = mousePosition.x + moveX;
const newMouseY = mousePosition.y + moveY;
let canMove = true;
for (let i = 0; i < letters.length; i++) {
const letter = letters[i];
if (checkCollisionWithObject(newMouseX, newMouseY, 40, 40, letter.x, letter.y, letter.size, letter.size)) {
canMove = false;
break;
}
}
if (canMove) {
mousePosition.x += moveX;
mousePosition.y += moveY;
}
// Keep mouse within bounds
mousePosition.x = Math.max(0, Math.min(gameWidth - 40, mousePosition.x));
mousePosition.y = Math.max(0, Math.min(gameHeight - 40, mousePosition.y));
}
// AI cat movement when player is mouse
moveCatAI(deltaTime);
} else if (!multiplayer) {
// AI mouse movement when player is cat
moveMouseAI(deltaTime);
}
// Move letters
moveLetters(deltaTime);
// Check cat-mouse collision
checkCollision();
// Update DOM
updateCatPosition();
updateMousePosition();
updateLettersPosition();
updateJoystickPositions();
// Continue loop
requestAnimationFrame(gameLoop);
}
// AI movement for cat when player is mouse
function moveCatAI(deltaTime) {
const dx = catPosition.x - mousePosition.x;
const dy = catPosition.y - mousePosition.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
const moveX = (dx / distance) * catSpeed * deltaTime;
const moveY = (dy / distance) * catSpeed * deltaTime;
// Check collisions with letters before moving
const newCatX = catPosition.x - moveX;
const newCatY = catPosition.y - moveY;
let canMove = true;
for (let i = 0; i < letters.length; i++) {
const letter = letters[i];
if (checkCollisionWithObject(newCatX, newCatY, 60, 60, letter.x, letter.y, letter.size, letter.size)) {
canMove = false;
break;
}
}
if (canMove) {
catPosition.x = newCatX;
catPosition.y = newCatY;
}
// Keep cat within bounds
catPosition.x = Math.max(0, Math.min(gameWidth - 60, catPosition.x));
catPosition.y = Math.max(0, Math.min(gameHeight - 60, catPosition.y));
}
}
// Check collision between two objects
function checkCollisionWithObject(x1, y1, w1, h1, x2, y2, w2, h2) {
return x1 < x2 + w2 &&
x1 + w1 > x2 &&
y1 < y2 + h2 &&
y1 + h1 > y2;
}
// Enhanced intelligent mouse movement with delta time
function moveMouseAI(deltaTime) {
const difficulty = difficultySettings[currentDifficulty];
const intelligence = difficulty.mouseIntelligence;
// Calculate distance to cat
const dx = mousePosition.x - catPosition.x;
const dy = mousePosition.y - catPosition.y;
const distance = Math.sqrt(dx * dx + dy * dy);
// If cat is close, run away
if (distance < 300) {
// Run in opposite direction with speed based on difficulty
const runX = (dx / distance) * mouseSpeed * (1 + intelligence) * deltaTime;
const runY = (dy / distance) * mouseSpeed * (1 + intelligence) * deltaTime;
// Check collisions with letters before moving
const newMouseX = mousePosition.x + runX;
const newMouseY = mousePosition.y + runY;
let canMove = true;
// Optimized letter collision check
for (let i = 0; i < letters.length; i++) {
const letter = letters[i];
if (checkCollisionWithObject(newMouseX, newMouseY, 40, 40, letter.x, letter.y, letter.size, letter.size)) {
canMove = false;
break;
}
}
if (canMove) {
mousePosition.x += runX;
mousePosition.y += runY;
} else {
// If blocked by letter, try to move perpendicular
const perpendicularX = -dy / distance * mouseSpeed * deltaTime;
const perpendicularY = dx / distance * mouseSpeed * deltaTime;
const altMouseX = mousePosition.x + perpendicularX;
const altMouseY = mousePosition.y + perpendicularY;
let altCanMove = true;
for (let i = 0; i < letters.length; i++) {
const letter = letters[i];
if (checkCollisionWithObject(altMouseX, altMouseY, 40, 40, letter.x, letter.y, letter.size, letter.size)) {
altCanMove = false;
break;
}
}
if (altCanMove) {
mousePosition.x = altMouseX;
mousePosition.y = altMouseY;
}
}
// If running into wall, change direction
if (mousePosition.x < 0 || mousePosition.x > gameWidth - 40) {
mousePosition.x = Math.max(0, Math.min(gameWidth - 40, mousePosition.x));
mousePosition.y += (Math.random() - 0.5) * mouseSpeed * 2 * deltaTime;
}
if (mousePosition.y < 0 || mousePosition.y > gameHeight - 40) {
mousePosition.y = Math.max(0, Math.min(gameHeight - 40, mousePosition.y));
mousePosition.x += (Math.random() - 0.5) * mouseSpeed * 2 * deltaTime;
}
} else {
// Random movement with some intelligence
if (Math.random() < intelligence) {
// Occasionally change direction
mouseSpeed = difficulty.mouseSpeed * (0.8 + Math.random() * 0.4);
}
// Move towards empty space (avoid letters)
let bestDirection = { x: 0, y: 0 };
let bestScore = -Infinity;
// Check 8 possible directions
for (let angle = 0; angle < Math.PI * 2; angle += Math.PI / 4) {
const testX = mousePosition.x + Math.cos(angle) * 150;
const testY = mousePosition.y + Math.sin(angle) * 150;
// Stay within bounds
if (testX < 0 || testX > gameWidth - 40 || testY < 0 || testY > gameHeight - 40) {
continue;
}
// Calculate score for this direction (distance to letters)
let score = 0;
// Avoid letters
for (let i = 0; i < letters.length; i++) {
const letter = letters[i];
const ldx = testX - (letter.x + letter.size/2);
const ldy = testY - (letter.y + letter.size/2);
const ldistance = Math.sqrt(ldx * ldx + ldy * ldy);
score += Math.max(0, 200 - ldistance);
}
// Also consider distance to cat (avoid getting too close)
const cdx = testX - catPosition.x;
const cdy = testY - catPosition.y;
const cdistance = Math.sqrt(cdx * cdx + cdy * cdy);
score -= Math.max(0, 400 - cdistance);
if (score > bestScore) {
bestScore = score;
bestDirection = { x: Math.cos(angle), y: Math.sin(angle) };
}
}
// Check collisions with letters before moving
const newMouseX = mousePosition.x + bestDirection.x * mouseSpeed * deltaTime;
const newMouseY = mousePosition.y + bestDirection.y * mouseSpeed * deltaTime;
let canMove = true;
for (let i = 0; i < letters.length; i++) {
const letter = letters[i];
if (checkCollisionWithObject(newMouseX, newMouseY, 40, 40, letter.x, letter.y, letter.size, letter.size)) {
canMove = false;
break;
}
}
if (canMove) {
mousePosition.x += bestDirection.x * mouseSpeed * deltaTime;
mousePosition.y += bestDirection.y * mouseSpeed * deltaTime;
}
}
// Keep mouse within bounds
mousePosition.x = Math.max(0, Math.min(gameWidth - 40, mousePosition.x));
mousePosition.y = Math.max(0, Math.min(gameHeight - 40, mousePosition.y));
}
// Move letters around with delta time
function moveLetters(deltaTime) {
for (let i = 0; i < letters.length; i++) {
const letter = letters[i];
// Move letter
letter.x += letter.speedX * deltaTime;
letter.y += letter.speedY * deltaTime;
// Bounce off walls
if (letter.x < 0 || letter.x > gameWidth - letter.size) {
letter.speedX *= -1.1;
letter.x = Math.max(0, Math.min(gameWidth - letter.size, letter.x));
}
if (letter.y < 0 || letter.y > gameHeight - letter.size) {
letter.speedY *= -1.1;
letter.y = Math.max(0, Math.min(gameHeight - letter.size, letter.y));
}
// Rotate
letter.rotation += letter.rotationSpeed * deltaTime;
}
}
// Check for cat-mouse collision
function checkCollision() {
const dx = catPosition.x + 30 - (mousePosition.x + 20);
const dy = catPosition.y + 30 - (mousePosition.y + 20);
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 35) {
// Game over - mouse caught
mouseCaught = true;
gameOver(true);
}
}
// Update cat position in DOM
function updateCatPosition() {
cat.style.left = `${catPosition.x}px`;
cat.style.top = `${catPosition.y}px`;
// Rotate cat based on movement direction
if (joystick1Active && (playerRole === "cat" || multiplayer)) {
const rotation = joystick1Angle * (180 / Math.PI) + 90;
cat.style.transform = `rotate(${rotation}deg)`;
} else if (!multiplayer && playerRole === "mouse") {
// Rotate cat to face mouse when AI is controlling
const dx = catPosition.x - mousePosition.x;
const dy = catPosition.y - mousePosition.y;
const angle = Math.atan2(dy, dx) * (180 / Math.PI) + 180;
cat.style.transform = `rotate(${angle}deg)`;
}
}
// Update mouse position in DOM
function updateMousePosition() {
mouse.style.left = `${mousePosition.x}px`;
mouse.style.top = `${mousePosition.y}px`;
// Rotate mouse based on movement direction
if (multiplayer && joystick2Active) {
const rotation = joystick2Angle * (180 / Math.PI) + 180;
mouse.style.transform = `rotate(${rotation}deg)`;
} else if (!multiplayer && playerRole === "mouse") {
// Rotate mouse based on joystick when player is mouse
if (joystick1Active) {
const rotation = joystick1Angle * (180 / Math.PI) + 180;
mouse.style.transform = `rotate(${rotation}deg)`;
}
} else {
// Rotate mouse to face away from cat when running
const dx = mousePosition.x - catPosition.x;
const dy = mousePosition.y - catPosition.y;
const angle = Math.atan2(dy, dx) * (180 / Math.PI) + 180;
mouse.style.transform = `rotate(${angle}deg)`;
}
}
// Update letters position in DOM
function updateLettersPosition() {
for (let i = 0; i < letters.length; i++) {
const letter = letters[i];
letter.element.style.left = `${letter.x}px`;
letter.element.style.top = `${letter.y}px`;
letter.element.style.transform = `rotate(${letter.rotation}deg)`;
}
}
// Update joystick positions in DOM
function updateJoystickPositions() {
joystickKnob1.style.left = `${joystick1KnobPosition.x - joystick1Position.x + 40 - 15}px`;
joystickKnob1.style.top = `${joystick1KnobPosition.y - joystick1Position.y + 40 - 15}px`;
if (multiplayer) {
joystickKnob2.style.left = `${joystick2KnobPosition.x - joystick2Position.x + 40 - 15}px`;
joystickKnob2.style.top = `${joystick2KnobPosition.y - joystick2Position.y + 40 - 15}px`;
}
}
// Game over
function gameOver(caught) {
gameActive = false;
clearInterval(timerInterval);
finalTimeDisplay.textContent = (difficultySettings[currentDifficulty].gameTime - gameTime).toFixed(1);
// Show appropriate message
if (caught) {
if (playerRole === "cat" || multiplayer) {
resultMessage.innerHTML = "Fareyi yakaladın!<br>Geçen Süre: <span id='finalTime'>" + (difficultySettings[currentDifficulty].gameTime - gameTime).toFixed(1) + "</span>s";
} else {
resultMessage.innerHTML = "Kedi seni yakaladı!<br>Geçen Süre: <span id='finalTime'>" + (difficultySettings[currentDifficulty].gameTime - gameTime).toFixed(1) + "</span>s";
}
} else {
if (playerRole === "cat" || multiplayer) {
resultMessage.innerHTML = "Fare kaçtı!<br>Geçen Süre: <span id='finalTime'>" + difficultySettings[currentDifficulty].gameTime + "</span>s";
} else {
resultMessage.innerHTML = "Kaçmayı başardın!<br>Geçen Süre: <span id='finalTime'>" + difficultySettings[currentDifficulty].gameTime + "</span>s";
}
}
gameOverScreen.style.display = 'flex';
}
// Reset game
function resetGame() {
gameOverScreen.style.display = 'none';
initGame();
}
// Event listeners
startBtn.addEventListener('click', () => {
sentence = sentenceInput.value.trim().toUpperCase();
if (sentence === '') {
alert('Lütfen bir cümle girin!');
return;
}
startScreen.style.display = 'none';
// Set multiplayer mode
multiplayer = gameMode === "multi";
// Show/hide joysticks based on mode and role
if (multiplayer) {
joystick2.style.display = "flex";
} else {
joystick2.style.display = "none";
}
initGame();
});
restartBtn.addEventListener('click', resetGame);
fullscreenBtn.addEventListener('click', () => {
if (!document.fullscreenElement) {
gameContainer.requestFullscreen().catch(err => {
console.error(`Fullscreen error: ${err.message}`);
});
} else {
document.exitFullscreen();
}
});
// Difficulty selection
difficultyBtns.forEach(btn => {
btn.addEventListener('click', () => {
difficultyBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentDifficulty = btn.dataset.difficulty;
});
});
// Game mode selection
gameModeBtns.forEach(btn => {
btn.addEventListener('click', () => {
gameModeBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
gameMode = btn.dataset.mode;
// Show/hide role selection based on game mode
if (gameMode === "single") {
roleSelection.style.display = "flex";
} else {
roleSelection.style.display = "none";
}
});
});
// Role selection
roleBtns.forEach(btn => {
btn.addEventListener('click', () => {
roleBtns.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
playerRole = btn.dataset.role;
});
});
// Handle joystick events for player 1
joystickKnob1.addEventListener('touchstart', (e) => handleJoystickStart(e, 1));
joystickKnob1.addEventListener('mousedown', (e) => handleJoystickStart(e, 1));
// Handle joystick events for player 2
joystickKnob2.addEventListener('touchstart', (e) => handleJoystickStart(e, 2));
joystickKnob2.addEventListener('mousedown', (e) => handleJoystickStart(e, 2));
document.addEventListener('touchmove', (e) => handleJoystickMove(e));
document.addEventListener('mousemove', (e) => handleJoystickMove(e));
document.addEventListener('touchend', (e) => handleJoystickEnd(e));
document.addEventListener('mouseup', (e) => handleJoystickEnd(e));
function handleJoystickStart(e, playerNum) {
e.preventDefault();
if (playerNum === 1) {
joystick1Active = true;
// Get initial position
const rect = joystick1.getBoundingClientRect();
joystick1Position = {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2
};
// Set knob position
if (e.type === 'mousedown') {
joystick1KnobPosition = { x: e.clientX, y: e.clientY };
} else {
joystick1KnobPosition = { x: e.touches[0].clientX, y: e.touches[0].clientY };
}
} else if (playerNum === 2 && multiplayer) {
joystick2Active = true;
// Get initial position
const rect = joystick2.getBoundingClientRect();
joystick2Position = {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2
};
// Set knob position
if (e.type === 'mousedown') {
joystick2KnobPosition = { x: e.clientX, y: e.clientY };
} else {
joystick2KnobPosition = { x: e.touches[0].clientX, y: e.touches[0].clientY };
}
}
updateJoystickPositions();
}
function handleJoystickMove(e) {
if (!joystick1Active && !joystick2Active) return;
e.preventDefault();
// Get current position
let clientX, clientY;
if (e.type === 'mousemove') {
clientX = e.clientX;
clientY = e.clientY;
} else {
clientX = e.touches[0].clientX;
clientY = e.touches[0].clientY;
}
// Handle joystick 1
if (joystick1Active) {
// Calculate angle and distance
const dx = clientX - joystick1Position.x;
const dy = clientY - joystick1Position.y;
joystick1Angle = Math.atan2(dy, dx);
joystick1Distance = Math.min(joystickRadius, Math.sqrt(dx * dx + dy * dy));
// Calculate knob position
joystick1KnobPosition = {
x: joystick1Position.x + Math.cos(joystick1Angle) * joystick1Distance,
y: joystick1Position.y + Math.sin(joystick1Angle) * joystick1Distance
};
}
// Handle joystick 2
if (joystick2Active && multiplayer) {
// Calculate angle and distance
const dx = clientX - joystick2Position.x;
const dy = clientY - joystick2Position.y;
joystick2Angle = Math.atan2(dy, dx);
joystick2Distance = Math.min(joystickRadius, Math.sqrt(dx * dx + dy * dy));
// Calculate knob position
joystick2KnobPosition = {
x: joystick2Position.x + Math.cos(joystick2Angle) * joystick2Distance,
y: joystick2Position.y + Math.sin(joystick2Angle) * joystick2Distance
};
}
updateJoystickPositions();
}
function handleJoystickEnd(e) {
if (!joystick1Active && !joystick2Active) return;
e.preventDefault();
if (joystick1Active) {
joystick1Active = false;
joystick1KnobPosition = { x: joystick1Position.x, y: joystick1Position.y };
}
if (joystick2Active) {
joystick2Active = false;
joystick2KnobPosition = { x: joystick2Position.x, y: joystick2Position.y };
}
updateJoystickPositions();
}
// Handle window resize
window.addEventListener('resize', () => {
gameWidth = window.innerWidth;
gameHeight = window.innerHeight;
if (gameActive) {
// Adjust positions
catPosition.x = Math.min(catPosition.x, gameWidth - 60);
catPosition.y = Math.min(catPosition.y, gameHeight - 60);
mousePosition.x = Math.min(mousePosition.x, gameWidth - 40);
mousePosition.y = Math.min(mousePosition.y, gameHeight - 40);
// Update joystick positions
joystick1Position = {
x: gameWidth / 2,
y: gameHeight - 60 - 40
};
joystick2Position = {
x: gameWidth / 2,
y: 60 + 40
};
if (!joystick1Active) {
joystick1KnobPosition = {
x: joystick1Position.x,
y: joystick1Position.y
};
}
if (!joystick2Active) {
joystick2KnobPosition = {
x: joystick2Position.x,
y: joystick2Position.y
};
}
updateCatPosition();
updateMousePosition();
updateJoystickPositions();
}
});
// Initial setup
catPosition = {
x: gameWidth / 2 - 30,
y: gameHeight / 2 - 30
};
mousePosition = {
x: Math.random() * (gameWidth - 40),
y: Math.random() * (gameHeight - 40)
};
updateCatPosition();
updateMousePosition();
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=0c0ps2619/catmause" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>