有没有一种有效的方法来使函数拖放多个png? [英] Is there an effiecient way of making a function to drag and drop multiple png's?
问题描述
我正在做一个国际象棋游戏,但是我完全停留在拖放元素上,那里有一些指南,但是它们要么是拖动形状,要么只是拖动一个图像。
I'm making a chess game, but I'm completely stuck on the drag and drop element, there's a few guides out there but they're all either dragging shapes, or only dragging one image.
我尝试了几种代码变体,但全部都是50余行,只是为了移动一个 .png
,而大多数代码效率极低, / p>
I've tried several variants of code, but all were 50+ lines just to move one .png
and most were incredibly inefficient
pygame.init()
pygame.display.set_caption("Python Chess")
clock = pygame.time.Clock()
red = (213,43,67)
chew = pygame.image.load("chew.png")
gameDisplay.fill(red)
gameDisplay.blit(chew, (400, 400))
pygame.display.update()
drag = 0
if pygame.MOUSEBUTTONDOWN:
drag = 1
if pygame.MOUSEBUTTONUP:
drag = 0
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
I法师根本不会拖动。
Image simply doesn't drag.
推荐答案
让我们逐步进行操作。
import pygame
def main():
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
screen.fill(pygame.Color('grey'))
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
我们创建一个窗口,然后开始循环以侦听事件并绘制该窗口。
We create a window and then start a loop to listen for events and drawing the window.
到目前为止,很好。
所以,我们要下棋。因此,我们需要一个董事会。我们创建一个列表来代表我们的董事会,并创建一个 Surface
来在屏幕上绘制我们的董事会。我们希望始终将游戏的状态与实际绘制功能区分开,因此我们创建了 board
变量和 board_surf
。
So, we want a chess game. So we need a board. We create a list of lists to represent our board, and we create a Surface
that draws our board on the screen. We want to always seperate our game's state from the actual drawing functions, so we create a board
variable and a board_surf
.
import pygame
TILESIZE = 32
def create_board_surf():
board_surf = pygame.Surface((TILESIZE*8, TILESIZE*8))
dark = False
for y in range(8):
for x in range(8):
rect = pygame.Rect(x*TILESIZE, y*TILESIZE, TILESIZE, TILESIZE)
pygame.draw.rect(board_surf, pygame.Color('black' if dark else 'white'), rect)
dark = not dark
dark = not dark
return board_surf
def create_board():
board = []
for y in range(8):
board.append([])
for x in range(8):
board[y].append(None)
return board
def main():
screen = pygame.display.set_mode((640, 480))
board = create_board()
board_surf = create_board_surf()
clock = pygame.time.Clock()
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
screen.fill(pygame.Color('grey'))
screen.blit(board_surf, (0, 0))
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
我们需要知道要选择哪一块,因此我们必须翻译屏幕坐标(鼠标相对于窗口的位置在哪里?)到世界坐标(鼠标指向板的哪个正方形? em>)。
We need to know which piece we want to select, so we have to translate the screen coordinates (where's the mouse relative to the window?) to the world coordinates (which square of the board is the mouse pointing to?).
因此,如果董事会为n因为它位于 origin (位置(0,0)
)上,所以我们还必须将此 offset
So if the board is not located at the origin (the position (0, 0)
), we also have to take this offset into account.
基本上,我们必须从鼠标位置减去偏移量(板在屏幕上的位置)我们有鼠标相对于木板的位置),然后除以正方形的大小。
Basically, we have to substract that offset (which is the position of the board on the screen) from the mouse position (so we have the mouse position relative to the board), and divide by the size of the squares.
要查看是否可行,让我们在选定的正方形上绘制一个红色矩形
To see if this works, let's draw a red rectangle on the selected square.
import pygame
TILESIZE = 32
BOARD_POS = (10, 10)
def create_board_surf():
board_surf = pygame.Surface((TILESIZE*8, TILESIZE*8))
dark = False
for y in range(8):
for x in range(8):
rect = pygame.Rect(x*TILESIZE, y*TILESIZE, TILESIZE, TILESIZE)
pygame.draw.rect(board_surf, pygame.Color('black' if dark else 'white'), rect)
dark = not dark
dark = not dark
return board_surf
def create_board():
board = []
for y in range(8):
board.append([])
for x in range(8):
board[y].append(None)
return board
def get_square_under_mouse(board):
mouse_pos = pygame.Vector2(pygame.mouse.get_pos()) - BOARD_POS
x, y = [int(v // TILESIZE) for v in mouse_pos]
try:
if x >= 0 and y >= 0: return (board[y][x], x, y)
except IndexError: pass
return None, None, None
def main():
screen = pygame.display.set_mode((640, 480))
board = create_board()
board_surf = create_board_surf()
clock = pygame.time.Clock()
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
piece, x, y = get_square_under_mouse(board)
screen.fill(pygame.Color('grey'))
screen.blit(board_surf, BOARD_POS)
if x != None:
rect = (BOARD_POS[0] + x * TILESIZE, BOARD_POS[1] + y * TILESIZE, TILESIZE, TILESIZE)
pygame.draw.rect(screen, (255, 0, 0, 50), rect, 2)
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
国际象棋很无聊,没有一些棋子可以移动,所以让我们创建一些棋子。
Chess is boring without some pieces to move around, so let's create some pieces.
我只使用 SysFont
绘制一些文本而不是使用真实图像,因此每个人都可以复制/粘贴代码并立即运行它。
I just use a SysFont
to draw some text instead of using real images, so everyone can just copy/paste the code and run it immediately.
我们存储了一个嵌套板
列表中的元组(颜色,类型)
。另外,让我们在板上使用其他颜色。
We store a tuple (color, type)
in the nested board
list. Also, let's use some other colors for our board.
import pygame
TILESIZE = 32
BOARD_POS = (10, 10)
def create_board_surf():
board_surf = pygame.Surface((TILESIZE*8, TILESIZE*8))
dark = False
for y in range(8):
for x in range(8):
rect = pygame.Rect(x*TILESIZE, y*TILESIZE, TILESIZE, TILESIZE)
pygame.draw.rect(board_surf, pygame.Color('darkgrey' if dark else 'beige'), rect)
dark = not dark
dark = not dark
return board_surf
def get_square_under_mouse(board):
mouse_pos = pygame.Vector2(pygame.mouse.get_pos()) - BOARD_POS
x, y = [int(v // TILESIZE) for v in mouse_pos]
try:
if x >= 0 and y >= 0: return (board[y][x], x, y)
except IndexError: pass
return None, None, None
def create_board():
board = []
for y in range(8):
board.append([])
for x in range(8):
board[y].append(None)
for x in range(0, 8):
board[1][x] = ('black', 'pawn')
for x in range(0, 8):
board[6][x] = ('white', 'pawn')
return board
def draw_pieces(screen, board, font):
for y in range(8):
for x in range(8):
piece = board[y][x]
if piece:
color, type = piece
s1 = font.render(type[0], True, pygame.Color(color))
s2 = font.render(type[0], True, pygame.Color('darkgrey'))
pos = pygame.Rect(BOARD_POS[0] + x * TILESIZE+1, BOARD_POS[1] + y * TILESIZE + 1, TILESIZE, TILESIZE)
screen.blit(s2, s2.get_rect(center=pos.center).move(1, 1))
screen.blit(s1, s1.get_rect(center=pos.center))
def draw_selector(screen, piece, x, y):
if piece != None:
rect = (BOARD_POS[0] + x * TILESIZE, BOARD_POS[1] + y * TILESIZE, TILESIZE, TILESIZE)
pygame.draw.rect(screen, (255, 0, 0, 50), rect, 2)
def main():
pygame.init()
font = pygame.font.SysFont('', 32)
screen = pygame.display.set_mode((640, 480))
board = create_board()
board_surf = create_board_surf()
clock = pygame.time.Clock()
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
piece, x, y = get_square_under_mouse(board)
screen.fill(pygame.Color('grey'))
screen.blit(board_surf, BOARD_POS)
draw_pieces(screen, board, font)
draw_selector(screen, piece, x, y)
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
对于拖放,我们需要做两件事:
For drag and drop we need two things:
- 我们必须更改游戏状态(进行进入拖动模式)
- 事件处理以进入和离开拖动模式
实际上并不那么复杂。要进入拖动模式,只需在发生 MOUSEBUTTONDOWN
事件时设置一个变量( selected_piece
)。由于我们已经有了 get_square_under_mouse
函数,因此很容易知道鼠标光标下是否确实有一块。
It's actually not that complicated. To enter the "drag-mode", we just set a variable (selected_piece
) when the MOUSEBUTTONDOWN
event occurs. Since we already have the get_square_under_mouse
function, it's easy to know if there's actually a piece under the mouse cursor.
如果设置了 selected_piece
,我们将在鼠标光标下绘制一条线和一块,并在的情况下跟踪光标下的当前正方形发生MOUSEBUTTONUP
事件。如果是这样,我们会在板
中交换该作品的位置。
if selected_piece
is set, we draw a line and the piece under the mouse cursor, and we keep track of the current square under the cursor in case the MOUSEBUTTONUP
event occurs. If that's the case, we swap the position of the piece in our board
.
import pygame
TILESIZE = 32
BOARD_POS = (10, 10)
def create_board_surf():
board_surf = pygame.Surface((TILESIZE*8, TILESIZE*8))
dark = False
for y in range(8):
for x in range(8):
rect = pygame.Rect(x*TILESIZE, y*TILESIZE, TILESIZE, TILESIZE)
pygame.draw.rect(board_surf, pygame.Color('darkgrey' if dark else 'beige'), rect)
dark = not dark
dark = not dark
return board_surf
def get_square_under_mouse(board):
mouse_pos = pygame.Vector2(pygame.mouse.get_pos()) - BOARD_POS
x, y = [int(v // TILESIZE) for v in mouse_pos]
try:
if x >= 0 and y >= 0: return (board[y][x], x, y)
except IndexError: pass
return None, None, None
def create_board():
board = []
for y in range(8):
board.append([])
for x in range(8):
board[y].append(None)
for x in range(0, 8):
board[1][x] = ('black', 'pawn')
for x in range(0, 8):
board[6][x] = ('white', 'pawn')
return board
def draw_pieces(screen, board, font, selected_piece):
sx, sy = None, None
if selected_piece:
piece, sx, sy = selected_piece
for y in range(8):
for x in range(8):
piece = board[y][x]
if piece:
selected = x == sx and y == sy
color, type = piece
s1 = font.render(type[0], True, pygame.Color('red' if selected else color))
s2 = font.render(type[0], True, pygame.Color('darkgrey'))
pos = pygame.Rect(BOARD_POS[0] + x * TILESIZE+1, BOARD_POS[1] + y * TILESIZE + 1, TILESIZE, TILESIZE)
screen.blit(s2, s2.get_rect(center=pos.center).move(1, 1))
screen.blit(s1, s1.get_rect(center=pos.center))
def draw_selector(screen, piece, x, y):
if piece != None:
rect = (BOARD_POS[0] + x * TILESIZE, BOARD_POS[1] + y * TILESIZE, TILESIZE, TILESIZE)
pygame.draw.rect(screen, (255, 0, 0, 50), rect, 2)
def draw_drag(screen, board, selected_piece, font):
if selected_piece:
piece, x, y = get_square_under_mouse(board)
if x != None:
rect = (BOARD_POS[0] + x * TILESIZE, BOARD_POS[1] + y * TILESIZE, TILESIZE, TILESIZE)
pygame.draw.rect(screen, (0, 255, 0, 50), rect, 2)
color, type = selected_piece[0]
s1 = font.render(type[0], True, pygame.Color(color))
s2 = font.render(type[0], True, pygame.Color('darkgrey'))
pos = pygame.Vector2(pygame.mouse.get_pos())
screen.blit(s2, s2.get_rect(center=pos + (1, 1)))
screen.blit(s1, s1.get_rect(center=pos))
selected_rect = pygame.Rect(BOARD_POS[0] + selected_piece[1] * TILESIZE, BOARD_POS[1] + selected_piece[2] * TILESIZE, TILESIZE, TILESIZE)
pygame.draw.line(screen, pygame.Color('red'), selected_rect.center, pos)
return (x, y)
def main():
pygame.init()
font = pygame.font.SysFont('', 32)
screen = pygame.display.set_mode((640, 480))
board = create_board()
board_surf = create_board_surf()
clock = pygame.time.Clock()
selected_piece = None
drop_pos = None
while True:
piece, x, y = get_square_under_mouse(board)
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
if e.type == pygame.MOUSEBUTTONDOWN:
if piece != None:
selected_piece = piece, x, y
if e.type == pygame.MOUSEBUTTONUP:
if drop_pos:
piece, old_x, old_y = selected_piece
board[old_y][old_x] = 0
new_x, new_y = drop_pos
board[new_y][new_x] = piece
selected_piece = None
drop_pos = None
screen.fill(pygame.Color('grey'))
screen.blit(board_surf, BOARD_POS)
draw_pieces(screen, board, font, selected_piece)
draw_selector(screen, piece, x, y)
drop_pos = draw_drag(screen, board, selected_piece, font)
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
当然还有很多可以改进的地方(例如使用比元组更好的数据类型,将通用逻辑提取到函数中等),但这应该
Of course there's a lot that can be improved (like using better datatypes than tuples, extract common logic into functions etc), but this should give you a good start on how to implement such things.
始终牢记:
- 编写处理事件,游戏逻辑和绘图的单个游戏循环
- 确保仅调用
pygame.display.flip
每帧一次 - 从绘图功能中分离游戏状态
- 从不调用
time.sleep
或pygame.time.wait
- 使用诸如
Vector2 $这样的内置类c $ c>和
Rect
,它们将使您的生活更加轻松(我在此不是Sprite
类代码,但它也非常有用) - 使用函数清理代码
- 避免使用全局变量,常量除外
- write a single game loop that handles events, game logic, and drawing
- make sure to only call
pygame.display.flip
once per frame - seperate your game state from your drawing functions
- never call
time.sleep
orpygame.time.wait
- use the build-in classes like
Vector2
andRect
, they'll make your live easier (I didn't theSprite
class in this code, but it's also very usefull) - use functions to clean up your code
- avoid global variables, except for constants
这篇关于有没有一种有效的方法来使函数拖放多个png?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!