Advertisement
Windspar

Pygame Isometric Test Example

Aug 24th, 2021
1,415
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.52 KB | None | 0 0
  1. import pygame
  2. import itertools
  3. from types import SimpleNamespace
  4.  
  5. color = SimpleNamespace(**dict([(k, pygame.Color(v)) for k, v in pygame.color.THECOLORS.items()]))
  6.  
  7. def create_box_image(color, size):
  8.     size = size, size
  9.     surface = pygame.Surface(size, pygame.SRCALPHA)
  10.     surface.fill((0, 0, 0, 0))
  11.     pygame.draw.rect(surface, color, (0, 0, *size), 1)
  12.     return surface
  13.  
  14. def shift_image(image):
  15.     w, h = image.get_size()
  16.     size = w + h, h
  17.     surface = pygame.Surface(size, pygame.SRCALPHA)
  18.     for x in range(w):
  19.         for y in range(h):
  20.             color = image.get_at((x, y))
  21.             surface.set_at((x + y, y), color)
  22.  
  23.     return surface
  24.  
  25. class TileMap:
  26.     def __init__(self, tilemap, tilekey):
  27.         self.tilemap = tilemap
  28.         self.tilekey = tilekey
  29.         self.hover = None
  30.         self.hover2 = None
  31.  
  32.     def draw(self, camera, surface):
  33.         for y, row in enumerate(self.tilemap):
  34.             for x, key in enumerate(row):
  35.                 if key != 0:
  36.                     image = self.tilekey[key]
  37.  
  38.                     if self.hover == self.hover2 and self.hover != None:
  39.                         if self.hover[0] == x and self.hover[1] == y:
  40.                             image = self.tilekey["hover3"]
  41.                     else:
  42.                         if self.hover:
  43.                             if self.hover[0] == x and self.hover[1] == y:
  44.                                 image = self.tilekey["hover"]
  45.  
  46.                         if self.hover2:
  47.                             if self.hover2[0] == x and self.hover2[1] == y:
  48.                                 image = self.tilekey["hover2"]
  49.  
  50.                     surface.blit(image, camera.map_to_screen((x, y)))
  51.  
  52. class TileCamera:
  53.     def __init__(self, worldsize, position, view, tilesize, map):
  54.         self.map = map
  55.         self.view = view
  56.         self.position = position
  57.         self.tile = pygame.Rect(0, 0, tilesize, tilesize)
  58.         self.surface = pygame.Surface(worldsize, pygame.SRCALPHA)
  59.  
  60.     def draw(self, surface):
  61.         self.surface.fill(color.gray40)
  62.         self.map.draw(self, self.surface)
  63.  
  64.         surface.blit(self.surface, self.position)
  65.  
  66.     def map_to_screen(self, position):
  67.         return self.view[0] + position[0] * self.tile.w, self.view[1] + position[1] * self.tile.h
  68.  
  69.     def iso_hover(self, position):
  70.         self.map.hover = position[0] // self.tile.w, position[1] // self.tile.h
  71.  
  72. class IsoCamera:
  73.     def __init__(self, worldsize, position, view, tilesize, map):
  74.         self.map = map
  75.         self.view = view
  76.         self.position = position
  77.         self.tile = pygame.Rect(0, 0, tilesize * 2, tilesize)
  78.         self.surface = pygame.Surface(worldsize, pygame.SRCALPHA)
  79.  
  80.     def draw(self, surface):
  81.         self.surface.fill(color.gray30)
  82.         self.map.draw(self, self.surface)
  83.  
  84.         surface.blit(self.surface, self.position)
  85.  
  86.     def get_position(self, mpos):
  87.         return mpos[0] - self.view[0] - self.position[0], mpos[1] - self.view[1] - self.position[1]
  88.  
  89.     # Formula found on the net
  90.     def real_screen_to_map(self, position):
  91.         x = (position[0] - self.view[0] - self.position[0]) / self.tile.width
  92.         y = (position[1] - self.view[1] - self.position[1]) / self.tile.height
  93.         return int(x + y), int(y - x)
  94.  
  95.     # Formula I came up with
  96.     def screen_to_map(self, position):
  97.         # Remove all offset
  98.         posx = position[0] - self.position[0] - self.view[0]
  99.         posy = position[1] - self.position[1] - self.view[1]
  100.         # Change to map position
  101.         y = (posy - posx * 0.5 + self.tile.centery)
  102.         x = (posx + y - self.tile.height) // self.tile.height
  103.         y /= self.tile.height
  104.         if y < 0:
  105.             y -= 1
  106.         return int(x), int(y)
  107.  
  108.     # Formula found on the net. Did not work for me.
  109.     def map_to_screen(self, position):
  110.         x, y = position
  111.         return (self.view[0] + (x - y) * self.tile.centerx,
  112.                 self.view[1] + (x + y) * self.tile.centery)
  113.  
  114. class TileLabels:
  115.     def __init__(self):
  116.         pen = Pen(pygame.font.Font(None, 24), color.white)
  117.         iso_ypos = itertools.count(10, 30)
  118.         ypos = itertools.count(10, 30)
  119.         self.labels = {
  120.             "Mouse" : Label(pen, "Mouse Pos: ({}, {})", (0, 0), (10, next(iso_ypos)), "topleft"),
  121.             "ISO Position" : Label(pen, "ISO Position: ({}, {})", (0, 0), (10, next(iso_ypos)), "topleft"),
  122.  
  123.             "Position" : Label(pen, "Position: ({}, {})", (0, 0), (410, next(ypos)), "topleft"),
  124.             "Position2" : Label(pen, "Position: ({}, {})", (0, 0), (410, next(ypos)), "topleft"),
  125.             }
  126.  
  127.     def draw(self, surface):
  128.         for value in self.labels.values():
  129.             value.draw(surface)
  130.  
  131.     # Formula I came up with
  132.     def update(self, mpos, iso_cam):
  133.         self.labels["Mouse"].render(*mpos)
  134.         ix, iy = iso_cam.get_position(mpos)
  135.         self.labels["ISO Position"].render(ix, iy)
  136.         y = iy - ix * 0.5 + iso_cam.tile.centery
  137.         x = ix + y - iso_cam.tile.h
  138.         self.labels["Position"].render(x, y)
  139.         self.labels["Position2"].render(*iso_cam.screen_to_map(mpos))
  140.         return x, y
  141.  
  142. class Pen:
  143.     def __init__(self, font, color):
  144.         self.font = font
  145.         self.color = color
  146.  
  147.     def render(self, string):
  148.         return self.font.render(string, 1, self.color)
  149.  
  150. class Label:
  151.     def __init__(self, pen, fstring, data, position, anchor):
  152.         self.pen = pen
  153.         self.fstring = fstring
  154.         self.position = position
  155.         self.anchor = anchor
  156.         self.render(*data)
  157.  
  158.     def draw(self, surface):
  159.         surface.blit(self.image, self.rect)
  160.  
  161.     def render(self, *data):
  162.         text = self.fstring.format(*data)
  163.         self.image = self.pen.render(text)
  164.         self.rect = self.image.get_rect(**{self.anchor: self.position})
  165.  
  166. class Main:
  167.     def __init__(self, caption, width, height, flags=0):
  168.         pygame.display.set_caption(caption)
  169.         self.surface = pygame.display.set_mode((width, height), flags)
  170.         self.rect = self.surface.get_rect()
  171.         self.clock = pygame.time.Clock()
  172.         self.running = False
  173.         self.delta = 0
  174.         self.fps = 60
  175.  
  176.         self.tile_labels = TileLabels()
  177.  
  178.         tilesize = 32
  179.         worldsize = 400, 400
  180.         view = 150, 100
  181.         self.maptile = [[1, 1, 1, 1, 1],
  182.                         [1, 1, 1, 1, 1],
  183.                         [1, 1, 1, 1, 1],
  184.                         [1, 1, 1, 1, 1]]
  185.  
  186.         self.tilekey = {
  187.             "hover" : create_box_image(color.lawngreen, tilesize),
  188.             "hover2" : create_box_image(color.firebrick, tilesize),
  189.             "hover3" : create_box_image(color.dodgerblue, tilesize),
  190.             1 : create_box_image(color.snow, tilesize)
  191.         }
  192.  
  193.         rotate = pygame.transform.rotate
  194.         scale = pygame.transform.smoothscale
  195.         self.isokey = {
  196.             "hover" : scale(rotate(self.tilekey["hover"], 45), (64, 32)),
  197.             "hover2" : scale(rotate(self.tilekey["hover2"], 45), (64, 32)),
  198.             "hover3" : scale(rotate(self.tilekey["hover3"], 45), (64, 32)),
  199.             1 : scale(pygame.transform.rotate(self.tilekey[1], 45), (64, 32))
  200.         }
  201.  
  202.         self.tile_map = TileMap(self.maptile, self.tilekey)
  203.         self.iso_map = TileMap(self.maptile, self.isokey)
  204.         self.tile_camera = TileCamera(worldsize, (400, 100), view, tilesize, self.tile_map)
  205.         self.iso_camera = IsoCamera(worldsize, (0, 100), view, tilesize, self.iso_map)
  206.  
  207.         self.inverse_mouse = None
  208.  
  209.     def draw(self):
  210.         self.iso_camera.draw(self.surface)
  211.         self.tile_camera.draw(self.surface)
  212.         self.tile_labels.draw(self.surface)
  213.  
  214.     def mainloop(self):
  215.         self.running = True
  216.         while self.running:
  217.             for event in pygame.event.get():
  218.                 if event.type == pygame.MOUSEMOTION:
  219.                     self.iso_camera.map.hover2 = self.iso_camera.screen_to_map(event.pos)
  220.                     pos = self.tile_labels.update(event.pos, self.iso_camera)
  221.                     self.tile_camera.iso_hover(pos)
  222.                     self.iso_camera.map.hover = self.tile_camera.map.hover
  223.                 elif event.type == pygame.QUIT:
  224.                     self.running = False
  225.  
  226.             self.surface.fill(color.black)
  227.             self.draw()
  228.             pygame.display.flip()
  229.             self.delta = self.clock.tick(self.fps) * 0.001
  230.  
  231. def main():
  232.     pygame.init()
  233.     app = Main("IsoMetric", 800, 500)
  234.     app.mainloop()
  235.     pygame.quit()
  236.  
  237. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement