first commit
This commit is contained in:
commit
792fbfa5bb
5 changed files with 329 additions and 0 deletions
1
CNAME
Normal file
1
CNAME
Normal file
|
@ -0,0 +1 @@
|
|||
catchthedot.ronniie.dev
|
25
README.md
Normal file
25
README.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Catch the Dot
|
||||
|
||||
A fun web-based game where you try to catch elusive dots that multiply and move around the screen. The dots are designed to be challenging to catch, with smooth movement patterns and smart mouse avoidance.
|
||||
|
||||
## Features
|
||||
|
||||
- Smooth dot movement with physics-based motion
|
||||
- Dots multiply over time
|
||||
- Smart mouse avoidance behavior
|
||||
- Modern UI with glass-morphism effects
|
||||
- Fullscreen gameplay
|
||||
- Pacman-style screen wrapping
|
||||
|
||||
## How to Play
|
||||
|
||||
1. Open `index.html` in a web browser
|
||||
2. Move your mouse to interact with the dots
|
||||
3. Watch as the dots multiply and try to catch them
|
||||
4. The counter shows how many dots are currently on screen
|
||||
|
||||
## Technologies Used
|
||||
|
||||
- HTML5
|
||||
- CSS3
|
||||
- JavaScript (Vanilla)
|
24
index.html
Normal file
24
index.html
Normal file
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Catch the Dot</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="game-area">
|
||||
<div class="game-header">
|
||||
<h1>Catch the Dot</h1>
|
||||
<div class="score-container">
|
||||
<span>Dots: </span>
|
||||
<span id="dotCount">1</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="game-footer">
|
||||
<p class="message">Watch them multiply!</p>
|
||||
</div>
|
||||
</div>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
157
script.js
Normal file
157
script.js
Normal file
|
@ -0,0 +1,157 @@
|
|||
const gameArea = document.querySelector('.game-area');
|
||||
const dotCountDisplay = document.getElementById('dotCount');
|
||||
const message = document.querySelector('.message');
|
||||
|
||||
let dots = [];
|
||||
let lastMouseX = 0;
|
||||
let lastMouseY = 0;
|
||||
let lastMouseTime = 0;
|
||||
let mouseVelocityX = 0;
|
||||
let mouseVelocityY = 0;
|
||||
|
||||
class Dot {
|
||||
constructor(x, y) {
|
||||
this.element = document.createElement('div');
|
||||
this.element.className = 'dot';
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.velocityX = (Math.random() - 0.5) * 200;
|
||||
this.velocityY = (Math.random() - 0.5) * 200;
|
||||
this.lastDuplication = Date.now();
|
||||
this.acceleration = 0;
|
||||
gameArea.appendChild(this.element);
|
||||
this.updatePosition();
|
||||
}
|
||||
|
||||
updatePosition() {
|
||||
this.element.style.left = `${this.x}px`;
|
||||
this.element.style.top = `${this.y}px`;
|
||||
}
|
||||
|
||||
move() {
|
||||
this.velocityX += (Math.random() - 0.5) * 20;
|
||||
this.velocityY += (Math.random() - 0.5) * 20;
|
||||
|
||||
this.x += this.velocityX * 0.016;
|
||||
this.y += this.velocityY * 0.016;
|
||||
|
||||
if (this.x < 0) {
|
||||
this.x = window.innerWidth;
|
||||
} else if (this.x > window.innerWidth) {
|
||||
this.x = 0;
|
||||
}
|
||||
|
||||
if (this.y < 0) {
|
||||
this.y = window.innerHeight;
|
||||
} else if (this.y > window.innerHeight) {
|
||||
this.y = 0;
|
||||
}
|
||||
|
||||
this.velocityX *= 0.98;
|
||||
this.velocityY *= 0.98;
|
||||
|
||||
const currentSpeed = Math.sqrt(this.velocityX * this.velocityX + this.velocityY * this.velocityY);
|
||||
if (currentSpeed < 100) {
|
||||
const angle = Math.atan2(this.velocityY, this.velocityX);
|
||||
this.velocityX = Math.cos(angle) * 100;
|
||||
this.velocityY = Math.sin(angle) * 100;
|
||||
}
|
||||
|
||||
if (currentSpeed > 400) {
|
||||
const angle = Math.atan2(this.velocityY, this.velocityX);
|
||||
this.velocityX = Math.cos(angle) * 400;
|
||||
this.velocityY = Math.sin(angle) * 400;
|
||||
}
|
||||
|
||||
this.updatePosition();
|
||||
|
||||
const now = Date.now();
|
||||
if (now - this.lastDuplication > 3000 && Math.random() < 0.002) {
|
||||
this.duplicate();
|
||||
this.lastDuplication = now;
|
||||
}
|
||||
}
|
||||
|
||||
duplicate() {
|
||||
if (dots.length < 8) {
|
||||
const newDot = new Dot(this.x, this.y);
|
||||
newDot.velocityX = this.velocityX * 1.2;
|
||||
newDot.velocityY = this.velocityY * 1.2;
|
||||
dots.push(newDot);
|
||||
updateDotCount();
|
||||
}
|
||||
}
|
||||
|
||||
avoidMouse(mouseX, mouseY, mouseVelX, mouseVelY) {
|
||||
const dx = this.x - mouseX;
|
||||
const dy = this.y - mouseY;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance < 300) {
|
||||
const speed = 300;
|
||||
const mouseSpeed = Math.sqrt(mouseVelX * mouseVelX + mouseVelY * mouseVelY);
|
||||
|
||||
const dotToMouseAngle = Math.atan2(dy, dx);
|
||||
const mouseMovementAngle = Math.atan2(mouseVelY, mouseVelX);
|
||||
const angleDiff = Math.abs(dotToMouseAngle - mouseMovementAngle);
|
||||
|
||||
const distanceFactor = Math.min(1, (300 - distance) / 300);
|
||||
|
||||
if (angleDiff < Math.PI / 2) {
|
||||
const targetSpeed = speed + mouseSpeed * 800 * distanceFactor;
|
||||
const currentSpeed = Math.sqrt(this.velocityX * this.velocityX + this.velocityY * this.velocityY);
|
||||
const acceleration = Math.min(0.2, (targetSpeed - currentSpeed) / 1000);
|
||||
|
||||
this.velocityX = this.velocityX * (1 - acceleration) + Math.cos(dotToMouseAngle) * targetSpeed * acceleration;
|
||||
this.velocityY = this.velocityY * (1 - acceleration) + Math.sin(dotToMouseAngle) * targetSpeed * acceleration;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateDotCount() {
|
||||
dotCountDisplay.textContent = dots.length;
|
||||
}
|
||||
|
||||
function initializeGame() {
|
||||
const firstDot = new Dot(
|
||||
Math.random() * window.innerWidth,
|
||||
Math.random() * window.innerHeight
|
||||
);
|
||||
dots.push(firstDot);
|
||||
updateDotCount();
|
||||
}
|
||||
|
||||
function moveDot(event) {
|
||||
const currentTime = Date.now();
|
||||
const timeDiff = currentTime - lastMouseTime;
|
||||
|
||||
if (lastMouseTime !== 0) {
|
||||
mouseVelocityX = (event.clientX - lastMouseX) / timeDiff;
|
||||
mouseVelocityY = (event.clientY - lastMouseY) / timeDiff;
|
||||
}
|
||||
|
||||
lastMouseX = event.clientX;
|
||||
lastMouseY = event.clientY;
|
||||
lastMouseTime = currentTime;
|
||||
|
||||
dots.forEach(dot => dot.avoidMouse(event.clientX, event.clientY, mouseVelocityX, mouseVelocityY));
|
||||
}
|
||||
|
||||
function updateDots() {
|
||||
dots.forEach(dot => dot.move());
|
||||
requestAnimationFrame(updateDots);
|
||||
}
|
||||
|
||||
gameArea.addEventListener('mousemove', moveDot);
|
||||
|
||||
initializeGame();
|
||||
updateDots();
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
dots.forEach(dot => {
|
||||
dot.x = Math.min(dot.x, window.innerWidth);
|
||||
dot.y = Math.min(dot.y, window.innerHeight);
|
||||
dot.updatePosition();
|
||||
});
|
||||
});
|
122
styles.css
Normal file
122
styles.css
Normal file
|
@ -0,0 +1,122 @@
|
|||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: #0f0f0f;
|
||||
min-height: 100vh;
|
||||
overflow: hidden;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.game-container {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
width: 90%;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.game-header {
|
||||
position: fixed;
|
||||
top: 2rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
z-index: 100;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
padding: 1.5rem 3rem;
|
||||
border-radius: 20px;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
font-weight: 800;
|
||||
margin-bottom: 0.5rem;
|
||||
background: linear-gradient(45deg, #ff3366, #ff6b6b);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
.score-container {
|
||||
font-size: 1.4rem;
|
||||
color: #ff3366;
|
||||
font-weight: 600;
|
||||
text-shadow: 0 0 20px rgba(255, 51, 102, 0.3);
|
||||
}
|
||||
|
||||
.game-area {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: radial-gradient(circle at center, #1a1a1a 0%, #0f0f0f 100%);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dot {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: #ff3366;
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transition: transform 0.1s ease-out;
|
||||
box-shadow: 0 0 30px rgba(255, 51, 102, 0.5);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.dot::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(255, 51, 102, 0.3);
|
||||
border-radius: 50%;
|
||||
animation: ripple 2s ease-out infinite;
|
||||
}
|
||||
|
||||
.game-footer {
|
||||
position: fixed;
|
||||
bottom: 2rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
color: #ffffff;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
padding: 1rem 2rem;
|
||||
border-radius: 15px;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.message {
|
||||
font-weight: 500;
|
||||
color: #ff3366;
|
||||
text-shadow: 0 0 20px rgba(255, 51, 102, 0.3);
|
||||
}
|
||||
|
||||
@keyframes ripple {
|
||||
0% { transform: translate(-50%, -50%) scale(1); opacity: 0.5; }
|
||||
100% { transform: translate(-50%, -50%) scale(2); opacity: 0; }
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateX(-50%) translateY(0); }
|
||||
50% { transform: translateX(-50%) translateY(-10px); }
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue