Ensure js are always loaded with fresh versions
This commit is contained in:
parent
e6f6732eaa
commit
67991b8a3e
10
.htaccess
10
.htaccess
@ -16,3 +16,13 @@ RewriteRule ^(.+?)/?$ $1.php [L]
|
|||||||
# 2) Optional: strip trailing slash for non-directories (keeps .php links working)
|
# 2) Optional: strip trailing slash for non-directories (keeps .php links working)
|
||||||
RewriteCond %{REQUEST_FILENAME} !-d
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
RewriteRule ^(.+)/$ $1 [R=301,L]
|
RewriteRule ^(.+)/$ $1 [R=301,L]
|
||||||
|
|
||||||
|
<FilesMatch "\.(js)$">
|
||||||
|
FileETag None
|
||||||
|
<IfModule mod_headers.c>
|
||||||
|
Header unset ETag
|
||||||
|
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
|
||||||
|
Header set Pragma "no-cache"
|
||||||
|
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
|
||||||
|
</IfModule>
|
||||||
|
</FilesMatch>
|
||||||
@ -62,4 +62,48 @@
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background-color: #4CAF50;
|
background-color: #4CAF50;
|
||||||
color: white;
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tutorial-modal {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: white;
|
||||||
|
font-family: sans-serif;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
text-align: center;
|
||||||
|
background-color: #333;
|
||||||
|
padding: 40px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content h2 {
|
||||||
|
font-size: 50px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content p {
|
||||||
|
font-size: 20px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#start-game-btn {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 15px 30px;
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
@ -44,8 +44,7 @@ export class Ball {
|
|||||||
const fieldLength = 100;
|
const fieldLength = 100;
|
||||||
const ballRadius = 0.8;
|
const ballRadius = 0.8;
|
||||||
|
|
||||||
this.mesh.position.x = Math.max(-fieldWidth / 2 + ballRadius, Math.min(fieldWidth / 2 - ballRadius, this.mesh.position.x));
|
|
||||||
this.mesh.position.z = Math.max(-fieldLength / 2 + ballRadius, Math.min(fieldLength / 2 - ballRadius, this.mesh.position.z));
|
|
||||||
|
|
||||||
|
|
||||||
// --- Force 2D movement on the XZ plane ---
|
// --- Force 2D movement on the XZ plane ---
|
||||||
|
|||||||
@ -2,19 +2,23 @@
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
|
|
||||||
export class Player {
|
export class Player {
|
||||||
constructor(scene, color, position, team) {
|
constructor(scene, color, position, type, team) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.position = position;
|
this.velocity = new THREE.Vector3(0, 0, 0);
|
||||||
|
this.type = type;
|
||||||
this.team = team;
|
this.team = team;
|
||||||
this.createPlayer();
|
this.radius = 1.5;
|
||||||
|
this.hasBall = false;
|
||||||
|
this.createPlayer(new THREE.Vector3(position.x, position.y, position.z));
|
||||||
}
|
}
|
||||||
|
|
||||||
createPlayer() {
|
createPlayer(initialPosition) {
|
||||||
const playerGeometry = new THREE.CapsuleGeometry(1, 2, 4, 8);
|
const playerGeometry = new THREE.CapsuleGeometry(1, 2, 4, 8);
|
||||||
const playerMaterial = new THREE.MeshStandardMaterial({ color: this.color });
|
const playerMaterial = new THREE.MeshStandardMaterial({ color: this.color });
|
||||||
this.mesh = new THREE.Mesh(playerGeometry, playerMaterial);
|
this.mesh = new THREE.Mesh(playerGeometry, playerMaterial);
|
||||||
this.mesh.position.set(this.position.x, this.position.y, this.position.z);
|
this.mesh.position.copy(initialPosition);
|
||||||
|
this.mesh.initialPosition = initialPosition.clone();
|
||||||
this.mesh.castShadow = true;
|
this.mesh.castShadow = true;
|
||||||
this.mesh.lastVelocity = new THREE.Vector3();
|
this.mesh.lastVelocity = new THREE.Vector3();
|
||||||
this.mesh.team = this.team;
|
this.mesh.team = this.team;
|
||||||
|
|||||||
@ -14,18 +14,16 @@ export class Team {
|
|||||||
createTeam() {
|
createTeam() {
|
||||||
for (let i = 0; i < this.numberOfPlayers; i++) {
|
for (let i = 0; i < this.numberOfPlayers; i++) {
|
||||||
const position = this.generatePosition(i);
|
const position = this.generatePosition(i);
|
||||||
const player = new Player(this.scene, this.color, position, this.isPlayerTeam ? 'player' : 'bot');
|
const player = new Player(this.scene, this.color, position, this.isPlayerTeam ? 'player' : 'bot', this);
|
||||||
this.players.push(player);
|
this.players.push(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resetPositions() {
|
resetPositions() {
|
||||||
for (let i = 0; i < this.players.length; i++) {
|
this.players.forEach(player => {
|
||||||
const player = this.players[i];
|
player.mesh.position.copy(player.mesh.initialPosition);
|
||||||
const position = this.generatePosition(i);
|
player.velocity.set(0, 0, 0);
|
||||||
player.mesh.position.set(position.x, position.y, position.z);
|
});
|
||||||
player.mesh.velocity.set(0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
generatePosition(i) {
|
generatePosition(i) {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
import { Field } from './Field.js';
|
import { Field } from 'app/field';
|
||||||
import { Ball } from './Ball.js';
|
import { Ball } from 'app/ball';
|
||||||
import { Team } from './Team.js';
|
import { Team } from 'app/team';
|
||||||
|
|
||||||
class Game {
|
class Game {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -10,8 +10,6 @@ class Game {
|
|||||||
this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||||
this.renderer = new THREE.WebGLRenderer({ antialias: true });
|
this.renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||||
this.keyboardState = {};
|
this.keyboardState = {};
|
||||||
|
|
||||||
this.init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
@ -403,4 +401,14 @@ class Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new Game();
|
const game = new Game();
|
||||||
|
|
||||||
|
const startGameBtn = document.getElementById('start-game-btn');
|
||||||
|
const tutorialModal = document.getElementById('tutorial-modal');
|
||||||
|
|
||||||
|
function startGame() {
|
||||||
|
tutorialModal.style.display = 'none';
|
||||||
|
game.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
startGameBtn.addEventListener('click', startGame);
|
||||||
|
|||||||
36
game.php
36
game.php
@ -1,36 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Pocket 5 Soccer</title>
|
|
||||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
|
||||||
<style>
|
|
||||||
body { margin: 0; overflow: hidden; }
|
|
||||||
canvas { display: block; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="scoreboard">
|
|
||||||
<span id="red-score">0</span> - <span id="blue-score">0</span>
|
|
||||||
</div>
|
|
||||||
<div id="timer">30</div>
|
|
||||||
<div id="game-over-modal" style="display: none;">
|
|
||||||
<div id="game-over-content">
|
|
||||||
<h2>Game Over</h2>
|
|
||||||
<p id="final-score"></p>
|
|
||||||
<p id="winner"></p>
|
|
||||||
<button id="restart-button">Restart Game</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script type="importmap">
|
|
||||||
{
|
|
||||||
"imports": {
|
|
||||||
"three": "https://unpkg.com/three@0.163.0/build/three.module.js",
|
|
||||||
"three/addons/": "https://unpkg.com/three@0.163.0/examples/jsm/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script type="module" src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
175
index.php
175
index.php
@ -3,151 +3,44 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Pocket 5 Soccer - Fast-Paced 5v5 Action</title>
|
<title>Pocket 5 Soccer</title>
|
||||||
<meta name="description" content="Experience Pocket 5 Soccer, a real-time multiplayer 5v5 soccer game designed for quick, engaging matches on mobile and desktop.">
|
|
||||||
|
|
||||||
<!-- Bootstrap 5 CDN -->
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
|
|
||||||
<!-- Google Fonts -->
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@700&family=Roboto:wght@400;500&display=swap" rel="stylesheet">
|
|
||||||
|
|
||||||
<!-- Custom CSS -->
|
|
||||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||||
|
<style>
|
||||||
<!-- Open Graph Meta Tags -->
|
body { margin: 0; overflow: hidden; }
|
||||||
<meta property="og:title" content="Pocket 5 Soccer - Fast-Paced 5v5 Action">
|
canvas { display: block; }
|
||||||
<meta property="og:description" content="Real-time 5v5 multiplayer soccer. Quick matches, smart AI, and cross-platform controls.">
|
</style>
|
||||||
<meta property="og:image" content="https://picsum.photos/seed/soccermeta/1200/630">
|
|
||||||
<meta property="og:url" content="">
|
|
||||||
<meta property="og:type" content="website">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div id="tutorial-modal">
|
||||||
<!-- Navigation Bar -->
|
<div class="modal-content">
|
||||||
<nav class="navbar navbar-expand-lg navbar-light bg-white fixed-top shadow-sm">
|
<h2>Pocket 5 Soccer</h2>
|
||||||
<div class="container">
|
<p>Use Arrow Keys to move. Press S to pass, D to shoot.</p>
|
||||||
<a class="navbar-brand" href="#">Pocket 5 Soccer</a>
|
<button id="start-game-btn">Start Game</button>
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
|
||||||
<ul class="navbar-nav ms-auto">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#rules">Game Rules</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#controls">Controls</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item ms-lg-3">
|
|
||||||
<a class="btn btn-primary" href="game.php">Play Now</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</div>
|
||||||
|
<div id="scoreboard">
|
||||||
<!-- Hero Section -->
|
<span id="red-score">0</span> - <span id="blue-score">0</span>
|
||||||
<header class="hero">
|
</div>
|
||||||
<div class="container">
|
<div id="timer">30</div>
|
||||||
<h1 class="display-3">Fast-Paced 5v5 Action</h1>
|
<div id="game-over-modal" style="display: none;">
|
||||||
<p class="lead">Real-time multiplayer soccer designed for quick, intense matches.</p>
|
<div id="game-over-content">
|
||||||
<a href="game.php" class="btn btn-primary btn-lg">Play Now</a>
|
<h2>Game Over</h2>
|
||||||
<a href="#rules" class="btn btn-secondary btn-lg">Learn More</a>
|
<p id="final-score"></p>
|
||||||
|
<p id="winner"></p>
|
||||||
|
<button id="restart-button">Restart Game</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</div>
|
||||||
|
<script type="importmap">
|
||||||
<main>
|
{
|
||||||
<!-- Game Rules Section -->
|
"imports": {
|
||||||
<section id="rules">
|
"three": "https://unpkg.com/three@0.163.0/build/three.module.js",
|
||||||
<div class="container">
|
"three/addons/": "https://unpkg.com/three@0.163.0/examples/jsm/",
|
||||||
<h2 class="section-title">Game Rules & Play Style</h2>
|
"app/field": "./assets/js/Field.js?v=<?php echo time(); ?>",
|
||||||
<div class="row g-4 align-items-center">
|
"app/ball": "./assets/js/Ball.js?v=<?php echo time(); ?>",
|
||||||
<div class="col-lg-6">
|
"app/team": "./assets/js/Team.js?v=<?php echo time(); ?>"
|
||||||
<img src="https://picsum.photos/seed/soccerstrategy/800/600" class="img-fluid rounded shadow" alt="A top-down view of a soccer game strategy board.">
|
}
|
||||||
</div>
|
}
|
||||||
<div class="col-lg-6">
|
</script>
|
||||||
<div class="accordion" id="rulesAccordion">
|
<script type="module" src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="headingOne">
|
|
||||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
|
||||||
Core Gameplay
|
|
||||||
</button>
|
|
||||||
</h2>
|
|
||||||
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#rulesAccordion">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<ul class="list-group list-group-flush">
|
|
||||||
<li class="list-group-item"><strong>Match Specs:</strong> 5v5 teams, 2-minute match duration.</li>
|
|
||||||
<li class="list-group-item"><strong>Control Model:</strong> Each human controls one player.</li>
|
|
||||||
<li class="list-group-item"><strong>Orientation:</strong> Vertical screen for mobile.</li>
|
|
||||||
<li class="list-group-item"><strong>AI Players:</strong> AI fills all positions not controlled by humans.</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="headingTwo">
|
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
|
||||||
Advanced Mechanics
|
|
||||||
</button>
|
|
||||||
</h2>
|
|
||||||
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#rulesAccordion">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<ul class="list-group list-group-flush">
|
|
||||||
<li class="list-group-item"><strong>Smart Passing:</strong> Auto-targets nearest teammate in a 30-degree arc.</li>
|
|
||||||
<li class="list-group-item"><strong>Directional Shooting:</strong> Ball trajectory follows player's facing direction.</li>
|
|
||||||
<li class="list-group-item"><strong>Active Tackle:</strong> High-speed sprint to win the ball. Failure results in a 1-second movement penalty.</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- Controls Section -->
|
|
||||||
<section id="controls" class="bg-white">
|
|
||||||
<div class="container">
|
|
||||||
<h2 class="section-title">Dual Platform Controls</h2>
|
|
||||||
<div class="row g-4 align-items-center">
|
|
||||||
<div class="col-lg-6 order-lg-2">
|
|
||||||
<img src="https://picsum.photos/seed/soccercontrols/800/600" class="img-fluid rounded shadow" alt="Close-up on a person's hands using a mobile phone for gaming.">
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-6 order-lg-1">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>Mobile</h4>
|
|
||||||
<div class="control-item"><strong>Movement:</strong> Virtual Joystick</div>
|
|
||||||
<div class="control-item"><strong>Actions:</strong> On-screen Buttons</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>Desktop</h4>
|
|
||||||
<div class="control-item"><strong>Movement:</strong> Arrow Keys</div>
|
|
||||||
<div class="control-item"><strong>Pass:</strong> 'S' Key</div>
|
|
||||||
<div class="control-item"><strong>Shoot:</strong> 'D' Key</div>
|
|
||||||
<div class="control-item"><strong>Tackle:</strong> Spacebar</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<!-- Footer -->
|
|
||||||
<footer class="text-center">
|
|
||||||
<div class="container">
|
|
||||||
<p class="mb-0">© <?php echo date("Y"); ?> Pocket 5 Soccer. All Rights Reserved.</p>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<!-- Bootstrap 5 JS Bundle -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<!-- Custom JS -->
|
|
||||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user