class Entries(list): def __init__(self): self.coords = (0, 0) self.baseColor = (0, 0, 1) self.selectedColor = (1, 0, 0) W, H = glfwGetWindowSize() self.entryFontScale = gameglobals.fontScale * 1.5 self.entryLineSpacing = 3 * self.entryFontScale self.cursorPos = (W / 2, H / 2) self.cursorAngle = 0.0 self.font_aa = GLFont(r"DATA\\FNT\\bold_aa.glf") self.defaultColor = (0.0, 1.0, 1.0) self.textureCursor = objects.loadTexture("DATA\\TEX\\cursor.png") def addEntry(self, string, state): #[text, active = False, state] self.append([string, False, state]) def setSelectionIndex(self, selection, entryIndex): if selection == 'Start Game': entryIndex.set(1) #set the menu index to ingame menu if selection == 'Restart Game': entryIndex.set(1) #set the menu index to ingame menu if selection == 'Exit to Main Menu': entryIndex.set(0) #set the menu index to main menu if selection == 'Rules of the game': entryIndex.set(2) #set the menu index to Rules of the game menu def applyInputs(self, entryIndex): W, H = glfwGetWindowSize() mx, my = glfwGetMousePos() my = -my if (mx, my + H) != self.cursorPos: if mx <= 0: mx = 0 if mx >= W: mx = W if my >= 0: my = 0 if my <= -H: my = -H self.cursorPos = (mx, my + H) glfwSetMousePos(mx, -my) #if mousebutton1 is pressed, enter selected menu W, H = glfwGetWindowSize() menuY = H / 2 + 50 * self.entryFontScale for i in range(len(self)): pos = i + 1 string = self[i][0] #vertical positioning will work fine only with one height for all entries x0 = W / 2 - self.font_aa.getSize( string)[0] * self.entryFontScale / 2 y0 = menuY - pos * self.font_aa.getSize( string)[1] * self.entryFontScale #+ self.entryLineSpacing x1 = x0 + self.font_aa.getSize(string)[0] * self.entryFontScale y1 = y0 + self.entryLineSpacing - self.font_aa.getSize( string)[1] * self.entryFontScale if vectormath.isPointInSquare( (self.cursorPos[0], 0, self.cursorPos[1]), (x0, y1), (x1, y0)): self[i][1] = True if glfwGetMouseButton(GLFW_MOUSE_BUTTON_1) == GLFW_PRESS\ and glfwGetMouseButton(GLFW_MOUSE_BUTTON_1) == GLFW_RELEASE: sounds.playSound("Menu", (0, 0, 0)) selection = self[i][0] gameglobals.gameState = self[i][2] self.setSelectionIndex(selection, entryIndex) def drawCursor(self): x, y = self.cursorPos self.font_aa.begin() glBindTexture(GL_TEXTURE_2D, self.textureCursor) glTranslatef(x, y, 0.0) glRotatef(self.cursorAngle, 0.0, 0.0, 1.0) self.cursorAngle += 0.5 glColor3f(1.0, 1.0, 1.0) glBegin(GL_QUADS) L = 10 * gameglobals.fontScale glTexCoord2f(0.0, 0.0) glVertex2i(-L, -L) glTexCoord2f(1.0, 0.0) glVertex2i(L, -L) glTexCoord2f(1.0, 1.0) glVertex2i(L, L) glTexCoord2f(0.0, 1.0) glVertex2i(-L, L) glEnd() self.font_aa.end() def drawDeveloper(self): W = glfwGetWindowSize()[0] glColor4f(1.0, 1.0, 1.0, 0.9) self.font_aa.begin() dScale = gameglobals.fontScale / 2 x = W - (self.font_aa.getSize(gameinfo.developer)[0] + 5) * dScale y = (self.font_aa.getSize(gameinfo.developer)[1] + 5) * dScale self.font_aa.renderOutlined(gameinfo.developer, x, y, (0, 0, 0), dScale) self.font_aa.end() def drawTitle(self): W, H = glfwGetWindowSize() title = ["3D game", "Squares"] glColor4f(0.0, 0.0, 1.0, 0.9) self.font_aa.begin() #unscaled font size is 14, i believe titleScale = gameglobals.fontScale * 2 y = H - H / 8 for row in title: x = W / 2 - self.font_aa.getSize(row)[0] * titleScale / 2 self.font_aa.renderOutlined(row, x, y, (0, 0, 0), titleScale) y -= self.font_aa.getSize(row)[1] * titleScale / 2 titleScale = gameglobals.fontScale * 4 self.font_aa.end() def draw(self): W, H = glfwGetWindowSize() menuY = H / 2 + 50 * self.entryFontScale for i in range(len(self)): pos = i + 1 string = self[i][0] #vertical positioning will work fine only with one height for all entries x = W / 2 - self.font_aa.getSize( string)[0] * self.entryFontScale / 2 y = menuY - pos * self.font_aa.getSize( string)[1] * self.entryFontScale + self.entryLineSpacing if self[i][1] == True: #if active color = [1, 0, 0] else: color = self.defaultColor glColor3f(color[0], color[1], color[2]) self.font_aa.begin() self.font_aa.render(string, x, y, self.entryFontScale) self.font_aa.end() self[i][1] = False self.resetColors() #render cursor self.drawDeveloper() def resetColors(self): for entry in self: entry[1] = self.defaultColor
class Entries(list): def __init__(self): self.coords = (0, 0) self.baseColor = (0,0,1) self.selectedColor = (1,0,0) W, H = glfwGetWindowSize() self.entryFontScale = gameglobals.fontScale * 1.5 self.entryLineSpacing = 3 * self.entryFontScale self.cursorPos = (W/2, H/2) self.cursorAngle = 0.0 self.font_aa = GLFont(r"DATA\\FNT\\bold_aa.glf") self.defaultColor = (0.0, 1.0, 1.0) self.textureCursor = objects.loadTexture("DATA\\TEX\\cursor.png") def addEntry(self, string, state): #[text, active = False, state] self.append([string, False, state]) def setSelectionIndex(self, selection, entryIndex): if selection == 'Start Game': entryIndex.set(1) #set the menu index to ingame menu if selection == 'Restart Game': entryIndex.set(1) #set the menu index to ingame menu if selection == 'Exit to Main Menu': entryIndex.set(0) #set the menu index to main menu if selection == 'Rules of the game': entryIndex.set(2) #set the menu index to Rules of the game menu def applyInputs(self, entryIndex): W, H = glfwGetWindowSize() mx, my = glfwGetMousePos() my = -my if (mx, my + H) != self.cursorPos: if mx <= 0: mx = 0 if mx >= W: mx = W if my >= 0: my = 0 if my <= -H: my = -H self.cursorPos = (mx, my + H) glfwSetMousePos(mx, -my) #if mousebutton1 is pressed, enter selected menu W, H = glfwGetWindowSize() menuY = H / 2 + 50 * self.entryFontScale for i in range(len(self)): pos = i + 1 string = self[i][0] #vertical positioning will work fine only with one height for all entries x0 = W / 2 - self.font_aa.getSize(string)[0] * self.entryFontScale / 2 y0 = menuY - pos * self.font_aa.getSize(string)[1] * self.entryFontScale #+ self.entryLineSpacing x1 = x0 + self.font_aa.getSize(string)[0] * self.entryFontScale y1 = y0 + self.entryLineSpacing - self.font_aa.getSize(string)[1] * self.entryFontScale if vectormath.isPointInSquare((self.cursorPos[0], 0, self.cursorPos[1]), (x0, y1), (x1, y0)): self[i][1] = True if glfwGetMouseButton(GLFW_MOUSE_BUTTON_1) == GLFW_PRESS\ and glfwGetMouseButton(GLFW_MOUSE_BUTTON_1) == GLFW_RELEASE: sounds.playSound("Menu", (0,0,0)) selection = self[i][0] gameglobals.gameState = self[i][2] self.setSelectionIndex(selection, entryIndex) def drawCursor(self): x, y = self.cursorPos self.font_aa.begin() glBindTexture(GL_TEXTURE_2D, self.textureCursor) glTranslatef(x, y, 0.0) glRotatef(self.cursorAngle, 0.0, 0.0, 1.0) self.cursorAngle += 0.5 glColor3f(1.0, 1.0, 1.0) glBegin(GL_QUADS) L = 10 * gameglobals.fontScale glTexCoord2f(0.0, 0.0); glVertex2i(-L, -L) glTexCoord2f(1.0, 0.0); glVertex2i( L, -L) glTexCoord2f(1.0, 1.0); glVertex2i( L, L) glTexCoord2f(0.0, 1.0); glVertex2i(-L, L) glEnd() self.font_aa.end() def drawDeveloper(self): W = glfwGetWindowSize()[0] glColor4f(1.0, 1.0, 1.0, 0.9) self.font_aa.begin() dScale = gameglobals.fontScale / 2 x = W - (self.font_aa.getSize(gameinfo.developer)[0] + 5) * dScale y = (self.font_aa.getSize(gameinfo.developer)[1] + 5) * dScale self.font_aa.renderOutlined(gameinfo.developer, x, y, (0,0,0), dScale) self.font_aa.end() def drawTitle(self): W, H = glfwGetWindowSize() title = ["3D game", "Squares"] glColor4f(0.0, 0.0, 1.0, 0.9) self.font_aa.begin() #unscaled font size is 14, i believe titleScale = gameglobals.fontScale * 2 y = H - H / 8 for row in title: x = W / 2 - self.font_aa.getSize(row)[0] * titleScale / 2 self.font_aa.renderOutlined(row, x, y, (0,0,0), titleScale) y -= self.font_aa.getSize(row)[1] * titleScale / 2 titleScale = gameglobals.fontScale * 4 self.font_aa.end() def draw(self): W, H = glfwGetWindowSize() menuY = H / 2 + 50 * self.entryFontScale for i in range(len(self)): pos = i + 1 string = self[i][0] #vertical positioning will work fine only with one height for all entries x = W / 2 - self.font_aa.getSize(string)[0] * self.entryFontScale / 2 y = menuY - pos * self.font_aa.getSize(string)[1] * self.entryFontScale + self.entryLineSpacing if self[i][1] == True: #if active color = [1,0,0] else: color = self.defaultColor glColor3f(color[0], color[1], color[2]) self.font_aa.begin() self.font_aa.render(string, x, y, self.entryFontScale) self.font_aa.end() self[i][1] = False self.resetColors() #render cursor self.drawDeveloper() def resetColors(self): for entry in self: entry[1] = self.defaultColor
class Coach: def __init__(self): self.state = 1 self.afterCollideTriggerBox = False self.beforeCollideTriggerBox = False self.initEvents() self.matchPoints = 21 self.ball = None self.gameOver = False #faults list will contain msg text, points, and delta up px for text self.faultMsgList = [] #hits list will contain combo, delta up px and coords of the collision (X HITS!) self.hitMsgList = [] self.taunts = [] self.players = {} self.scoreBoard = ScoreBoard(self.players) self.objectList = [] self.font_aa = GLFont(r"DATA\\FNT\\bold_aa.glf") def addTaunt(self, player, msg): pos = [player.body.getPosition()[0], player.body.getPosition()[1], player.body.getPosition()[2]] self.taunts.append([msg, 1.0, pos, player.color]) def restart(self): self.gameOver = False self.scoreBoard.reset() self.resetBall() self.resetPlayers() def setGameOver(self): sounds.playSound("GameOver", (0,0,0)) self.gameOver = True def getLoserNameColor(self): for name, object in self.players.items(): if self.scoreBoard[name][0] >= self.matchPoints: return name, object.color def initEvents(self): self.events = {'lastFieldOwner':None, 'lastTouchedObject':None, 'lastTouchedPlayer':None} def resetBall(self, resetCoords = (0.0, 10.0, 0.0)): if resetCoords == (0.0, 10.0, 0.0): #a little bit misadjust centered coords pairs = ((-0.01, 0.0), (-0.01, -0.01), (0.0, -0.01), (0.01, -0.01), (0.01, 0.0), (0.01, 0.01), (0.0, 0.01)) newXZ = pairs[randint(0, 6)] resetCoords = (newXZ[0], 10.0, newXZ[1]) self.ball.geom.reset = True self.ball.geom.resetCoords = resetCoords def resetPlayers(self): for player in self.players.values(): player.setInitPosition() player.setAngle() def getBallCoords(self, playerName): player = self.players[playerName] littleBit = ((player.min[0] + player.max[0]) / 5, (player.min[1] + player.max[1]) / 5) ballCoords = ((player.min[0] + player.max[0]) / 2 - littleBit[0], 3.3, (player.min[1] + player.max[1]) / 2 - littleBit[1]) return ballCoords def checkIsBallInSquare(self, ball, min, max): min0 = min[0] min1 = min[1] max0 = max[0] max1 = max[1] #0.5 is for the middle line if min0 == 0: min0 = max0 / 10 * 0.5 if min1 == 0: min1 = max1 / 10 * 0.5 if max0 == 0: max0 = min0 / 10 * 0.5 if max1 == 0: max1 = min1 / 10 * 0.5 return vectormath.isPointInSquare(ball, (min0, min1), (max0, max1)) def registerGroundEvent(self): #our objects of interest: ball, ground = self.ball, None #asign objects of interest for object in self.objectList: if object.name == 'Ground': ground = object #handle events ballCoords = ball.geom.getPosition() #ball + ground if ball.body.getLinearVel()[1] < -0.3: sounds.playSound("BallGround", ballCoords) if not vectormath.isPointInSquare(ballCoords, (-10, -10), (10, 10)): #critical event #BALL HAS HIT THE FIELD OUTSIDE #and we handle score here out = False if self.events['lastTouchedObject'] != None: #if last touched was not middle line lastTouchedObject = self.events['lastTouchedObject'].name if 'Player' in lastTouchedObject: #player has kicked the ball out pts = self.scoreBoard.addSelfPoints(lastTouchedObject) resetCoords = self.getBallCoords(lastTouchedObject) self.faultMsgList.append(['Out from ' + lastTouchedObject + '!', str(pts), 0]) out = lastTouchedObject getsPoints = lastTouchedObject elif self.events['lastFieldOwner']: #if ground was touched in one of the players field last add points to owner owner = self.events['lastFieldOwner'].name if self.events['lastTouchedPlayer']: #case when noone touched the ball after throwing minus lastPlayer = self.events['lastTouchedPlayer'].name if owner == lastPlayer: pts = self.scoreBoard.addSelfPoints(owner) else: pts = self.scoreBoard.addTotalPoints(owner) else: pts = self.scoreBoard.addPoint(owner) out = owner self.faultMsgList.append(['Out from ' + owner + '`s field!', str(pts), 0]) resetCoords = self.getBallCoords(owner) getsPoints = owner if self.scoreBoard[getsPoints][0] >= self.matchPoints: self.setGameOver() return else: self.faultMsgList.append(['Ball out from middle line!', '', 0]) resetCoords = (0, 10, 0) if out=="Player": pl = self.players[["Player_Red", "Player_Green", "Player_Yellow"][randint(0,2)]] #pl2 = self.players[["Player_Red", "Player_Green", "Player_Yellow"][randint(0,2)]] #while pl2==pl: # pl2 = self.players[["Player_Red", "Player_Green", "Player_Yellow"][randint(0,2)]] sounds.playTauntMsg(pl, "GreatShot", pl.body.getPosition()) self.addTaunt(pl, "Great shot!") # sounds.playTauntMsg(pl2, "Yes", pl.body.getPosition()) # self.addTaunt(pl2, "Yes!") ## print self.scoreBoard #finishing handling critical branch self.scoreBoard.resetJoinedCombo() self.initEvents() self.resetBall(resetCoords) self.resetPlayers() if out!=False and out!="Player": pl = self.players[out] sounds.playTauntMsg(pl, "MoveIn", pl.body.getPosition()) self.addTaunt(pl, "Move in!") else: #BALL HAS HIT THE FIELD INSIDE #save the touched field for p in self.players.values(): if self.checkIsBallInSquare(ballCoords, p.min, p.max): self.events['lastFieldOwner'] = p.geom self.events['lastTouchedObject'] = ground break self.events['lastTouchedObject'] = None #if has hit the middle line def registerPlayerEvent(self): ball = self.ball for object in self.objectList: if 'Player' in object.name: player = object #ball + player sounds.playSound("BallPlayer", ball.geom.getPosition()) lastTouchedObject = self.events['lastTouchedObject'] if lastTouchedObject == None: #picked from middle line self.scoreBoard.resetJoinedCombo() #clear combo self.scoreBoard.incrementCombo(player, self.hitMsgList) #(+1) else:#picked from ground or player if lastTouchedObject.name == 'Ground': #picked from ground inside self.scoreBoard.resetJoinedCombo() playerName = player.name self.scoreBoard.incrementCombo(player, self.hitMsgList) if (self.events['lastFieldOwner'] == player)\ and (self.events['lastTouchedPlayer'] == player)\ and vectormath.isPointInSquare(ball.geom.getPosition() , self.players[playerName].min , self.players[playerName].max): #critical event. double-touched -> fault if playerName=="Player": pl = self.players[["Player_Red", "Player_Green", "Player_Yellow"][randint(0,2)]] #pl2 = self.players[["Player_Red", "Player_Green", "Player_Yellow"][randint(0,2)]] #while pl2==pl: # pl2 = self.players[["Player_Red", "Player_Green", "Player_Yellow"][randint(0,2)]] sounds.playTauntMsg(pl, "AreYouCrazy", pl.body.getPosition()) self.addTaunt(pl, "Are you crazy?") #sounds.playTauntMsg(pl2, "No", pl.body.getPosition()) #self.addTaunt(pl2, "No!") resetCoords = self.getBallCoords(playerName) self.scoreBoard.addSelfPoints(playerName) self.faultMsgList.append([playerName + ' touched twice!', '1', 0]) if self.scoreBoard[playerName][0] >= self.matchPoints: self.setGameOver() return self.initEvents() self.resetBall(resetCoords) self.resetPlayers() return else: #picked from player if self.events['lastTouchedPlayer'] != player: #reset own combo, when picked from other self.scoreBoard.resetOwnCombo(player.name) self.scoreBoard.incrementCombo(player, self.hitMsgList) self.events['lastTouchedObject'] = player self.events['lastTouchedPlayer'] = player def register(self, player): name = player.geom.name self.players[name] = player #see scoreBoard.reset self.scoreBoard[name] = [0, 0] def msgFlowFunction(self, x, px): #this method is used to make the fault messages and "HITS" msg flow up and dissapear return 1.0 - (x/px) * (x/px)* (x/px)* (x/px) def draw(self, performance): W, H = glfwGetWindowSize() scale = gameglobals.fontScale nameScoreList = [] #draw players scores player = self.players['Player'] text = 'Player: ' + str(self.scoreBoard['Player'][0]) x = 10.0 y = self.font_aa.getSize(text)[1] * scale nameScoreList.append([text, x, y, player.color]) playerName = 'Player_Red' player = self.players[playerName] text = playerName + ': ' + str(self.scoreBoard[playerName][0]) x = 10.0 y = H nameScoreList.append([text, x, y, player.color]) playerName = 'Player_Green' player = self.players[playerName] text = playerName + ': ' + str(self.scoreBoard[playerName][0]) x = W - self.font_aa.getSize(text)[0] * scale - 10 y = H nameScoreList.append([text, x, y, player.color]) playerName = 'Player_Yellow' player = self.players[playerName] text = playerName + ': ' + str(self.scoreBoard[playerName][0]) x = W - self.font_aa.getSize(text)[0] * scale - 10 y = self.font_aa.getSize(text)[1] * scale nameScoreList.append([text, x, y, player.color]) self.font_aa.begin() for nameScore in nameScoreList: glColor3f(nameScore[3][0], nameScore[3][1], nameScore[3][2]) self.font_aa.renderShadowed(nameScore[0], nameScore[1], nameScore[2], (0,0,0), scale) self.font_aa.end() #draw "hits" messages px = 50 for hit in self.hitMsgList: if hit[1] < px: addend = self.msgFlowFunction(hit[1], px) hitText = ' HITS!' if hit[0] < 2: hitText = ' HIT!' text = '+' + str(hit[0]) + hitText pCoords = hit[2] x, y, _ = gluProject(pCoords[0], pCoords[1], pCoords[2]) y = y + hit[1] glColor4f(hit[3][0], hit[3][1], hit[3][2], addend) self.font_aa.begin() self.font_aa.renderOutlined(text, x, y, (0,0,0), scale) self.font_aa.end() hit[1] += 200 * (1.2 - addend) * performance else: self.hitMsgList = self.hitMsgList[1:] #draw the faults messages px = 80 for fault in self.faultMsgList: if fault[2] < px: addend = self.msgFlowFunction(fault[2], px) text = fault[0] pts = fault[1] x, y = W / 2 - self.font_aa.getSize(text)[0] * scale / 2, H - 50 * scale y = y + fault[2] glColor4f(1.0, 0.8, 0.0, addend) self.font_aa.begin() self.font_aa.renderShadowed(text, x, y, (0,0,0), scale) if pts: glColor4f(0.5, 0.8, 0.1, addend) pts = '+' + pts x = W / 2 - self.font_aa.getSize(pts)[0] * scale / 2 y -= self.font_aa.getSize(pts)[1] * scale self.font_aa.renderShadowed(pts, x, y, (0,0,0), scale) self.font_aa.end() fault[2] += 200 * (1.2 - addend) * performance else: self.faultMsgList = self.faultMsgList[1:] #draw the taunts px = 100 for taunt in self.taunts: if taunt[1] < px: addend = self.msgFlowFunction(taunt[1], px) text = taunt[0] pCoords = taunt[2] x, y, _ = gluProject(pCoords[0], pCoords[1], pCoords[2]) y = y + taunt[1] x = x - self.font_aa.getSize(text)[0] * scale / 2 c = taunt[3] #players.colorNamesColors[taunt[2]] glColor4f(c[0], c[1], c[2], addend) self.font_aa.begin() self.font_aa.renderShadowed(text, x, y, (0,0,0), scale) self.font_aa.end() taunt[1] += 200 * (1.2 - addend) * performance else: self.taunts= self.taunts[1:] #draw current total combo total = self.scoreBoard.getTotalPoints() if total > 1: comboScale = scale * 1.25 totalText = 'Combo ' + str(total) + '!' x = W / 2 - self.font_aa.getSize(totalText)[0] * comboScale / 2 y = 2 * self.font_aa.getSize(totalText)[1] * comboScale glColor4f(0.0, 1.0, 1.0, 1) self.font_aa.begin() self.font_aa.renderShadowed(totalText, x, y, (0,0,0), comboScale) self.font_aa.end() #draw game over message if self.gameOver == True: loserMsg, loserColor = self.getLoserNameColor() loserMsg += ' lost!' msg = 'Game Over' loserScale = scale * 1.25 gOverScale = scale * 2.5 x0 = W / 2 - self.font_aa.getSize(loserMsg)[0] * loserScale / 2 y0 = H / 2 + H / 4 - self.font_aa.getSize(loserMsg)[1] * loserScale / 2 x1 = W / 2 - self.font_aa.getSize(msg)[0] * gOverScale / 2 y1 = H / 2 - self.font_aa.getSize(msg)[1] * gOverScale / 2 self.font_aa.begin() glColor4f(loserColor[0], loserColor[1], loserColor[2], 0.9) self.font_aa.render(loserMsg, x0, y0, loserScale) glColor4f(1.0, 0.0, 0.0, 0.9) self.font_aa.render(msg, x1, y1, gOverScale) self.font_aa.end() def manageGame(self): #This is the main logic function of the coach #Coach has 3 states to keep in mind when registering event #States are needed to avoid registering ball+player event when #the ball is standing on player not bouncing #This is the place where TriggerBox is used if not self.gameOver: objectNames = [object.name for object in self.objectList] beforeCollideTriggerBox = self.afterCollideTriggerBox #initvalue=False self.afterCollideTriggerBox = ('Trigger' in objectNames)# True if ball and TriggerBox collide else False afterCollidePlayer = ('Player' in ''.join(objectNames)) # True if ball and Player collide else False if 'Ground' in objectNames: self.registerGroundEvent() if self.state==1 and beforeCollideTriggerBox==False and self.afterCollideTriggerBox==True: self.state=2 if self.state==2 and afterCollidePlayer==True: self.registerPlayerEvent() self.state=3 elif self.state==2 and beforeCollideTriggerBox==True and self.afterCollideTriggerBox==False: self.state=1 elif self.state==3 and self.afterCollideTriggerBox==False: self.state=1
class Coach: def __init__(self): self.state = 1 self.afterCollideTriggerBox = False self.beforeCollideTriggerBox = False self.initEvents() self.matchPoints = 21 self.ball = None self.gameOver = False #faults list will contain msg text, points, and delta up px for text self.faultMsgList = [] #hits list will contain combo, delta up px and coords of the collision (X HITS!) self.hitMsgList = [] self.taunts = [] self.players = {} self.scoreBoard = ScoreBoard(self.players) self.objectList = [] self.font_aa = GLFont(r"DATA\\FNT\\bold_aa.glf") def addTaunt(self, player, msg): pos = [ player.body.getPosition()[0], player.body.getPosition()[1], player.body.getPosition()[2] ] self.taunts.append([msg, 1.0, pos, player.color]) def restart(self): self.gameOver = False self.scoreBoard.reset() self.resetBall() self.resetPlayers() def setGameOver(self): sounds.playSound("GameOver", (0, 0, 0)) self.gameOver = True def getLoserNameColor(self): for name, object in self.players.items(): if self.scoreBoard[name][0] >= self.matchPoints: return name, object.color def initEvents(self): self.events = { 'lastFieldOwner': None, 'lastTouchedObject': None, 'lastTouchedPlayer': None } def resetBall(self, resetCoords=(0.0, 10.0, 0.0)): if resetCoords == (0.0, 10.0, 0.0): #a little bit misadjust centered coords pairs = ((-0.01, 0.0), (-0.01, -0.01), (0.0, -0.01), (0.01, -0.01), (0.01, 0.0), (0.01, 0.01), (0.0, 0.01)) newXZ = pairs[randint(0, 6)] resetCoords = (newXZ[0], 10.0, newXZ[1]) self.ball.geom.reset = True self.ball.geom.resetCoords = resetCoords def resetPlayers(self): for player in self.players.values(): player.setInitPosition() player.setAngle() def getBallCoords(self, playerName): player = self.players[playerName] littleBit = ((player.min[0] + player.max[0]) / 5, (player.min[1] + player.max[1]) / 5) ballCoords = ((player.min[0] + player.max[0]) / 2 - littleBit[0], 3.3, (player.min[1] + player.max[1]) / 2 - littleBit[1]) return ballCoords def checkIsBallInSquare(self, ball, min, max): min0 = min[0] min1 = min[1] max0 = max[0] max1 = max[1] #0.5 is for the middle line if min0 == 0: min0 = max0 / 10 * 0.5 if min1 == 0: min1 = max1 / 10 * 0.5 if max0 == 0: max0 = min0 / 10 * 0.5 if max1 == 0: max1 = min1 / 10 * 0.5 return vectormath.isPointInSquare(ball, (min0, min1), (max0, max1)) def registerGroundEvent(self): #our objects of interest: ball, ground = self.ball, None #asign objects of interest for object in self.objectList: if object.name == 'Ground': ground = object #handle events ballCoords = ball.geom.getPosition() #ball + ground if ball.body.getLinearVel()[1] < -0.3: sounds.playSound("BallGround", ballCoords) if not vectormath.isPointInSquare(ballCoords, (-10, -10), (10, 10)): #critical event #BALL HAS HIT THE FIELD OUTSIDE #and we handle score here out = False if self.events[ 'lastTouchedObject'] != None: #if last touched was not middle line lastTouchedObject = self.events['lastTouchedObject'].name if 'Player' in lastTouchedObject: #player has kicked the ball out pts = self.scoreBoard.addSelfPoints(lastTouchedObject) resetCoords = self.getBallCoords(lastTouchedObject) self.faultMsgList.append( ['Out from ' + lastTouchedObject + '!', str(pts), 0]) out = lastTouchedObject getsPoints = lastTouchedObject elif self.events[ 'lastFieldOwner']: #if ground was touched in one of the players field last add points to owner owner = self.events['lastFieldOwner'].name if self.events['lastTouchedPlayer']: #case when noone touched the ball after throwing minus lastPlayer = self.events['lastTouchedPlayer'].name if owner == lastPlayer: pts = self.scoreBoard.addSelfPoints(owner) else: pts = self.scoreBoard.addTotalPoints(owner) else: pts = self.scoreBoard.addPoint(owner) out = owner self.faultMsgList.append( ['Out from ' + owner + '`s field!', str(pts), 0]) resetCoords = self.getBallCoords(owner) getsPoints = owner if self.scoreBoard[getsPoints][0] >= self.matchPoints: self.setGameOver() return else: self.faultMsgList.append(['Ball out from middle line!', '', 0]) resetCoords = (0, 10, 0) if out == "Player": pl = self.players[[ "Player_Red", "Player_Green", "Player_Yellow" ][randint(0, 2)]] #pl2 = self.players[["Player_Red", "Player_Green", "Player_Yellow"][randint(0,2)]] #while pl2==pl: # pl2 = self.players[["Player_Red", "Player_Green", "Player_Yellow"][randint(0,2)]] sounds.playTauntMsg(pl, "GreatShot", pl.body.getPosition()) self.addTaunt(pl, "Great shot!") # sounds.playTauntMsg(pl2, "Yes", pl.body.getPosition()) # self.addTaunt(pl2, "Yes!") ## print self.scoreBoard #finishing handling critical branch self.scoreBoard.resetJoinedCombo() self.initEvents() self.resetBall(resetCoords) self.resetPlayers() if out != False and out != "Player": pl = self.players[out] sounds.playTauntMsg(pl, "MoveIn", pl.body.getPosition()) self.addTaunt(pl, "Move in!") else: #BALL HAS HIT THE FIELD INSIDE #save the touched field for p in self.players.values(): if self.checkIsBallInSquare(ballCoords, p.min, p.max): self.events['lastFieldOwner'] = p.geom self.events['lastTouchedObject'] = ground break self.events[ 'lastTouchedObject'] = None #if has hit the middle line def registerPlayerEvent(self): ball = self.ball for object in self.objectList: if 'Player' in object.name: player = object #ball + player sounds.playSound("BallPlayer", ball.geom.getPosition()) lastTouchedObject = self.events['lastTouchedObject'] if lastTouchedObject == None: #picked from middle line self.scoreBoard.resetJoinedCombo() #clear combo self.scoreBoard.incrementCombo(player, self.hitMsgList) #(+1) else: #picked from ground or player if lastTouchedObject.name == 'Ground': #picked from ground inside self.scoreBoard.resetJoinedCombo() playerName = player.name self.scoreBoard.incrementCombo(player, self.hitMsgList) if (self.events['lastFieldOwner'] == player)\ and (self.events['lastTouchedPlayer'] == player)\ and vectormath.isPointInSquare(ball.geom.getPosition() , self.players[playerName].min , self.players[playerName].max): #critical event. double-touched -> fault if playerName == "Player": pl = self.players[[ "Player_Red", "Player_Green", "Player_Yellow" ][randint(0, 2)]] #pl2 = self.players[["Player_Red", "Player_Green", "Player_Yellow"][randint(0,2)]] #while pl2==pl: # pl2 = self.players[["Player_Red", "Player_Green", "Player_Yellow"][randint(0,2)]] sounds.playTauntMsg(pl, "AreYouCrazy", pl.body.getPosition()) self.addTaunt(pl, "Are you crazy?") #sounds.playTauntMsg(pl2, "No", pl.body.getPosition()) #self.addTaunt(pl2, "No!") resetCoords = self.getBallCoords(playerName) self.scoreBoard.addSelfPoints(playerName) self.faultMsgList.append( [playerName + ' touched twice!', '1', 0]) if self.scoreBoard[playerName][0] >= self.matchPoints: self.setGameOver() return self.initEvents() self.resetBall(resetCoords) self.resetPlayers() return else: #picked from player if self.events[ 'lastTouchedPlayer'] != player: #reset own combo, when picked from other self.scoreBoard.resetOwnCombo(player.name) self.scoreBoard.incrementCombo(player, self.hitMsgList) self.events['lastTouchedObject'] = player self.events['lastTouchedPlayer'] = player def register(self, player): name = player.geom.name self.players[name] = player #see scoreBoard.reset self.scoreBoard[name] = [0, 0] def msgFlowFunction(self, x, px): #this method is used to make the fault messages and "HITS" msg flow up and dissapear return 1.0 - (x / px) * (x / px) * (x / px) * (x / px) def draw(self, performance): W, H = glfwGetWindowSize() scale = gameglobals.fontScale nameScoreList = [] #draw players scores player = self.players['Player'] text = 'Player: ' + str(self.scoreBoard['Player'][0]) x = 10.0 y = self.font_aa.getSize(text)[1] * scale nameScoreList.append([text, x, y, player.color]) playerName = 'Player_Red' player = self.players[playerName] text = playerName + ': ' + str(self.scoreBoard[playerName][0]) x = 10.0 y = H nameScoreList.append([text, x, y, player.color]) playerName = 'Player_Green' player = self.players[playerName] text = playerName + ': ' + str(self.scoreBoard[playerName][0]) x = W - self.font_aa.getSize(text)[0] * scale - 10 y = H nameScoreList.append([text, x, y, player.color]) playerName = 'Player_Yellow' player = self.players[playerName] text = playerName + ': ' + str(self.scoreBoard[playerName][0]) x = W - self.font_aa.getSize(text)[0] * scale - 10 y = self.font_aa.getSize(text)[1] * scale nameScoreList.append([text, x, y, player.color]) self.font_aa.begin() for nameScore in nameScoreList: glColor3f(nameScore[3][0], nameScore[3][1], nameScore[3][2]) self.font_aa.renderShadowed(nameScore[0], nameScore[1], nameScore[2], (0, 0, 0), scale) self.font_aa.end() #draw "hits" messages px = 50 for hit in self.hitMsgList: if hit[1] < px: addend = self.msgFlowFunction(hit[1], px) hitText = ' HITS!' if hit[0] < 2: hitText = ' HIT!' text = '+' + str(hit[0]) + hitText pCoords = hit[2] x, y, _ = gluProject(pCoords[0], pCoords[1], pCoords[2]) y = y + hit[1] glColor4f(hit[3][0], hit[3][1], hit[3][2], addend) self.font_aa.begin() self.font_aa.renderOutlined(text, x, y, (0, 0, 0), scale) self.font_aa.end() hit[1] += 200 * (1.2 - addend) * performance else: self.hitMsgList = self.hitMsgList[1:] #draw the faults messages px = 80 for fault in self.faultMsgList: if fault[2] < px: addend = self.msgFlowFunction(fault[2], px) text = fault[0] pts = fault[1] x, y = W / 2 - self.font_aa.getSize( text)[0] * scale / 2, H - 50 * scale y = y + fault[2] glColor4f(1.0, 0.8, 0.0, addend) self.font_aa.begin() self.font_aa.renderShadowed(text, x, y, (0, 0, 0), scale) if pts: glColor4f(0.5, 0.8, 0.1, addend) pts = '+' + pts x = W / 2 - self.font_aa.getSize(pts)[0] * scale / 2 y -= self.font_aa.getSize(pts)[1] * scale self.font_aa.renderShadowed(pts, x, y, (0, 0, 0), scale) self.font_aa.end() fault[2] += 200 * (1.2 - addend) * performance else: self.faultMsgList = self.faultMsgList[1:] #draw the taunts px = 100 for taunt in self.taunts: if taunt[1] < px: addend = self.msgFlowFunction(taunt[1], px) text = taunt[0] pCoords = taunt[2] x, y, _ = gluProject(pCoords[0], pCoords[1], pCoords[2]) y = y + taunt[1] x = x - self.font_aa.getSize(text)[0] * scale / 2 c = taunt[3] #players.colorNamesColors[taunt[2]] glColor4f(c[0], c[1], c[2], addend) self.font_aa.begin() self.font_aa.renderShadowed(text, x, y, (0, 0, 0), scale) self.font_aa.end() taunt[1] += 200 * (1.2 - addend) * performance else: self.taunts = self.taunts[1:] #draw current total combo total = self.scoreBoard.getTotalPoints() if total > 1: comboScale = scale * 1.25 totalText = 'Combo ' + str(total) + '!' x = W / 2 - self.font_aa.getSize(totalText)[0] * comboScale / 2 y = 2 * self.font_aa.getSize(totalText)[1] * comboScale glColor4f(0.0, 1.0, 1.0, 1) self.font_aa.begin() self.font_aa.renderShadowed(totalText, x, y, (0, 0, 0), comboScale) self.font_aa.end() #draw game over message if self.gameOver == True: loserMsg, loserColor = self.getLoserNameColor() loserMsg += ' lost!' msg = 'Game Over' loserScale = scale * 1.25 gOverScale = scale * 2.5 x0 = W / 2 - self.font_aa.getSize(loserMsg)[0] * loserScale / 2 y0 = H / 2 + H / 4 - self.font_aa.getSize( loserMsg)[1] * loserScale / 2 x1 = W / 2 - self.font_aa.getSize(msg)[0] * gOverScale / 2 y1 = H / 2 - self.font_aa.getSize(msg)[1] * gOverScale / 2 self.font_aa.begin() glColor4f(loserColor[0], loserColor[1], loserColor[2], 0.9) self.font_aa.render(loserMsg, x0, y0, loserScale) glColor4f(1.0, 0.0, 0.0, 0.9) self.font_aa.render(msg, x1, y1, gOverScale) self.font_aa.end() def manageGame(self): #This is the main logic function of the coach #Coach has 3 states to keep in mind when registering event #States are needed to avoid registering ball+player event when #the ball is standing on player not bouncing #This is the place where TriggerBox is used if not self.gameOver: objectNames = [object.name for object in self.objectList] beforeCollideTriggerBox = self.afterCollideTriggerBox #initvalue=False self.afterCollideTriggerBox = ( 'Trigger' in objectNames ) # True if ball and TriggerBox collide else False afterCollidePlayer = ( 'Player' in ''.join(objectNames) ) # True if ball and Player collide else False if 'Ground' in objectNames: self.registerGroundEvent() if self.state == 1 and beforeCollideTriggerBox == False and self.afterCollideTriggerBox == True: self.state = 2 if self.state == 2 and afterCollidePlayer == True: self.registerPlayerEvent() self.state = 3 elif self.state == 2 and beforeCollideTriggerBox == True and self.afterCollideTriggerBox == False: self.state = 1 elif self.state == 3 and self.afterCollideTriggerBox == False: self.state = 1