- Add multi online game
Django
    - add somes paths
This commit is contained in:
Kum1ta
2024-09-15 15:57:40 +02:00
parent e1b8275c16
commit 448b377012
1340 changed files with 69 additions and 835528 deletions

View File

@ -3,10 +3,10 @@
# ::: :::::::: #
# Game.py :+: :+: :+: #
# +:+ +:+ +:+ #
# By: tomoron <tomoron@student.42.fr> +#+ +:+ +#+ #
# By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ #
# +#+#+#+#+#+ +#+ #
# Created: 2024/09/13 16:20:58 by tomoron #+# #+# #
# Updated: 2024/09/15 13:33:31 by tomoron ### ########.fr #
# Updated: 2024/09/15 14:44:14 by edbernar ### ########.fr #
# #
# **************************************************************************** #
@ -48,16 +48,10 @@ class Game:
self.p1 = socket
else:
self.p2 = socket
print("set game to self")
socket.game = self
if(self.p2 != None and self.p1 != None):
data = json.dumps({"type":"game", "content":{
"action" : 1,
"id": socket.id,
"username": socket.username
}})
self.p1.sync_send(data)
self.p2.sync_send(data)
self.p1.sync_send({"type":"game", "content":{"action":1,"id":self.p2.id,"username":self.p2.username}})
self.p2.sync_send({"type":"game", "content":{"action":1,"id":self.p1.id,"username":self.p1.username}})
except Exception as e:
socket.sendError("invalid request", 9005, e)

View File

@ -1,3 +1 @@
<body>
<p id="score"></p>
</body>
<p id="score"></p>

View File

@ -22,6 +22,7 @@ urlpatterns = [
path("homePage",views.homePage, name='homePage'),
path("lobbyPage", views.lobbyPage, name='lobbyPage'),
path("multiLocalGamePage", views.multiLocalGamePage, name='multiLocalGamePage'),
path("multiOnlineGamePage", views.multiOnlineGamePage, name='multiOnlineGamePage'),
path("waitingGamePage", views.waitingGamePage, name='waitingGamePage'),
path("game", views.game, name='game'),
path("wait_game", views.game, name='wait_game'),

View File

@ -37,6 +37,13 @@ def multiLocalGamePage(request):
return(HttpResponse("you are not logged in",status=403))
return render(request, "multiLocalGamePage.html", {})
def multiOnlineGamePage(request):
if(request.method != "POST"):
return index(request)
if(not request.session.get("logged_in", False)):
return(HttpResponse("you are not logged in",status=403))
return render(request, "multiOnlineGamePage.html", {})
def waitingGamePage(request):
if(request.method != "POST"):
return index(request)

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

View File

@ -6,10 +6,11 @@
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/25 00:00:21 by edbernar #+# #+# */
/* Updated: 2024/09/14 21:36:06 by edbernar ### ########.fr */
/* Updated: 2024/09/15 15:48:43 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import { MultiOnlineGamePage } from "/static/javascript/multiOnlineGame/multiOnlineGamePage.js"
import { multiLocalGamePage } from "/static/javascript/multiLocalGame/multiLocalGamePage.js"
import { WaitingGamePage } from "/static/javascript/waitingGame/main.js"
import { LobbyPage } from "/static/javascript/lobbyPage/main.js";
@ -23,6 +24,7 @@ class Page
{url:'/lobby', servUrl: '/lobbyPage', class: LobbyPage, name: 'lobbyPage', title: 'PTME - Lobby'},
{url:'/game', servUrl: '/multiLocalGamePage', class: multiLocalGamePage, name: 'multiLocalGamePage', title: 'PTME - Game'},
{url:'/wait_game', servUrl: '/waitingGamePage', class: WaitingGamePage, name: 'waitingGamePage', title: 'PTME - Wait for a game'},
{url:'/game', servUrl: '/multiOnlineGamePage', class: MultiOnlineGamePage, name: 'multiOnlineGamePage', title: 'PTME - Game'},
]
constructor()

View File

@ -0,0 +1,129 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Ball.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/20 17:02:47 by edbernar #+# #+# */
/* Updated: 2024/09/15 14:56:07 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import * as THREE from '/static/javascript/three/build/three.module.js'
class Ball
{
object = null;
centerPos = {};
limits = {};
interval = null;
constructor(scene, map)
{
this.object = this.#createBall();
this.centerPos = map.centerPos;
this.centerPos.y += this.object.geometry.parameters.radius;
this.limits = map.playerLimits;
this.resetPosBall();
scene.add(this.object);
}
#createBall()
{
const geometry = new THREE.SphereGeometry(0.15);
const material = new THREE.MeshPhysicalMaterial({ color: 0xff5555 });
const mesh = new THREE.Mesh(geometry, material);
mesh.receiveShadow = true;
mesh.castShadow = true;
mesh.position.set(this.centerPos.x, this.centerPos.y, this.centerPos.z);
return (mesh);
}
resetPosBall()
{
this.setPosition(this.centerPos.x, this.centerPos.y, this.centerPos.z);
}
setPosition(x, y, z)
{
this.object.position.set(x, y, z);
}
changeGravity(ballIsOnJumper)
{
let diffTop = this.limits.up - this.object.position.y;
let diffBot = this.object.position.y - this.limits.down;
let speed = 0.15;
const slower = speed / 3;
if (diffBot > diffTop)
speed *= -1;
if (this.interval)
clearInterval(this.interval);
this.interval = setInterval(() => {
this.object.position.y += speed;
if ((speed > 0 && this.object.position.y >= this.limits.up)
|| (speed < 0 && this.object.position.y <= this.limits.down))
{
clearInterval(this.interval);
this.interval = null;
if (speed > 0)
this.setPosition(this.object.position.x, this.limits.up, this.object.position.z);
else
this.setPosition(this.object.position.x, this.limits.down, this.object.position.z);
ballIsOnJumper.can = true;
}
speed -= speed * slower;
}, 10);
}
/*---------------- FUNCTION FOR TEST ----------------*/
initMoveBallTmp()
{
console.warn("Don't forget to remove function initMoveBallTmp");
const speedBallTmp = 0.1;
let warn = false;
document.addEventListener('keypress', (e) => {
if (!this.object && !warn)
{
console.warn("EventListener in initMoveBallTmp() is still here");
warn = true;
return ;
}
if (e.key == '4')
this.object.position.x -= speedBallTmp;
if (e.key == '6')
this.object.position.x += speedBallTmp;
if (e.key == '8')
this.object.position.z -= speedBallTmp;
if (e.key == '2')
this.object.position.z += speedBallTmp;
if (e.key == '9')
this.changeGravity();
});
}
/*---------------------------------------------------*/
dispose()
{
if (this.interval)
clearInterval(this.interval);
this.interval = null;
if (this.object)
{
if (this.object.geometry)
this.object.geometry.dispose();
if (this.object.material)
this.object.material.dispose();
if (this.object.texture)
this.object.texture.dispose();
}
this.object = null;
}
}
export { Ball };

View File

@ -0,0 +1,620 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Map.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/20 14:52:55 by hubourge #+# #+# */
/* Updated: 2024/09/15 15:24:37 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import { GLTFLoader } from '/static/javascript/three/examples/jsm/loaders/GLTFLoader.js';
import * as THREE from '/static/javascript/three/build/three.module.js'
import { Video } from '/static/javascript/multiOnlineGame/Video.js';
let loader = null;
let scene = null;
let videoList = [];
let interval2 = null;
let videoCanvas = null;
let videoCanvasTexture = null;
let materialCanvas = null;
let textureLoaderPlane = null;
let texturePlane = null;
let ctx = null;
let path = [
{name: 'goal', onChoice: true, src:'/static/video/multiOnlineGamePage/goal2.webm'},
{name: 'easteregg', onChoice: true, src:'/static/video/multiOnlineGamePage/easteregg.webm'},
{name: 'outstanding', onChoice: true, src:'/static/video/multiOnlineGamePage/outstanding.webm'},
{name: 'ping', onChoice: false, src:'/static/video/multiOnlineGamePage/pingpong.mp4'},
{name: 'catch', onChoice: false, src:'/static/video/multiOnlineGamePage/catch.mp4'},
{name: 'fortnite', onChoice: false, src:'/static/video/multiOnlineGamePage/fortnite.mp4'},
]
let spacingImages = [
100 * 2.33 * 10 - (100 * 2.33), // 2 images
100 * 2.33 * 5 - (100 * 2.33), // 4 images
100 * 2.33 * 2.5 - (100 * 2.33), // 8 images
100 * 2.33 * 1.25 - (100 * 2.33), // 16 images
];
class Map
{
arrObject = [];
ballObject = null;
mapLength = 0;
banner = null;
centerPos = {
x: -1,
y: -1,
z:-1
};
playerLimits = {
up : 3,
down: 0.3,
left: -3,
right: 3,
};
ballIsOnJumper = {
can: true
};
dispose()
{
videoList.forEach(elem => {
elem.video.pause();
elem.video.src = '';
elem.video.removeAttribute('src');
elem.video.load();
})
videoList = null;
videoCanvas.remove();
if (videoCanvasTexture)
videoCanvasTexture.dispose();
if (materialCanvas)
materialCanvas.dispose();
videoCanvas = null;
textureLoaderPlane = null;
loader = null;
if (texturePlane)
texturePlane.dispose();
this.arrObject.forEach(elem => {
if (elem.mesh instanceof THREE.Group)
{
elem.mesh.children.forEach(child => {
if (child.geometry)
child.geometry.dispose();
if (child.material)
child.material.dispose();
if (child.texture)
child.texture.dispose();
});
}
else
{
if (elem.mesh.geometry)
elem.mesh.geometry.dispose();
if (elem.mesh.material)
elem.mesh.material.dispose();
if (elem.mesh.texture)
elem.mesh.texture.dispose();
}
scene.remove(elem.mesh);
});
this.arrObject = null;
if (interval2)
clearInterval(interval2);
scene = null;
}
constructor(sceneToSet, length, obstacles)
{
loader = new GLTFLoader();
scene = sceneToSet;
this.centerPos.x = 0;
this.centerPos.y = 0.15;
this.centerPos.z = -length / 2 + length / 2;
this.mapLength = length;
scene.add(this.#createPlanes(7.5, length, -(Math.PI / 2), "planeBottom", true, '/static/img/multiOnlineGamePage/pastel.jpg'));
scene.add(this.#createPlanes(7.5, length, (Math.PI / 2), "planeTop", false, '/static/img/multiOnlineGamePage/pastel.jpg'));
scene.add(this.#createWall(-3.5, 0.4, -length/2, "wallLeft"));
scene.add(this.#createWall(3.5, 0.4, -length/2, "wallRight"));
if (obstacles)
this.#generateObstacle();
};
#createPlanes(x, y, rot, name, isBottom, visual)
{
let geometryPlane = null;
let materialPlane = null;
let meshPlane = null;
for (let i = 0; i < this.arrObject.length; i++)
{
if (this.arrObject[i].name == name)
throw Error("Name already exist.");
}
geometryPlane = new THREE.PlaneGeometry(x, y);
if (typeof(visual) == 'string')
{
textureLoaderPlane = new THREE.TextureLoader();
texturePlane = textureLoaderPlane.load(visual);
materialPlane = new THREE.MeshPhysicalMaterial({ map: texturePlane });
}
else if (typeof(visual) == 'number')
materialPlane = new THREE.MeshPhysicalMaterial({ color: visual });
else
materialPlane = new THREE.MeshPhysicalMaterial();
meshPlane = new THREE.Mesh(geometryPlane, materialPlane);
meshPlane.rotateX(rot);
if (isBottom)
meshPlane.position.set(0, 0.15, 0);
else
meshPlane.position.set(0, 3.15, 0);
this.arrObject.push({mesh: meshPlane, name: name, type: "plane"});
meshPlane.receiveShadow = true;
return (meshPlane);
};
changePlane(texture)
{
console.log(this.arrObject);
for (let i = 0; i < this.arrObject.length; i++)
{
if (this.arrObject[i].name == "planeBottom" || this.arrObject[i].name == "planeTop")
{
if (this.arrObject[i].mesh.material)
this.arrObject[i].mesh.material.dispose();
if (typeof(texture) == 'string')
{
let textureLoader = new THREE.TextureLoader();
texture = textureLoader.load(texture);
this.arrObject[i].mesh.material.map = texture;
}
else if (typeof(texture) == 'number')
this.arrObject[i].mesh.material.color.set(texture);
}
}
}
#createWall(x, y, z, name)
{
let geometryWall = null;
let materialWall = null;
let meshWall = null;
for (let i = 0; i < this.arrObject.length; i++)
{
if (this.arrObject[i].name == name)
throw Error("Name already exist.");
}
geometryWall = new THREE.BoxGeometry(0.05, 0.5, 0.75);
materialWall = new THREE.MeshPhysicalMaterial();
meshWall = new THREE.Mesh(geometryWall, materialWall);
meshWall.position.set(x, y, z);
materialWall.transparent = true;
materialWall.opacity = 0.5;
this.arrObject.push({mesh: meshWall, name: name, type: "wall"});
return (meshWall);
};
#createGravityChanger(x, y, z, name, typeName, onTop)
{
let geometry1 = null;
let material1 = null;
let ring1 = null;
let geometry2 = null;
let material2 = null;
let ring2 = null;
let geometry3 = null;
let material3 = null;
let ring3 = null;
let geometry4 = null;
let material4 = null;
let circle1 = null;
let geometry5 = null;
let material5 = null;
let circle2 = null;
let geometry6 = null;
let material6 = null;
let collider = null;
let groupJumper = null;
for (let i = 0; i < this.arrObject.length; i++)
{
if (this.arrObject[i].name == name)
throw Error("Name already exist.");
}
geometry1 = new THREE.TorusGeometry(1, 0.1, 12, 24);
material1 = new THREE.MeshPhysicalMaterial({color: 0x00ff00});
ring1 = new THREE.Mesh(geometry1, material1);
ring1.rotateX(-Math.PI / 2);
ring1.position.set(0, 0, 0);
ring1.scale.set(0.2, 0.2, 0.2);
material1.transparent = true;
material1.opacity = 0.75;
geometry2 = new THREE.TorusGeometry(1, 0.1, 12, 24);
material2 = new THREE.MeshPhysicalMaterial({color: 0x00ff00});
ring2 = new THREE.Mesh(geometry2, material2);
ring2.rotateX(-Math.PI / 2);
ring2.position.set(0, 0 + 0.1, 0);
ring2.scale.set(0.18, 0.18, 0.18);
material2.transparent = true;
material2.opacity = 0.65;
geometry3 = new THREE.TorusGeometry(1, 0.1, 12, 24);
material3 = new THREE.MeshPhysicalMaterial({color: 0x00ff00});
ring3 = new THREE.Mesh(geometry3, material3);
ring3.rotateX(-Math.PI / 2);
ring3.position.set(0, 0 + 0.2, 0);
ring3.scale.set(0.16, 0.16, 0.16);
material3.transparent = true;
material3.opacity = 0.35;
geometry4 = new THREE.CircleGeometry(0.2, 24);
material4 = new THREE.MeshPhysicalMaterial({color: 0xaaffaa});
circle1 = new THREE.Mesh(geometry4, material4);
circle1.rotateX(-Math.PI / 2);
circle1.position.set(0, 0 - 0.048, 0);
geometry5 = new THREE.CircleGeometry(0.24, 24);
material5 = new THREE.MeshPhysicalMaterial({color: 0x00ff00});
circle2 = new THREE.Mesh(geometry5, material5);
circle2.rotateX(-Math.PI / 2);
circle2.position.set(0, 0 - 0.049, 0);
geometry6 = new THREE.CylinderGeometry(0.15, 0.15, 0.35);
material6 = new THREE.MeshPhysicalMaterial({color: 0x00ff00});
collider = new THREE.Mesh(geometry6, material6);
collider.position.set(0, 0 + 0.1, 0);
material6.transparent = true;
material6.opacity = 0.1;
groupJumper = new THREE.Group();
groupJumper.add(ring1);
groupJumper.add(ring2);
groupJumper.add(ring3);
groupJumper.add(circle1);
groupJumper.add(circle2);
groupJumper.add(collider);
// Set groupJumper position groud / top
for (let i = 0; i < groupJumper.children.length && onTop; i++)
groupJumper.children[i].position.set(x, y - 0.1, z);
for (let i = 0; i < groupJumper.children.length && !onTop; i++)
groupJumper.children[i].position.set(x, y, z);
let distanceY = [-0.04, -0.14, -0.24, 0.048, 0.049, -0.125];
let rotate = [0, 0, 0, 1, 1, 0];
// Set distance between each object
for (let i = 0; i < groupJumper.children.length; i++)
{
if (onTop)
{
if (rotate[i])
groupJumper.children[i].rotateX(Math.PI);
groupJumper.children[i].position.set(groupJumper.children[i].position.x, groupJumper.children[i].position.y + distanceY[i], groupJumper.children[i].position.z);
}
else
groupJumper.children[i].position.set(groupJumper.children[i].position.x, groupJumper.children[i].position.y - distanceY[i], groupJumper.children[i].position.z);
}
this.arrObject.push({mesh: groupJumper, name: name, type: typeName});
scene.add(groupJumper);
};
#createWallObstacle(x, y, size, onTop)
{
let geometryWallObs = null;
let materialWallObs = null;
let meshWallObs = null;
geometryWallObs = new THREE.BoxGeometry(size, 0.5, 0.1);
materialWallObs = new THREE.MeshPhysicalMaterial({color: 0xaaaafe});
meshWallObs = new THREE.Mesh(geometryWallObs, materialWallObs);
if (onTop)
meshWallObs.position.set(x, this.playerLimits.up - 0.1, y);
else
meshWallObs.position.set(x, 0.4, y);
return (meshWallObs);
}
/* Todo (Hugo) :
- Faire une zone Player banner (importer un model blender)
- Faire une zone pour les pub (ok)
- Effet gros pixel (ok)
- Effet de lumière en 2d (essayer shader ou filtre)
- Preparer differents events (ok)
*/
putVideoOnCanvas(nbImage, vNameNb)
{
this.#clearVideoCanvas();
if (nbImage <= 0)
return ;
let startIndex = 0;
let nbVideos = 1;
path.sort(() => Math.random() - 0.5);
// Create the canvas for the video
videoCanvas = document.createElement('canvas');
ctx = videoCanvas.getContext('2d');
videoCanvas.width = 100 * 2.33 * 20;
videoCanvas.height = 100;
// Get the number of videos to display
if (vNameNb && typeof(vNameNb) == 'number')
nbVideos = vNameNb;
if (vNameNb && typeof(vNameNb) == 'string')
startIndex = getIndex(vNameNb);
function getIndex(vNameNb)
{
for (let i = 0; i < path.length; i++)
{
if (path[i].name == vNameNb)
return (i);
}
return (0);
}
// Fill the videoList with the videos
for (let i = startIndex; i < (nbVideos + startIndex); i++)
{
if (path[i].onChoice == true && !(vNameNb && typeof(vNameNb) == 'string'))
{
startIndex++;
continue ;
}
let videoTmp = null;
if (Math.random() < 0.99)
videoTmp = new Video(path[i].src).video;
else
videoTmp = new Video(path[getIndex('easteregg')].src).video;
videoTmp.addEventListener('loadeddata', () => {
videoTmp.play();
drawVideoOnCanvas();
});
videoList.push({video: videoTmp, imageWidth: 100 * 2.33, imageHeight: 100});
}
// Draw the video on the canvas
function drawVideoOnCanvas()
{
if (videoCanvas)
{
ctx.clearRect(0, 0, videoCanvas.width, videoCanvas.height);
if (nbVideos == 0)
return ;
let nbDraw = 0;
let vIndex = 0;
let y = 0;
for (let x = 0; x < videoCanvas.width; x += (videoList[vIndex].imageWidth + spacingImages[nbImage]))
{
ctx.drawImage(videoList[vIndex].video, x, y, videoList[vIndex].imageWidth, videoList[vIndex].imageHeight);
nbDraw++;
if (nbVideos > 1)
vIndex++;
if (vIndex >= nbVideos)
vIndex = 0;
if (!(videoList && videoList[vIndex]))
break ;
}
if (videoCanvasTexture)
videoCanvasTexture.needsUpdate = true;
requestAnimationFrame(drawVideoOnCanvas);
}
}
// Create the material and the banner
videoCanvasTexture = new THREE.CanvasTexture(videoCanvas);
videoCanvasTexture.wrapS = THREE.RepeatWrapping;
videoCanvasTexture.wrapT = THREE.RepeatWrapping;
videoCanvasTexture.repeat.set(-1, 1);
materialCanvas = new THREE.MeshBasicMaterial({ map: videoCanvasTexture, side: THREE.BackSide , transparent: true});
// Load the banner
loader.load( '/static/models3D/multiOnlineGame/banner.glb', (gltf) => {
this.banner = gltf.scene.children[0];
gltf = null;
this.banner.material = materialCanvas;
this.banner.position.y += 1.7;
this.banner.rotation.x = (Math.PI);
this.banner.rotation.y += -0.15;
scene.add(this.banner);
interval2 = setInterval(() => {
this.banner.rotation.y += 0.001;
}, 10);
}, undefined, function ( error ) {
console.error( error );
} );
}
#clearVideoCanvas()
{
if (videoCanvas)
{
videoCanvas.remove();
videoCanvas = null;
}
if (videoList)
{
videoList.forEach(elem => {
elem.video.pause();
elem.video.src = '';
elem.video.removeAttribute('src');
elem.video.load();
})
}
videoList = [];
if (videoCanvasTexture)
{
videoCanvasTexture.dispose();
videoCanvasTexture = null;
}
if (materialCanvas)
{
materialCanvas.dispose();
materialCanvas = null;
}
if (interval2)
{
clearInterval(interval2);
interval2 = null;
}
scene.remove(this.banner);
}
#animationGravityChanger(group, onTop)
{
let geometryGC = new THREE.TorusGeometry(1.5, 0.05, 12, 24);
let materialGC = new THREE.MeshPhysicalMaterial({color: 0x00ff00});
let ringGC = new THREE.Mesh(geometryGC, materialGC);
let landmarkGC = group.children[0];
let speed = 0.1;
let interval = null;
ringGC.rotateX(-Math.PI / 2);
ringGC.position.set(landmarkGC.position.x, landmarkGC.position.y, landmarkGC.position.z);
ringGC.scale.set(0.2, 0.2, 0.2);
materialGC.transparent = true;
scene.add(ringGC);
interval = setInterval(() => {
if (onTop)
ringGC.position.y -= speed;
else
ringGC.position.y += speed;
materialGC.opacity -= 0.02;
speed *= 0.90;
if (materialGC.opacity == 0)
clearInterval(interval);
}, 10);
}
#generateObstacle()
{
const wallPos = [
{ x: 1, y: 0, z: 1, onTop: false},
{ x: 1, y: 0, z: 1, onTop: true},
{ x: -1, y: 0, z: 1, onTop: false},
{ x: -1, y: 0, z: 1, onTop: true}
];
for (let i = 0; i < wallPos.length; i++)
{
if (Math.random() < 0.5)
scene.add(this.#createWallObstacle(wallPos[i].x, wallPos[i].y, wallPos[i].z, wallPos[i].onTop));
}
const type = "gravityChanger";
const typeNameBottom = "jumperBottom";
const typeNameTop = "jumperTop";
const jumperPos = [
{ x: -1.5, y: 0.2, z: this.mapLength / 4, type: type, typeName: typeNameBottom, onTop: false},
{ x: -1.5, y: 3.2, z: this.mapLength / 4, type: type, typeName: typeNameTop, onTop: true},
{ x: 1.5, y: 0.2, z: this.mapLength / 4, type: type, typeName: typeNameBottom, onTop: false},
{ x: 1.5, y: 3.2, z: this.mapLength / 4, type: type, typeName: typeNameTop, onTop: true},
{ x: -1.5, y: 0.2, z: -this.mapLength / 4, type: type, typeName: typeNameBottom, onTop: false},
{ x: -1.5, y: 3.2, z: -this.mapLength / 4, type: type, typeName: typeNameTop, onTop: true},
{ x: 1.5, y: 0.2, z: -this.mapLength / 4, type: type, typeName: typeNameBottom, onTop: false},
{ x: 1.5, y: 3.2, z: -this.mapLength / 4, type: type, typeName: typeNameTop, onTop: true}
];
for (let i = 0; i < jumperPos.length; i++)
{
if (Math.random() < 0.5)
{
this.#createGravityChanger(jumperPos[i].x, jumperPos[i].y, jumperPos[i].z, jumperPos[i].type + i, jumperPos[i].typeName, jumperPos[i].onTop);
if (i % 2 == 0)
i++;
}
}
};
update(ball)
{
for (let i = 0; this.arrObject && i < this.arrObject.length; i++)
{
if (this.arrObject[i].name == "wallLeft")
{
// Move the wall with the ball position
if (ball.object.position.z < this.mapLength / 2 - 0.35 && ball.object.position.z > -this.mapLength / 2 + 0.35)
this.arrObject[i].mesh.position.z = ball.object.position.z;
if (ball.object.position.y > 0.4 + 0.1 && ball.object.position.y < 3.2)
this.arrObject[i].mesh.position.y = ball.object.position.y - 0.1;
// Change the opacity of the wall
let diff = ball.object.position.x - this.arrObject[i].mesh.position.x - 0.1;
if (diff > 2)
this.arrObject[i].mesh.material.opacity = 0;
else
this.arrObject[i].mesh.material.opacity = 1 - (diff / 2);
}
if (this.arrObject[i].name == "wallRight")
{
// Move the wall with the ball position
if (ball.object.position.z < this.mapLength / 2 - 0.35 && ball.object.position.z > -this.mapLength / 2 + 0.35)
this.arrObject[i].mesh.position.z = ball.object.position.z;
if (ball.object.position.y > 0.4 + 0.1 && ball.object.position.y < 3.2)
this.arrObject[i].mesh.position.y = ball.object.position.y - 0.1;
// Change the opacity of the wall
let diff = this.arrObject[i].mesh.position.x - ball.object.position.x - 0.1;
if (diff > 2)
this.arrObject[i].mesh.material.opacity = 0;
else
this.arrObject[i].mesh.material.opacity = 1 - (diff / 2);
}
if (this.arrObject[i].type == 'jumperBottom')
{
const cylinder = this.arrObject[i].mesh.children[5];
const distance = ball.object.position.distanceTo(cylinder.position);
const speed = 0.1;
// Detect if the ball is on the jumper
if (distance < 0.25 && this.ballIsOnJumper.can)
{
this.ballIsOnJumper.can = false;
ball.changeGravity(this.ballIsOnJumper);
this.#animationGravityChanger(this.arrObject[i].mesh, false);
}
// Gravity changer animation
for (let j = 0; j < 3; j++)
{
this.arrObject[i].mesh.children[j].rotation.x = Math.sin(Date.now() * 0.001 + (j - 2) * 5) * 0.1 + Math.PI / 2;
this.arrObject[i].mesh.children[j].rotation.y = Math.sin(Date.now() * 0.001 + (j - 2) * 5) * 0.1 + Math.cos(Date.now() * 0.001) * 0.1;;
}
}
if (this.arrObject[i].type == 'jumperTop')
{
const cylinder = this.arrObject[i].mesh.children[5];
const distance = ball.object.position.distanceTo(cylinder.position);
const speed = 0.1;
// Detect if the ball is on the jumper
if (distance < 0.4 && this.ballIsOnJumper.can)
{
this.ballIsOnJumper.can = false;
ball.changeGravity(this.ballIsOnJumper);
this.#animationGravityChanger(this.arrObject[i].mesh, true);
}
// Gravity changer animation
for (let j = 0; j < 3; j++)
{
this.arrObject[i].mesh.children[j].rotation.x = Math.sin(Date.now() * 0.001 + (j - 2) * 5) * 0.1 + Math.PI / 2;
this.arrObject[i].mesh.children[j].rotation.y = Math.sin(Date.now() * 0.001 + (j - 2) * 5) * 0.1 + Math.cos(Date.now() * 0.001) * 0.1;;
}
}
}
};
};
export { Map };

View File

@ -0,0 +1,44 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Opponent.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/21 10:34:49 by edbernar #+# #+# */
/* Updated: 2024/09/15 14:56:35 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
let opponentExist = false;
class Opponent
{
object = null;
speed = 0.1;
interval = null;
limits = {};
player = null;
constructor (object, map)
{
if (opponentExist)
throw Error("Opponent is already init.");
opponentExist = true;
this.object = object;
this.limits = map.limits;
this.object.position.set(0, 0.3, -map.mapLength / 2 + 0.2);
}
dispose()
{
opponentExist = false;
}
update()
{
//en attente du serveur
}
}
export { Opponent };

View File

@ -0,0 +1,302 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Player.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/18 00:30:31 by edbernar #+# #+# */
/* Updated: 2024/09/15 14:57:56 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import * as THREE from '/static/javascript/three/build/three.module.js'
/*
Explication du code :
- Un seul joueur peut etre instancié, sinon ça throw une erreur
- Lorsqu'une touche est pressée, celle-ci sera ajoutée à la variable "pressedButton"
Exemple : w et a sont pressées -> pressedButton = ['w', 'a']
- Les lignes avec cleanup sont l'êquivalent d'un destructeur en CPP
- Pour appliquer des actions sur les touches, il suffit de faire ça dans la fonction
update en regardant si la touche voulue est dans la variable "pressedButton"
- Par défaut, la caméra est accrochée, si on veut qu'elle ne bouge plus, il faut
modifier "cameraFixed" à true (se fait avec la touche 'm' en jeu)
- Si on utilise une touche qui ne sera utilisée que pour un appui simple, il faudra la
mettre dans 'addEventListerner('keypress') et pas dans update() pour eviter les
problèmes de touche non détecté
- La variable "limits" sert à délimiter les mouvements de la barre
*/
/*
Todo (Eddy) :
- Ajouter une camera sur l'object (OK)
- Faire une fonction pour changer le mode de la camera (fix ou accrochée) (OK)
- Ajouter une rotation quand la caméra est fixe (OK)
- Corriger bug quand changement de caméra (camera qui se remet au dessus
quand on repasse au dessus alors qu'elle devrait être en dessous vu que la
barre est en haut). Mais peut etre faire ça quand la barre aura des mouvements
définis sur la hauteur. (OK)
- Ajouter les mouvements définis sur l'axe y (OK)
- Faire une fonction qui change de camera quand il y a un but avec un fondu en noir (OK)
- Ajouter un zoom sur la camera de la fonction pointAnimation (OK)
- Ajouter une fonction pour l'animation de point marqué (OK)
*/
let playerExist = false;
let isOnPointAnim = false;
let pressedButton = [];
class Player
{
object = null;
camera = null;
speed = 4;
cameraFixed = false;
interval = null;
limits = {};
previousTime = Date.now();
deltaTime = 1;
constructor (object, map)
{
if (playerExist)
throw Error("Player is already init.");
playerExist = true;
isOnPointAnim = false;
pressedButton = [];
this.object = object;
this.limits = map.playerLimits;
this.camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 10000);
this.object.position.set(0, this.limits.down, map.mapLength / 2 - 0.2);
this.setCameraPosition(
this.object.position.x,
this.object.position.y + 0.7,
this.object.position.z + 1.5
);
document.addEventListener('keydown', addKeyInArr);
document.addEventListener('keyup', remKeyInArr);
document.addEventListener('keypress', simplePressKey);
}
dispose()
{
playerExist = false;
isOnPointAnim = false;
document.removeEventListener('keydown', addKeyInArr);
document.removeEventListener('keyup', remKeyInArr);
document.removeEventListener('keypress', simplePressKey);
pressedButton = [];
if (this.interval)
clearInterval(interval);
}
pointAnimation(map)
{
const tmpCamera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 10000);
const tmp = this.camera;
let interval = null;
const startColor = this.object.material.color.clone();
let hue = 0;
document.getElementsByTagName('canvas')[0].style.animation = 'fadeIn 0.199s';
document.getElementsByTagName('canvas')[0].style.filter = 'brightness(0)';
setTimeout(() => {
document.getElementsByTagName('canvas')[0].style.animation = 'fadeOut 0.199s';
document.getElementsByTagName('canvas')[0].style.filter = 'brightness(1)';
}, 300)
setTimeout(() => {
tmpCamera.position.set(this.limits.left, this.limits.up / 2 + 0.5, map.centerPos.z);
isOnPointAnim = true;
this.camera = tmpCamera;
interval = setInterval(() => {
tmpCamera.lookAt(this.object.position);
hue += 0.01;
if (hue > 1)
hue = 0;
this.object.material.color.setHSL(hue, 1, 0.5);
tmpCamera.fov -= 0.05;
tmpCamera.updateProjectionMatrix();
}, 10);
setTimeout(() => {
clearInterval(interval);
document.getElementsByTagName('canvas')[0].style.animation = null;
document.getElementsByTagName('canvas')[0].style.animation = 'fadeIn 0.19s';
document.getElementsByTagName('canvas')[0].style.filter = 'brightness(0)';
setTimeout(() => {
this.camera = tmp;
this.object.material.color.copy(startColor);
isOnPointAnim = false;
if (!this.cameraFixed)
{
this.setCameraPosition(
this.object.position.x,
this.object.position.y - (this.object.position.y >= this.limits.up ? 0.7 : -0.7),
this.object.position.z + 2
);
}
document.getElementsByTagName('canvas')[0].style.animation = 'fadeOut 0.199s';
document.getElementsByTagName('canvas')[0].style.filter = 'brightness(1)';
}, 200);
}, 4000);
}, 200)
}
pointOpponentAnimation(map, oppponentObject)
{
const tmpCamera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 10000);
const tmp = this.camera;
let interval = null;
const startColor = oppponentObject.material.color.clone();
let hue = 0;
document.getElementsByTagName('canvas')[0].style.animation = 'fadeIn 0.199s';
document.getElementsByTagName('canvas')[0].style.filter = 'brightness(0)';
setTimeout(() => {
document.getElementsByTagName('canvas')[0].style.animation = 'fadeOut 0.199s';
document.getElementsByTagName('canvas')[0].style.filter = 'brightness(1)';
}, 300)
setTimeout(() => {
tmpCamera.position.set(this.limits.left, this.limits.up / 2 + 0.5, map.centerPos.z);
isOnPointAnim = true;
this.camera = tmpCamera;
interval = setInterval(() => {
tmpCamera.lookAt(oppponentObject.position);
console.log(tmpCamera.position)
hue += 0.01;
if (hue > 1)
hue = 0;
oppponentObject.material.color.setHSL(hue, 1, 0.5);
tmpCamera.fov -= 0.05;
tmpCamera.updateProjectionMatrix();
}, 10);
setTimeout(() => {
clearInterval(interval);
document.getElementsByTagName('canvas')[0].style.animation = null;
document.getElementsByTagName('canvas')[0].style.animation = 'fadeIn 0.19s';
document.getElementsByTagName('canvas')[0].style.filter = 'brightness(0)';
setTimeout(() => {
this.camera = tmp;
oppponentObject.material.color.copy(startColor);
isOnPointAnim = false;
if (!this.cameraFixed)
{
this.setCameraPosition(
this.object.position.x,
this.object.position.y - (this.object.position.y >= this.limits.up ? 0.7 : -0.7),
this.object.position.z + 2
);
}
document.getElementsByTagName('canvas')[0].style.animation = 'fadeOut 0.199s';
document.getElementsByTagName('canvas')[0].style.filter = 'brightness(1)';
}, 200);
}, 4000);
}, 200)
}
update()
{
const currentTime = Date.now();
this.deltaTime = (currentTime - this.previousTime) / 1000;
this.previousTime = currentTime;
let i;
i = 0;
while (i < pressedButton.length)
{
if (pressedButton[i] == 'w' && this.object.position.y < this.limits.up)
{
if (this.interval)
clearInterval(this.interval);
this.interval = setInterval(() => {
this.object.position.y += this.speed / 40;
if (!this.cameraFixed && !isOnPointAnim)
this.camera.position.y += (this.speed / 80);
if (this.object.position.y >= this.limits.up)
{
clearInterval(this.interval);
this.interval = null;
}
}, 5);
}
if (pressedButton[i] == 's' && this.object.position.y > this.limits.down)
{
if (this.interval)
clearInterval(this.interval);
this.interval = setInterval(() => {
this.object.position.y -= this.speed / 40;
if (!this.cameraFixed && !isOnPointAnim)
this.camera.position.y -= (this.speed / 80);
if (this.object.position.y <= this.limits.down)
{
clearInterval(this.interval);
this.interval = null;
this.object.position.y = this.limits.down;
}
}, 5);
}
if (pressedButton[i] == 'd' && this.object.position.x < this.limits.right)
{
this.object.position.x += this.speed * this.deltaTime;
if (!this.cameraFixed && !isOnPointAnim)
this.camera.position.x += this.speed * this.deltaTime;
}
if (pressedButton[i] == 'a' && this.object.position.x > this.limits.left)
{
this.object.position.x -= this.speed * this.deltaTime;
if (!this.cameraFixed && !isOnPointAnim)
this.camera.position.x -= this.speed * this.deltaTime;
}
i++;
}
}
setCameraPosition(x, y, z)
{
this.camera.position.set(x, y, z);
}
};
function addKeyInArr(e)
{
let i;
i = 0;
while (i < pressedButton.length && e.key != pressedButton[i])
i++;
if (i == pressedButton.length)
pressedButton.push(e.key);
}
function remKeyInArr(e)
{
let i;
i = 0;
while (i < pressedButton.length && e.key != pressedButton[i])
i++;
if (i != pressedButton.length)
pressedButton.splice(i, 1);
}
function simplePressKey(e)
{
if (e.key == 'm' && !isOnPointAnim)
{
this.cameraFixed = !this.cameraFixed;
if (!this.cameraFixed)
{
this.setCameraPosition(
this.object.position.x,
this.object.position.y - (this.object.position.y >= this.limits.up ? 0.7 : -0.7),
this.object.position.z + 1.5
);
this.camera.rotation.set(0, 0, 0);
}
else
this.setCameraPosition(0, 1.5, this.object.position.z + 3);
}
}
export { Player, playerExist };

View File

@ -0,0 +1,27 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Video.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/26 18:57:00 by hubourge #+# #+# */
/* Updated: 2024/09/15 15:01:30 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
class Video
{
video = null;
constructor(path)
{
this.video = document.createElement('video');
this.video.src = path;
this.video.muted = true;
this.video.autoplay = true;
this.video.loop = true;
}
}
export { Video };

View File

@ -0,0 +1,167 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* multiOnlineGamePage.js :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/18 00:53:53 by edbernar #+# #+# */
/* Updated: 2024/09/15 15:07:29 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import * as THREE from '/static/javascript/three/build/three.module.js'
import { Player } from '/static/javascript/multiOnlineGame/Player.js'
import { Map } from '/static/javascript/multiOnlineGame/Map.js'
import { Ball } from '/static/javascript/multiOnlineGame/Ball.js'
import { Opponent } from '/static/javascript/multiOnlineGame/Opponent.js'
/*
Controls :
- w : monter
- s : descendre
- a : gauche
- d : droite
- g : animation de point
- h : animation de point pour l'adversaire
- c : switch entre la vue du joueur et la vue de la caméra
- q : lancer animation sur les jumpers
- 8 : avance la balle
- 2 : recule la balle
- 4 : balle vers la gauche
- 6 : balle vers ladroite
- 9 : inversion gravite
- p : clear video
- o : goal video
- i : outstanding video
- u : 16 video
- y : 8 video
- t : 4 video
*/
let scene = null;
let map = null;
let ball = null;
let renderer = null;
let player = null;
let spotLight = null;
let ambiantLight = null;
let opponent = null;
class MultiOnlineGamePage
{
static create()
{
const bar1 = createBarPlayer(0xed56ea);
const bar2 = createBarPlayer(0xf3e11e);
document.body.setAttribute('style', '');
scene = new THREE.Scene()
map = new Map(scene, 13, true);
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.domElement.style.animation = 'fadeOutStartGames 1s';
renderer.domElement.style.filter = 'brightness(1)';
player = new Player(bar1, map);
spotLight = new THREE.SpotLight(0xffffff, 10000, 0, 0.2);
spotLight.castShadow = true;
ambiantLight = new THREE.AmbientLight(0xffffff, 0.5);
ball = new Ball(scene, map);
opponent = new Opponent(bar2, map);
scene.add(player.object);
scene.add(opponent.object);
scene.add(ambiantLight);
spotLight.position.set(0, 100, 0);
scene.add(spotLight);
scene.background = new THREE.Color(0x1a1a1a);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
ball.initMoveBallTmp();
map.ballObject = ball.object;
document.addEventListener('keypress', (e) => {
if (e.key == 'g')
player.pointAnimation(map);
if (e.key == 'h')
player.pointOpponentAnimation(map, opponent.object);
if (e.key == 'c')
debug = !debug;
if (e.key == 'p')
map.putVideoOnCanvas(0, null);
if (e.key == 'o')
map.putVideoOnCanvas(3, 'goal');
if (e.key == 'i')
map.putVideoOnCanvas(3, 'outstanding');
if (e.key == 'u')
map.putVideoOnCanvas(3, 3);
if (e.key == 'y')
map.putVideoOnCanvas(2, 3);
if (e.key == 't')
map.putVideoOnCanvas(1, 3);
})
renderer.setAnimationLoop(loop)
}
static dispose()
{
if (renderer)
renderer.dispose();
renderer = null;
if (map)
map.dispose();
map = null;
if (ball)
ball.dispose();
ball = null;
if (player)
player.dispose();
player = null;
if (opponent)
opponent.dispose();
opponent = null;
if (scene)
{
scene.children.forEach(child => {
if (child.geometry)
child.geometry.dispose();
if (child.material)
child.material.dispose();
if (child.texture)
child.texture.dispose();
scene.remove(child);
});
}
scene = null;
}
}
function createBarPlayer(color)
{
const geometry = new THREE.BoxGeometry(1, 0.1, 0.1);
const material = new THREE.MeshPhysicalMaterial({color: color});
const mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
return (mesh);
}
function changeBarColor(bar, color)
{
bar.material.color.set(color);
}
function loop()
{
player.update();
map.update(ball);
renderer.render(scene, player.camera);
}
export { MultiOnlineGamePage };

View File

@ -6,7 +6,7 @@
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/09/15 12:00:01 by edbernar #+# #+# */
/* Updated: 2024/09/15 12:46:12 by edbernar ### ########.fr */
/* Updated: 2024/09/15 14:23:31 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
@ -15,6 +15,7 @@ import { pageRenderer } from '/static/javascript/main.js'
function typeGame(content)
{
console.log("New action game : " + content.action);
if (content.action == 1)
{
if (pageRenderer.actualPage == WaitingGamePage)

View File

@ -6,7 +6,7 @@
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/09/14 21:20:45 by edbernar #+# #+# */
/* Updated: 2024/09/15 12:57:52 by edbernar ### ########.fr */
/* Updated: 2024/09/15 14:53:22 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
@ -45,14 +45,16 @@ class WaitingGamePage
static dispose()
{
const returnButton = document.getElementById('returnToLobbyButton');
if (intervalPoints)
clearInterval(intervalPoints);
intervalPoints = null;
if (timeout)
clearTimeout(timeout);
timeout = null;
returnButton.removeEventListener('click', returnToLobby);
if (returnButton)
returnButton.removeEventListener('click', returnToLobby);
}
static showOpponent(username)
@ -63,7 +65,18 @@ class WaitingGamePage
if (intervalPoints)
clearInterval(intervalPoints);
intervalPoints = null;
sentence.innerText = "Match found";
sentence.style.animation = 'anim3 0.5s';
sentence.style.opacity = 0;
setTimeout(() => {
sentence.innerText = "Your opponent is " + username;
sentence.style.animation = 'animShowMenuDiv 0.5s';
sentence.style.opacity = 1;
setTimeout(() => {
document.body.style.animation = 'anim3 0.5s';
document.body.style.opacity = 0;
pageRenderer.changePage("multiOnlineGamePage");
}, 1000);
}, 500);
document.body.removeChild(returnButton);
}
}