在 Pygame 中获取等距平铺鼠标选择
我没能正确地计算出这个数学,而且用语言解释起来有点困难。我成功地创建了一个等距网格,您可以用鼠标完美地选择图块,并且我成功地使用 was 实现相机移动d 键,仍然可以正确选择图块,但是有一个小错误,我无法弄清楚它来自哪里。 这就是发生的情况,但只是有时,取决于相机偏移的位置:
当发生这种情况时,它仅在 x 轴上,而不是在每个图块中。 我几乎要放弃这个了,因为我找不到这个错误,想在这里发帖看看是否有人遇到类似的问题。
import time
import pygame
import sys
import math
from os import path
from settings import *
from sprites import *
# ------------------------- SETTINGS ---------------------------- #
# COLORS (r, g, b)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
DARKGREY = (40, 40, 40)
LIGHTGREY = (100, 100, 100)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
# game settings
WIDTH = 1024
HEIGHT = 768
FPS = 60
title = "Isometric-Based game"
BGCOLOUR = DARKGREY
TILE_X = 80
TILE_Y = 40
WORLD_X, WORLD_Y = 14, 10
ORIGIN_X, ORIGIN_Y = 5, 1
# Debug
pygame.init()
font = pygame.font.Font(None, 25)
CAMERA_SPEED = 300
def get_info(info_list):
display_surface = pygame.display.get_surface()
for i, key in enumerate(info_list):
text = font.render(str(key) + " : " + str(info_list[key]), True, (255, 255, 255), (0, 0, 0))
text_rect = text.get_rect()
text_rect.y = 20 * i
display_surface.blit(text, text_rect)
# ------------------------- SPRITES ---------------------------- #
class Camera:
def __init__(self, game, x, y):
self.game = game
self.x, self.y = self.game.to_screen(x, y)
self.vx, self.vy = 0, 0
def update(self):
self.get_keys()
self.x += self.vx * self.game.dt
self.y += self.vy * self.game.dt
def get_keys(self):
self.vx, self.vy = 0, 0
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
self.vy = -CAMERA_SPEED
if keys[pygame.K_s]:
self.vy = CAMERA_SPEED
if keys[pygame.K_a]:
self.vx = -CAMERA_SPEED
if keys[pygame.K_d]:
self.vx = CAMERA_SPEED
if self.vx != 0 and self.vy != 0:
self.vx *= 1.0
self.vy *= 0.50
class MouseSelection:
def __init__(self, game, image):
self.game = game
self.image = image
def update(self):
# get mouse x and y
self.mouse_x, self.mouse_y = pygame.mouse.get_pos()
# get the mouse offset position inside the tile
self.offset_x, self.offset_y = self.mouse_x % TILE_X, self.mouse_y % TILE_Y
self.offset_x += self.game.scroll_x % TILE_X # Add camera scroll to offset
self.offset_y += self.game.scroll_y % TILE_Y
# get the cell number
self.cell_x, self.cell_y = (self.mouse_x // TILE_X), (self.mouse_y // TILE_Y)
self.cell_x += int((self.game.scroll_x // TILE_X)) # Add camera scroll to cell
self.cell_y += int((self.game.scroll_y // TILE_Y))
# get the selected cell in iso grid
self.selected_x = (self.cell_y - ORIGIN_Y) + (self.cell_x - ORIGIN_X)
self.selected_y = (self.cell_y - ORIGIN_Y) - (self.cell_x - ORIGIN_X)
# height and width of a quarter of a tile, select the corner of the tile to nodge to a direction
h, w = TILE_Y / 2, TILE_X / 2
if self.offset_y < (h / w) * (w - self.offset_x):
self.selected_x -= 1
if self.offset_y > (h / w) * self.offset_x + h:
self.selected_y += 1
if self.offset_y < (h / w) * self.offset_x - h:
self.selected_y -= 1
if self.offset_y > (h / w) * (2 * w - self.offset_x) + h:
self.selected_x += 1
# translate the selected cell to world coordinate
self.selectedWorld_x, self.selectedWorld_y = self.game.to_screen(self.selected_x, self.selected_y)
def draw(self):
# Draw the selected tile with the camera scroll offset
self.game.screen.blit(self.image, (self.selectedWorld_x - self.game.scroll_x,
self.selectedWorld_y - self.game.scroll_y))
class SpriteSheet:
def __init__(self, image):
self.image = image
self.frames = []
def get_image(self):
for row in range(2):
for col in range(4):
if row == 0:
image = pygame.Surface((TILE_Y, TILE_Y / 2)).convert_alpha()
image.blit(self.image, (0, 0), (col * TILE_X / 2, row * TILE_Y / 2, TILE_X, TILE_Y))
image = pygame.transform.scale(image, (TILE_X, TILE_Y))
else:
image = pygame.Surface((TILE_Y, TILE_Y)).convert_alpha()
image.blit(self.image, (0, 0), (col * TILE_X / 2, row * TILE_Y / 2, TILE_X, TILE_Y * 2))
image = pygame.transform.scale(image, (TILE_X, TILE_Y * 2))
image.set_colorkey(WHITE)
self.frames.append(image)
return self.frames
# ------------------------- GAME LOOP ---------------------------- #
class Game:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(title)
self.clock = pygame.time.Clock()
pygame.key.set_repeat(400, 100)
self.debug = {}
self.sprite_sheet_image = pygame.image.load("isometric_whitebg - Copy.png")
self.index = 1
self.scroll_x, self.scroll_y = 0, 0
def new(self):
# initialize all variables and do all the setup for a new game
self.sprite_sheet = SpriteSheet(self.sprite_sheet_image)
self.tile_selected = self.sprite_sheet.get_image()[0]
self.tiles = self.sprite_sheet.get_image()
self.mouse_selection = MouseSelection(self, self.tile_selected)
self.camera = Camera(self, 1, 1)
def run(self):
# game loop - set self.playing = False to end the game
self.playing = True
while self.playing:
self.dt = self.clock.tick(FPS) / 1000
self.events()
self.update()
self.draw()
def quit(self):
pygame.quit()
sys.exit()
def update(self):
# update portion of the game loop
self.camera.update()
self.mouse_selection.update()
self.mx, self.my = pygame.mouse.get_pos()
# -------------------------------------------------- CAMERA SCROLLING ----------------------------------------#
if self.camera.x - self.scroll_x != WIDTH / 2:
self.scroll_x += (self.camera.x - (self.scroll_x + WIDTH / 2)) / 10
if self.camera.y - self.scroll_y != HEIGHT / 2:
self.scroll_y += (self.camera.y - (self.scroll_y + HEIGHT / 2)) / 10
# -------------------------------------------------- CAMERA SCROLLING ----------------------------------------#
self.debug_info()
def to_screen(self, x, y):
screen_x = (ORIGIN_X * TILE_X) + (x - y) * (TILE_X / 2)
screen_y = (ORIGIN_Y * TILE_Y) + (x + y) * (TILE_Y / 2)
return screen_x, screen_y
def draw_world(self):
for y in range(WORLD_Y):
for x in range(WORLD_X):
vWorld_x, vWorld_y = self.to_screen(x, y)
# Invisible tile
if self.index == 0:
self.screen.blit(self.tiles[1], (vWorld_x, vWorld_y))
# Grass
elif self.index == 1:
self.screen.blit(self.tiles[2], (vWorld_x - self.scroll_x, vWorld_y - self.scroll_y))
def draw(self):
self.screen.fill(BGCOLOUR)
self.draw_world()
self.mouse_selection.draw()
get_info(self.debug)
pygame.display.flip()
def debug_info(self):
self.debug["FPS"] = int(self.clock.get_fps())
self.debug["Cell"] = self.mouse_selection.cell_x, self.mouse_selection.cell_y
self.debug["Selected"] = int(self.mouse_selection.selected_x), int(self.mouse_selection.selected_y)
self.debug["Scroll"] = int(self.scroll_x), int(self.scroll_y)
self.debug["Mouse"] = int(self.mx), int(self.my)
self.debug["Mouse_offset"] = int(self.mouse_selection.offset_x), int(self.mouse_selection.offset_y)
def events(self):
# catch all events here
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
self.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
pass
game = Game()
while True:
game.new()
game.run()
I'm not managing to get this math correct, and it's a little bit difficult to explain in words. I have managed to create a isometric grid, which you can select the tiles with the mouse perfectly, and I have managed to implement a camera movement using wasd keys and still get the tiles correctly selected, but there is a slightly bug which I can not figure out where is coming from.
This is what happens, but only sometimes, depend where the camera offset is:
when this happens, it is only on the x axis, and not in every tile.
I'm almost giving up on this cause I can't find the bug, thought of posting here to see if anyone had similar problem.
import time
import pygame
import sys
import math
from os import path
from settings import *
from sprites import *
# ------------------------- SETTINGS ---------------------------- #
# COLORS (r, g, b)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
DARKGREY = (40, 40, 40)
LIGHTGREY = (100, 100, 100)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
# game settings
WIDTH = 1024
HEIGHT = 768
FPS = 60
title = "Isometric-Based game"
BGCOLOUR = DARKGREY
TILE_X = 80
TILE_Y = 40
WORLD_X, WORLD_Y = 14, 10
ORIGIN_X, ORIGIN_Y = 5, 1
# Debug
pygame.init()
font = pygame.font.Font(None, 25)
CAMERA_SPEED = 300
def get_info(info_list):
display_surface = pygame.display.get_surface()
for i, key in enumerate(info_list):
text = font.render(str(key) + " : " + str(info_list[key]), True, (255, 255, 255), (0, 0, 0))
text_rect = text.get_rect()
text_rect.y = 20 * i
display_surface.blit(text, text_rect)
# ------------------------- SPRITES ---------------------------- #
class Camera:
def __init__(self, game, x, y):
self.game = game
self.x, self.y = self.game.to_screen(x, y)
self.vx, self.vy = 0, 0
def update(self):
self.get_keys()
self.x += self.vx * self.game.dt
self.y += self.vy * self.game.dt
def get_keys(self):
self.vx, self.vy = 0, 0
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
self.vy = -CAMERA_SPEED
if keys[pygame.K_s]:
self.vy = CAMERA_SPEED
if keys[pygame.K_a]:
self.vx = -CAMERA_SPEED
if keys[pygame.K_d]:
self.vx = CAMERA_SPEED
if self.vx != 0 and self.vy != 0:
self.vx *= 1.0
self.vy *= 0.50
class MouseSelection:
def __init__(self, game, image):
self.game = game
self.image = image
def update(self):
# get mouse x and y
self.mouse_x, self.mouse_y = pygame.mouse.get_pos()
# get the mouse offset position inside the tile
self.offset_x, self.offset_y = self.mouse_x % TILE_X, self.mouse_y % TILE_Y
self.offset_x += self.game.scroll_x % TILE_X # Add camera scroll to offset
self.offset_y += self.game.scroll_y % TILE_Y
# get the cell number
self.cell_x, self.cell_y = (self.mouse_x // TILE_X), (self.mouse_y // TILE_Y)
self.cell_x += int((self.game.scroll_x // TILE_X)) # Add camera scroll to cell
self.cell_y += int((self.game.scroll_y // TILE_Y))
# get the selected cell in iso grid
self.selected_x = (self.cell_y - ORIGIN_Y) + (self.cell_x - ORIGIN_X)
self.selected_y = (self.cell_y - ORIGIN_Y) - (self.cell_x - ORIGIN_X)
# height and width of a quarter of a tile, select the corner of the tile to nodge to a direction
h, w = TILE_Y / 2, TILE_X / 2
if self.offset_y < (h / w) * (w - self.offset_x):
self.selected_x -= 1
if self.offset_y > (h / w) * self.offset_x + h:
self.selected_y += 1
if self.offset_y < (h / w) * self.offset_x - h:
self.selected_y -= 1
if self.offset_y > (h / w) * (2 * w - self.offset_x) + h:
self.selected_x += 1
# translate the selected cell to world coordinate
self.selectedWorld_x, self.selectedWorld_y = self.game.to_screen(self.selected_x, self.selected_y)
def draw(self):
# Draw the selected tile with the camera scroll offset
self.game.screen.blit(self.image, (self.selectedWorld_x - self.game.scroll_x,
self.selectedWorld_y - self.game.scroll_y))
class SpriteSheet:
def __init__(self, image):
self.image = image
self.frames = []
def get_image(self):
for row in range(2):
for col in range(4):
if row == 0:
image = pygame.Surface((TILE_Y, TILE_Y / 2)).convert_alpha()
image.blit(self.image, (0, 0), (col * TILE_X / 2, row * TILE_Y / 2, TILE_X, TILE_Y))
image = pygame.transform.scale(image, (TILE_X, TILE_Y))
else:
image = pygame.Surface((TILE_Y, TILE_Y)).convert_alpha()
image.blit(self.image, (0, 0), (col * TILE_X / 2, row * TILE_Y / 2, TILE_X, TILE_Y * 2))
image = pygame.transform.scale(image, (TILE_X, TILE_Y * 2))
image.set_colorkey(WHITE)
self.frames.append(image)
return self.frames
# ------------------------- GAME LOOP ---------------------------- #
class Game:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(title)
self.clock = pygame.time.Clock()
pygame.key.set_repeat(400, 100)
self.debug = {}
self.sprite_sheet_image = pygame.image.load("isometric_whitebg - Copy.png")
self.index = 1
self.scroll_x, self.scroll_y = 0, 0
def new(self):
# initialize all variables and do all the setup for a new game
self.sprite_sheet = SpriteSheet(self.sprite_sheet_image)
self.tile_selected = self.sprite_sheet.get_image()[0]
self.tiles = self.sprite_sheet.get_image()
self.mouse_selection = MouseSelection(self, self.tile_selected)
self.camera = Camera(self, 1, 1)
def run(self):
# game loop - set self.playing = False to end the game
self.playing = True
while self.playing:
self.dt = self.clock.tick(FPS) / 1000
self.events()
self.update()
self.draw()
def quit(self):
pygame.quit()
sys.exit()
def update(self):
# update portion of the game loop
self.camera.update()
self.mouse_selection.update()
self.mx, self.my = pygame.mouse.get_pos()
# -------------------------------------------------- CAMERA SCROLLING ----------------------------------------#
if self.camera.x - self.scroll_x != WIDTH / 2:
self.scroll_x += (self.camera.x - (self.scroll_x + WIDTH / 2)) / 10
if self.camera.y - self.scroll_y != HEIGHT / 2:
self.scroll_y += (self.camera.y - (self.scroll_y + HEIGHT / 2)) / 10
# -------------------------------------------------- CAMERA SCROLLING ----------------------------------------#
self.debug_info()
def to_screen(self, x, y):
screen_x = (ORIGIN_X * TILE_X) + (x - y) * (TILE_X / 2)
screen_y = (ORIGIN_Y * TILE_Y) + (x + y) * (TILE_Y / 2)
return screen_x, screen_y
def draw_world(self):
for y in range(WORLD_Y):
for x in range(WORLD_X):
vWorld_x, vWorld_y = self.to_screen(x, y)
# Invisible tile
if self.index == 0:
self.screen.blit(self.tiles[1], (vWorld_x, vWorld_y))
# Grass
elif self.index == 1:
self.screen.blit(self.tiles[2], (vWorld_x - self.scroll_x, vWorld_y - self.scroll_y))
def draw(self):
self.screen.fill(BGCOLOUR)
self.draw_world()
self.mouse_selection.draw()
get_info(self.debug)
pygame.display.flip()
def debug_info(self):
self.debug["FPS"] = int(self.clock.get_fps())
self.debug["Cell"] = self.mouse_selection.cell_x, self.mouse_selection.cell_y
self.debug["Selected"] = int(self.mouse_selection.selected_x), int(self.mouse_selection.selected_y)
self.debug["Scroll"] = int(self.scroll_x), int(self.scroll_y)
self.debug["Mouse"] = int(self.mx), int(self.my)
self.debug["Mouse_offset"] = int(self.mouse_selection.offset_x), int(self.mouse_selection.offset_y)
def events(self):
# catch all events here
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
self.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
pass
game = Game()
while True:
game.new()
game.run()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
定义地图的角点:
利用此信息,您可以计算地图的 x 轴和 y 轴:
< img src="https://i.sstatic.net/76T75.png" alt="">
您可以使用 x 轴和 y 轴来计算地图中的点作为以下函数行和列:
如果你想根据鼠标光标获取行和列,则需要执行相反的操作。您需要从 x 轴和 y 轴计算2x2 逆矩阵。使用逆矩阵,您可以将行和列计算为地图上点的函数:
另请参阅 PyGameExamplesAndAnswers - 等距
最小示例:
replit.com/@Rabbid76/Pygame-IsometircMap
Define the corner points of the map:
With this information you can calculate the x and y axis of the map:
You can use the x-axis and the y-axis to calculate a point in the map as a function of the row and column:
If you want to get the row and column depending on the mouse cursor, you need to do the opposite. You need to calculate the inverse 2x2 matrix from the x and y axis. Using the inverse matrix, you can calculate the row and column as a function of a point on the map:
Also see PyGameExamplesAndAnswers - Isometric
Minimal example:
replit.com/@Rabbid76/Pygame-IsometircMap