예제 #1
0
class Frogger(QWidget):
    def __init__(self):
        super().__init__()
        Config.mainWindow = self  #odma se postavi koji objekat je mainWindow da bi tamo u Rectangle.py Qlabeli znali gde treba da se nacrtaju. Lose je resenje, al radi bar za testiranje
        self.Menu = None  # glavni meni

        self.InitFlagsAndVariables()

        self.scoreboard = Scoreboard(self)
        self.highscore = HighScore()
        self.highscore.readFromFile()

        ###############################################
        self.videoWidget = QVideoWidget(self)
        self.videoWidget.resize(Config.mapSize * Config.gridSize,
                                Config.mapSize * Config.gridSize + 50)
        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.mediaPlayer.setVideoOutput(self.videoWidget)
        self.mediaPlayer.setMedia(
            QMediaContent(QUrl(Config.spriteLocation + "Intro.wmv")))
        ###############################################

        self.setWindowState(Qt.WindowNoState)
        self.__init_ui__()

        self.key_notifier = KeyNotifier()
        self.key_notifier.key_signal.connect(self.__update_position__)
        self.key_notifier.start()

        self.ZevsJavljaVremeQueue = Queue()
        self.procUKomZiviZevs = Zeus.PokreniZevsa(
            self.ZevsJavljaVremeQueue
        )  #pokrece proces koji u kju stavlja kakvo vreme treba da bude (sunce, kisa, sneg)

    def InitFlagsAndVariables(self):
        self.Map = []  # lista lejnova
        self.previousWeather = 'n'
        self.player1 = None
        self.player2 = None
        self.player1RectId = -1  # ovo je potrebno za mrezu
        self.player2RectId = -1  # ovo je potrebno za mrezu

        self.gamePaused = False

        self.GameOverBrojac = 0  # za zivote, ako je 2PlayerMode, kad igrac izgubi sve zivote povecava brojac za 1, kad oba izgube sve zivote, brojac je 2 i tad je gameOver
        # ako je SinglePlayer mod onda je gameOver ako je brojac 1
        self.Level = 1  # za levele

        Config.p1Score = 0
        Config.p2Score = 0
        Config.p1Lives = 5
        Config.p2Lives = 5

        try:
            self.ShutDownHost()
        except:
            pass

        try:
            self.ShutDownClient()
        except:
            pass

        self.host = None
        self.client = None
        self.isHost = False
        self.isClient = False

    def initVideo(self):
        self.videoWidget.show()
        self.mediaPlayer.play()

    def __init_ui__(self):
        self.setWindowTitle('Frogger')
        self.setWindowIcon(QtGui.QIcon(Config.spriteLocation +
                                       'iconFrog.png'))  #ikonica
        self.resize(Config.mapSize * Config.gridSize,
                    Config.mapSize * Config.gridSize + 50)
        self.FixWindowSize()
        self.show()
        self.initVideo()

        q = QTimer()
        q.singleShot(6000, self.DisplayMainMenu)

    def HsFunkc(self):
        self.Menu.HsElementsShow(self.highscore.top3)

    #obicna funkcija za fiksiranje velicine prozora
    def FixWindowSize(self):
        self.setMinimumHeight((Config.mapSize + 1) * Config.gridSize)
        self.setMinimumWidth(Config.mapSize * Config.gridSize)
        self.setMaximumHeight((Config.mapSize + 1) * Config.gridSize)
        self.setMaximumWidth(Config.mapSize * Config.gridSize)

    def RemoveVideoIntro(self):
        try:
            self.mediaPlayer.stop()
            self.videoWidget.setParent(None)
            self.videoWidget = None
        except:
            pass

    def DisplayMainMenu(self):
        self.RemoveVideoIntro()
        self.Menu = None
        self.Menu = Meni(self, self.SinglePlayerMode, self.TwoPlayerMode,
                         self.HsFunkc, self.MainMenuHostClick,
                         self.MainMenuJoinClick, self.CloseWindow)

    def PauseGame(self):
        self.gamePaused = True
        self.updaterGameObjekataThread.PauseGame()

    def ResumeGame(self):
        self.gamePaused = False
        self.updaterGameObjekataThread.ResumeGame()

    def RemoveAllGameUIObjects(self):
        for lejer, lista in Rectangle.allRectangles.items():
            for rect in lista:
                rect.RemoveFromScreen()
        GameObject.allGameObjects = []
        Rectangle.allRectangles = {}
        Rectangle.ResetId()

    def SinglePlayerMode(self):
        self.ClearZeusQueue()
        self.Menu.HideMainMenu()
        self.DisplayMap(
        )  #u displayMap se kreira objekat self.updaterGameObjekataThread i zato DisplayMap mora ici prvi
        self.createThreadToUpdateGameObjects()
        self.startThreadForUpdatingGameObjects()
        self.scoreboard.ShowScore()
        self.CreatePlayers()
        Config.collectLilypadsToAdvanceLevel = 1

    def ClearZeusQueue(self):
        while not self.ZevsJavljaVremeQueue.empty():
            self.ZevsJavljaVremeQueue.get()

    def TwoPlayerMode(self, OverNetworkGame=False):
        self.ClearZeusQueue()
        self.Menu.HideMainMenu()
        if not OverNetworkGame:  #kad je preko mreze onda updateovanje krece kad klijent bude spreman
            self.createThreadToUpdateGameObjects()
            self.startThreadForUpdatingGameObjects()
        self.DisplayMap(TwoPlayers=True)
        self.scoreboard.ShowScores()
        self.CreatePlayers(TwoPlayers=True)
        Config.collectLilypadsToAdvanceLevel = 3

    def MainMenuHostClick(self):
        self.HostServer(Config.serverAddress, Config.serverPort)

    def MainMenuJoinClick(self):
        #self.Menu.JoinWidgetHide()
        self.setFocus()

        #ovde sacuvamo ip adresu i port u fajl. da kad se sledeci put upali igra da odma ucita tu ipadresu i port
        try:
            with open(Config.lastIp_filename, "w") as f:
                f.write(str(self.Menu.ipAddr) + ":" + str(self.Menu.port))
        except:
            pass

        self.JoinServer(self.Menu.ipAddr, int(self.Menu.port))

    def CreatePlayers(self, TwoPlayers=False):
        self.player1 = Frog(Config.player1StartPosition[0],
                            Config.player1StartPosition[1], self.GameOverCheck,
                            self.updateP1Score, self.createGreenLives)
        self.player1RectId = self.player1.id
        if TwoPlayers:
            self.player2 = Frog(Config.player2StartPosition[0],
                                Config.player2StartPosition[1],
                                self.GameOverCheck,
                                self.updateP2Score,
                                self.createPinkLives,
                                isPlayerTwo=True)
            self.player2RectId = self.player2.id

    def updateP1Score(self, newScore):
        self.scoreboard.updateP1Score(newScore)
        if self.isHost:
            self.host.SendToClient(Config.network_updateGameScoreAndLives +
                                   ":" + "P1S_" +
                                   str(newScore))  #P2L => Player 2 Lives

    def updateP2Score(self, newScore):
        self.scoreboard.updateP2Score(newScore)
        if self.isHost:
            self.host.SendToClient(Config.network_updateGameScoreAndLives +
                                   ":" + "P2S_" +
                                   str(newScore))  #P2L => Player 2 Lives

    def createPinkLives(self, lives):
        self.scoreboard.CreatePinkLives(lives)
        if self.isHost:
            self.host.SendToClient(Config.network_updateGameScoreAndLives +
                                   ":" + "P2L_" +
                                   str(lives))  #P2L => Player 2 Lives

    def createGreenLives(self, lives):
        self.scoreboard.CreateGreenLives(lives)
        if self.isHost:
            self.host.SendToClient(Config.network_updateGameScoreAndLives +
                                   ":" + "P1L_" +
                                   str(lives))  #P1L => Player 2 Lives

    def DisplayMap(self, TwoPlayers=False):
        self.Map.append(Lane.GenerateSafetyLane())  #prvi je uvek sejf lejn
        self.GenerateLanes('Road')  #fja da generise lejnove za put
        #self.Map.append(Lane.GenerateSafetyLane())
        ##ovaj ce da bude uvek tu da bi se moglo duze igrati
        ##lejn sa zivotom
        self.Map.append(Lane.GenerateSafetyLaneWithDeus())
        self.GenerateLanes('Water')  #fja da generise lejnove za reku
        if TwoPlayers:
            self.Map.append(Lane.GenerateFinalLane(
                self.LevelPassed))  # zadnji je uvek finalLane
        else:
            self.Map.append(
                Lane.GenerateFinalLane(
                    self.LevelPassed,
                    lilyPadPattern=Config.lilypadPatternBO5Standard)
            )  # zadnji je uvek finalLane

    def GameOverCheck(self, isPlayerTwo):
        #fja koja se poziva kada igrac ima 0 zivota, prosledjuje se igracima kroz konstruktor
        self.GameOverBrojac += 1
        if self.player1 != None and self.player2 != None:
            if self.GameOverBrojac == 1:
                if isPlayerTwo:
                    self.highscore.checkIfHighScore(self.player2.playerName,
                                                    self.player2.score)
                    self.player2.RemoveFromScreen()
                    self.player2 = None
                    Config.p2Lives = 0
                else:
                    self.highscore.checkIfHighScore(self.player1.playerName,
                                                    self.player1.score)
                    self.player1.RemoveFromScreen()
                    self.player1 = None
                    Config.p1Lives = 0
        elif self.player1 != None:
            self.highscore.checkIfHighScore(self.player1.playerName,
                                            self.player1.score)
            self.GameOver()
        elif self.player2 != None:
            self.highscore.checkIfHighScore(self.player2.playerName,
                                            self.player2.score)
            self.GameOver()

    def GameOver(self):
        # javimo klijentu da bi se vratio na meni
        if self.isHost:
            self.host.SendToClient(Config.network_ConnectionError)

        #fja koja se poziva kad su svi igraci igraci ostali bez zivota
        self.stopThreadForUpdatingObjects()
        self.DeleteMap(deleteP1=True, deleteP2=True)
        self.Menu.ShowMainMenu()
        Lane.ResetLaneStartingIndex()
        self.scoreboard.HideScores()
        self.Menu.kisa.hide()
        self.Menu.sneg.hide()
        self.scoreboard.CreateGreenLives(0)
        self.scoreboard.CreatePinkLives(0)

        self.InitFlagsAndVariables()

    def ShutDownHost(self):
        if self.host != None:
            print("gasim hosta")
            self.host.StopHosting()
            self.isHost = False
            self.host = None

    def ShutDownClient(self):
        if self.client != None:
            self.client.StopClienting()
            self.isClient = False
            self.client = None

    def LevelPassed(self):
        #fja koja se poziva kad su svih 5 Lilypada popunjena, prosledjuje se u konstruktoru, prvo finalLejnu pa samim objektima
        self.Level += 1
        Lane.ResetLaneStartingIndex()
        self.GameOverBrojac = 0
        self.DeleteMap()
        if self.player1 != None and self.player2 != None:
            Config.p1Score = self.player1.score
            Config.p2Score = self.player2.score
            Config.p1Lives = self.player1.lives
            Config.p2Lives = self.player2.lives
            self.DisplayMap(TwoPlayers=True)
            self.CreatePlayers(TwoPlayers=True)
        elif self.player1 != None:
            Config.p1Score = self.player1.score
            Config.p1Lives = self.player1.lives
            self.DisplayMap()
            self.CreatePlayers()
        elif self.player2 != None:
            Config.p2Score = self.player2.score
            Config.p2Lives = self.player2.lives
            self.DisplayMap()
            self.CreatePlayers(TwoPlayers=True)
            self.player1.RemoveFromScreen()
            self.player1 = None

        if self.isHost and self.player2 != None:
            self.SendClientToReplicateObjects()

    def DeleteMap(self, deleteP1=False, deleteP2=False):
        if deleteP1:
            try:
                self.player1.RemoveFromScreen()
                self.player1 = None
            except:
                print('P1 vec postavljen na None')

        if deleteP2:
            try:
                self.player2.RemoveFromScreen()
                self.player2 = None
            except:
                print('P2 vec postavljen na None')

        for lane in self.Map:
            for obs in lane.obstacles:
                obs.RemoveFromScreen()
            lane.obstacles.clear()
            lane.RemoveFromScreen()

        for layer, listOfRectanglesInLayer in Rectangle.allRectangles.items():
            for rect in listOfRectanglesInLayer:
                rect.RemoveFromScreen()
            listOfRectanglesInLayer.clear()

        self.Map.clear()

    def DisplayTestMap(self):
        Lane.ResetLaneStartingIndex()
        self.Map.append(Lane.GenerateSafetyLane())
        self.Map.append(Lane.GenerateEasyLane())
        self.Map.append(Lane.GenerateEasyLane())
        self.Map.append(Lane.GenerateEasyLane())
        self.Map.append(Lane.GenerateSafetyLane())
        self.Map.append(Lane.GenerateFinalLane())
        self.Map.append(
            Lane.GenerateFinalLane(lilyPadPattern=Config.lilypadPatternBO3))
        self.Map.append(
            Lane.GenerateFinalLane(lilyPadPattern=Config.lilypadPatternBO5V2))
        self.Map.append(Lane.GenerateFinalLane(randomPatternBO5=True))

    def keyPressEvent(self, event):
        if not event.isAutoRepeat():
            self.key_notifier.add_key(event.key())

    def __update_position__(self, key):
        if not self.isClient:
            if key == Qt.Key_Escape and self.gamePaused:
                self.ResumeGame()
            elif key == Qt.Key_Escape and not self.gamePaused:
                self.PauseGame()

        if self.isClient:  #ako sam klijent onda pored pomeranja zabe, hocu da posaljem INPUT serveru
            if key == Qt.Key_Right:
                self.client.SendToServer(Config.network_inputKlijentaPrefix +
                                         "DESNO")
            elif key == Qt.Key_Down:
                self.client.SendToServer(Config.network_inputKlijentaPrefix +
                                         "DOLE")
            elif key == Qt.Key_Up:
                self.client.SendToServer(Config.network_inputKlijentaPrefix +
                                         "GORE")
            elif key == Qt.Key_Left:
                self.client.SendToServer(Config.network_inputKlijentaPrefix +
                                         "LEVO")

        if key == Qt.Key_T:
            for go in GameObject.allGameObjects:
                print(str(go.id) + "__" + str(go.loadedSprite))

        if self.gamePaused:  #sve sto je ispod nece biti odradjeno kad je game pauziran
            return

        if self.player1 != None:
            self.player1.KeyPress(key)
        if self.player2 != None:
            self.player2.KeyPress(key)

    def CloseWindow(self):
        # OVDE TREBA DA SE POZOVE KOD KOJI CE DA ZAUSTAVI ZEVSA
        # (ako uopste postoji neko toliko jak da zaustavi zevsa)
        try:
            self.procUKomZiviZevs.terminate()
        except:
            pass

        try:
            self.updaterGameObjekataThread.updaterThreadWork = False  # self.updaterGameObjekataThread se kreira samo kad pocne IGRA. Ako budes na meniju i nista ne radis nece se kreirati
        except:
            pass
        self.key_notifier.die()

    def closeEvent(self, event):
        self.CloseWindow()

    def createThreadToUpdateGameObjects(self):
        self.updaterGameObjekataThread = GOUpdater()
        self.updaterGameObjekataThread.nekiObjekat.connect(
            self.updateAllGameObjects)

        #OVO (thread koji updateuje objekte) SE POKRECE KAD KLIJENT BUDE SPREMAN (nakon sto preuzme sve objekte i nacrta ih na ekranu), ili kad pocne neki od lokalnih game modova
        #self.updaterGameObjekataThread.start()

    def startThreadForUpdatingGameObjects(self):
        self.updaterGameObjekataThread.start()

    def stopThreadForUpdatingObjects(self):
        try:  #na klijentu ovaj objekat za updateovanje ce biti null
            self.updaterGameObjekataThread.updaterThreadWork = False
        except:
            pass

    def updateAllGameObjects(self, dummy):  #callback funkcija
        for gameObject in GameObject.allGameObjects:
            gameObject.update()

        # ako je instanca server i postoje gameobjekti onda da salje klijentu pozicije tih objekata
        if self.isHost and len(GameObject.allGameObjects) > 0:
            self.SendRectPositionUpdateToClient()

        if not self.ZevsJavljaVremeQueue.empty():
            self.updateWeather(self.ZevsJavljaVremeQueue.get())
        else:
            return

    def updateWeather(self, newWeather):
        if self.isHost:
            self.host.SendToClient(Config.network_updateWeatherInfo + ":" +
                                   newWeather)

        if newWeather == 'k':
            if self.previousWeather == 'k':
                self.ZaustaviKisu()
            elif self.previousWeather == 's':
                self.ZaustaviSneg()
            self.PokreniKisu()
        elif newWeather == 's':
            if self.previousWeather == 'k':
                self.ZaustaviKisu()
            elif self.previousWeather == 's':
                self.ZaustaviSneg()
            self.PokreniSneg()
        elif newWeather == 'n':
            if self.previousWeather == 'k':
                self.ZaustaviKisu()
            elif self.previousWeather == 's':
                self.ZaustaviSneg()

        self.previousWeather = newWeather

    def createLanes(self, niz, type):
        #funkcija koja generise lejnove u zavisnosti od prosledjenog niza i karaktera u njemu
        if type == 'Road':
            for letter in niz:
                if letter == 'e':
                    self.Map.append(Lane.GenerateEasyLane())
                elif letter == 'm':
                    self.Map.append(Lane.GenerateMediumLane())
                elif letter == 'h':
                    self.Map.append(Lane.GenerateHardLane())
        elif type == 'Water':
            for letter in niz:
                if letter == 'e':
                    self.Map.append(Lane.GenerateEasyWaterLane())
                elif letter == 'm':
                    self.Map.append(Lane.GenerateMediumWaterLane())
                elif letter == 'h':
                    self.Map.append(Lane.GenerateHardWaterLane())
        elif type == 'Random':
            for letter in niz:
                if letter == 's':  # safe lane
                    self.Map.append(Lane.GenerateSafetyLane())
                elif letter == 'e':  # easy lane, if generated -1 -> easyWaterLane if 1 easyTrafficLane, isto vazi za ostale samo se menja tezina s,m,h...
                    if [-1, 1][randrange(2)] == -1:
                        self.Map.append(Lane.GenerateEasyWaterLane())
                    else:
                        self.Map.append(Lane.GenerateEasyLane())
                elif letter == 'm':
                    if [-1, 1][randrange(2)] == -1:
                        self.Map.append(Lane.GenerateMediumWaterLane())
                    else:
                        self.Map.append(Lane.GenerateMediumLane())
                elif letter == 'h':
                    if [-1, 1][randrange(2)] == -1:
                        self.Map.append(Lane.GenerateHardWaterLane())
                    else:
                        self.Map.append(Lane.GenerateHardLane())

    def GenerateLanes(self, type):
        # 6 lejnova, fja u kojoj se odlucuje tezina po levelima, moze da se menja po volji
        nizTezine = []
        if self.Level <= 2:
            nizTezine.append('e')
            nizTezine.append('e')
            nizTezine.append('e')
            nizTezine.append('e')
            nizTezine.append('e')
            nizTezine.append('e')
        elif self.Level > 2 and self.Level <= 4:
            nizTezine.append('e')
            nizTezine.append('e')
            nizTezine.append('e')
            nizTezine.append('e')
            nizTezine.append('e')
            nizTezine.append('e')
            type = 'Random'
        elif self.Level > 4 and self.Level <= 6:
            nizTezine.append('e')
            nizTezine.append('e')
            nizTezine.append('e')
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('m')
        elif self.Level > 6 and self.Level <= 8:
            nizTezine.append('e')
            nizTezine.append('e')
            nizTezine.append('e')
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('m')
            type = 'Random'
        elif self.Level > 8 and self.Level <= 10:
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('m')
        elif self.Level > 10 and self.Level <= 12:
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('m')
            type = 'Random'
        elif self.Level > 12 and self.Level <= 14:
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('h')
            nizTezine.append('h')
            nizTezine.append('h')
        elif self.Level > 12 and self.Level <= 14:
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('m')
            nizTezine.append('h')
            nizTezine.append('h')
            nizTezine.append('h')
            type = 'Random'
        elif self.Level > 14 and self.Level <= 16:
            nizTezine.append('h')
            nizTezine.append('h')
            nizTezine.append('h')
            nizTezine.append('h')
            nizTezine.append('h')
            nizTezine.append('h')
        elif self.Level > 16:
            nizTezine.append('h')
            nizTezine.append('h')
            nizTezine.append('h')
            nizTezine.append('h')
            nizTezine.append('h')
            nizTezine.append('h')
            type = 'Random'

        shuffle(nizTezine)  #permutuj niz da lejnovi budu random
        self.createLanes(nizTezine, type)

    def PokreniKisu(self):  #Fja da se prikaze kisa
        self.Menu.PrikaziPadavinu('kisa')
        for lane in self.Map:
            if lane.laneType == Config.laneTypeWater:
                lane.ChangeSpeed(
                    Config.speedChange)  #brzina drveca se povecava kad je kisa
            elif lane.laneType == Config.laneTypeTraffic or lane.laneType == Config.laneTypeTrafficTop or lane.laneType == Config.laneTypeTrafficBottom:
                lane.ChangeSpeed(-Config.speedChange
                                 )  #brzina automobila se smanjuje kad je kisa

    def PokreniSneg(self):  #Fja da se prikaze sneg
        self.Menu.PrikaziPadavinu('sneg')
        for lane in self.Map:
            if lane.laneType == Config.laneTypeWater:
                lane.ChangeSpeed(-Config.speedChange
                                 )  #brzina drveca se smanjuje kad je sneg
            elif lane.laneType == Config.laneTypeTraffic or lane.laneType == Config.laneTypeTrafficTop or lane.laneType == Config.laneTypeTrafficBottom:
                lane.ChangeSpeed(Config.speedChange
                                 )  #brzina automobila se povecava kad je sneg

    def ZaustaviKisu(self):  #Fja da se zaustavi kisa
        self.Menu.SakrijPadavinu('kisa')
        for lane in self.Map:
            if lane.laneType == Config.laneTypeWater:
                lane.ChangeSpeed(
                    -Config.speedChange
                )  #obrnuto, ako smo bili povecali brzinu drveca kad je kisa pocela, sad je smanjujemo, vracamo na default
            elif lane.laneType == Config.laneTypeTraffic or lane.laneType == Config.laneTypeTrafficTop or lane.laneType == Config.laneTypeTrafficBottom:
                lane.ChangeSpeed(
                    Config.speedChange
                )  #obrnuto, ako smo bili smanjili brzinu automobila kad je kisa pocela, sad je povecavamo, vracamo na default

    def ZaustaviSneg(self):  #Fja da se zaustavi sneg
        self.Menu.SakrijPadavinu('sneg')
        for lane in self.Map:
            if lane.laneType == Config.laneTypeWater:
                lane.ChangeSpeed(
                    Config.speedChange
                )  #obrnuto, ako smo bili smanjili brzinu drveca kad je poceo sneg, sad je povecavamo, vracamo na default
            elif lane.laneType == Config.laneTypeTraffic or lane.laneType == Config.laneTypeTrafficTop or lane.laneType == Config.laneTypeTrafficBottom:
                lane.ChangeSpeed(
                    -Config.speedChange
                )  #obrnuto, ako smo bili povecali brzinu automobila kad je poceo sneg, sad je smanjujemo, vracamo na default

    ################################################################################
    #FUNKCIJE ISPOD SE KORISTE SAMO ZA MULITPLAYER
    ################################################################################

    def HostServer(self, address, port):
        self.isHost = True
        self.host = Host(address, port)
        self.host.receiveCallBack.connect(self.ReceiveFromClient)
        self.host.start()

    def JoinServer(self, address, port):
        self.isClient = True
        self.client = Client(address, port)
        self.client.receiveCallBack.connect(self.ReceiveFromServer)
        self.client.start()

    def SendClientToReplicateObjects(self):
        self.host.SendToClient(Config.network_kreirajSveObjekteNaKlijentu +
                               ":" + self.CreateInitObjectsString())

    # ovo ce biti pozvano kad server primi poruku od klijenta
    def ReceiveFromClient(self, data):
        # print("Primio od klijenta: " + str(data))
        if data == Config.network_clientIsReady:  # kad primi ovo znaci da se klijent povezao
            self.TwoPlayerMode(OverNetworkGame=True)
            self.player2.keyBoardInputEnabled = False
            self.SendClientToReplicateObjects(
            )  #da ne generise updater svaki put kad se predje level, vec samo incijalno kad se uspostavi veza
        elif data == Config.network_potvrdaKlijentaDaJeNapravioSveObjekte and self.Level == 1:  # klijent je potvrdio da je napravio sve objekte i sad pokrecemo igru (pravimo i pokrecemo thread koji updateuje igru)
            self.createThreadToUpdateGameObjects()
            self.startThreadForUpdatingGameObjects()
        elif Config.network_inputKlijentaPrefix in data and self.player2 != None:  #ovo da li je igrac razlicit od None je ustvari provera da li je ziv
            if Config.network_inputKlijentaPrefix + "DESNO" == data:
                self.player2.GoRight()
            elif Config.network_inputKlijentaPrefix + "DOLE" == data:
                self.player2.GoDown()
            elif Config.network_inputKlijentaPrefix + "GORE" == data:
                self.player2.GoUp()
            elif Config.network_inputKlijentaPrefix + "LEVO" == data:
                self.player2.GoLeft()
        elif Config.network_ConnectionError == data:
            print("Klijent je otiso :(")
            self.ResetGameStateOnError()

    # ovo ce biti pozvano kad klijent primi poruku od servera
    def ReceiveFromServer(self, data):
        #print("Primio od servera: " + str(data))
        if data == Config.network_serverWelcomeMsg:  # znaci da smo se uspesno povezali sa serverom i inicijalizujemo gejm
            self.InitNetworkGame()
        elif Config.network_kreirajSveObjekteNaKlijentu in data:
            self.GenerateObjects(data.split(":")[1])
            self.client.SendToServer(
                Config.network_potvrdaKlijentaDaJeNapravioSveObjekte)
        elif Config.network_updateSveObjekteNaKlijentu in data:
            self.UpdateObjectsPosition(data.split(":")[1])
        elif Config.network_updateGameScoreAndLives in data:
            #ako ovde udje PAYLOAD moze da izgleda ovako:
            #P2L_3
            #P1S_2
            #P2S_4
            #P1L_1
            payload = data.split(":")[1]
            player, scoreOrLives = payload.split('_')
            #print(str(payload))
            if "P1" in player:
                if "S" in player:
                    self.updateP1Score(scoreOrLives)
                elif "L" in player:
                    self.createGreenLives(int(scoreOrLives))
            elif "P2" in player:
                if "S" in player:
                    self.updateP2Score(scoreOrLives)
                elif "L" in player:
                    self.createPinkLives(int(scoreOrLives))

        elif Config.network_updateWeatherInfo in data:
            self.updateWeather(data.split(":")[1])
        elif Config.network_ConnectionError == data:
            self.ResetGameStateOnError()

    #ovo se poziva na klijentu.
    def InitNetworkGame(self):
        self.TwoPlayerMode(
            OverNetworkGame=True
        )  #nije potrebno ovo True, al da se dzabe nebi pravio thread koji se ne koristi :D

        #sklanjamo sve objekte, jer ce nam server poslati sta je on generisao (velicine, pozicije, sprajtove)
        for go in GameObject.allGameObjects:
            go.RemoveFromScreen()
        GameObject.allGameObjects.clear()
        #klijent javi serveru da je spreman (spreman da primi podatke o svim objektima)
        self.client.SendToServer(Config.network_clientIsReady)

    #poziva se ako dodje do greske prilikom komunikacije sa klijentom
    def ResetGameStateOnError(self):
        self.RemoveAllGameUIObjects()
        self.GameOver()

    #poziva se samo na serveru
    def SendRectPositionUpdateToClient(self):
        self.host.SendToClient(Config.network_updateSveObjekteNaKlijentu +
                               ":" + self.CreateUpdateObjectsString())

    #ova metoda moze ici u GameObject Klasu
    def CreateInitObjectsString(self):
        objektiUString = []
        for go in GameObject.allGameObjects:  #saljemo podatke koji su potrebni da bi se napravili objekti na klijentu
            objektiUString.append(
                str(go.id) + "%" + go.loadedSprite + "%" + str(go.x) + "%" +
                str(go.y) + "%" + str(go.w) + "%" + str(go.h))
        return "#".join(objektiUString)

    # ova metoda moze ici u GameObject Klasu
    def CreateUpdateObjectsString(self):
        objektiUString = []
        for go in GameObject.allGameObjects:  #saljemo podatke koji su potrebni da bi se updateovale pozicije objekata na klijentu

            #optimizovano, ne saljem update za sve gameObjecte vec samo one koji su u lejeru prepreke i imaju neku brzinu
            if go.layer == Config.layerPrepreke and go.speed != 0:
                objektiUString.append(
                    str(go.id) + "%" + str(go.x) + "%" + str(go.y))
            elif go.layer == Config.layerZabe or go.layer == Config.layerLilypad:  #igraci i lokvanji mogu da promene sprite i zato saljem i sprite :D
                objektiUString.append(
                    str(go.id) + "%" + str(go.x) + "%" + str(go.y) + "%" +
                    str(go.loadedSprite))

        # ovo je dodato ako neki od igraca umre da ga klijent skloni sa ekrana (sprite se stavi na prazan string)
        if self.player1 == None and self.player1RectId != -1:
            objektiUString.append(
                str(self.player1RectId) + "%" + str(0) + "%" + str(0) +
                "%DEAD")
            self.player1RectId = -1
        if self.player2 == None and self.player2RectId != -1:
            objektiUString.append(
                str(self.player2RectId) + "%" + str(0) + "%" + str(0) +
                "%DEAD")
            self.player2RectId = -1

        return "#".join(objektiUString)

    #ova funkcija se poziva na klijentu, da napravi objekte iste kao sto su na serveru. Pozove se samo na pocetku
    def GenerateObjects(self, data):
        for layer, listOfRects in Rectangle.allRectangles.items():
            for rect in listOfRects:
                rect.RemoveFromScreen()
            listOfRects.clear()

        objs = data.split("#")
        Rectangle.ResetId()
        for obj in objs:
            objData = obj.split("%")
            r = Rectangle(float(objData[2]),
                          float(objData[3]),
                          int(objData[4]),
                          int(objData[5]),
                          objData[1],
                          layer=objData[0],
                          forceId=int(objData[0]))
            r.Show()

    #ova funkcija se poziva na klijentu, sluzi za updateovanje (samo X i Y kordinate) svih rectanglova na klijentu.
    #server ce ovo slati klijentu svaki frejm (30 puta u sekundi)
    def UpdateObjectsPosition(self, data):
        objs = data.split("#")
        dictObj = {}
        for obj in objs:
            objData = obj.split("%")

            if len(objData) == 4:
                dictObj[objData[0]] = (float(objData[1]), float(objData[2]),
                                       objData[3])
            elif len(objData) == 3:
                dictObj[objData[0]] = (float(objData[1]), float(objData[2]))

        for go in GameObject.allGameObjects:
            strId = str(go.id)
            if strId in dictObj.keys():
                go.SetPosition(dictObj[strId][0], dictObj[strId][1])
                if len(dictObj[strId]
                       ) == 3:  #ako je 3 znaci da imamo i sprite poslat
                    go.ChangeSprite(dictObj[strId][2])
예제 #2
0
class Player(QWidget):
    """Sub-class of QWidget"""
    def __init__(self, parent=None, *args, **kwargs):
        """Initialize class attributes"""
        super(Player, self).__init__(parent, *args, **kwargs)
        self.init_ui()

    def init_ui(self):
        """Create local components"""
        # loop
        self.loop = False
        # time label text
        self.time_text = '{:0>2d}:{:0>2d}:{:0>2d}/{:0>2d}:{:0>2d}:{:0>2d}'
        self.hours = self.minutes = self.seconds = 0
        # create media player object
        self.mediaPlayer = QMediaPlayer(self, QMediaPlayer.VideoSurface)
        # create videowidget object
        self.videoWidget = QVideoWidget()

        # create open button
        self.btn_size = QSize(16, 16)
        openButton = Button("Open")
        openButton.setToolTip("Open Media File")
        openButton.setStatusTip("Open Media File")
        openButton.setFixedHeight(24)
        openButton.setIconSize(self.btn_size)
        openButton.setIcon(
            QIcon.fromTheme("document-open", QIcon("Icons/Open.bmp")))
        # openButton.setStyleSheet("background-color: #B0C4DE")
        openButton.clicked.connect(self.abrir)

        # create play button
        self.playButton = Button()
        self.playButton.setEnabled(False)
        self.playButton.setFixedHeight(24)
        self.playButton.setIconSize(self.btn_size)
        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        # self.playButton.setStyleSheet("background-color: #B0C4DE")
        self.playButton.clicked.connect(self.play)

        # create slider
        self.positionSlider = PositionSlider(self.mediaPlayer, Qt.Horizontal)
        self.positionSlider.setRange(0, 0)
        self.positionSlider.setObjectName("positionSlider")

        # create status bar
        self.statusBar = QStatusBar()
        self.statusBar.setFont(QFont("Noto sans", 8))
        self.statusBar.setFixedHeight(14)
        self.statusBar.setStyleSheet('color:#ffffff')

        # create duration time label
        self.durationLabel = QLabel()
        self.durationLabel.setStyleSheet(
            'background-color:rgba(255, 255, 255, 0)')
        self.durationLabel.setText('00:00:00/00:00:00')

        # create hbox layout
        controlLayoutWidget = QWidget(self)
        controlLayout = QHBoxLayout(controlLayoutWidget)
        controlLayoutWidget.setLayout(controlLayout)
        controlLayout.setContentsMargins(2, 2, 2, 2)
        # set widgets to the hbox layout
        controlLayout.addWidget(openButton)
        controlLayout.addWidget(self.playButton)
        controlLayout.addWidget(self.positionSlider)
        controlLayout.addWidget(self.durationLabel)
        # change hbox color
        controlLayoutWidget.setStyleSheet(
            'background-color:rgba(255, 255, 255, 50)')
        controlLayoutWidget.setWindowOpacity(0.1)

        # create vbox layout
        self.layout = QVBoxLayout()
        self.layout.setSpacing(0)
        # set widgets to vbox layout
        self.layout.addWidget(self.videoWidget)
        self.layout.addWidget(controlLayoutWidget)
        self.sub_controls()
        self.layout.addWidget(self.statusBar)

        self.setLayout(self.layout)

        self.mediaPlayer.setVideoOutput(self.videoWidget)
        self.mediaPlayer.stateChanged.connect(self.mediaStateChanged)
        self.mediaPlayer.positionChanged.connect(self.positionChanged)
        self.mediaPlayer.durationChanged.connect(self.durationChanged)
        self.mediaPlayer.error.connect(self.handleError)
        self.statusBar.showMessage('{:->33s}{:-<33s}'.format("Have Fun", ""))
        self.key_bindings()

    def key_bindings(self):
        # bind Keys to methods
        self.onplaypause = self.create_shortcut(Qt.Key_Space, self.videoWidget,
                                                self.play)  # Space key for

        self.on_fscreen = self.create_shortcut(
            Qt.Key_F, self.videoWidget,
            self.toggle_fullscreen)  # F key for fullscreen on

        self.onforward = self.create_shortcut(
            Qt.Key_Right, self.videoWidget,
            self.forward)  # Right key for forward

        self.redvolume = self.create_shortcut(
            Qt.Key_Down, self.videoWidget,
            self.red_volume)  # Down key reduce volume

        self.incvolume = self.create_shortcut(
            Qt.Key_Up, self.videoWidget,
            self.inc_volume)  # Up key increase volume

        self.onsetloop = self.create_shortcut(
            "L",
            self.videoWidget,  # L key for repeat on,
            (lambda self=self: self.repeat.toggle() or self.play_again()))

        self.onrewind = self.create_shortcut(
            Qt.Key_Left, self.videoWidget, self.rewind)  # Left key for rewind

        self.volmute = self.create_shortcut(Qt.Key_M, self.videoWidget,
                                            self.mute)  # M for mute and unmute

        self.onopen = self.create_shortcut('Ctrl+O', self.videoWidget,
                                           self.abrir)  # Ctrl+O for open

        self.onstop = self.create_shortcut(Qt.Key_S, self.videoWidget,
                                           self.stop_media)  # S key for stop

    def create_shortcut(self, sequence, widget, obj):
        """generate key shortcuts"""
        return QShortcut(QKeySequence(sequence),
                         widget,
                         obj,
                         context=Qt.ApplicationShortcut)

    def sub_controls(self):
        """Repeat, volume, and mute controls"""
        # repeat button
        self.repeat = Button()
        self.repeat.setCheckable(True)
        self.repeat.toggle()
        self.repeat.setIconSize(self.btn_size)
        self.repeat.setFixedHeight(24)
        self.repeat.setFixedWidth(26)
        self.repeat.setToolTip("repeat")
        self.repeat.setStatusTip("repeat")

        # Icons to correspond with button state
        icon = QIcon()
        icon.addPixmap(QPixmap(os.path.join(FOLDER, "Icons/repeat(1).png")),
                       QIcon.Normal, QIcon.On)
        icon.addPixmap(QPixmap(os.path.join(FOLDER, "Icons/repeat(2).png")),
                       QIcon.Active)
        self.repeat.setIcon(icon)
        # self.repeat.setStyleSheet("background-color: #B0C4DE; margin: 0px 0px 0px 2px;")
        self.repeat.clicked.connect(self.play_again)

        # stop button
        self.stop = Button()
        self.stop.setIconSize(self.btn_size)
        self.stop.setFixedHeight(24)
        self.stop.setFixedWidth(26)
        self.stop.setToolTip("Stop playing media")
        self.stop.setStatusTip("Stop playing media")
        self.stop.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))
        # self.stop.setStyleSheet("background-color: #B0C4DE; margin: 0px 0px 0px 2px;")
        self.stop.clicked.connect(self.stop_media)

        # volume slider
        self.volumeSlider = VolumeSlider(self.mediaPlayer, Qt.Horizontal)
        self.volumeSlider.setRange(0, 100)
        self.volumeSlider.setFixedWidth(200)
        self.mediaPlayer.setVolume(50)
        self.volumeSlider.sliderMoved.connect(self.set_volume)

        # volume button
        self.volume = Button(self)
        self.volume.setIconSize(self.btn_size)
        self.volume.setFixedHeight(24)
        self.volume.setFixedWidth(26)
        self.volume.setToolTip("Mute or Unmute")
        self.volume.setStatusTip("Mute or Unmute")
        self.volume.setIcon(self.style().standardIcon(QStyle.SP_MediaVolume))
        # self.volume.setStyleSheet("background-color: #B0C4DE; margin: 0px 0px 0px 2px;")
        self.volume.clicked.connect(self.mute)

        # create control widget
        subControlWidget = QWidget(self)
        subControlWidget.setStyleSheet(
            'background-color:rgba(255, 255, 255, 30)')
        # create Horizontal Layout
        subControlLayout = QHBoxLayout(subControlWidget)
        subControlLayout.setContentsMargins(0, 0, 0, 0)
        subControlLayout.addWidget(self.repeat, 0, Qt.AlignLeft)
        subControlLayout.addWidget(self.stop, 1, Qt.AlignLeft)
        # sub layout for volume control
        self.sub_layout = QHBoxLayout()
        self.sub_layout.addWidget(self.volume)
        self.sub_layout.addWidget(self.volumeSlider)
        subControlLayout.addLayout(self.sub_layout)
        subControlLayout.setContentsMargins(2, 2, 2, 2)

        self.layout.addWidget(subControlWidget)

    def abrir(self, event=None, url=None):
        """" Equivalent to open for most GUIs"""
        fileName = None
        if self.videoWidget.isFullScreen():
            self.toggle_fullscreen()
        if not url:
            fileName, _ = QFileDialog.getOpenFileName(self, "Select media")
            if fileName:
                self.mediaPlayer.setMedia(
                    QMediaContent(QUrl.fromLocalFile(fileName)))
        else:
            self.mediaPlayer.setMedia(QMediaContent(QUrl(url)))
        if url or fileName:
            self.volumeSlider.setValue(self.mediaPlayer.volume())
            self.playButton.setEnabled(True)
            self.statusBar.showMessage((fileName or url))
            if not self.loop:
                self.play()

    def play(self):
        """Start media player"""
        if self.playButton.isEnabled():
            if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
                self.mediaPlayer.pause()
            else:
                self.mediaPlayer.play()

    def mediaStateChanged(self, state):
        """Callback for media player state change"""
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.playButton.setIcon(self.style().standardIcon(
                QStyle.SP_MediaPause))
        else:
            self.playButton.setIcon(self.style().standardIcon(
                QStyle.SP_MediaPlay))
        if state == QMediaPlayer.StoppedState and self.loop:
            self.play()

    def positionChanged(self, position):
        """Callback for media player position change"""
        if self.mediaPlayer.state() == QMediaPlayer.StoppedState:
            position = 0
        self.positionSlider.setValue(position)
        hours, position = position // 3600000, position % 3600000
        minutes, position = position // 60000, position % 60000
        seconds = position // 1000
        self.durationLabel.setText(
            self.time_text.format(hours, minutes, seconds, self.hours,
                                  self.minutes, self.seconds))

    def durationChanged(self, duration):
        """Callback for media player duration of media change"""
        self.positionSlider.setRange(0, duration)
        self.hours, duration = duration // 3600000, duration % 3600000
        self.minutes, duration = duration // 60000, duration % 60000
        self.seconds = duration // 1000
        self.durationLabel.setText(
            self.time_text.format(0, 0, 0, self.hours, self.minutes,
                                  self.seconds))

    def setPosition(self, position):
        """set media player play position"""
        self.mediaPlayer.setPosition(position)

    def handleError(self):
        """Callback for multiplayer errors"""
        self.playButton.setEnabled(False)
        self.statusBar.showMessage("Error: " + self.mediaPlayer.errorString())

    def play_again(self):
        """Set repeat on or off"""
        self.loop = not self.loop

    def stop_media(self):
        """Callback for stop button"""
        if self.loop:
            self.loop = False
            self.repeat.toggle()
        self.mediaPlayer.stop()

    def toggle_fullscreen(self):
        """Toggle in or out of fullscreen mode"""
        self.videoWidget.setWindowFlags(Qt.FramelessWindowHint
                                        | Qt.WindowStaysOnTopHint)
        if self.videoWidget.isFullScreen():
            self.videoWidget.setFullScreen(False)
            self.videoWidget.setWindowState(Qt.WindowNoState)
            self.videoWidget.setParent(self)
            self.layout.insertWidget(0, self.videoWidget)
            self.videoWidget.showNormal()
            self.show()
        else:
            self.videoWidget.setFullScreen(True)
            self.hide()

    def rewind(self, lapse=2500):
        """Rewind the current media file by 1 second"""
        new_position = self.mediaPlayer.position() - lapse
        self.setPosition(new_position)

    def forward(self, lapse=2500):
        """Forward media file by 1 second"""
        new_position = self.mediaPlayer.position() + lapse
        self.setPosition(new_position)

    def set_volume(self, vol=0):
        """Set media player volume volume"""
        if vol:
            self.mediaPlayer.setVolume(vol)

    def red_volume(self, vol=1):
        """Reduce volume by a factor of 0.01"""
        volume = self.mediaPlayer.volume()
        if volume >= 0:
            new_volume = volume - 1
            self.volumeSlider.setValue(new_volume)
            self.set_volume(new_volume)

    def inc_volume(self, vol=1):
        """Increase volume by a factor of 0.01"""
        volume = self.mediaPlayer.volume()
        if self.mediaPlayer.isMuted():
            self.mediaPlayer.setMuted(False)
            self.volume.setIcon(self.style().standardIcon(
                QStyle.SP_MediaVolume))
        if volume <= 100:
            new_volume = volume + 1
            self.volumeSlider.setValue(new_volume)
            self.set_volume(new_volume)

    def mute(self):
        """Mute media player"""
        if self.mediaPlayer.isMuted():
            self.mediaPlayer.setMuted(False)
            self.volume.setIcon(self.style().standardIcon(
                QStyle.SP_MediaVolume))
        else:
            self.mediaPlayer.setMuted(True)
            self.volume.setIcon(self.style().standardIcon(
                QStyle.SP_MediaVolumeMuted))
예제 #3
0
class MindReaderApp(QtWidgets.QMainWindow, design.Ui_MainWindow):
    def __init__(self):
        # Это здесь нужно для доступа к переменным, методам
        # и т.д. в файле design.py
        super().__init__()
        self.setupUi(self)  # Это нужно для инициализации нашего дизайна
        self.setWindowTitle("MindReader")
        self.startButton.clicked.connect(self.start_timer)

        self.timer = None
        self.time = QtCore.QTime(0, 0, 0)

        self.maxTimer = 0.0

        # настраиваем графики
        self.plot1 = self.graphic1.addPlot()
        self.curve1 = self.plot1.plot()

        self.plot2 = self.graphic2.addPlot()
        self.curve2 = self.plot2.plot()
        self.setGraphs()

        # задаем массивы для хранения данных
        self.data1 = []
        self.data2 = []
        self.timings = []
        self.emotions = []
        self.counter = 0
        self.counter1 = 0

        # для кнопки
        self.clicked = False

        # настройка видео
        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.mediaPlayer.setVideoOutput(self.videoWidget)
        self.qw = QWidget()
        self.qw.setGeometry(10, 360, 611, 280)
        self.qw.setParent(self)
        self.faceVideoWidget = QVideoWidget()
        self.faceVideoWidget.setParent(self.qw)
        self.faceVideoWidget.show()
        self.facePlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.facePlayer.setVideoOutput(self.faceVideoWidget)
        self.facePlayer.durationChanged.connect(self.getDuration)
        self.chooseVideo.triggered.connect(self.openFile)
        self.videoChosed = False

        # для записи лица
        self.videoTimer = None
        self.frame = None
        self.capture = None
        self.fps = int(30)
        self.videoSaver = None
        if not os.path.exists('Recordings'):
            os.makedirs('Recordings')

        # настройка порта
        self.ser = serial.Serial()
        self.ser.baudrate = 57600
        self.port = ""
        self.choosePort.triggered.connect(self.inputCom)

        # файл
        if not os.path.exists('Sessions'):
            os.makedirs('Sessions')
        self.vidFileName = ""
        self.faceFileName = ""

        # для считки
        self.fromFile = False
        act = QAction("Выбрать файл", self)
        act.triggered.connect(self.loadFile)
        self.openPrevSession.addAction(act)

        act1 = QAction("Очистить", self)
        act1.triggered.connect(self.cancel)
        self.openPrevSession.addAction(act1)

        # файл настроек
        self.sname = 'settings.txt'
        self.emotions = []
        if not os.path.isfile(self.sname):
            self.f = open(self.sname, 'w')
            self.f.close()
        self.f = open(self.sname, 'r')

        #для считки настроек из файла
        self.settings.addAction(self.setEmotions)
        self.setEmotionsData.triggered.connect(self.loadSettings)

        # эмоции
        self.settings = SettingsWindow()
        self.setEmotions.triggered.connect(self.openSettings)
        self.emotionsList = []

    def cancel(self):
        self.fromFile = False

    def stop(self):
        self.startButton.setText("Запустить")
        self.timer.stop()
        self.timer.deleteLater()
        self.pause_video()
        self.mediaPlayer.stop()
        self.facePlayer.stop()
        self.clicked = False

        # show all in graphics
        xdict = dict(enumerate(self.timings))
        self.plot1.getAxis('bottom').setTicks([xdict.items()])
        self.curve1.setData(self.data1)
        self.plot2.getAxis('bottom').setTicks([xdict.items()])
        self.curve2.setData(self.data2)

        # close file
        self.f.close()

    # запускает таймер, который работает сколько влезет, пауза кнопкой
    def start_timer(self):
        if self.clicked:
            self.stop()

        else:
            if self.fromFile:
                try:
                    self.faceWidget.hide()
                    self.facePlayer.setMedia(
                        QMediaContent(QUrl.fromLocalFile(self.faceFileName)))
                    self.qw.show()
                    self.facePlayer.play()
                    self.start = time.time()
                except Exception as e:
                    QMessageBox.about(self, "Ошибка!",
                                      "Видеофайл отсутствует или поврежден.")
            if not self.fromFile:
                if self.port == "":
                    QMessageBox.about(self, "Ошибка!", "Выберите COM порт!")
                    return

                if not self.videoChosed:
                    QMessageBox.about(
                        self, "Ошибка!",
                        "Выберите видеофайл для воспроизведения!")
                    return

                # открытие порта
                self.ser.port = self.port
                if not self.ser.isOpen():
                    try:
                        self.ser.open()
                    except serial.SerialException:
                        QMessageBox.about(self, "Ошибка!",
                                          "Выберите работающий COM порт!")
                        return

                self.qw.hide()
                self.faceWidget.show()

                self.set_camera(self.frame)

                # reset data for graphs
                self.data1 = []
                self.data2 = []
                self.timings = []
                self.emotions = []
                self.plot1.getAxis('bottom').setTicks([])
                self.plot2.getAxis('bottom').setTicks([])

                # new file
                self.fname = str(
                    len([
                        name for name in os.listdir('Sessions')
                        if os.path.isfile(os.path.join('Sessions', name))
                    ])) + '.emtn'
                if not os.path.isfile('Sessions/' + self.fname):
                    self.f = open('Sessions/' + self.fname, 'w')
                    self.f.close()
                self.f = open('Sessions/' + self.fname, 'r')
                self.f = open('Sessions/' + self.fname, 'w')
                self.f.write(self.vidFileName + "\n")
                self.f.write(os.getcwd() +
                             '/Recordings/{}.avi'.format(self.faceFileName) +
                             "\n")
            self.startButton.setText("Остановить")
            self.counter = 0
            self.counter1 = 0

            self.emotionsList = self.settings.emotions
            self.mediaPlayer.setMedia(
                QMediaContent(QUrl.fromLocalFile(self.vidFileName)))

            self.time = QtCore.QTime(0, 0, 0)
            self.timer = QtCore.QTimer()

            self.timer.timeout.connect(self.update)
            self.timer.start(4)

            self.mediaPlayer.play()
            self.clicked = True

    def set_camera(self, frame):
        try:
            if not self.fromFile:
                self.capture = cv2.VideoCapture(0)
                self.width = self.capture.get(cv2.CAP_PROP_FRAME_WIDTH)
                self.height = self.capture.get(cv2.CAP_PROP_FRAME_HEIGHT)
                self.fps = self.capture.get(cv2.CAP_PROP_FPS)
                if self.fps == 0 or self.fps == -1:
                    self.fps = int(25)
                    print(
                        "Warning: OpenCV failed to get your camera's frame rate, set to {}."
                        .format(self.fps))
                # start
                fourcc = cv2.VideoWriter_fourcc(*'XVID')
                self.faceFileName = len([
                    name for name in os.listdir('Recordings')
                    if os.path.isfile(os.path.join('Recordings', name))
                ])
                self.videoSaver = cv2.VideoWriter(
                    'Recordings/{}.avi'.format(self.faceFileName), fourcc,
                    cv2.CAP_PROP_FPS, (int(self.width), int(self.height)))
                self.start_video()

        except Exception as e:
            self.capture = None
            QMessageBox.about(self, "Ошибка!",
                              "Невозможно использовать вашу камеру.")
            print(str(e))

    def _draw_frame(self, frame):
        # convert to pixel
        cvtFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        img = QImage(cvtFrame, self.width, self.height, QImage.Format_RGB888)
        pix = QPixmap.fromImage(img)
        self.faceWidget.setPixmap(pix)
        outFrame = cv2.cvtColor(cvtFrame, cv2.COLOR_BGR2RGB)
        self.videoSaver.write(outFrame)
        QtGui.QApplication.processEvents()

    def _next_frame(self):
        try:
            if self.capture is not None:
                _ret, frame = self.capture.read()
                if frame is None:
                    QMessageBox.about(self, "Ошибка!",
                                      "Ошибка считывания изображения.")
                    print(
                        "ERROR: Read next frame failed with returned value {}."
                        .format(_ret))

                # Draw.
                self._draw_frame(frame)

        except Exception as e:
            QMessageBox.about(self, "Ошибка!",
                              "Ошибка считывания изображения.")
            print(str(e))
            # Saving output video
            if self.videoSaver:
                self.videoSaver.release()

    def start_video(self):
        self.videoTimer = QtCore.QTimer()
        self.videoTimer.timeout.connect(self._next_frame)
        self.videoTimer.start(1000 // self.fps)

    def pause_video(self):
        try:
            if self.capture != None:
                self.capture.release()
            self.capture = None
            self.faceWidget.clear()
            self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
            self.mediaPlayer.setVideoOutput(self.videoWidget)
            self.qw.show()
            self.faceWidget.show()
            self.videoSaver = None
            cv2.destroyAllWindows()
            self.clicked = False
            print("INFO: Streaming paused.")
        except Exception as e:
            print(str(e))

    def getDuration(self):
        self.maxTimer = float(self.facePlayer.duration() / 1000)
        print(self.maxTimer)

    # то что происходит каждый тик таймера
    def update(self):

        self.counter += 1
        # заглушка для считываемого потока
        # x = random.randint(0, 100)
        # y = random.randint(0, 100)
        ########################

        if not self.fromFile:
            # считка с устройства
            ch1, ch2 = self.readFromEEG()

            # получаем эмоцию
            emtn = self.getEmotion(ch1, ch2)

        # точки выводятся каждые 100 мс
        interval = 100 / 4
        if not self.fromFile:
            interval = 0.1 / 4
        if self.counter >= interval:
            interval *= 4
            self.counter = 0

            # добавляем точки только если их надо считывать
            if not self.fromFile:
                self.time = self.time.addMSecs(interval * 1000)
                self.timings.append(self.time.toString('mm:ss.zzz'))
                self.emotions.append(emtn)
                self.data1.append(ch1)
                self.data2.append(ch2)

                # запись в файл
                self.f.write(
                    str(ch1) + "|" + str(ch2) + "|" +
                    self.time.toString('mm:ss.zzz') + "|" + emtn + "\n")

            # все отображается по готовому набору данных и прокручивается каунтером1
            if (self.counter1 < len(self.data1)):
                self.EmotionLabel.setText("Текущая эмоция: " +
                                          self.emotions[self.counter1])
                self.updateGraphs()
                self.counter1 += 1
            curTime = time.time()
            # если все данные уже показаны то стоп
            if self.fromFile and (curTime - self.start
                                  ) > self.maxTimer and self.counter1 >= len(
                                      self.data1):
                self.stop()

    def updateGraphs(self):

        numbp = 200
        # скорость прокрутки - выводятся последние numbp точек
        pos = int(self.counter1 - numbp)
        if pos < 0:
            pos = 0

        xdict = dict(enumerate(self.timings[pos:self.counter1]))

        self.curve1.setData(self.data1[pos:self.counter1])
        self.plot1.getAxis('bottom').setTicks([xdict.items()])
        self.plot1.setXRange(0, numbp)

        self.curve2.setData(self.data2[pos:self.counter1])
        self.plot2.getAxis('bottom').setTicks([xdict.items()])
        self.plot2.setXRange(0, numbp)

    def getEmotion(self, ch1, ch2):

        for emt in self.emotionsList:
            isRight = False
            if emt.from_strength <= ch1 <= emt.to_strength:
                if emt.from_color <= ch2 <= emt.to_color:
                    isRight = True

            if isRight:
                return emt.name

        return "не определена"

    def setGraphs(self):
        # self.win.setWindowTitle('pyqtgraph example: Scrolling Plots')
        # Use automatic downsampling and clipping to reduce the drawing load
        self.plot1.setDownsampling(mode='peak')
        self.plot1.setClipToView(True)
        self.plot1.setRange(xRange=[0, 100])
        self.plot1.setLimits(xMin=0)

        self.plot2.setDownsampling(mode='peak')
        self.plot2.setClipToView(True)
        self.plot2.setRange(xRange=[0, 100])
        self.plot2.setLimits(xMin=0)

    def openFile(self):
        self.vidFileName, _ = QFileDialog.getOpenFileName(
            self, "Открыть видео", QDir.homePath(),
            "video files (*.avi *.mp4 *.gif)")

        if self.vidFileName != '':
            self.videoChosed = True

    def butter_bandpass(self, lowcut, highcut, fs, order=5):
        nyq = 0.5 * fs
        low = lowcut / nyq
        high = highcut / nyq
        b, a = butter(order, [low, high], btype='band')
        return b, a

    def butter_bandpass_filter(self, data, lowcut, highcut, fs=256, order=5):
        b, a = self.butter_bandpass(lowcut, highcut, fs, order=order)
        y = lfilter(b, a, data)
        return y

    def filter(self, data, hi, lo):
        fs = np.fft.rfft(data)
        q = np.fft.rfftfreq(len(data), 256)

        fs[(q > hi)] = 0
        fs[(q < lo)] = 0
        return np.fft.irfft(fs)

    def readFromEEG(self):
        n = 26
        strArr = np.zeros(n)
        pArr = np.zeros(n)

        for i in range(0, n):
            gotBegin = False

            # seek start
            while not gotBegin:

                # 1
                x = self.ser.read()
                while int.from_bytes(x, byteorder='big') != 165:
                    x = self.ser.read()
                gotBegin = True

                # 2
                x = self.ser.read()
                gotBegin = gotBegin and int.from_bytes(x,
                                                       byteorder='big') == 90

                # 3
                x = self.ser.read()
                gotBegin = gotBegin and int.from_bytes(x, byteorder='big') == 2

            # 4
            self.ser.read()

            def conv2sig(xb, yb):
                xi = int.from_bytes(xb, byteorder='big')
                yi = int.from_bytes(yb, byteorder='big')
                a = format(xi, 'b') + format(yi, 'b')
                return int(a, 2)

            # 5 and 6
            ch1 = conv2sig(self.ser.read(), self.ser.read())
            strArr[i] = ch1
            # 7 and 8
            ch2 = conv2sig(self.ser.read(), self.ser.read())
            pArr[i] = ch2

        out1 = self.butter_bandpass_filter(strArr, 8, 12)
        out2 = self.butter_bandpass_filter(pArr, 12, 30)
        # out1 = self.filter(strArr, 8, 12)
        # out2 = self.butter_bandpass_filter(strArr, 8, 12)

        a1 = np.mean(out1)
        a2 = abs(out1.min()) + abs(out1.max())
        a3 = out1[len(out1) - 1]

        b1 = np.mean(out2)
        b2 = abs(out2.min()) + abs(out2.max())
        b3 = out2[len(out2) - 1]

        return a2, b2

    def inputCom(self):

        text, ok = QInputDialog.getText(
            self, 'Выбор COM порта',
            'Введите номер COM порта, к которому подключено устройство:')

        if ok:
            if sys.platform.startswith('win'):
                self.port = 'COM' + text
            elif sys.platform.startswith('linux') or sys.platform.startswith(
                    'cygwin'):
                self.port = '/dev/ttyUSB' + text
            elif sys.platform.startswith('darwin'):
                self.port = '/dev/ttyUSB' + text
            else:
                raise EnvironmentError('Unsupported platform')
            self.ser.port = self.port
            if not self.ser.isOpen():
                try:
                    self.ser.open()
                except serial.SerialException:
                    QMessageBox.about(self, "Ошибка!",
                                      "Выберите работающий COM порт!")

    def loadFile(self):

        path, _ = QFileDialog.getOpenFileName(self, "Открыть файл",
                                              QDir.homePath(),
                                              "Emotion Files (*.emtn)")
        if path != '':
            self.fromFile = True
            f = open(path, 'r', encoding='utf-8', errors='ignore')

            allLines = f.readlines()
            f.close()
            try:
                self.vidFileName = allLines[0]
                self.vidFileName = self.vidFileName[:-1]

                self.faceFileName = allLines[1]
                self.faceFileName = self.faceFileName[:-1]
                allLines.remove(allLines[0])
                allLines.remove(allLines[0])

                # reset data for graphse
                self.data1 = []
                self.data2 = []
                self.timings = []
                self.emotions = []
                self.plot1.getAxis('bottom').setTicks([])
                self.plot2.getAxis('bottom').setTicks([])

                for line in allLines:
                    x = line.split('|')

                    self.data1.append(float(x[0]))
                    self.data2.append(float(x[1]))
                    self.timings.append(x[2])
                    self.emotions.append(x[3])

            except Exception as e:
                QMessageBox.about(self, "Ошибка!",
                                  "Файл поврежден или неверно сформирован.")

    def loadSettings(self):

        path, _ = QFileDialog.getOpenFileName(self, "Открыть настройки",
                                              QDir.homePath(),
                                              "txt files (*.txt)")
        if path != '':
            f = open(path, 'r')

            allLines = f.readlines()
            f.close()

            # считываем данные из файла и записываем эмоции
            self.emotions.clear()
            for line in allLines:
                s = line.rstrip("\r\n")
                x = s.split('|')
                emotion = Emotion(x[0], int(x[1]), int(x[2]), int(x[3]),
                                  int(x[4]))
                self.emotions.append(emotion)
            self.settings.loadEmotions(self.emotions)
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Information)
            msg.setText("Настройки загружены из файла.")
            msg.setWindowTitle("Уведомление")
            msg.exec_()
            self.openSettings()

    def openSettings(self):
        self.settings.show()
예제 #4
0
class VideoWindow(QWidget):
    def __init__(self, vidPath):
        super().__init__()
        self.fullPath = vidPath
        self.startTime = 0
        self.endTime = 0
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout()
        self.setLayout(layout)
        self.setWindowTitle(self.fullPath)

        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)

        self.videoWidget = QVideoWidget()

        self.playButton = QPushButton()
        self.playButton.setEnabled(True)
        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.playButton.setFixedWidth(100)
        self.playButton.setFixedHeight(50)
        self.playButton.clicked.connect(self.play)

        self.trimButton = QPushButton("Trim")
        self.trimButton.setFixedWidth(150)
        self.trimButton.setFixedHeight(50)
        self.trimButton.clicked.connect(self.trimVid)

        self.positionSlider = QSlider(QtCore.Qt.Horizontal)
        self.positionSlider.setRange(0, 0)
        self.positionSlider.sliderMoved.connect(self.setPosition)

        self.rangeSlider = qrangeslider.QRangeSlider()
        self.rangeSlider.setRange(0, 0)
        self.rangeSlider.endValueChanged.connect(self.adjustForEnd)
        self.rangeSlider.startValueChanged.connect(self.adjustForStart)
        self.rangeSlider.setFixedHeight(15)

        self.startTimeInput = QTimeEdit()
        self.endTimeInput = QTimeEdit()
        self.startTimeInput.setDisplayFormat('hh:mm:ss.zzz')
        self.endTimeInput.setDisplayFormat('hh:mm:ss.zzz')

        self.startTimeInput.timeChanged.connect(self.startInputChanged)
        self.endTimeInput.timeChanged.connect(self.endInputChanged)

        self.mediaPlayer.setMedia(
            QMediaContent(QtCore.QUrl.fromLocalFile(self.fullPath)))

        layout.addWidget(self.videoWidget)
        self.mediaPlayer.setVideoOutput(self.videoWidget)
        self.mediaPlayer.setNotifyInterval(10)
        self.mediaPlayer.stateChanged.connect(self.mediaStateChanged)
        self.mediaPlayer.positionChanged.connect(self.positionChanged)
        self.mediaPlayer.durationChanged.connect(self.durationChanged)

        controlLayout = QVBoxLayout()
        controlLayout.setContentsMargins(0, 0, 0, 0)
        controlLayout.addWidget(self.rangeSlider)
        controlLayout.addWidget(self.positionSlider)

        timeInputLayout = QHBoxLayout()
        timeInputLayout.addWidget(self.playButton)
        timeInputLayout.addWidget(self.startTimeInput)
        timeInputLayout.addWidget(self.endTimeInput)
        timeInputLayout.addWidget(self.trimButton)

        controlLayout.addLayout(timeInputLayout)

        layout.addLayout(controlLayout)

        self.mediaPlayer.play()

        self.resize(1024, 700)

        self.show()

    def closeEvent(self, event):
        self.mediaPlayer.stop()
        self.videoWidget.setParent(None)
        self.mediaPlayer.setParent(None)
        self.mediaPlayer.deleteLater()
        self.videoWidget.deleteLater()

    def trimVid(self):
        self.trimButton.setEnabled(False)
        outName = mytools.getAvailableName(self.fullPath, 'Trim')
        print(outName)
        trimStartTime = self.startTimeInput.time().toString('hh:mm:ss.zzz')
        trimEndTime = self.endTimeInput.time().toString('hh:mm:ss.zzz')
        try:
            ff = FFmpeg(inputs={self.fullPath: None},
                        outputs={
                            outName: [
                                '-ss',
                                trimStartTime,
                                '-to',
                                trimEndTime,
                                '-c:v',
                                'copy',
                                '-c:a',
                                'copy',
                            ]
                        })
            ff.run()
        except Exception as e:
            msg = QMessageBox()
            msg.setWindowTitle("Trim Failed")
            msg.setText(str(e))
            msg.setIcon(QMessageBox.Critical)

            showMsg = msg.exec_()
        self.trimButton.setEnabled(True)

    def play(self):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.mediaPlayer.pause()
        else:
            self.mediaPlayer.play()

    def mediaStateChanged(self, state):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.playButton.setIcon(self.style().standardIcon(
                QStyle.SP_MediaPause))
        else:
            self.playButton.setIcon(self.style().standardIcon(
                QStyle.SP_MediaPlay))

    def positionChanged(self, position):
        self.positionSlider.setValue(position)
        if position > self.endTime:
            self.mediaPlayer.setPosition(self.startTime)

    def adjustForStart(self, startPos):
        self.startTime = startPos
        self.mediaPlayer.setPosition(startPos)

        self.startTimeInput.setTime(QtCore.QTime(0, 0).addMSecs(startPos))
        self.endTimeInput.setMinimumTime(QtCore.QTime(0, 0).addMSecs(startPos))

    def adjustForEnd(self, endPos):
        self.endTime = endPos
        if self.positionSlider.value() > endPos:
            self.mediaPlayer.setPosition(endPos)

        self.endTimeInput.setTime(QtCore.QTime(0, 0).addMSecs(endPos))
        self.startTimeInput.setMaximumTime(QtCore.QTime(0, 0).addMSecs(endPos))

    def startInputChanged(self, inputTime):
        self.rangeSlider.setStart(QtCore.QTime(0, 0, 0, 0).msecsTo(inputTime))

    def endInputChanged(self, inputTime):
        self.rangeSlider.setEnd(QtCore.QTime(0, 0, 0, 0).msecsTo(inputTime))

    def durationChanged(self, duration):
        self.positionSlider.setRange(0, duration)
        self.rangeSlider.setMax(duration)
        self.rangeSlider.setEnd(duration)

        self.startTimeInput.setMinimumTime(QtCore.QTime(0, 0))
        self.endTimeInput.setMinimumTime(QtCore.QTime(0, 0))
        self.endTimeInput.setTime(QtCore.QTime(0, 0).addMSecs(duration))
        self.startTimeInput.setMaximumTime(
            QtCore.QTime(0, 0).addMSecs(duration))
        self.endTimeInput.setMaximumTime(QtCore.QTime(0, 0).addMSecs(duration))

    def setPosition(self, position):
        self.mediaPlayer.setPosition(position)