game.py 5.03 KB
Newer Older
1 2 3 4 5 6 7 8
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Apr 18 18:34:40 2018

@author: Antoine Lima, Leo Reynaert, Domitille Jehenne
"""

9
import os
10 11
import logging

12 13
from PyQt5 import QtWidgets
from PyQt5.QtGui import QRegion
Antoine Lima's avatar
Antoine Lima committed
14 15 16
from PyQt5.QtCore import QTime, QTimer, QRect, Qt, QUrl
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget
17

18
from player import Side, PlayerGuest
19
from replay import Replay
20
from module import Module
Antoine Lima's avatar
Antoine Lima committed
21
from settings import Settings
22 23 24
import modules
from ui.game_ui import Ui_Form as GameWidget

Antoine Lima's avatar
Antoine Lima committed
25 26 27 28
class GameOverChecker():
	def __init__(self, conditionType, limit):
		self.conditionType = conditionType
		self.limit = limit
Antoine Lima's avatar
Antoine Lima committed
29

Antoine Lima's avatar
Antoine Lima committed
30 31 32
	def check(self, time, scores):
		'''
		Checks if a game is over and return the winner if that's the case
33
		Returns the winning side or Side.Undef otherwise
Antoine Lima's avatar
Antoine Lima committed
34

Antoine Lima's avatar
Antoine Lima committed
35 36
		Takes the game time is seconds and a list containing the two scores
		'''
Antoine Lima's avatar
Antoine Lima committed
37 38

		# Gets the index of the highest scoring player
39
		bestPlayer = max(scores, key=scores.get)
Antoine Lima's avatar
Antoine Lima committed
40

Antoine Lima's avatar
Antoine Lima committed
41 42 43 44 45
		if self.conditionType=='score' and scores[bestPlayer]>=self.limit:
			return bestPlayer
		elif self.conditionType=='time' and time>self.limit:
			return bestPlayer
		else:
46
			return Side.Undef
Antoine Lima's avatar
Antoine Lima committed
47

48 49 50 51 52 53 54 55 56
class GameModule(Module):
	def __init__(self, parent=None):
		super().__init__(parent, GameWidget())

		# Timer managment
		self.timerUpdateChrono = QTimer(self)
		self.timerUpdateChrono.timeout.connect(self.updateChrono)

		# Button connections
57 58
		self.ui.btnScore1.clicked.connect(lambda: self.goal(Side.Left))
		self.ui.btnScore2.clicked.connect(lambda: self.goal(Side.Right))
Antoine Lima's avatar
Antoine Lima committed
59

60 61 62 63 64
	def load(self):
		logging.debug('Loading GameModule')

		self.gameStartTime = QTime.currentTime()
		self.timerUpdateChrono.start(1000)
65
		self.ui.lcdChrono.display(QTime(0,0).toString("hh:mm:ss"))
Antoine Lima's avatar
Antoine Lima committed
66

67
		self.showingReplay = False
Antoine Lima's avatar
Antoine Lima committed
68
		self.replayer.start_recording()
Antoine Lima's avatar
Antoine Lima committed
69
		self.gameoverChecker = GameOverChecker('score', 10)
Antoine Lima's avatar
Antoine Lima committed
70

71 72 73
		if all([len(val)==0 for val in self.players.values()]):
			self.players[Side.Left ].append(PlayerGuest)
			self.players[Side.Right].append(PlayerGuest)
74

75
		self.scores = {Side.Left: 0, Side.Right: 0}
76
		self.updateScores()
77 78 79 80 81

	def unload(self):
		logging.debug('Unloading GameModule')
		del self.gameStartTime
		self.timerUpdateChrono.stop()
Antoine Lima's avatar
Antoine Lima committed
82 83
		self.replayer.stop_recording()

84 85
	def other(self, **kwargs):
		logging.debug('Other GameModule')
Antoine Lima's avatar
Antoine Lima committed
86

87 88 89
		for key, val in kwargs.items():
			if key=='goal' and 'source' in kwargs:
				self.goal(kwargs['source'])
Antoine Lima's avatar
Antoine Lima committed
90

91 92
			elif key=='players':
				self.players = val
Antoine Lima's avatar
Antoine Lima committed
93

94 95 96 97
			elif key=='replayThread':
				self.replayer = val
                            

98 99
	def resizeEvent(self, event):
		# 40% of the window width to have (5% margin)-(40% circle)-(10% middle)-(40% circle)-(5% margin)
Antoine Lima's avatar
Antoine Lima committed
100
		btnDiameter = self.mainwin.width()*0.4
101 102 103 104 105
		region = QRegion(QRect(0, 0, btnDiameter, btnDiameter), QRegion.Ellipse)
		self.ui.btnScore1.setMinimumSize(btnDiameter, btnDiameter)
		self.ui.btnScore2.setMinimumSize(btnDiameter, btnDiameter)
		self.ui.btnScore1.setMask(region)
		self.ui.btnScore2.setMask(region)
Antoine Lima's avatar
Antoine Lima committed
106

107 108 109 110
		QtWidgets.QWidget.resizeEvent(self, event)

	def keyPressEvent(self, e):
		if e.key() == Qt.Key_Escape:
111
			self.handleCancel()
112
		elif e.key() == Qt.Key_Left:
113
			self.goal(Side.Left)
114
		elif e.key() == Qt.Key_Right:
115
			self.goal(Side.Right)
116 117 118

	def updateChrono(self):
		# Updated each second
Antoine Lima's avatar
Antoine Lima committed
119
		self.ui.lcdChrono.display(QTime(0,0).addSecs(self.getGameTime()).toString("hh:mm:ss"))
Antoine Lima's avatar
Antoine Lima committed
120 121

		# Don't check scores while showing a replay to avoid closing the engame screen too soon
Antoine Lima's avatar
Antoine Lima committed
122 123
		if not self.showingReplay:
			self.checkEndGame()
124

Antoine Lima's avatar
Antoine Lima committed
125 126
	def getGameTime(self):
		return self.gameStartTime.secsTo(QTime.currentTime())
Antoine Lima's avatar
Antoine Lima committed
127

128
	def updateScores(self):
129 130
		self.ui.btnScore1.setText(str(self.scores[Side.Left]))
		self.ui.btnScore2.setText(str(self.scores[Side.Right]))
Antoine Lima's avatar
Antoine Lima committed
131
		self.checkEndGame()
Antoine Lima's avatar
Antoine Lima committed
132

Antoine Lima's avatar
Antoine Lima committed
133
	def goal(self, side):
134
		if side not in Side:
Antoine Lima's avatar
Antoine Lima committed
135 136 137
			logging.error('Wrong goal side: {}'.format(side))
		else:
			self.scores[side] += 1
Antoine Lima's avatar
Antoine Lima committed
138

Antoine Lima's avatar
Antoine Lima committed
139 140
			# Show replay
			# May require `sudo apt-get install qtmultimedia5-examples` in order to install the right libraries
Antoine Lima's avatar
Antoine Lima committed
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155

			replayFile = self.replayer.stop_recording()

			if not (Settings['replay.show'] and os.path.exists(replayFile)):
				self.updateScores()
			else:
				self.showingReplay = True
				self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
				self.player.stateChanged.connect(self.endOfReplay)
				self.player.setMuted(True)
				self.player.setVideoOutput(self.ui.videoWidget)
				self.player.setMedia(QMediaContent(QUrl.fromLocalFile(replayFile)))
				self.player.play()
				self.ui.videoWidget.setFullScreen(True)

Antoine Lima's avatar
Antoine Lima committed
156 157 158 159 160
	def endOfReplay(self, status):
		if status!=QMediaPlayer.PlayingState:
			self.ui.videoWidget.setFullScreen(False);
			self.showingReplay = False
			self.updateScores()
161
			self.replayer.start_recording()
Antoine Lima's avatar
Antoine Lima committed
162

163
	def handleCancel(self):
164
		self.switchModule(modules.MenuModule)
Antoine Lima's avatar
Antoine Lima committed
165

Antoine Lima's avatar
Antoine Lima committed
166
	def checkEndGame(self):
167
		winSide = self.gameoverChecker.check(self.getGameTime(), self.scores)
Antoine Lima's avatar
Antoine Lima committed
168

169 170
		if winSide!=Side.Undef:
			self.send(modules.EndGameModule, players=self.players, winSide=winSide, scores=self.scores, time=self.getGameTime())
Antoine Lima's avatar
Antoine Lima committed
171
			self.switchModule(modules.EndGameModule)