diff --git a/lab5/src/app.py b/lab5/src/app.py index d989969542f5be6f2adf51a6c10409eae4031b67..2831297e1ea549d54c5ca5a24125124b723e226d 100644 --- a/lab5/src/app.py +++ b/lab5/src/app.py @@ -12,9 +12,9 @@ def root(): @app.route('/get/map/<id>/') def getMap(id): - content = mapManager.loadImage(mapManager.getPathOfMapFile('map'+id+'.png')) + content = mapManager.loadMapImage(mapManager.getPathOfMapFile(id+'.png')) return json.dumps(content) @app.route('/get/maps/') def getMaps(): - return 'todo' + return json.dumps(mapManager.findMaps()) diff --git a/lab5/src/mapManager.py b/lab5/src/mapManager.py index 009a79e44a74ecea8d9d5197013ab143b87d5cec..5d30afbecaa775820bea71a7c308083f054c0973 100644 --- a/lab5/src/mapManager.py +++ b/lab5/src/mapManager.py @@ -10,7 +10,7 @@ def getPathOfMapFile(fileName): -def loadImage(filepath): +def loadMapImage(filepath): #if (exist(filepath)): # return 'Error 404, file not found' @@ -43,5 +43,11 @@ def loadImage(filepath): elif (r == 255) & (g == 255) & (b == 0): # yellow pixel - special food content.append('SPAWN_P') - - return content \ No newline at end of file + return content + +def findMaps(): + files = [] + for file in os.listdir("maps"): + if file.endswith(".png") & file.startswith("map"): + files.append([file.split('.')[0], getPathOfMapFile(file)]) + return files \ No newline at end of file diff --git a/lab5/src/maps/README.md b/lab5/src/maps/README.md index 46fd73d61630a78075b8c276a14cdac42681b66c..59938192ad39944424a8c727d50cf197e7614849 100644 --- a/lab5/src/maps/README.md +++ b/lab5/src/maps/README.md @@ -1,9 +1,9 @@ # Maps -A map is represented by a 21x21 pixel image. +A map is represented by a 21x21 pixel image in '.png'. Each pixel may represent a different element dependindg on its color in RGB * Walls : blue pixels `0x0000FF` -* Path : black pixels `0x000000` -* Food/Score : green pixels `0x00ff00` +* Path : black pixels `0x000000`. The path may also be represented by Food, Special food, Pac man spanw zone, Enemies spwan zone +* Food : green pixels `0x00ff00` * Special food : white pixels `0xffffff` -* Pac man : yellow pixel `0xffff00` +* Pac man spanw zone : yellow pixel `0xffff00` * Enemies spwan zone : red pixels `0xff0000` \ No newline at end of file diff --git a/lab5/src/static/js/Enemy.js b/lab5/src/static/js/Enemy.js new file mode 100644 index 0000000000000000000000000000000000000000..19b87b231e1c77549eec158ba3f0be0a4f540894 --- /dev/null +++ b/lab5/src/static/js/Enemy.js @@ -0,0 +1,73 @@ +class Enemy { + constructor(obj) { + this.object = obj; + this.direction = DIRECTION.NONE; + this.newDirection = DIRECTION.NONE; + + } + + move(path){ + let { x, y } = MOVEMENT[this.direction]; + this.object.position.x += x; + this.object.position.y += y; + + + var posX = this.object.position.x; + var posY = this.object.position.y; + + + // check for edge -> loop + if(posX > SIZE /2 | posX < SIZE /2 * (-1)){ + this.object.position.x *= -1; + } + if(posY > SIZE /2 | posY < SIZE /2 * (-1)){ + this.object.position.y *= -1; + } + + //autoriser les movement uniquement lorsque la position x et y est très proche de nombre entier + if((Math.abs(posX) % 1 < 0.05 | Math.abs(posX) % 1 > 0.95) + & (Math.abs(posY) % 1 < 0.05 | Math.abs(posY) % 1 > 0.95)) { + + + + // postion to coordinates + let x = Math.round(posX + SIZE/2 - 0.5); + let y = (Math.round(posY - SIZE/2 - 0.5) * -1) -1; + + // check if direction can be changed according to path + + var nextBox; + // check collision with wall + switch(this.direction){ + case DIRECTION.DOWN: + nextBox = path[(y+1)%SIZE][x]; + break; + case DIRECTION.UP: + nextBox = path[(y-1)%SIZE][x]; + break; + case DIRECTION.LEFT: + nextBox = path[y][(x-1)%SIZE]; + break; + case DIRECTION.RIGHT: + nextBox = path[y][(x+1)%SIZE] + break; + + } + if (nextBox == 0){ + //change direction + this.direction = DIRECTION.NONE; + } + } + } + + setDirection(dir){ + // postion to coordinates + this.newDirection = dir; + //this.direction = dir; + } + + getDirection(){ + return this.direction; + } + +} \ No newline at end of file diff --git a/lab5/src/static/js/GameManager.js b/lab5/src/static/js/GameManager.js index cf3f1a47a1bbecc174c32d5ee40154c2c6c441b8..ae8b79350e0cf39389c37f4206aa41f63670d95e 100644 --- a/lab5/src/static/js/GameManager.js +++ b/lab5/src/static/js/GameManager.js @@ -31,8 +31,11 @@ var player; var enemies = []; var foods = [] var walls = []; +var plane; var mapGenerator var score = 0; +var enemies_spawns =[] +const MAX_ENEMIES = 4; const SIZE = 21 @@ -44,45 +47,77 @@ function main() { // init scene scene = new THREE.Scene(); scene.background = new THREE.Color( 0x3f3f3f ); - camera = new THREE.PerspectiveCamera(85, window.innerWidth / window.innerHeight, 0.1, 1000); + renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); - - //create objects - var plane; - scene.add(camera); - [plane, walls, foods, playerObj, path] = mapGenerator.generateMap(1, scene); - - // get all wall object from scene - + camera = new THREE.PerspectiveCamera(85, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.z = 12; camera.position.x = 0; /*camera.position.y = -10; camera.rotation.x = 0.5;*/ + scene.add(camera); + // Modal management + /*var span = document.getElementsByClassName("close")[0]; + var modal = document.getElementById("myModal"); + span.onclick = function() { + modal.style.display = "none"; + } + + window.onclick = function(event) { + if (event.target == modal) { + modal.style.display = "none"; + } + }*/ + + //create objects + - // player - player = new Player(playerObj); + LoadMap('map1'); + // spawn enemey + for (let i = 0; i < MAX_ENEMIES; i++) { + spawnEnemy(); + } - function render(){ + //getListofMaps(); + + function render(){ //checkCollision(); player.move(path); + + enemies.forEach(enemy => { + enemy.move(path); + }); requestAnimationFrame(render); renderer.render(scene, camera); - } render(); +} - const times = []; - let fps; +function spawnEnemy(){ + var geometry = new THREE.SphereGeometry(0.4); + var material = new THREE.MeshBasicMaterial( {color: 0xff0000} ); + var enemy = new THREE.Mesh( geometry, material ); + var i = Math.floor(Math.random() * enemies_spawns.length); + let {x,y} = enemies_spawns[i]; + enemy.position.x = x; + enemy.position.y = y; + scene.add(enemy); + enemies.push(new Enemy(enemy)); +} + +function LoadMap(id){ + [plane, walls, foods, playerObj, path, enemies_spawns] = mapGenerator.generateMap(id, scene); + player = new Player(playerObj); } +// check player collision with food/specail food and enemies function checkCollision() { var playerObj = scene.getObjectByName("Player"); @@ -97,14 +132,11 @@ function checkCollision() { var directionVector = globalVertex.sub(playerObj.position); // check collision with walls - var ray = new THREE.Raycaster(originPointFastForward, directionVector.clone().normalize()); + /*var ray = new THREE.Raycaster(originPointFastForward, directionVector.clone().normalize()); var collisionResults = ray.intersectObjects(walls); if (collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) { player.setDirection(DIRECTION.NONE); - - /*collisionResults[0].object.material.transparent = true; - collisionResults[0].object.material.opacity = 0.4;*/ - } + }*/ ray = new THREE.Raycaster(originPoint, directionVector.clone().normalize()); collisionResults = ray.intersectObjects(enemies); @@ -116,10 +148,11 @@ function checkCollision() { collisionResults[0].object.material.opacity = 0.4;*/ } - /*collisionResults = ray.intersectObjects(foods); + collisionResults = ray.intersectObjects(foods); if (collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) { + console.log("Miam"); score++; - }*/ + } } } @@ -130,3 +163,31 @@ window.addEventListener("keydown", function (event) { player.setDirection(KEYS[event.code]); }); + +/*function getListofMaps(){ + // send synchronous request + var request = new XMLHttpRequest(); + //request.overrideMimeType("application/json"); + request.open('GET', '/get/maps/', false); // `false` makes the request synchronous + request.send(null); + + if (request.status === 200) { + document.getElementById("myModal").style.display = "block"; + var mapsData = JSON.parse(request.responseText); + console.log(mapsData); + mapsData.forEach(array => { + var img = document.createElement("img"); + img.src = array[1]; + //img.width = width; + //img.height = height; + //img.alt = alt; + document.getElementById("form").appendChild(img); + + }); + + + }else { + alert(request.responseText); + } +}*/ + diff --git a/lab5/src/static/js/MapGenerator.js b/lab5/src/static/js/MapGenerator.js index 2e1a991328bea744e5c1469eb0de9297a15dead5..6bcc8629bf82367f504d42fd90c572066bd4642c 100644 --- a/lab5/src/static/js/MapGenerator.js +++ b/lab5/src/static/js/MapGenerator.js @@ -4,11 +4,7 @@ function convert2Dto1D(x, y, sz){ class MapGenerator { - constructor() { - //SIZE = 21; - } - - //// 2 dimension coordinates to 1 dimension + constructor() {} generateMap(id, scene) { @@ -17,6 +13,7 @@ class MapGenerator { var walls = []; var foods = []; var path = []; + var enemies_spawn = []; var player; var map_content = []; @@ -58,19 +55,19 @@ class MapGenerator { wallPosX = x; wallPosY = y; - path[y].push(0); + path[y].push(0); //define path map_content[i] = 'WALL_DONE' ; //prevent from creating 2 walls at the same spot // check for a horizontal line of wall - while (map_content[convert2Dto1D(x + offsetX, y,SIZE)] == 'WALL' & x + offsetX < SIZE){ + while (map_content[convert2Dto1D(x + offsetX, y,SIZE)] == 'WALL' & (x + offsetX) < SIZE){ map_content[convert2Dto1D(x + offsetX, y,SIZE)] = 'WALL_DONE'; wallWidth++; offsetX++; } //check for a vertical line of wall only if it was not a horizonatl wall - while (wallWidth <= 1 & map_content[convert2Dto1D(x, y + offsetY,SIZE)] == 'WALL' & y + offsetY < SIZE){ + while (wallWidth <= 1 & map_content[convert2Dto1D(x, y + offsetY,SIZE)] == 'WALL' & (y + offsetY) < SIZE){ map_content[convert2Dto1D(x, y + offsetY,SIZE)] = 'WALL_DONE'; wallHeight++; offsetY++; @@ -98,10 +95,11 @@ class MapGenerator { scene.add(food); foods.push(food); - path[y].push(1); + path[y].push(1); //define path break; case "S_FOOD": + // special foo object spawn var geometry = new THREE.SphereGeometry(0.2); var material = new THREE.MeshBasicMaterial( {color: 0x00ff00} ); var food = new THREE.Mesh( geometry, material ); @@ -109,7 +107,7 @@ class MapGenerator { food.position.y = -y + (SIZE - 1)/2; scene.add(food); foods.push(food); - path[y].push(1); + path[y].push(1); //define path break; case "": @@ -117,20 +115,23 @@ class MapGenerator { break; case "SPAWN_E": + var spawnX = (-x + (SIZE - 1)/2); + var spawnY = (-y + (SIZE - 1)/2); + enemies_spawn.push({"x":spawnX, "y": spawnY}); path[y].push(1); break; case "SPAWN_P": + // Player spawn zone var geometry = new THREE.SphereGeometry(0.4); var material = new THREE.MeshBasicMaterial( {color: 0xffff00} ); player = new THREE.Mesh( geometry, material ); - player.position.x = -x + (SIZE - 1)/2; + player.position.x = -x + (SIZE - 1)/2; player.position.y = -y + (SIZE - 1)/2; player.name = "Player"; scene.add(player); - console.log(x, y); - path[y].push(1); + path[y].push(1); //define path break; case "WALL_DONE": @@ -140,8 +141,7 @@ class MapGenerator { } } } - console.log(path); - return [plane, walls, foods, player, path]; + return [plane, walls, foods, player, path, enemies_spawn]; } } \ No newline at end of file diff --git a/lab5/src/templates/index.html b/lab5/src/templates/index.html index 9920e5565f333c963ee7b57707bf284bacae7c24..50f709deb700e90bfd670237531baa3610d2ab7c 100644 --- a/lab5/src/templates/index.html +++ b/lab5/src/templates/index.html @@ -7,8 +7,45 @@ <style type="text/css"> body { margin: 0; } canvas { width: 100%; height: 100% } + .modal { + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 1; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ + } + + /* Modal Content/Box */ + .modal-content { + background-color: #fefefe; + margin: 15% auto; /* 15% from the top and centered */ + padding: 20px; + border: 1px solid #888; + width: 80%; /* Could be more or less, depending on screen size */ + } + + /* The Close Button */ + .close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; + } + + .close:hover, + .close:focus { + color: black; + text-decoration: none; + cursor: pointer; + } </style> <script src="{{ url_for('static', filename="js/Player.js")}}"></script> + <script src="{{ url_for('static', filename="js/Enemy.js")}}"></script> <script src="{{ url_for('static', filename="js/MapGenerator.js")}}"></script> <script src="{{ url_for('static', filename="js/GameManager.js")}}"></script> <script src="{{ url_for('static', filename="js/lib/three.js")}}"></script> @@ -16,7 +53,17 @@ </head> <body onload="main()"> <div id="main"> + </div> + + <!--<div id="myModal" class="modal"> + <div class="modal-content"> + <span class="close">×</span> + <p>Choose the map you want to play..</p> + <div id="form"> + </div> + </div> + </div>--> </body> </html> \ No newline at end of file