added a BOT player, and some fixes in the game logic

This commit is contained in:
CHIBOUB Chakib 2024-07-24 22:29:48 +02:00
parent 63ee8bc75b
commit e7797eac2c
4 changed files with 78 additions and 37 deletions

View File

View File

@ -2,7 +2,7 @@ COMPOSE_FILE=docker-compose.yaml
COMPOSE=docker compose -f $(COMPOSE_FILE) COMPOSE=docker compose -f $(COMPOSE_FILE)
CONTAINER=$(c) CONTAINER=$(c)
up: up: down
sudo mkdir -p data/db sudo mkdir -p data/db
$(COMPOSE) build $(COMPOSE) build
$(COMPOSE) up $(CONTAINER) $(COMPOSE) up $(CONTAINER)

View File

@ -9,9 +9,10 @@ class Game:
self.game_id = game_id self.game_id = game_id
self.player1 = player1 self.player1 = player1
self.player2 = player2 self.player2 = player2
self.botgame = player2 is None
self.game_state = { self.game_state = {
'player1_name': player1.user.username, 'player1_name': player1.user.username,
'player2_name': player2.user.username, 'player2_name': player2.user.username if player2 else 'BOT',
'player1_position': 150, 'player1_position': 150,
'player2_position': 150, 'player2_position': 150,
'ball_position': {'x': 390, 'y': 190}, 'ball_position': {'x': 390, 'y': 190},
@ -28,37 +29,49 @@ class Game:
async def game_loop(self): async def game_loop(self):
while True: while True:
if self.botgame:
await self.update_bot_position()
self.update_game_state() self.update_game_state()
await self.send_game_state() await self.send_game_state()
await asyncio.sleep(1/60) # 60 FPS await asyncio.sleep(1/60) # Around 60 FPS
# The amazing AI BOT player
async def update_bot_position(self):
target_y = self.game_state['ball_position']['y']
if self.game_state['player2_position'] < target_y < self.game_state['player2_position'] + 80:
pass
elif self.game_state['player2_position'] < target_y:
self.game_state['player2_position'] = min(self.game_state['player2_position'] + (5 * self.speed), 300)
elif self.game_state['player2_position'] + 80 > target_y:
self.game_state['player2_position'] = max(self.game_state['player2_position'] - (5 * self.speed), 0)
def update_game_state(self): def update_game_state(self):
# Update ball position # Update ball position
self.game_state['ball_position']['x'] += self.game_state['ball_velocity']['x'] self.game_state['ball_position']['x'] += self.game_state['ball_velocity']['x']
self.game_state['ball_position']['y'] += self.game_state['ball_velocity']['y'] self.game_state['ball_position']['y'] += self.game_state['ball_velocity']['y']
# Check for collisions with top and bottom walls # Check for collisions with top and bottom walls
if self.game_state['ball_position']['y'] <= 10 or self.game_state['ball_position']['y'] >= 390: if self.game_state['ball_position']['y'] <= 10 or self.game_state['ball_position']['y'] >= 390:
self.game_state['ball_velocity']['y'] *= -1 self.game_state['ball_velocity']['y'] *= -1
# Check for collisions with paddles
if self.game_state['ball_position']['x'] <= 20 and \
self.game_state['player1_position'] - 10 <= self.game_state['ball_position']['y'] <= self.game_state['player1_position'] + 90:
if self.game_state['ball_velocity']['x'] < 0:
self.game_state['ball_velocity']['x'] *= -1
self.update_ball_velocity()
elif self.game_state['ball_position']['x'] >= 760 and \
self.game_state['player2_position'] - 10 <= self.game_state['ball_position']['y'] <= self.game_state['player2_position'] + 90:
if self.game_state['ball_velocity']['x'] > 0:
self.game_state['ball_velocity']['x'] *= -1
self.update_ball_velocity()
# Check for scoring # Check for scoring
if self.game_state['ball_position']['x'] <= 10: if self.game_state['ball_position']['x'] <= 10:
self.game_state['player2_score'] += 1 self.game_state['player2_score'] += 1
self.reset_ball() self.reset_ball()
elif self.game_state['ball_position']['x'] >= 790: elif self.game_state['ball_position']['x'] >= 790:
self.game_state['player1_score'] += 1 self.game_state['player1_score'] += 1
print(f"*** Ball in position ({self.game_state['ball_position']['x']},{self.game_state['ball_position']['y']}) with a speed ratio of {self.speed}")
self.reset_ball() self.reset_ball()
# Check for collisions with paddles
if self.game_state['ball_position']['x'] <= 20 and \
self.game_state['player1_position'] <= self.game_state['ball_position']['y'] <= self.game_state['player1_position'] + 80:
self.update_ball_velocity()
self.game_state['ball_velocity']['x'] *= -1
elif self.game_state['ball_position']['x'] >= 760 and \
self.game_state['player2_position'] <= self.game_state['ball_position']['y'] <= self.game_state['player2_position'] + 80:
self.update_ball_velocity()
self.game_state['ball_velocity']['x'] *= -1
def reset_ball(self): def reset_ball(self):
self.game_state['ball_position'] = {'x': 390, 'y': 190} self.game_state['ball_position'] = {'x': 390, 'y': 190}
self.game_state['ball_velocity'] = {'x': random.choice([-5, 5]), 'y': random.choice([-5, 5])} self.game_state['ball_velocity'] = {'x': random.choice([-5, 5]), 'y': random.choice([-5, 5])}
@ -68,8 +81,6 @@ class Game:
self.speed += 0.05 self.speed += 0.05
if self.speed > 2: if self.speed > 2:
self.speed = 2 self.speed = 2
else:
print(f"Ball velocity: {self.speed}")
self.game_state['ball_velocity']['x'] *= self.speed self.game_state['ball_velocity']['x'] *= self.speed
if self.game_state['ball_velocity']['x'] < -10: if self.game_state['ball_velocity']['x'] < -10:
self.game_state['ball_velocity']['x'] = -10 self.game_state['ball_velocity']['x'] = -10
@ -87,7 +98,8 @@ class Game:
'game_state': self.game_state 'game_state': self.game_state
}) })
await self.player1.send(message) await self.player1.send(message)
await self.player2.send(message) if not self.botgame:
await self.player2.send(message)
async def handle_key_press(self, player, key): async def handle_key_press(self, player, key):
if player == self.player1: if player == self.player1:
@ -99,7 +111,7 @@ class Game:
self.game_state['player1_position'] += 25 self.game_state['player1_position'] += 25
if self.game_state['player1_position'] > 300: if self.game_state['player1_position'] > 300:
self.game_state['player1_position'] = 300 self.game_state['player1_position'] = 300
elif player == self.player2: elif not self.botgame and player == self.player2:
if key == 'arrowup': if key == 'arrowup':
self.game_state['player2_position'] -= 25 self.game_state['player2_position'] -= 25
if self.game_state['player2_position'] < 0: if self.game_state['player2_position'] < 0:

View File

@ -9,6 +9,8 @@ class MatchMaker:
self.waiting_players = [] self.waiting_players = []
self.active_games = {} self.active_games = {}
self.matching_task = None self.matching_task = None
self.timer = 0
self.botgame = False
async def add_player(self, player): async def add_player(self, player):
if player not in self.waiting_players: if player not in self.waiting_players:
@ -27,10 +29,17 @@ class MatchMaker:
player1 = self.waiting_players.pop(0) player1 = self.waiting_players.pop(0)
player2 = self.waiting_players.pop(0) player2 = self.waiting_players.pop(0)
print(f"MATCH FOUND: {player1.user.username} vs {player2.user.username}") print(f"MATCH FOUND: {player1.user.username} vs {player2.user.username}")
game_id = await self.create_game(player1, player2) await self.create_game(player1, player2)
else: else:
# No players to match, wait for a short time before checking again
await asyncio.sleep(1) await asyncio.sleep(1)
self.timer += 1
# Waiting for more than 30s -> BOT game
if self.timer >= 30:
player1 = self.waiting_players.pop(0)
print(f"MATCH FOUND: {player1.user.username} vs BOT")
self.botgame = True
self.timer = 0
await self.create_bot_game(player1)
async def create_game(self, player1, player2): async def create_game(self, player1, player2):
game_id = len(self.active_games) + 1 game_id = len(self.active_games) + 1
@ -39,25 +48,45 @@ class MatchMaker:
self.active_games[game_id] = new_game self.active_games[game_id] = new_game
await self.notify_players(player1, player2, game_id) await self.notify_players(player1, player2, game_id)
asyncio.create_task(new_game.start_game()) asyncio.create_task(new_game.start_game())
return game_id
async def create_bot_game(self, player1):
game_id = len(self.active_games) + 1
print(f"- Creating BOT game: {game_id}")
new_game = Game(game_id, player1, None)
self.active_games[game_id] = new_game
await self.notify_players(player1, None, game_id)
asyncio.create_task(new_game.start_game())
async def notify_players(self, player1, player2, game_id): async def notify_players(self, player1, player2, game_id):
await player1.send(json.dumps({ if player2:
'type': 'game_start', await player1.send(json.dumps({
'game_id': game_id, 'type': 'game_start',
'player1': player1.user.username, 'game_id': game_id,
'player2': player2.user.username 'player1': player1.user.username,
})) 'player2': player2.user.username
await player2.send(json.dumps({ }))
'type': 'game_start', await player2.send(json.dumps({
'game_id': game_id, 'type': 'game_start',
'player1': player1.user.username, 'game_id': game_id,
'player2': player2.user.username 'player1': player1.user.username,
})) 'player2': player2.user.username
}))
else:
await player1.send(json.dumps({
'type': 'game_start',
'game_id': game_id,
'player1': player1.user.username,
'player2': 'BOT'
}))
async def handle_key_press(self, player, key): async def handle_key_press(self, player, key):
for game in self.active_games.values(): for game in self.active_games.values():
if player in [game.player1, game.player2]: if not self.botgame:
if player in [game.player1, game.player2]:
await game.handle_key_press(player, key)
break
else:
await game.handle_key_press(player, key) await game.handle_key_press(player, key)
break break