game.py 4.95 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

		self.replayer = Replay(Side.Left)

62
63
64
65
66
	def load(self):
		logging.debug('Loading GameModule')

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

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

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

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

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

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

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

93
94
			elif key=='players':
				self.players = val
Antoine Lima's avatar
Antoine Lima committed
95

96
97
	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
98
		btnDiameter = self.mainwin.width()*0.4
99
100
101
102
103
		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
104

105
106
107
108
		QtWidgets.QWidget.resizeEvent(self, event)

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

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

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

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

126
	def updateScores(self):
127
128
		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
129
		self.checkEndGame()
Antoine Lima's avatar
Antoine Lima committed
130

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

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

			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
154
155
156
157
158
	def endOfReplay(self, status):
		if status!=QMediaPlayer.PlayingState:
			self.ui.videoWidget.setFullScreen(False);
			self.showingReplay = False
			self.updateScores()
Antoine Lima's avatar
Antoine Lima committed
159

160
	def handleCancel(self):
161
		self.switchModule(modules.MenuModule)
Antoine Lima's avatar
Antoine Lima committed
162

Antoine Lima's avatar
Antoine Lima committed
163
	def checkEndGame(self):
164
		winSide = self.gameoverChecker.check(self.getGameTime(), self.scores)
Antoine Lima's avatar
Antoine Lima committed
165

166
167
		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
168
			self.switchModule(modules.EndGameModule)