How can i fix angled line error in pyqt5? - pyqt

I'm implementing paint program with pyqt5.
Currently, I am making a service that targets not only fhd but also 4k.
But it is difficult to adjust in 4K (high-resolution).
In fhd, the line is not angled, but in 4k, the line is angled.
Please help me how can i fix this problem. :(
If it is difficult to understand the code, if you request additionally, I will share it on github.
class LogoClass(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.setGeometry(0, 0, APP.desktop().screenGeometry().width(), APP.desktop().screenGeometry().height())
self.image = []
self.image.append(0)
self.image[0] = QtGui.QImage(self.size(), QtGui.QImage.Format_ARGB32)
self.image[0].fill(backColor)
self.imageDraw = []
self.imageDraw.append(0)
self.imageDraw[0] = QImage(self.size(), QImage.Format_ARGB32)
self.imageDraw[0].fill(QtCore.Qt.transparent)
print("size is " + str(self.size()) + " "+str(self.imageDraw[0].rect()))
self.imageDraw2 = QImage(self.size(), QImage.Format_ARGB32)
self.imageDraw2.fill(QtCore.Qt.transparent)
self.drawing = False
# self._clear_size = 50
self.brushColor = QtGui.QColor(QtCore.Qt.black)
self.lastPoint = QtCore.QPoint()
self.beginPoint = QtCore.QPoint()
self.last_x, self.last_y = None, None
self.timer = QTimer(self)
self.timer.setInterval(2000)
self.timer.timeout.connect(self.timeout)
self.rectanglestartx = []
self.rectanglestarty = []
self.rectanglesendx = []
self.rectanglesendy = []
self.lines = []
self.drawingPath= None
self.drawingPath_pen = None
self.stack_logo = QStackedWidget(self)
self.stack_logo.setGeometry(0, 0, APP.desktop().screenGeometry().width(), APP.desktop().screenGeometry().height())
self.setWindowFlag(QtCore.Qt.Tool)
self.startPoint = None
self.endPoint = None
self.stack_logo.addWidget(QWidget())
self.max = 1
self.point = QPoint()
def paintEvent(self, event):
canvasPainter = QPainter(self)
# canvasPainter.setRenderHints(QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform)
#print("current index is "+str(self.stack.currentIndex()))
canvasPainter.drawImage(self.rect(), self.image[self.stack_logo.currentIndex()], self.image[self.stack_logo.currentIndex()].rect())
canvasPainter.drawImage(self.rect(), self.imageDraw[self.stack_logo.currentIndex()], self.imageDraw[self.stack_logo.currentIndex()].rect())
canvasPainter.drawImage(self.rect(), self.imageDraw2, self.imageDraw2.rect())
if self.drawingPath:
pen = QtGui.QPen(QColor(colorR, colorG, colorB, alpha), penthick, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
QtCore.Qt.RoundJoin)
canvasPainter.setPen(pen)
canvasPainter.drawPath(self.drawingPath)
canvasPainter.end()
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
if cutwidget.isVisible() == 1:
cutwidget.hide()
if checkthick.isVisible() == 1:
checkthick.hide()
if checkbackgroundcolor.isVisible() == 1:
checkbackgroundcolor.hide()
if cutoption.isVisible() == 1:
cutoption.hide()
if objectoption.isVisible() == 1:
objectoption.hide()
if logooption.isVisible() == 1:
logooption.hide()
if setting.isVisible() == 1:
setting.hide()
if undertoolbar.btn_deleteAll_check == 1:
painter = QtGui.QPainter(self.imageDraw[self.stack_logo.currentIndex()])
# print("enter deletall button")
painter.save()
painter.setCompositionMode(QtGui.QPainter.CompositionMode_Clear)
painter.eraseRect(0, 0, APP.desktop().screenGeometry().width(), APP.desktop().screenGeometry().height())
painter.restore()
elif undertoolbar.btn_hold_check == 1:
self.beginPoint = event.pos()
elif undertoolbar.btn_lightpen_check == 1:
self.drawingPath = QPainterPath()
self.drawingPath.moveTo(event.pos())
elif undertoolbar.btn_pen1_check == 1:
self.drawingPath_pen = QPainterPath()
self.drawingPath_pen.moveTo(event.pos())
elif undertoolbar.btn_eraser_check == 1:
self.changeColour()
if undostack_logo.index()==0:
undocommand_logo = UndoCommand_logo(0,0,0,0,
self.imageDraw[self.stack_logo.currentIndex()], self)
undostack_logo.push(undocommand_logo)
self.drawing = True
self.lastPoint = event.pos()
self.beginPoint = event.pos()
"""if undertoolbar.btn_cut1_check == 1:
self.beginPoint = event.pos()
self.endPoint = event.pos()
self.update()"""
def mouseMoveEvent(self, event):
if event.buttons() and QtCore.Qt.LeftButton and self.drawing:
painter = QPainter(self.imageDraw[self.stack_logo.currentIndex()])
painter.setPen(
QtGui.QPen(QColor(colorR, colorG, colorB, alpha), penthick, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
QtCore.Qt.RoundJoin))
painter.setRenderHints(QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform)
if undertoolbar.btn_pen1_check == 1:
painter.drawLine(self.lastPoint, event.pos())
# self.drawingPath_pen.lineto(event.pos())
elif undertoolbar.btn_eraser_check == 1:
# print("mouse event eraser")
# self.changeColour()
r = QtCore.QRect(QtCore.QPoint(), erasersize * QtCore.QSize())
r.moveCenter(event.pos())
painter.save()
painter.setCompositionMode(QtGui.QPainter.CompositionMode_Clear)
painter.eraseRect(r)
painter.restore()
elif undertoolbar.btn_lightpen_check == 1 and self.drawingPath:
self.changeColour()
# print("mouse event lightpen")
painter.drawLine(self.lastPoint, event.pos())
# self.drawingPath.lineTo(event.pos())
elif undertoolbar.btn_hold_check == 1:
painter2 = QtGui.QPainter(self.imageDraw2)
painter2.setPen(
QtGui.QPen(QColor(255, 0, 0, 255), 3, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
QtCore.Qt.RoundJoin))
painter2.setRenderHints(QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform)
painter2.drawLine(self.lastPoint, event.pos())
self.timer.stop()
painter2.end()
painter.end()
self.lastPoint = event.pos()
self.update()
def mouseReleaseEvent(self, event):
if undertoolbar.btn_hold_check == 1:
self.timer.start()
self.rectanglestartx.append(self.beginPoint.x())
self.rectanglestarty.append(self.beginPoint.y())
self.rectanglesendx.append(self.lastPoint.x())
self.rectanglesendy.append(self.lastPoint.y())
elif undertoolbar.btn_pen1_check == 1:
undocommand_logo = UndoCommand_logo(self.lastPoint.x(), self.lastPoint.y(), event.pos().x(),
event.pos().y(),
self.imageDraw[self.stack_logo.currentIndex()], self)
undostack_logo.push(undocommand_logo)
# painter = QPainter(self.imageDraw[self.stack_logo.currentIndex()])
# painter.setRenderHints(QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform)
# painter.setPen(
# QtGui.QPen(QColor(colorR, colorG, colorB, 255), penthick, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
# QtCore.Qt.RoundJoin))
# painter.drawPath(self.drawingPath_pen)
# painter.end()
elif undertoolbar.btn_lightpen_check == 1:
undocommand_logo = UndoCommand_logo(self.lastPoint.x(), self.lastPoint.y(), event.pos().x(),
event.pos().y(),
self.imageDraw[self.stack_logo.currentIndex()], self)
undostack_logo.push(undocommand_logo)
painter = QPainter(self.imageDraw[self.stack_logo.currentIndex()])
painter.setRenderHints(QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform)
painter.setPen(
QtGui.QPen(QColor(colorR, colorG, colorB, alpha), penthick, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap,
QtCore.Qt.RoundJoin))
painter.drawPath(self.drawingPath)
painter.end()
elif undertoolbar.btn_eraser_check == 1:
QApplication.setOverrideCursor(Qt.ArrowCursor)
self.drawing = False
self.drawingPath = None
self.drawingPath_pen = None
def changeColour(self):
if undertoolbar.btn_eraser_check == 1:
print("change colour eraser check")
#pixmap = QtGui.QPixmap(QtCore.QSize(1, 1) * erasersize)
#pixmap.fill(QtCore.Qt.transparent)
# cursor = QtGui.QCursor(pixmap)
pixmap = QtGui.QPixmap('./icon/eraser/8.png').scaled(erasersize, erasersize, Qt.KeepAspectRatio)
cursor = QtGui.QCursor(pixmap)
QtWidgets.QApplication.setOverrideCursor(cursor)
# print(cursor)
# painter = QtGui.QPainter(pixmap)
# painter.setPen(QtGui.QPen(QtCore.Qt.black, 2))
# painter.drawRect(pixmap.rect())
# painter.end()
# elif undertoolbar.btn_pen1_check == 1 or undertoolbar.btn_lightpen_check == 1 or undertoolbar.btn_hold_check == 1 or undertoolbar.btn_pointer_check==1 or undertoolbar.btn_deleteAll_check==1 or undertoolbar.btn_cut1_check ==1 or undertoolbar.btn_background_color_check ==1:
# print("change colour pen check")
# #QtWidgets.QApplication.restoreOverrideCursor()
# # self.setCursor(QtCore.Qt.ArrowCursor)
def timeout(self):
qp = QPainter(self.imageDraw2)
for i in range(0, len(self.rectanglesendy)):
qp.save()
qp.setCompositionMode(QtGui.QPainter.CompositionMode_Clear)
qp.eraseRect(0, 0, sizex, sizey)
qp.restore()
self.update()
qp.end()
def keyPressEvent(self, event):
global undostack_logo
if event.key() == (Qt.Key_Control and Qt.Key_Y):
undostack_logo.redo()
if event.key() == (Qt.Key_Control and Qt.Key_Z):
length = len(logoclass.lines)
if length !=0:
i = length - 1
while i != 0:
if logoclass.lines[i][0] == logoclass.lines[i - 1][2] and logoclass.lines[i][1] == \
logoclass.lines[i - 1][3]:
undostack_logo.undo()
i = i - 1
else:
print(i)
undostack_logo.undo()
i = i - 1
break

Related

Py-Game Connect4 - Minimax (Program Halting Recursively)

main.py
from Player import Player
import tkinter as tk
import pygame
import pygame_menu
import time
import colors
import Connect4 as cFour
import Minimax as mx
def text_format(option, textSize, textColor):
"""
Creates a text object to show in the main menu
"""
newFont = pygame.font.Font(pygame_menu.font.FONT_FRANCHISE, textSize)
newText = newFont.render(option, 0, textColor)
return newText
def load_screen():
"""
This initializes the window for pygame to use
"""
screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Connect4")
return screen
def get_player_details(screen):
"""
Creates a tkinter object(button) that gets players names
"""
root = tk.Tk()
root.title("Player Names!")
tk.Label(root, text="Player One", fg="blue").grid(row=0)
tk.Label(root, text="Player Two", fg="red").grid(row=1)
p1 = tk.Entry(root, font=(None, 15))
p2 = tk.Entry(root, font=(None, 15))
p1.grid(row=0, column=1)
p2.grid(row=1, column=1)
tk.Button(root, text='Play!', command= lambda: play_game(p1.get(),p2.get(), root, screen)).grid(row=10, column=1, sticky=tk.W)
tk.mainloop()
def get_player_ai_details(screen):
"""
Creating the panel to allow the user to select a color and go against the AI
"""
options = ["Player 1", "Player 2"]
root = tk.Tk()
root.title("Player 1(Blue) or 2(Red)?")
colorChoice= tk.StringVar(root)
colorChoice.set(options[0])
tk.OptionMenu(root, colorChoice, *options).grid(row=3)
p1 = tk.Entry(root, font=(None, 15))
p1.grid(row=3, column=1)
tk.Button(root, text="Play Computer!", command=lambda: play_computer(colorChoice.get(), p1.get(), root, screen)).grid(row=10, column=1)
tk.mainloop()
def play_computer(colorChoice, playerName, root, screen):
"""
Connect4 play function (human v computer)
"""
root.destroy()
if colorChoice == "Player 1":
mx.Minimax(Player(playerName), Player("Ed"), screen).play_computer()
else:
mx.Minimax(Player("Ed"), Player(playerName), screen).play_computer()
def play_game(p1Name, p2Name, root, screen):
"""
Connect4 play function (human v human)
"""
root.destroy()
game = cFour.Connect4(Player(p1Name.strip()), Player(p2Name.strip()), screen).play()
if __name__ == "__main__":
pygame.init()
screen = load_screen()
features = [
("Player Vs Player", colors.yellow),
("Player Vs AI", colors.red),
("Quit", colors.gray)
]
iterator = 0
menu = True
while menu:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
#This if block makes it where the user doesnt have to click arrow key up/down if they have exhausted the possible options, it will loop you throughout options
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
iterator += 1
if iterator == len(features):
iterator = 0
if event.key == pygame.K_UP:
iterator -= 1
if iterator < 0:
iterator = len(features) - 1
if event.key == pygame.K_RETURN:
if selected == "Player Vs Player":
get_player_details(screen)
if selected == "Player Vs AI":
get_player_ai_details(screen)
if selected == "Quit":
pygame.quit()
quit()
selected = features[iterator][0]
screen.fill(colors.blue)
screen_rect = screen.get_rect()
for i in range(0, len(features)):
counter = -50 + (i * 90) # Equation that sets distance between each choice in main menu
if i == iterator:
text = text_format(features[i][0], 80, features[i][1])
else:
text = text_format(features[i][0], 80, colors.black)
player_rect = text.get_rect(center=screen_rect.center)
player_rect[1] = player_rect[1] + counter
screen.blit(text, player_rect)
pygame.display.update()
Connect4.py
import pygame
import colors
import tkinter as tk
import pygame_menu
# import pandas as pd
import random
class Connect4:
"""
Class used to represent connect4 game
"""
def __init__(self, player1, player2, screen):
# Use 1 version of the screen instead of trying to create a new one
self.screen = screen
# Circle Radius and Width
self.WIDTH = 0
self.CIRCLERADIUS = 25
# Game-Time Variables
self.player1 = player1
self.player2 = player2
self.moveNumber = 0
self.gameOver = False
self.COLUMNS = 7
self.ROWS = 6
self.EMPTY = 99
self.board = [[self.EMPTY for x in range(self.COLUMNS)] for y in range(self.ROWS)]
# The distance between where the window starts and the game board is placed
self.DISTANCE = 90
# Space between each circle
self.DISTANCEGAP = 70
# Setting rectangle default
self.LEFT = 50
self.TOP = 70
self.HEIGHT = 470
self.RECWIDTH = 500
#Creating new tkinterobject
self.root = tk.Tk()
self.scoreboard = {self.player1.name: 0, self.player2.name: 0, "ties": 0}
# Storing locations of available moves given a user clicks the window -- Tuple of locations
self.POSITIONS = [
(
self.DISTANCE + (self.DISTANCEGAP*column) - self.CIRCLERADIUS,
self.DISTANCE + (self.DISTANCEGAP*column) + self.CIRCLERADIUS
)
for column in range(0, self.COLUMNS)
]
def who_won(self, board, piece):
"""
Determines the state of the game and finds if there is a winner
"""
# Horizontal
for col in range(0, self.COLUMNS - 3):
for row in range(0, self.ROWS):
if board[row][col] == piece and board[row][col + 1] == piece and board[row][col + 2] == piece and board[row][col + 3] == piece:
return True
# Vertical
for col in range(0, self.COLUMNS):
for row in range(0, self.ROWS - 3):
if board[row][col] == piece and board[row + 1][col] == piece and board[row + 2][col] == piece and board[row + 3][col] == piece:
return True
# Up-Left/Down-Right
for col in range(3, self.COLUMNS):
for row in range(3, self.ROWS):
if board[row][col] == piece and board[row - 1][col - 1] == piece and board[row - 2][col - 2] == piece and board[row - 3][col - 3] == piece:
return True
# Up-Right/Down-Left
for col in range(0, self.COLUMNS - 3):
for row in range(3, self.ROWS):
if board[row][col] == piece and board[row - 1][col + 1] == piece and board[row - 2][col + 2] == piece and board[row - 3][col + 3] == piece:
return True
# A winning move is not found
return False
def is_legal_move(self, position, board):
"""
Validates if a move is available/legal
"""
if board[0][position] == self.EMPTY:
return True
return False
def display_board(self):
"""
Displaying the game board to the user
"""
# Function: rect(surface, color, rectangle object, optional width) -- First one forms the outline of the board
pygame.draw.rect(self.screen, colors.salmon, (self.LEFT, self.TOP, self.RECWIDTH, self.HEIGHT), 13)
# This forms inner-most rectangle that users play on
pygame.draw.rect(self.screen, colors.burlywood, (self.LEFT, self.TOP, self.RECWIDTH, self.HEIGHT))
for column in range(0, self.COLUMNS):
colEq = self.DISTANCE + (self.DISTANCEGAP * column)
for row in range(0, self.ROWS):
# 125 is used here to make a the board placed in the center of the board and helps finding a value for self.TOP easier
rowEq = 125 + (self.DISTANCEGAP * row)
if self.board[row][column] == self.EMPTY:
color = colors.white
elif self.board[row][column] == 0:
color = colors.realBlue
elif self.board[row][column] == 1:
color = colors.red
pygame.draw.circle(self.screen, color, (colEq, rowEq), self.CIRCLERADIUS, self.WIDTH)
pygame.display.flip()
def play(self):
"""
This is the game-loop
"""
while not self.gameOver:
self.display_board()
if self.moveNumber % 2 == 0:
userText, userRect = self.display_player_name(self.player1.name, colors.realBlue)
elif self.moveNumber % 2 == 1:
userText, userRect = self.display_player_name(self.player2.name, colors.red)
self.screen.blit(userText, userRect)
for event in pygame.event.get():
self.screen.fill(colors.aquamarine) # Set up background color
if event.type == pygame.QUIT:
self.gameOver = True
elif event.type == pygame.MOUSEBUTTONDOWN:
x, y = pygame.mouse.get_pos()
position = self.get_column_position(x)
if self.moveNumber % 2 == 0 and position != self.EMPTY:
if self.is_legal_move(position, self.board):
self.drop_piece_animation(position)
if self.who_won(self.board, 0):
self.gameOver = True
self.scoreboard[self.player1.name] = self.scoreboard.get(self.player1.name) + 1
userText, userRect = self.display_player_name(self.player1.name + " " + "Wins!!!", colors.dark_gray)
elif self.check_if_tie(self.board):
self.gameOver = True
self.scoreboard["ties"] = self.scoreboard.get("ties") + 1
userText, userRect = self.display_player_name("It is a TIE!!!", colors.dark_gray)
elif self.moveNumber % 2 == 1 and position != self.EMPTY:
if self.is_legal_move(position, self.board):
self.drop_piece_animation(position)
if self.who_won(self.board, 1):
self.gameOver = True
self.scoreboard[self.player2.name] = self.scoreboard.get(self.player2.name) + 1
userText, userRect = self.display_player_name(self.player2.name + " " + "Wins!!!", colors.dark_gray)
elif self.check_if_tie(self.board):
self.gameOver = True
self.scoreboard["ties"] = self.scoreboard.get("ties") + 1
userText, userRect = self.display_player_name("It is a TIE!!!", colors.dark_gray)
self.display_board()
self.screen.blit(userText, userRect)
pygame.display.flip()
self.display_scoreboard(False)
def display_scoreboard(self, isAi):
"""
This enables the tkinter object so I can display the user options after : Victory/Loss/Tie
"""
self.root.geometry('460x150+300+0')
self.reset()
self.root.title("Choices")
# This creates the feedback information screen that the user sees after a game
tk.Label(self.root, text="Close window to go to main menu", font=(None, 15, 'underline'), anchor='w', justify='left').grid(row=0, column=1, sticky="NSEW")
tk.Label(self.root, text=self.player1.name + ": " + str(self.scoreboard.get(self.player1.name)), font=(None, 15), anchor='w', justify='left').grid(row=1, column=1, sticky = "NSEW")
tk.Label(self.root, text=self.player2.name + ": " + str(self.scoreboard.get(self.player2.name)), font=(None, 15), anchor='w', justify='left').grid(row=2, column=1, sticky="NSEW")
tk.Label(self.root, text="Ties: " + str(self.scoreboard.get("ties")), font=(None, 15), anchor='w', justify='left').grid(row=3, column=1, sticky="NSEW")
# if isAi == True:
# # tk.Button(self.root, text='Rematch!', command=self.playAi, font=(None, 12), fg="blue").grid(row=4, column=1, sticky=tk.W)
# else:
tk.Button(self.root, text='Rematch!', command=self.play, font=(None, 12), fg="blue").grid(row=4, column=1, sticky=tk.W)
# tk.Button(self.root, text='Rematch with Swap!', command= lambda: self.swapPlayers(isAi), font=(None, 12), fg="red").grid(row=4, column=2, sticky=tk.W)
tk.Entry(self.root)
self.root.mainloop()
def check_if_tie(self, board):
"""
A possible game state : Checking for a tie
"""
totalPieces = 0
for col in range(0, self.COLUMNS):
for row in range(0, self.ROWS):
if board[row][col] == 0 or board[row][col] == 1:
totalPieces += 1
if totalPieces == 42:
return True
else:
return False
def display_player_name(self, name, color):
"""
A feature to help users know who's turn it is that gets displayed
"""
font = pygame.font.Font(pygame_menu.font.FONT_FRANCHISE, 60)
text = font.render(name, True, color)
textRect = text.get_rect()
textRect.center = (len(name) * 30, 20)
return text, textRect
def drop_piece_animation(self, position):
"""
Inserting a piece at a given position with the animation of a piece drop
"""
tmpRow = 5
while self.board[tmpRow][position] == 1 or self.board[tmpRow][position] == 0:
tmpRow -= 1
for i in range(0, tmpRow + 1):
self.board[i][position] = self.moveNumber % 2
self.display_board()
pygame.time.delay(200)
pygame.display.flip()
self.board[i][position] = self.EMPTY
self.board[tmpRow][position] = self.moveNumber % 2
self.moveNumber += 1
def get_column_position(self, position):
"""
Takes a X coordinate value dependent on a click and determines what column user clicked
"""
index = 0
for i in self.POSITIONS:
if position + self.CIRCLERADIUS/2 >= i[0] and position - self.CIRCLERADIUS/2 <= i[1]:
return index
index += 1
return self.EMPTY
def reset(self):
"""
Restoring the game in its original state
"""
self.moveNumber = 0
self.board = [[self.EMPTY for x in range(self.COLUMNS)] for y in range(self.ROWS)]
self.gameOver = False
def play_computer(self):
"""
This is the game-loop used for AI play
"""
# If/else block to distinguish the human/Ai because the ai cant mouse click events
if self.player1.name == "Ed": # Ed Watkins (Staten Island)
humanPlayer = 1
computerPlayer = 0
humanName = self.player2.name
computerName = self.player1.name
elif self.player2.name == "Ed":
humanPlayer = 0
computerPlayer = 1
humanName = self.player1.name
computerName = self.player2.name
while not self.gameOver:
self.display_board()
if self.moveNumber % 2 == 0:
userText, userRect = self.display_player_name(self.player1.name, colors.blue)
elif self.moveNumber % 2 == 1:
userText, userRect = self.display_player_name(self.player2.name, colors.red)
self.screen.blit(userText, userRect)
for event in pygame.event.get():
self.screen.fill(colors.aquamarine) # Set up background color
if event.type == pygame.QUIT:
self.gameOver = True
elif event.type == pygame.MOUSEBUTTONDOWN:
x, y = pygame.mouse.get_pos()
position = self.get_column_position(x)
if self.moveNumber % 2 == humanPlayer and position != self.EMPTY:
if self.is_legal_move(position, self.board):
self.drop_piece_animation(position)
if self.who_won(self.board, humanPlayer):
self.gameOver = True
self.scoreboard[humanName] = self.scoreboard.get(humanName) + 1
userText, userRect = self.display_player_name(humanName + " " + "Wins!!!", colors.dark_gray)
elif self.check_if_tie(self.board):
self.gameOver = True
self.scoreboard["ties"] = self.scoreboard.get("ties") + 1
userText, userRect = self.display_player_name("It is a TIE!!!", colors.dark_gray)
if self.moveNumber % 2 == computerPlayer and self.gameOver == False:
move = self.generate_move(self.board, 4, computerPlayer, humanPlayer, True, self.moveNumber)
self.drop_piece_animation(move)
if self.who_won(self.board, computerPlayer):
self.gameOver = True
self.scoreboard[computerName] = self.scoreboard.get(computerName) + 1
userText, userRect = self.display_player_name(computerName + " " + "Wins!!!", colors.dark_gray)
elif self.check_if_tie(self.board):
self.gameOver = True
self.scoreboard["ties"] = self.scoreboard.get("ties") + 1
userText, userRect = self.display_player_name("It is a TIE!!!", colors.dark_gray)
self.display_board()
self.screen.blit(userText, userRect)
pygame.display.flip()
Minimax.py
from Connect4 import Connect4
import random
from copy import copy, deepcopy
import pygame
class Minimax(Connect4):
def __init__(self, player1, player2, screen):
super().__init__(player1, player2, screen)
def is_game_over(self, board):
if self.who_won(board, 1) or self.who_won(board, 0):
return True
return False
def generate_move(self, board, depth, computerPlayer, humanPlayer, maximizingPlayer, moveNumber):
if depth == 0 or self.is_game_over(board) or self.check_if_tie(board):
if self.is_game_over(board):
if self.who_won(board, computerPlayer):
return 1000000
elif self.who_won(board, humanPlayer):
return -1000000
elif self.check_if_tie(board):
return 0
else:
return self.get_game_score(board, computerPlayer, humanPlayer)
if maximizingPlayer:
maxValue = -1000000
for move in range(0, self.COLUMNS):
tmpBoard = self.copyBoard(board)
if self.is_legal_move(move, tmpBoard):
self.drop_piece_computer(move, tmpBoard, moveNumber)
result = self.generate_move(tmpBoard, depth - 1, computerPlayer, humanPlayer, False, moveNumber + 1)
if result >= maxValue:
maxValue = result
bestMove = move
return bestMove
else:
minValue = 1000000
for move in range(0,self.COLUMNS):
tmpBoard = self.copyBoard(board)
if self.is_legal_move(move, tmpBoard):
self.drop_piece_computer(move, tmpBoard, moveNumber)
result = self.generate_move(tmpBoard, depth - 1, humanPlayer, humanPlayer, True, moveNumber + 1)
if result <= minValue:
minValue = result
thismove = move
return thismove
def copyBoard(self, board):
tmpList = [[self.EMPTY for x in range(self.COLUMNS)] for y in range(self.ROWS)]
for row in range(0, self.ROWS):
for col in range(0, self.COLUMNS):
tmpList[row][col] = board[row][col]
return tmpList
def drop_piece_computer(self, position, board, moveNumber):
"""
Inserting a piece at a given position with the animation of a piece drop
"""
tmpRow = 5
while board[tmpRow][position] == 1 or board[tmpRow][position] == 0:
tmpRow -= 1
board[tmpRow][position] = moveNumber % 2
# moveNumber += 1
def get_game_score(self, board, computerPlayer, humanPlayer):
totalScore = 0
totalScore += self.get_hori_score(board, computerPlayer, humanPlayer)
# totalScore += self.get_vert_score(board, computerPlayer, humanPlayer)
# totalScore += self.get_upright_score(board, computerPlayer, humanPlayer)
# totalScore += self.get_upleft_score(board, computerPlayer, humanPlayer)
return totalScore
def get_hori_score(self, board, computerPlayer, humanPlayer):
score = 0
# List to collect all the groupings of 4(Horizontally) out of the current game state
groupingFourList = []
for col in range(0, self.COLUMNS - 3):
for row in range(0, self.ROWS):
groupingFourList.append(board[row][col])
groupingFourList.append(board[row][col + 1])
groupingFourList.append(board[row][col + 2])
groupingFourList.append(board[row][col + 3])
computerPieces = self.count_player_pieces(groupingFourList, 1)
humanPieces = self.count_player_pieces(groupingFourList, 0)
emptyPieces = self.count_player_pieces(groupingFourList, self.EMPTY)
score += self.score_metric(computerPieces, humanPieces, emptyPieces)
groupingFourList = []
return score
def get_upright_score(self, board, computerPlayer, humanPlayer):
score = 0
# List to collect all the groupings of 4(Horizontally) out of the current game state
groupingFourList = []
for col in range(0, self.COLUMNS - 3):
for row in range(3, self.ROWS):
groupingFourList.append(board[row][col])
groupingFourList.append(board[row - 1][col + 1])
groupingFourList.append(board[row - 2][col + 2])
groupingFourList.append(board[row - 3][col + 3])
computerPieces = self.count_player_pieces(groupingFourList, 1)
humanPieces = self.count_player_pieces(groupingFourList, 0)
emptyPieces = self.count_player_pieces(groupingFourList, self.EMPTY)
score += self.score_metric(computerPieces, humanPieces, emptyPieces)
groupingFourList = []
return score
def get_upleft_score(self, board, computerPlayer, humanPlayer):
score = 0
# List to collect all the groupings of 4(Horizontally) out of the current game state
groupingFourList = []
for col in range(3, self.COLUMNS):
for row in range(3, self.ROWS):
groupingFourList.append(board[row][col])
groupingFourList.append(board[row - 1][col - 1])
groupingFourList.append(board[row - 2][col - 2])
groupingFourList.append(board[row - 3][col - 3])
computerPieces = self.count_player_pieces(groupingFourList, 1)
humanPieces = self.count_player_pieces(groupingFourList, humanPlayer)
emptyPieces = self.count_player_pieces(groupingFourList, self.EMPTY)
score += self.score_metric(computerPieces, humanPieces, emptyPieces)
groupingFourList = []
return score
def get_vert_score(self, board, computerPlayer, humanPlayer):
score = 0
# List to collect all the groupings of 4(Horizontally) out of the current game state
groupingFourList = []
for col in range(0, self.COLUMNS):
for row in range(0, self.ROWS -3):
groupingFourList.append(board[row][col])
groupingFourList.append(board[row + 1][col])
groupingFourList.append(board[row + 2][col])
groupingFourList.append(board[row + 3][col])
computerPieces = self.count_player_pieces(groupingFourList, computerPlayer)
humanPieces = self.count_player_pieces(groupingFourList, humanPlayer)
emptyPieces = self.count_player_pieces(groupingFourList, self.EMPTY)
score += self.score_metric(computerPieces, humanPieces, emptyPieces)
groupingFourList = []
return score
def count_player_pieces(self, groupingFourList, playerPiece):
totalPieces = 0
for piece in groupingFourList:
if piece == playerPiece:
totalPieces += 1
return totalPieces
def score_metric(self, computerPieces, humanPieces, emptyPieces):
score = 0
# Making bot prioritize playing defense than offense
# Thats why the score is lower when regarding the enemy: AI chooses highest scoring move
if (computerPieces == 4):
score += 100
elif (computerPieces == 3 and emptyPieces == 1):
score += 20
elif (computerPieces == 2 and emptyPieces == 2):
score += 10
if (humanPieces == 3 and emptyPieces == 1):
score -= 100
return score
colors.py
"""
Valid colors to use got it from this link : https://python-forum.io/Thread-PyGame-PyGame-Colors
"""
realBlue = (0,0,255)
white = (255,255,255)
green = (0,255,0)
black = (0,0,0)
orange = (255,100,10)
blue_green = (0,255,170)
marroon = (115,0,0)
lime = (180,255,100)
pink = (255,100,180)
purple = (240,0,255)
magenta = (255,0,230)
brown = (100,40,0)
forest_green = (0,50,0)
navy_blue = (0,0,100)
rust = (210,150,75)
dandilion_yellow = (255,200,0)
highlighter = (255,255,100)
sky_blue = (0,255,255)
light_gray = (200,200,200)
dark_gray = (50,50,50)
tan = (230,220,170)
coffee_brown = (200,190,140)
moon_glow = (235, 245, 255)
burlywood = (255, 211, 155)
salmon = (139, 76, 57)
aquamarine = (127, 255, 212)
#Colors used for menu
blue = (135, 206, 250)
yellow = (255, 255, 0)
red = (255,0,0)
gray = (128, 128, 128)
Player.py
class Player():
def __init__(self, name):
self.name = name
The solution is solved but stackoverflow wont allow me to remove the question. The reason I would like the question removed because the answer provided isnt the solution so it would just throw other people off.
Ok the solution is as follows:
In this section of code this is going through a portion of the search space and evaluating the game states based on the best moves for each player. Through this algorithm the AI knows the best moves for each player and can make a "good" move.
if maximizingPlayer:
maxValue = -1000000
for move in range(0, self.COLUMNS):
tmpBoard = self.copyBoard(board)
if self.is_legal_move(move, tmpBoard):
self.drop_piece_computer(move, tmpBoard, moveNumber)
result = self.generate_move(tmpBoard, depth - 1, computerPlayer, humanPlayer, False, moveNumber + 1)
if result >= maxValue:
maxValue = result
bestMove = move
return bestMove
else:
minValue = 1000000
for move in range(0,self.COLUMNS):
tmpBoard = self.copyBoard(board)
if self.is_legal_move(move, tmpBoard):
self.drop_piece_computer(move, tmpBoard, moveNumber)
result = self.generate_move(tmpBoard, depth - 1, humanPlayer, humanPlayer, True, moveNumber + 1)
if result <= minValue:
minValue = result
thismove = move
return thismove
However, if you look closely when I recursively call the function back to the AI in the !maximizing player function I have:
result = self.generate_move(tmpBoard, depth - 1, humanPlayer, humanPlayer, True, moveNumber + 1)
In words when a simulated human player was playing on a generic board to generate the ai move it was assuming that there were 2 human players, and thats why the halt would happen because you cannot have a game with 2 of the same player.
so changing:
result = self.generate_move(tmpBoard, depth - 1, humanPlayer, humanPlayer, True, moveNumber + 1)
to this:
result = self.generate_move(tmpBoard, depth - 1, computerPlayer, humanPlayer, True, moveNumber + 1)
Putting False instead of True in the if maximizingPlayer block and True instead of False in the else clause for the second to last argument to the recursive calls to generate_move seems to fix the game.
i.e. Change False on line 33 of Minimax.py to True and change the True on line 44 to False.

Why doesn't the window update in curses?

I took this nice example of a simple curses application with a list. I wanted to make it scrollable, so I changed the part of the list that gets shown. However, I can scroll down and back up, but the contents shown doesn't change (only the highlighted line, not the lines shown).
What am I doing wrong?
MVCE
#!/usr/bin/env python
import curses
from curses import panel
class Menu(object):
def __init__(self, items, stdscreen):
self.window = stdscreen.subwin(0, 0)
self.window.keypad(1)
self.panel = panel.new_panel(self.window)
self.panel.hide()
panel.update_panels()
self.position = 0
self.items = items
def navigate(self, n):
self.position += n
if self.position < 0:
self.position = 0
elif self.position >= len(self.items):
self.position = len(self.items) - 1
def display(self):
self.panel.top()
self.panel.show()
self.window.clear()
while True:
self.window.refresh()
curses.doupdate()
start = 0
# The next 3 lines seem not to work as intended
while start + (curses.LINES - 1) < self.position:
start += curses.LINES
for index, item in enumerate(self.items[start:curses.LINES - 1], start=start):
if index == self.position:
mode = curses.A_REVERSE
else:
mode = curses.A_NORMAL
msg = "%d. %s" % (index, item[0])
self.window.addstr(1 + index, 1, msg, mode)
key = self.window.getch()
if key in [curses.KEY_ENTER, ord("\n"), curses.KEY_RIGHT]:
self.items[self.position][1]()
elif key == curses.KEY_UP:
self.navigate(-1)
elif key == curses.KEY_DOWN:
self.navigate(1)
elif key == curses.KEY_LEFT:
break
self.window.clear()
self.panel.hide()
panel.update_panels()
curses.doupdate()
class MyApp(object):
def __init__(self, stdscreen):
self.screen = stdscreen
curses.curs_set(0)
submenu_items = [("beep", curses.beep), ("flash", curses.flash)]
submenu = Menu(submenu_items, self.screen)
main_menu_items = [
("beep", curses.beep),
("flash", curses.flash),
("submenu", submenu.display),
]
for i in range(200):
main_menu_items.append((f"flash {i}", curses.flash))
main_menu = Menu(main_menu_items, self.screen)
main_menu.display()
if __name__ == "__main__":
curses.wrapper(MyApp)
Basically that's because you're not updating the upper limit on the slice used in this loop:
for index, item in enumerate(self.items[start:curses.LINES - 1], start=start):
Here's a better version
MVCE
#!/usr/bin/env python
import curses
from curses import panel
class Menu(object):
def __init__(self, items, stdscreen):
self.window = stdscreen.subwin(0, 0)
self.window.keypad(1)
self.panel = panel.new_panel(self.window)
self.panel.hide()
panel.update_panels()
self.position = 0
self.items = items
def navigate(self, n):
self.position += n
if self.position < 0:
self.position = 0
elif self.position >= len(self.items):
self.position = len(self.items) - 1
def display(self):
self.panel.top()
self.panel.show()
self.window.clear()
while True:
start = 0
self.window.clear()
while start + (curses.LINES - 1) < self.position:
start += curses.LINES
myrow = self.position - start
mycol = 0
for index, item in enumerate(self.items[start:start + curses.LINES - 1], start=start):
if index == self.position:
mode = curses.A_REVERSE
else:
mode = curses.A_NORMAL
msg = "%d. %s" % (index, item[0])
self.window.addstr(index - start, 0, msg, mode)
if index == self.position:
(myrow, mycol) = self.window.getyx()
self.window.move(myrow, mycol)
key = self.window.getch()
if key in [curses.KEY_ENTER, ord("\n"), curses.KEY_RIGHT]:
self.items[self.position][1]()
elif key == curses.KEY_UP:
self.navigate(-1)
elif key == curses.KEY_DOWN:
self.navigate(1)
elif key == curses.KEY_LEFT:
break
self.window.clear()
self.panel.hide()
panel.update_panels()
curses.doupdate()
class MyApp(object):
def __init__(self, stdscreen):
self.screen = stdscreen
curses.curs_set(1)
submenu_items = [("beep", curses.beep), ("flash", curses.flash)]
submenu = Menu(submenu_items, self.screen)
main_menu_items = [
("beep", curses.beep),
("flash", curses.flash),
("submenu", submenu.display),
]
for i in range(200):
main_menu_items.append((f"flash {i}", curses.flash))
main_menu = Menu(main_menu_items, self.screen)
main_menu.display()
if __name__ == "__main__":
curses.wrapper(MyApp)

Index Error: My snake game has an Error that I need help fixing

There is a problem in my snake game code and I am asking the community of stack overflow to help me out, there is a error in the update function which is in my class and seems to be coming from the screen update and the dir (direction) variable should still be stop but it still runs the code before I have even pressed the button.
I have tried writing the if function in another way but that still doesn't help.
import tkinter
import random
import time
class snakegame:
def __init__(self):
self.delay = 0.1
self.foodx = random.randint(0, 10)
self.foody = random.randint(0, 10)
self.screen = tkinter.Tk()
self.screen.config(bg='black')
self.segments = []
self.dir = 'stop'
self.game = []
self.square_list = []
self.head = head()
for row in range(10):
rowList = []
square_row = []
for column in range(10):
rowList.append(0)
self.game.append(rowList)
self.square_list.append(square_row)
for row, rowList in enumerate(self.game):
for column, columnEntry in enumerate(self.game):
square = tkinter.Label(self.screen, text=' ', relief='raised')
square.grid(row=row, column=column)
square.config(bg='black')
self.square_list[row].append(square)
self.square_list[5][5].config(bg='green')
self.square_list[self.foody][self.foodx].config(bg='red')
self.screen.bind('w', self.up())
self.screen.bind('s', self.down())
self.screen.bind('a', self.left())
self.screen.bind('d', self.right())
while True:
time.sleep(self.delay)
self.update()
def up(self):
if self.dir != 'down':
self.dir = 'up'
def down(self):
if self.dir != 'up':
self.dir = 'down'
def left(self):
if self.dir != 'right':
self.dir = 'left'
def right(self):
if self.dir != 'left':
self.dir = 'right'
def update(self):
if self.head.x == self.foodx and self.head.y == self.foody:
self.delay -= 0.001
self.square_list[self.foody][self.foodx].config(bg='black')
self.foodx = random.randint(0, 9)
self.foody = random.randint(0, 9)
self.square_list[self.foody][self.foodx].config(bg='green')
newsegment = segment(segments[-1].x, segments[-1].y)
self.segments.append(newsegment)
if self.dir == 'left':
self.square_list[self.head.y][self.head.x].config(bg='black')
count = 0
for segment in self.segments:
count += 1
if count == 1:
self.square_list[segment.y][segment.x].config(bg='black')
segment.x = self.head.x
segment.y = self.head.y
self.square_list[segment.y][segment.x].config(bg='green')
else:
place = count - 1
self.square_list[segment.y][segment.x].config(bg='black')
segment.x = segments[place].x
segment.y = segments[place].y
self.square_list[segment.y][segment.x].config(bg='green')
self.head.x -= 1
self.square_list[self.head.y][self.head.x].config(bg='green')
if self.dir == 'right':
self.square_list[self.head.y][self.head.x].config(bg='black')
count = 0
for segment in self.segments:
count += 1
if count == 1:
self.square_list[segment.y][segment.x].config(bg='black')
segment.x = self.head.x
segment.y = self.head.y
self.square_list[segment.y][segment.x].config(bg='green')
else:
place = count - 1
self.square_list[segment.y][segment.x].config(bg='black')
segment.x = segments[place].x
segment.y = segments[place].y
self.square_list[segment.y][segment.x].config(bg='green')
self.head.x += 1
self.square_list[self.head.y][self.head.x].config(bg='green')
if self.dir == 'up':
self.square_list[self.head.y][self.head.x].config(bg='black')
count = 0
for segment in self.segments:
count += 1
if count == 1:
self.square_list[segment.y][segment.x].config(bg='black')
segment.x = self.head.x
segment.y = self.head.y
self.square_list[segment.y][segment.x].config(bg='green')
else:
place = count - 1
self.square_list[segment.y][segment.x].config(bg='black')
segment.x = segments[place].x
segment.y = segments[place].y
self.square_list[segment.y][segment.x].config(bg='green')
self.head.y += 1
self.square_list[self.head.y][self.head.x].config(bg='green')
if self.dir == 'down':
self.square_list[self.head.y][self.head.x].config(bg='black')
count = 0
for segment in self.segments:
count += 1
if count == 1:
self.square_list[segment.y][segment.x].config(bg='black')
segment.x = self.head.x
segment.y = self.head.y
self.square_list[segment.y][segment.x].config(bg='green')
else:
place = count - 1
self.square_list[segment.y][segment.x].config(bg='black')
segment.x = segments[place].x
segment.y = segments[place].y
self.square_list[segment.y][segment.x].config(bg='green')
self.head.y -= 1
self.square_list[self.head.y][self.head.x].config(bg='green')
if self.head.x > 9 or self.head.x < 0 or self.head.y > 9 or self.head.y < 0:
pass
for segment in self.segments:
if self.head.x == segment.x and self.head.y == segment.y:
pass
class head:
def __init__(self):
self.x = self.y = 5
class segment:
def __init__(self, posx, posy):
self.x = posx
self.y = posy
mysnakegame = snakegame()
I should expect the if to not run but I get the following error:
Traceback (most recent call last):
File "snakegame.py", line 149, in <module>
mysnakegame = snakegame()
File "snakegame.py", line 31, in __init__
self.square_list[self.foody][self.foodx].config(bg='red')
IndexError: list index out of range
Your first issue is in the following lines:
self.screen.bind('w', self.up())
self.screen.bind('s', self.down())
self.screen.bind('a', self.left())
self.screen.bind('d', self.right())
They should be
self.screen.bind('w', self.up)
self.screen.bind('s', self.down)
self.screen.bind('a', self.left)
self.screen.bind('d', self.right)
You just want to bind such functions, but you are actually calling them. They are then changing the value of self.dir to something else, and that is why you are having such unexpected behavior.

Class player - Animation stop first frame

Quick question. I have my Player Class, working perfectly. Except for a small detail. This is the class:
from dict.entity_dict import player, player_class
from collections import OrderedDict
import pyglet, random
key = pyglet.window.key
class Player(pyglet.sprite.Sprite):
dir_stand = "south"
dir_run = "south"
sprite_stand = 3
sprite_run = 3
image = None
s = 0
def __init__(self, game):
self.game = game
self.keyboard = key.KeyStateHandler()
self.statistics_base = OrderedDict()
self.image_stand = pyglet.resource.image(player.get("player_stand", {'x': None}).get("resource"))
self.image_run = pyglet.resource.image(player.get("player_run", {'x': None}).get("resource"))
self.image_stand_width = player.get("player_stand", {'x': None}).get("width")
self.image_stand_height = player.get("player_stand", {'x': None}).get("height")
self.image_run_width = player.get("player_run", {'x': None}).get("width")
self.image_run_height = player.get("player_run", {'x': None}).get("height")
self.vx = self.game.wd / 2
self.vy = self.game.wh / 2
self.load_sprite()
def class_player(self, type):
self.statistics_base["hp"] = player_class.get(type, {'x': None}).get("hp")
self.statistics_base["atk"] = player_class.get(type, {'x': None}).get("atk")
self.statistics_base["dif"] = player_class.get(type, {'x': None}).get("dif")
self.statistics_base["atk_sp"] = player_class.get(type, {'x': None}).get("atk_sp")
self.statistics_base["dif_sp"] = player_class.get(type, {'x': None}).get("dif_sp")
self.statistics_base["vel"] = player_class.get(type, {'x': None}).get("vel")
for stat in self.statistics_base:
if self.statistics_base[stat] is None:
self.statistics_base[stat] = 10
def animation(self, image, da, width, height):
frame_list = [image.get_region(x=width * i, y=height * da, width=46, height=58) for i in range(22)]
image_animation = pyglet.image.Animation.from_image_sequence(frame_list, 0.10, True)
return image_animation
def direction_sprite(self):
if self.dir_stand == "north":
self.sprite_stand = 7
elif self.dir_stand == "east":
self.sprite_stand = 5
elif self.dir_stand == "south":
self.sprite_stand = 3
elif self.dir_stand == "west":
self.sprite_stand = 1
if self.dir_run == "north":
self.sprite_run = 7
elif self.dir_run == "north-east":
self.sprite_run = 6
elif self.dir_run == "east":
self.sprite_run = 5
elif self.dir_run == "south-east":
self.sprite_run = 4
elif self.dir_run == "south":
self.sprite_run = 3
elif self.dir_run == "south-west":
self.sprite_run = 2
elif self.dir_run == "west":
self.sprite_run = 1
elif self.dir_run == "north-west":
self.sprite_run = 0
def load_sprite(self):
if not self.keyboard[key.W] and not self.keyboard[key.S] and not self.keyboard[key.D] and not self.keyboard[key.A]:
self.keyboard.clear()
img = self.image_stand
img_width = self.image_stand_width
img_height = self.image_stand_height
da = self.sprite_stand
else:
img = self.image_run
img_width = self.image_run_width
img_height = self.image_run_height
da = self.sprite_run
self.direction_sprite()
self.image = self.animation(img, da, img_width, img_height)
self.image.width, self.image.height = img_width, img_height
self.image.anchor_x, self.image.anchor_y = img_width // 2, img_height // 2
self.sprite = pyglet.sprite.Sprite(self.image, batch=self.game.Batch, group=self.game.GroupEntitySprite)
self.sprite.x = self.vx
self.sprite.y = self.vy
def key_player(self):
if self.keyboard[key.W]:
self.vy += 1
self.dir_stand = "north"
self.dir_run = "north"
if self.keyboard[key.S]:
self.vy -= 1
self.dir_stand = "south"
self.dir_run = "south"
if self.keyboard[key.D]:
self.vx += 1
self.dir_stand = "east"
self.dir_run = "east"
if self.keyboard[key.A]:
self.vx -= 1
self.dir_stand = "west"
self.dir_run = "west"
if self.keyboard[key.W] and self.keyboard[key.D]:
random1 = random.randint(1, 2)
if random1 == 1:
self.dir_stand = "north"
else:
self.dir_stand = "east"
self.dir_run = "north-east"
if self.keyboard[key.S] and self.keyboard[key.D]:
random2 = random.randint(1, 2)
if random2 == 1:
self.dir_stand = "south"
else:
self.dir_stand = "east"
self.dir_run = "south-east"
if self.keyboard[key.W] and self.keyboard[key.A]:
random3 = random.randint(1, 2)
if random3 == 1:
self.dir_stand = "north"
else:
self.dir_stand = "west"
self.dir_run = "north-west"
if self.keyboard[key.S] and self.keyboard[key.A]:
random4 = random.randint(1, 2)
if random4 == 1:
self.dir_stand = "south"
else:
self.dir_stand = "west"
self.dir_run = "south-west"
def update(self):
self.key_player()
self.load_sprite()
Since to update the Player's sprite, I need to call the "load_sprite" function, which causes the animation to be constantly called. As a result, the same animation does not appear and remains still at the first frame. So how could I solve?
Edit: Modified the script, including the for loop. If you see, I modified the group, using Batch and OrderedGroup instead. In this way we can clearly see the problem I am having.
The problem I have is due to the fact that pyglet.sprite.Sprite is called in order to update which animation is executed. However, doing so at the same time, the animations are not shown exactly because of the constant call of pyglet.sprite.Sprite.
First, you can change the sprite's animation by setting its image attribute, instead of creating a new Sprite instance. Second, only change its animation when you actually need to. That is when the direction changes.
I've added a simple example (pseudo) code to roughly show what I mean.
def animation(image, da, width, height):
frame_list = [image.get_region(x=width * i, y=height * da, width=46, height=58) for i in range(22)]
image_animation = pyglet.image.Animation.from_image_sequence(frame_list, 0.10, True)
return image_animation
class Player:
def __init__(self, standing_animations, running_animations):
# ... code ...
self.standing_animations = standing_animations # List of animations
self.running_animations = running_animations # List of animations
self.current_animation = standing_animations[0] # Just to have a default animation
self.previous_running_direction = None
self.previous_standing_direction = None
def load_sprite(self):
self.sprite.x = self.vx
self.sprite.y = self.vy
if self.previous_running_direction == self.dir_run and self.previous_standing_direction == self.dir_stand:
return # Don't do anything more in here
if not self.keyboard[key.W] and not self.keyboard[key.S] and not self.keyboard[key.D] and not self.keyboard[key.A]:
self.keyboard.clear()
self.current_animation = self.standing_animations[self.sprite_stand]
else:
self.current_animation = self.running_animations[self.sprite_run]
self.sprite.image = self.current_animation
def update(self):
self.previous_running_direction = self.dir_run
self.previous_standing_direction = self.dir_stand
self.key_player()
self.load_sprite()

Pygame code not executing (window won't open)

I am currently trying to re create Pong in pygame. This is my code:
import sys, pygame
from pygame.locals import *
FPS = 60
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
WINDOWWIDTH = 400
WINDOWHEIGHT = 300
LINETHICKNESS = 10
PADDLESIZE = 50
PADDLEOFFSET = 20
def drawArena():
DISPLAYSURF.fill((BLACK))
pygame.draw.rect(DISPLAYSURF, WHITE, ((0,0),(WINDOWWIDTH,WINDOWHEIGHT)), LINETHICKNESS*2)
pygame.draw.line(DISPLAYSURF, WHITE, ((WINDOWWIDTH/2),0),((WINDOWWIDTH/2),WINDOWHEIGHT), (LINETHICKNESS/4))
def drawPaddle(paddle):
if paddle.bottom > (WINDOWHEIGHT - LINETHICKNESS):
paddle.bottom = WINDOWHEIGHT - LINETHICKNESS
elif paddle.top > LINETHICKNESS:
paddle.top = LINETHICKNESS
pygame.draw.rect(DISPLAYSURF, WHITE, paddle)
def drawBall(ball):
pygame.draw.rect(DISPLAYSURF, WHITE, ball)
def moveBall(ball, ballDirX, ballDirY):
ball.x += ballDirX
ball.y += ballDirY
return ball
def checkWallCollision(ball, ballDirX, ballDirY):
if ball.top == (LINETHICKNESS) or ball.bottom == (WINDOWHEIGHT - LINETHICKNESS):
ballDirY = ballDirY * -1
if ball.left == (LINETHICKNESS) or ball.right == (WINDOWHEIGHT - LINETHICKNESS):
ballDirX = ballDirX * -1
return ballDirX, ballDirY
def checkPaddleCollision(ball, ballDirX, paddle1, paddle2):
if ballDirX == -1 and paddle1.right == ball.left and paddle1.top < ball.top and paddle1.bottom > ball.bottom:
return -1
elif ballDirX == -1 and paddle2.left == ball.right and paddle2.top < ball.top and paddle2.bottom > ball.bottom:
return -1
else:
return 1
def checkPointScored(paddle1, ball, score, ballDirX):
if ball.left == LINETHICKNESS:
return 0
elif ballDirX == -1 and paddle1.right == ball.left and paddle1.top < ball.top and paddle1.bottom > ball.bottom:
score += 1
elif ball.right == WINDOWWIDTH - LINETHICKNESS:
score += 5
return score
else: return score
def aI(ball, ballDirX, paddle2):
if ballDirX == -1:
if paddle2.centery < (WINDOWHEIGHT/2):
paddle2.y += 1
elif paddle2.centery > (WINDOWHEIGHT/2):
paddle2.y -= 1
elif ballDirX == 1:
if paddle2.centery < ball.centery:
paddle2.y += 1
else:
paddle2.y -=1
return paddle2
def displayScore(score):
resultSurf = BASICFONT.render('Score = %s' %(score), True, WHITE)
resultRect = resultSurf,get_rect()
resultRect.topleft = WINDOWWIDTH = 150, 25
DISPLAYSURF.blit(resultSurf, resultRect)
def main():
pygame.init()
global DISPLAYSURF
global BASICFONT, BASICFONTSIZE
BASICFONTSIZE = 20
BASICFONT = pygame.font.Font('freesansbold.ttf', BASICFONTSIZE)
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH,WINDOWHEIGHT))
pygame.display.set_caption('Pong')
ballX = WINDOWWIDTH/2 - LINETHICKNESS/2
ballY = WINDOWHEIGHT/2 - LINETHICKNESS/2
playerOnePosition = (WINDOWHEIGHT - PADDLESIZE) /2
playerTwoPosition = (WINDOWHEIGHT - PADDLESIZE) /2
score = 0
ballDirX = -1
ballDirY = -1
paddle1 = pygame.Rect(PADDLEOFFSET, playerOnePosition, LINETHICKNESS, PADDLESIZE)
paddle2 = pygame.Rect(WINDOWWIDTH - PADDLEOFFSET - LINETHICKNESS, playerTwoPosition, LINETHICKNESS, PADDLESIZE)
ball = pygame.Rect(ballX, ballY, LINETHICKNESS, LINETHICKNESS)
drawArena()
drawPaddle(paddle1)
drawPaddle(paddle2)
drawBall(ball)
while True: #main game loop
pygame.event.get()
pygame.event.pump()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
drawArena()
drawPaddle(paddle1)
drawPaddle(paddle2)
drawBall(ball)
pygame.display.update()
FPSCLOCK.tick(FPS)
if __name__=='__main__':
main()
My problem is when I run the file through the shell the output is:
Python 3.6.0 |Continuum Analytics, Inc.| (default, Dec 23 2016, 11:57:41) on Windows (64 bits).
This is the Pyzo interpreter with integrated event loop for TK.
Type 'help' for help, type '?' for a list of *magic* commands.
Running script: "H:\pong.py"
However, the window that I created is not appearing and it seems as if it has crashed as soon as it had been opened or something of the sort. Help me find out what this is, please!
The code below runs OK, shows in the command line output the events and makes it possible to process events and close the window.
Besides the already mentioned (see comments) indentation problem, there was a problem with capturing events (see out-commented lines), so that it was not possible to process the events and to close the raised window.
import sys, pygame
from pygame.locals import *
FPS = 60
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
WINDOWWIDTH = 400
WINDOWHEIGHT = 300
LINETHICKNESS = 10
PADDLESIZE = 50
PADDLEOFFSET = 20
def drawArena():
DISPLAYSURF.fill((BLACK))
pygame.draw.rect(DISPLAYSURF, WHITE, ((0,0),(WINDOWWIDTH,WINDOWHEIGHT)), LINETHICKNESS*2)
pygame.draw.line(DISPLAYSURF, WHITE, ((int(WINDOWWIDTH/2)),0),((int(WINDOWWIDTH/2)),WINDOWHEIGHT), (int(LINETHICKNESS/4)))
def drawPaddle(paddle):
if paddle.bottom > (WINDOWHEIGHT - LINETHICKNESS):
paddle.bottom = WINDOWHEIGHT - LINETHICKNESS
elif paddle.top > LINETHICKNESS:
paddle.top = LINETHICKNESS
pygame.draw.rect(DISPLAYSURF, WHITE, paddle)
def drawBall(ball):
pygame.draw.rect(DISPLAYSURF, WHITE, ball)
def moveBall(ball, ballDirX, ballDirY):
ball.x += ballDirX
ball.y += ballDirY
return ball
def checkWallCollision(ball, ballDirX, ballDirY):
if ball.top == (LINETHICKNESS) or ball.bottom == (WINDOWHEIGHT - LINETHICKNESS):
ballDirY = ballDirY * -1
if ball.left == (LINETHICKNESS) or ball.right == (WINDOWHEIGHT - LINETHICKNESS):
ballDirX = ballDirX * -1
return ballDirX, ballDirY
def checkPaddleCollision(ball, ballDirX, paddle1, paddle2):
if ballDirX == -1 and paddle1.right == ball.left and paddle1.top < ball.top and paddle1.bottom > ball.bottom:
return -1
elif ballDirX == -1 and paddle2.left == ball.right and paddle2.top < ball.top and paddle2.bottom > ball.bottom:
return -1
else:
return 1
def checkPointScored(paddle1, ball, score, ballDirX):
if ball.left == LINETHICKNESS:
return 0
elif ballDirX == -1 and paddle1.right == ball.left and paddle1.top < ball.top and paddle1.bottom > ball.bottom:
score += 1
elif ball.right == WINDOWWIDTH - LINETHICKNESS:
score += 5
return score
else: return score
def aI(ball, ballDirX, paddle2):
if ballDirX == -1:
if paddle2.centery < (WINDOWHEIGHT/2):
paddle2.y += 1
elif paddle2.centery > (WINDOWHEIGHT/2):
paddle2.y -= 1
elif ballDirX == 1:
if paddle2.centery < ball.centery:
paddle2.y += 1
else:
paddle2.y -=1
return paddle2
def displayScore(score):
resultSurf = BASICFONT.render('Score = %s' %(score), True, WHITE)
resultRect = resultSurf,get_rect()
resultRect.topleft = WINDOWWIDTH = 150, 25
DISPLAYSURF.blit(resultSurf, resultRect)
def main():
pygame.init()
global DISPLAYSURF
global BASICFONT, BASICFONTSIZE
BASICFONTSIZE = 20
BASICFONT = pygame.font.Font('freesansbold.ttf', BASICFONTSIZE)
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH,WINDOWHEIGHT))
pygame.display.set_caption('Pong')
ballX = WINDOWWIDTH/2 - LINETHICKNESS/2
ballY = WINDOWHEIGHT/2 - LINETHICKNESS/2
playerOnePosition = (WINDOWHEIGHT - PADDLESIZE) /2
playerTwoPosition = (WINDOWHEIGHT - PADDLESIZE) /2
score = 0
ballDirX = -1
ballDirY = -1
paddle1 = pygame.Rect(PADDLEOFFSET, playerOnePosition, LINETHICKNESS, PADDLESIZE)
paddle2 = pygame.Rect(WINDOWWIDTH - PADDLEOFFSET - LINETHICKNESS, playerTwoPosition, LINETHICKNESS, PADDLESIZE)
ball = pygame.Rect(ballX, ballY, LINETHICKNESS, LINETHICKNESS)
drawArena()
drawPaddle(paddle1)
drawPaddle(paddle2)
drawBall(ball)
while True: #main game loop
# pygame.event.get()
# pygame.event.pump()
for event in pygame.event.get():
print("event", event)
if event.type == QUIT:
pygame.quit()
sys.exit()
drawArena()
drawPaddle(paddle1)
drawPaddle(paddle2)
drawBall(ball)
pygame.display.update()
FPSCLOCK.tick(FPS)
if __name__=='__main__':
main()

Resources