diff --git a/docker-compose/requirements/djangoserver/file/server/server/Ball.py b/docker-compose/requirements/djangoserver/file/server/server/Ball.py new file mode 100644 index 0000000..5cf83b9 --- /dev/null +++ b/docker-compose/requirements/djangoserver/file/server/server/Ball.py @@ -0,0 +1,195 @@ +# **************************************************************************** # +# # +# ::: :::::::: # +# Ball.py :+: :+: :+: # +# +:+ +:+ +:+ # +# By: tomoron +#+ +:+ +#+ # +# +#+#+#+#+#+ +#+ # +# Created: 2024/10/06 03:24:10 by tomoron #+# #+# # +# Updated: 2024/10/06 17:22:46 by tomoron ### ########.fr # +# # +# **************************************************************************** # + +from .GameSettings import GameSettings +import random +import math + +class Ball: + def __init__(self): + self.default() + self.obstacles = [] + + def setStartVel(self, inv): + self.speed = GameSettings.startSpeed + self.vel[0] = self.speed * (random.randint(-50, 50) / 100) + self.vel[1] = self.speed - abs(self.vel[0]) + if(inv == 2): + self.vel[1] = -self.vel[1] + + def default(self): + self.pos = [0, 0] + self.up = False + self.vel = [0, 0] + self.speed = GameSettings.startSpeed + + def setObstacles(self, obstacles): + self.obstacles = obstacles + + def solve_quadratic(self, a, b, c): + disc = (b ** 2) - (4 * a * c) + if(disc < 0): + return None + res = (((-b) + math.sqrt(disc)) / ( 2 * a )) + (((-b) - math.sqrt(disc)) / ( 2 * a )) + return(res / 2) + + def check_jumper_colision(self, jumper): + jpos = (jumper["pos"]["x"], jumper["pos"]["z"]) + pos1 = self.pos + pos2 = self.pos[0] + self.vel[0], self.pos[1] + self.vel[1] + slope = 0 + if(pos1[0] - pos2[0] == 0): + slope=100 + else: + slope = (pos1[1] - pos2[1])/(pos1[0] - pos2[0]) + offset = pos1[1] - (slope * pos1[0]) + + #salagadou la menchikabou la bibidi bobidi bou + a = 1 + (slope ** 2) + b = ((-jpos[0]) * 2) + (2 * (slope * (-jpos[1] + offset))) + c = (((-jpos[0]) ** 2) + (((-jpos[1]) + offset) ** 2)) - (GameSettings.jumperRadius ** 2) + return(self.solve_quadratic(a, b ,c)) + + def check_wall_colision(self, wall): + wpos = wall["pos"]["x"] + pos1 = self.pos + pos2 = self.pos[0] +self.vel[0], self.pos[1] + self.vel[1] + slope = 0 + if(abs(pos1[1]) <= (GameSettings.wallWidth / 2) + GameSettings.ballRadius): + print("inside") + return(None) + if(pos1[0] - pos2[0] == 0): + slope=100 + else: + slope = (pos1[1] - pos2[1])/(pos1[0] - pos2[0]) + offset = pos1[1] - (slope * pos1[0]) + + if(slope == 0): + return(None) + + wallSide = (GameSettings.wallWidth / 2) + GameSettings.ballRadius + if(pos1[1] < 0): + wallSide *= -1 + hitPos = (wallSide - offset) / slope + print(f'{hitPos=}') + relPos = wpos - hitPos + print("relative position : ", relPos) + print("max colision : ", (GameSettings.wallLength / 2) + GameSettings.ballRadius) + if(abs(relPos) < (GameSettings.wallLength / 2) + GameSettings.ballRadius): + return(hitPos) + print("not in wall 1") + return(None) + + def check_collision_obstacles(self): + min_time = -1 + for x in self.obstacles: + if x["isUp"] != self.up: + continue + pos = None + if x["type"] == 1: + pos = self.check_jumper_colision(x) + elif x["type"] == 2: + pos = self.check_wall_colision(x) + if(pos == None): + continue + dist = pos - self.pos[0] + time = 0 + if(self.vel[0] != 0): + time = dist / self.vel[0] + else: + time = -1 + if(time > 0): + if(min_time == -1): + min_time = time + else: + min_time = (min(min_time, time)) + return(min_time) + + def getTimeUntilColision(self, limitNeg, limitPos, position, velocity): + if(not velocity): + return(-1) + limit = GameSettings.limits[limitNeg] if velocity < 0 else GameSettings.limits[limitPos] + wallDistance = max(limit, position) - min(limit, position) + colision_time = wallDistance / abs(velocity) + return(colision_time) + + def getSleepTime(self): + time_x = self.getTimeUntilColision("left","right", self.pos[0], self.vel[0]) + time_z = self.getTimeUntilColision("back","front", self.pos[1], self.vel[1]) + time_objects = self.check_collision_obstacles() + if(time_objects != -1): + time_x = min(time_x, time_objects) + if(time_x == -1): + return(time_z) + if(time_z == -1): + return(time_x) + return(min(time_x, time_z)) + + def getPlayerDistance(self, player, ballPos): + playerPos = player["pos"] + return(playerPos - ballPos[0]) + + def twoPointsDistance(self, pos1, pos2): + return(math.sqrt(((pos2[0] - pos1[0]) ** 2) + ((pos2[1] - pos1[1]) ** 2))) + + def checkJumpersDistance(self, ballPos, p1, p2): + for i in range(0, len(self.obstacles)): + if(self.obstacles[i]["type"] != 1): + continue; + if(self.obstacles[i]["isUp"] != self.up): + continue + if(self.twoPointsDistance((self.obstacles[i]["pos"]["x"], self.obstacles[i]["pos"]["z"]), ballPos) < GameSettings.jumperRadius): + p1.socket.sync_send({"type":"game", "content":{"action":8,"name":self.obstacles[i]["name"]}}) + p2.socket.sync_send({"type":"game", "content":{"action":8,"name":self.obstacles[i]["name"]}}) + self.up = not self.up + + def checkWallsColision(self, ballPos): + for i in range(0, len(self.obstacles)): + if(self.obstacles[i]["type"] != 2): + continue; + if(self.obstacles[i]["isUp"] != self.up): + continue; + if(abs(ballPos[1]) <= (GameSettings.wallWidth / 2) + GameSettings.ballRadius): + if(abs(self.obstacles[i]["pos"]["x"] - ballPos[0]) < (GameSettings.wallLength / 2) + GameSettings.ballRadius): + return(True) + return(False) + + def increaseSpeed(self): + self.vel[0] += (GameSettings.bounceSpeedIncrease * (self.vel[0] / self.speed)) + self.vel[1] += (GameSettings.bounceSpeedIncrease * (self.vel[1] / self.speed)) + self.speed += GameSettings.bounceSpeedIncrease + + async def update(self, delta, p1, p2): + print("AAAAAAAAAAAAAAAAAAAAAAA update") + self.pos[0] += (delta * self.vel[0]) + self.pos[1] += (delta * self.vel[1]) + if(self.pos[1] <= GameSettings.limits["back"] or self.pos[1] >= GameSettings.limits["front"]): + player = p2.pos if self.pos[1] < 0 else p1.pos + playerDistance = self.getPlayerDistance(player, self.pos) + if(playerDistance >= -(GameSettings.playerLength / 2) and playerDistance <= GameSettings.playerLength / 2 and player["up"] == self.up): + self.vel[0] = -((self.speed * 0.80) * (playerDistance / (GameSettings.playerLength / 2))) + self.vel[1] = self.speed - abs(self.vel[0]) + if(self.pos[1] > 0): + self.vel[1] = -self.vel[1] + p1.socket.sync_send({"type":"game","content":{"action":4, "is_opponent": self.pos[1] < 0}}) + p2.socket.sync_send({"type":"game","content":{"action":4, "is_opponent": self.pos[1] > 0}}) + else: + return(1 if self.pos[1] < 0 else 2) + elif(self.pos[0] <= GameSettings.limits["left"] or self.pos[0] >= GameSettings.limits["right"]): + self.vel[0] = -self.vel[0] + elif(self.checkWallsColision(self.pos)): + self.vel[1] = -self.vel[1] + self.checkJumpersDistance(self.pos, p1, p2) + self.increaseSpeed() + return(0) + +#AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa diff --git a/docker-compose/requirements/djangoserver/file/server/server/Game.py b/docker-compose/requirements/djangoserver/file/server/server/Game.py index 5d4a398..4257844 100644 --- a/docker-compose/requirements/djangoserver/file/server/server/Game.py +++ b/docker-compose/requirements/djangoserver/file/server/server/Game.py @@ -6,13 +6,15 @@ # By: edbernar 0): - if(min_time == -1): - min_time = time - else: - min_time = (min(min_time, time)) - return(min_time) - - def getTimeUntilColision(self, limitNeg, limitPos, position, velocity): - if(not velocity): - return(-1) - limit = Game.limits[limitNeg] if velocity < 0 else Game.limits[limitPos] - wallDistance = max(limit, position) - min(limit, position) - colision_time = wallDistance / abs(velocity) - return(colision_time) - - def getSleepTime(self): - time_x = self.getTimeUntilColision("left","right", self.ballPos["pos"][0], self.ballVel[0]) - time_z = self.getTimeUntilColision("back","front", self.ballPos["pos"][1], self.ballVel[1]) - time_objects = self.check_collision_obstacles() - if(time_objects != -1): - time_x = min(time_x, time_objects) - if(time_x == -1): - return(time_z) - if(time_z == -1): - return(time_x) - return(min(time_x, time_z)) - - def getPlayerDistance(self, player, ballPos): - playerPos = player["pos"] - return(playerPos - ballPos[0]) - def checkGameEndGoal(self): - if(self.score[0] < Game.maxScore and self.score[1] < Game.maxScore): + if(self.score[0] < GameSettings.maxScore and self.score[1] < GameSettings.maxScore): return(False) print("someone won the game") - winner = 1 if self.score[0] == Game.maxScore else 2 + winner = 1 if self.score[0] == GameSettings.maxScore else 2 print("player", winner,"won the game") self.endGame(winner) return(True) @@ -352,83 +212,16 @@ class Game: await asyncio.sleep(3) self.prepareGame() return; - - def twoPointsDistance(self, pos1, pos2): - return(math.sqrt(((pos2[0] - pos1[0]) ** 2) + ((pos2[1] - pos1[1]) ** 2))) - def checkJumpersDistance(self, ballPos): - for i in range(0, len(self.obstacles)): - if(self.obstacles[i]["type"] != 1): - continue; - if(self.obstacles[i]["isUp"] != self.ballPos["up"]): - continue - if(self.twoPointsDistance((self.obstacles[i]["pos"]["x"], self.obstacles[i]["pos"]["z"]), ballPos) < Game.jumperRadius): - self.p1.socket.sync_send({"type":"game", "content":{"action":8,"name":self.obstacles[i]["name"]}}) - self.p2.socket.sync_send({"type":"game", "content":{"action":8,"name":self.obstacles[i]["name"]}}) - self.ballPos["up"] = not self.ballPos["up"] - - def checkWallsColision(self, ballPos): - for i in range(0, len(self.obstacles)): - if(self.obstacles[i]["type"] != 2): - continue; - if(self.obstacles[i]["isUp"] != self.ballPos["up"]): - continue; - if(abs(ballPos[1]) <= (Game.wallWidth / 2) + Game.ballRadius): - if(abs(self.obstacles[i]["pos"]["x"] - ballPos[0]) < (Game.wallLength / 2) + Game.ballRadius): - return(True) - return(False) - - def increaseSpeed(self): - x = self.ballVel[0] + (Game.bounceSpeedIncrease * (self.ballVel[0] / self.speed)) - y = self.ballVel[1] + (Game.bounceSpeedIncrease * (self.ballVel[1] / self.speed)) - self.ballVel = (x, y) - self.speed += Game.bounceSpeedIncrease - - async def updateBall(self, delta): - print("AAAAAAAAAAAAAAAAAAAAAAA update") - currentBallPos = self.ballPos["pos"] - velX = self.ballVel[0] - velZ = self.ballVel[1] - newBallPos = (round(currentBallPos[0] + (delta * velX), 5), - round(currentBallPos[1] + (delta * velZ), 5)) - if(newBallPos[1] <= Game.limits["back"] or newBallPos[1] >= Game.limits["front"]): - player = self.p2.pos if newBallPos[1] < 0 else self.p1.pos - playerDistance = self.getPlayerDistance(player, newBallPos) - if(playerDistance >= -(Game.playerLength / 2) and playerDistance <= Game.playerLength / 2 and player["up"] == self.ballPos["up"]): - velX = -((self.speed * 0.80) * (playerDistance / (Game.playerLength / 2))) - velZ = self.speed - abs(velX) - if(newBallPos[1] > 0): - velZ = -velZ - self.p1.socket.sync_send({"type":"game","content":{"action":4, "is_opponent": newBallPos[1] < 0}}) - self.p2.socket.sync_send({"type":"game","content":{"action":4, "is_opponent": newBallPos[1] > 0}}) - else: - await self.scoreGoal(1 if newBallPos[1] < 0 else 2) - return; - elif(newBallPos[0] <= Game.limits["left"] or newBallPos[0] >= Game.limits["right"]): - velX = -velX - elif(self.checkWallsColision(newBallPos)): - velZ = -velZ - self.checkJumpersDistance(newBallPos) - self.ballVel = (velX, velZ) - self.increaseSpeed() - self.lastUpdate = time.time() - self.ballPos["pos"] = newBallPos - self.sendNewBallInfo() - def prepareGame(self, stop = False): - self.speed = Game.startSpeed - self.ballPos = {"pos":(0, 0), "up": False} + self.speed = GameSettings.startSpeed + self.ball.default() if(stop): - self.ballVel = (0, 0) + self.ball.vel = [0, 0] else: - velX = self.speed * (random.randint(-50, 50) / 100) - velZ = self.speed - abs(velX) - if(self.lastWin == 2): - velZ = -velZ - self.ballVel = (velX, velZ) + self.ball.setStartVel(self.lastWin == 2) self.sendNewBallInfo(True) self.gameStart = time.time() - self.lastUpdate = time.time() async def gameLoop(self): self.started = True @@ -437,16 +230,23 @@ class Game: await asyncio.sleep(3) self.prepareGame() while(not self.end): - sleep_time = self.getSleepTime() + sleep_time = self.ball.getSleepTime() print("sleep time : " , sleep_time) if((time.time() - self.gameStart) - self.gameTime < sleep_time): await asyncio.sleep(sleep_time - ((time.time() - self.gameStart) - self.gameTime)) self.gameTime += sleep_time - await self.updateBall(sleep_time) + goal = await self.ball.update(sleep_time, self.p1, self.p2) + if(goal): + await self.scoreGoal(goal) + else: + self.sendNewBallInfo() print("game end") + if(self.p1.socket.game == self): + self.p1.socket.game = None + if(self.p2.socket.game == self): + self.p2.socket.game = None await self.saveResults() - self.p1.socket.game = None - self.p2.socket.game = None + del self @sync_to_async def saveResults(self): diff --git a/docker-compose/requirements/djangoserver/file/server/server/GameSettings.py b/docker-compose/requirements/djangoserver/file/server/server/GameSettings.py new file mode 100644 index 0000000..f94bc4d --- /dev/null +++ b/docker-compose/requirements/djangoserver/file/server/server/GameSettings.py @@ -0,0 +1,54 @@ +# **************************************************************************** # +# # +# ::: :::::::: # +# GameSettings.py :+: :+: :+: # +# +:+ +:+ +:+ # +# By: tomoron +#+ +:+ +#+ # +# +#+#+#+#+#+ +#+ # +# Created: 2024/10/06 16:33:56 by tomoron #+# #+# # +# Updated: 2024/10/06 16:34:24 by tomoron ### ########.fr # +# # +# **************************************************************************** # + +class GameSettings: + ballRadius = 0.15 + playerLength = 1 + (ballRadius * 4) + limits = { + "left" : -3.5 + ballRadius, + "right" : 3.5 - ballRadius, + "back" : -6.25 + ballRadius, + "front" : 6.25 - ballRadius + } + mapLength = 13 + startSpeed = 6 + jumperRadius = 0.2 + wallsPos = [ + { "type":2, "pos": {"x": 1, "y": 0, "z": 1}, "isUp": False}, + { "type":2, "pos": {"x": 1, "y": 0, "z": 1}, "isUp": True}, + { "type":2, "pos": {"x": -1, "y": 0, "z": 1}, "isUp": False}, + { "type":2, "pos": {"x": -1, "y": 0, "z": 1}, "isUp": True} + ] + jumpersPos = [ + { "type":1, "name":"J0", "pos":{"x": -1.5, "y": 0.2, "z":mapLength/4}, "isUp": False }, + { "type":1, "name":"J1", "pos":{"x": -1.5, "y": 3.2, "z": mapLength / 4}, "isUp": True }, + { "type":1, "name":"J2", "pos":{"x": 1.5, "y": 0.2, "z": mapLength / 4}, "isUp": False }, + { "type":1, "name":"J3", "pos":{"x": 1.5, "y": 3.2, "z": mapLength / 4}, "isUp": True }, + { "type":1, "name":"J4", "pos":{"x": -1.5, "y": 0.2, "z": -mapLength / 4}, "isUp": False }, + { "type":1, "name":"J5", "pos":{"x": -1.5, "y": 3.2, "z": -mapLength / 4}, "isUp": True }, + { "type":1, "name":"J6", "pos":{"x": 1.5, "y": 0.2, "z": -mapLength / 4}, "isUp": False }, + { "type":1, "name":"J7", "pos":{"x": 1.5, "y": 3.2, "z": -mapLength / 4}, "isUp": True } + ] + skins = [ + {id: 0, 'color': 0xff53aa, 'texture': None}, + {id: 1, 'color': 0xaa24ea, 'texture': None}, + {id: 2, 'color': 0x2c9c49, 'texture': None}, + {id: 3, 'color': 0x101099, 'texture': None}, + {id: 4, 'color': None, 'texture': '/static/img/skin/1.jpg'}, + {id: 5, 'color': None, 'texture': '/static/img/skin/2.jpg'}, + {id: 6, 'color': None, 'texture': '/static/img/skin/3.jpg'}, + {id: 7, 'color': None, 'texture': '/static/img/skin/4.jpg'}, + ] + wallLength = 1 + wallWidth = 0.05 + bounceSpeedIncrease = 0.2 + maxScore = 5 diff --git a/docker-compose/requirements/djangoserver/file/server/server/Player.py b/docker-compose/requirements/djangoserver/file/server/server/Player.py index 6aa4cbd..13a4a3c 100644 --- a/docker-compose/requirements/djangoserver/file/server/server/Player.py +++ b/docker-compose/requirements/djangoserver/file/server/server/Player.py @@ -6,13 +6,17 @@ # By: tomoron +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2024/10/05 03:22:32 by tomoron #+# #+# # -# Updated: 2024/10/05 03:46:24 by tomoron ### ########.fr # +# Updated: 2024/10/06 16:16:26 by tomoron ### ########.fr # # # # **************************************************************************** # class Player(): - def __init__(self): - self.socket = None + def __init__(self, socket, game): + self.socket = socket + socket.game = game self.ready = False self.pos = {"pos":0, "up": False} self.skin = 0 + + def __del__(self): + print("player destroy") diff --git a/docker-compose/requirements/djangoserver/file/server/server/typeRequests/gameActions/start.py b/docker-compose/requirements/djangoserver/file/server/server/typeRequests/gameActions/start.py index 5ede8fc..8c42b73 100644 --- a/docker-compose/requirements/djangoserver/file/server/server/typeRequests/gameActions/start.py +++ b/docker-compose/requirements/djangoserver/file/server/server/typeRequests/gameActions/start.py @@ -6,11 +6,12 @@ # By: edbernar = len(Game.skins)): + if(skinId < 0 or skinId >= len(GameSettings.skins)): socket.sendError("Skin id out of range", 9033) return; Game(socket, content.get("with_bot", False),skinId ,opponent) diff --git a/docker-compose/requirements/djangoserver/file/server/server/websocket.py b/docker-compose/requirements/djangoserver/file/server/server/websocket.py index 5351cac..b7dede3 100644 --- a/docker-compose/requirements/djangoserver/file/server/server/websocket.py +++ b/docker-compose/requirements/djangoserver/file/server/server/websocket.py @@ -6,7 +6,7 @@ # By: edbernar