Python Forum

Full Version: [split] image VS drawing
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
Simple improvement would to put images in a list or dict.
This would stop if block. When more image are added.
DISPLAYSURF.blit(tileImage[tile], (centered_x, centered_y)) #display the actual tile
My example. My math could be improve.
import pygame

class Square:
    def __init__(self, color):
        self.surface = pygame.Surface((64, 64))
        self.surface = self.surface.convert_alpha()
        self.surface.fill((0,0,0,0))

        pygame.draw.polygon(self.surface, color, [(32,32), (64,48), (32,64), (0,48)])

    def draw(self, surface, pos):
        surface.blit(self.surface, pos)

class Block:
    def __init__(self, color):
        self.surface = pygame.Surface((64, 64)).convert_alpha()
        self.surface.fill((0,0,0,0))

        pygame.draw.polygon(self.surface, color, [(32,32), (0,16), (32,0), (64,16)])

        c = color.hsla
        color.hsla = c[0], c[1], c[2] * 0.75, c[3]
        pygame.draw.polygon(self.surface, color, [(0,16), (32,32), (32,64), (0,48)])

        c = color.hsla
        color.hsla = c[0], c[1], c[2] * 0.75, c[3]
        pygame.draw.polygon(self.surface, color, [(32,32), (64,16), (64,48), (32,64)])

    def draw(self, surface, pos):
        surface.blit(self.surface, pos)

class Scene:
    def __init__(self):
        self.rect = pygame.Rect(0, 0, 800, 600)
        pygame.display.set_caption('Example')
        self.surface = pygame.display.set_mode(self.rect.size)
        self.clock = pygame.time.Clock()

        self.images = [Square(pygame.Color('lawngreen')),
                       Block(pygame.Color('cyan')),
                       Block(pygame.Color('firebrick'))
        ]

        self.map = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 1, 0, 0, 1, 0, 2, 2, 2, 0],
                    [0, 1, 0, 0, 1, 0, 0, 2, 0, 0],
                    [0, 1, 1, 1, 1, 0, 0, 2, 0, 0],
                    [0, 1, 0, 0, 1, 0, 0, 2, 0, 0],
                    [0, 1, 0, 0, 1, 0, 2, 2, 2, 0],
                    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

    def loop(self):
        self.running = True
        while self.running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.running = False

            self.surface.fill((0,0,0))

            cx = self.rect.centerx // 2 + len(self.map) * 32
            cy = self.rect.centery // 2 - len(self.map[0]) * 4
            w, h = self.rect.size
            for row, line in enumerate(self.map):
                for col, tile in enumerate(line):
                    pos = w - (row * 32 + cx) + col * 32, (col + row) * 16 + cy
                    self.images[tile].draw(self.surface, pos)

            pygame.display.flip()
            self.clock.tick(30)

        pygame.quit()

scene = Scene()
scene.loop()
What you're proposing is probably faster in term of CPU (I didn't time it though) but the usual way in a 2d game is to use 2d assets, not drawing them in the program.
You can use free 2d assets like here: https://devilsworkshop.itch.io/big-pixel...2d-sprites
(Dec-10-2018, 07:25 AM)ThePhi Wrote: [ -> ]the usual way in a 2d game is to use 2d assets, not drawing them in the program.
I would do this as well. I think its easier and when you need top-down assets something like Tiled makes it really easy to place positions and edit them in the future being able to see them. Not to mention you can make minute details in image software that would be horrific trying to replicate them.
Creating image in game and/or loading image is just a personal preference.
Loading image have higher quality. If you are going that way.
Creating image I can program to have different colors quickly.
So I can test out different task quickly.
Then if I want higher quality images. I can just replace it.
(Dec-10-2018, 03:19 PM)Windspar Wrote: [ -> ]Creating image in game and/or loading image is just a personal preference.
A bit more than that... Even you didn't manage to create the same image as in my example (see the red line around each face of the cube? Not so easy drawing that by the program isn't it?).
[Image: Screenshot-2018-12-11-08-24-35.png]

(Dec-10-2018, 03:19 PM)Windspar Wrote: [ -> ]Loading image have higher quality. If you are going that way. Creating image I can program to have different colors quickly. So I can test out different task quickly. Then if I want higher quality images. I can just replace it.
To get the same result with image assets, you can still use vertex images in pygame. Even if I didn't try it, it seems to work (https://stackoverflow.com/questions/4001...vector-art)
(Dec-11-2018, 07:34 AM)ThePhi Wrote: [ -> ]A bit more than that... Even you didn't manage to create the same image as in my example (see the red line around each face of the cube? Not so easy drawing that by the program isn't it?).
Confused

Example with my poor quality red lines.
import pygame

BRED = pygame.Color(200, 110, 110)

class Square:
    def __init__(self, color):
        self.surface = pygame.Surface((64, 64))
        self.surface = self.surface.convert_alpha()
        self.surface.fill((0,0,0,0))

        pygame.draw.polygon(self.surface, color, [(32,32), (64,48), (32,64), (0,48)])
        pygame.draw.polygon(self.surface, BRED, [(32,32), (64,48), (32,64), (0,48)], 1)

    def draw(self, surface, pos):
        surface.blit(self.surface, pos)

class Block:
    def __init__(self, color):
        self.surface = pygame.Surface((64, 64)).convert_alpha()
        self.surface.fill((0,0,0,0))

        pygame.draw.polygon(self.surface, color, [(32,32), (0,16), (32,0), (64,16)])

        c = color.hsla
        color.hsla = c[0], c[1], c[2] * 0.75, c[3]
        pygame.draw.polygon(self.surface, color, [(0,16), (32,32), (32,64), (0,48)])

        c = color.hsla
        color.hsla = c[0], c[1], c[2] * 0.75, c[3]
        pygame.draw.polygon(self.surface, color, [(32,32), (64,16), (64,48), (32,64)])
        pygame.draw.polygon(self.surface, BRED, [(32,32), (0,16), (32,0), (64,16)], 1)
        pygame.draw.polygon(self.surface, BRED, [(0,16), (32,32), (32,64), (0,48)], 1)
        pygame.draw.polygon(self.surface, BRED, [(32,32), (64,16), (64,48), (32,64)], 1)

    def draw(self, surface, pos):
        surface.blit(self.surface, pos)

class BlockHalf:
    def __init__(self, color):
        self.surface = pygame.Surface((64, 64)).convert_alpha()
        self.surface.fill((0,0,0,0))

        # top
        pygame.draw.polygon(self.surface, color, [(32,48), (0,32), (32,16), (64,32)])

        # left
        c = color.hsla
        color.hsla = c[0], c[1], c[2] * 0.75, c[3]
        pygame.draw.polygon(self.surface, color, [(0,32), (32,48), (32,64), (0,56)])

        # right
        c = color.hsla
        color.hsla = c[0], c[1], c[2] * 0.75, c[3]
        pygame.draw.polygon(self.surface, color, [(32,48), (64,32), (64,56), (32,64)])

    def draw(self, surface, pos):
        surface.blit(self.surface, pos)

class Scene:
    def __init__(self):
        self.rect = pygame.Rect(0, 0, 800, 600)
        pygame.display.set_caption('Example')
        self.surface = pygame.display.set_mode(self.rect.size)
        self.clock = pygame.time.Clock()

        self.images = [Square(pygame.Color('lawngreen')),
                       Block(pygame.Color('cyan')),
                       Block(pygame.Color('firebrick'))
        ]

        self.map = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 1, 0, 0, 1, 0, 2, 2, 2, 0],
                    [0, 1, 0, 0, 1, 0, 0, 2, 0, 0],
                    [0, 1, 1, 1, 1, 0, 0, 2, 0, 0],
                    [0, 1, 0, 0, 1, 0, 0, 2, 0, 0],
                    [0, 1, 0, 0, 1, 0, 2, 2, 2, 0],
                    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

    def loop(self):
        self.running = True
        while self.running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.running = False

            self.surface.fill((0,0,0))

            cx = self.rect.centerx // 2 + len(self.map) * 32 + 16
            cy = self.rect.centery // 2 - len(self.map[0]) * 4
            w, h = self.rect.size
            for row, line in enumerate(self.map):
                for col, tile in enumerate(line):
                    pos = w - (row * 32 + cx) + col * 32, (col + row) * 16 + cy
                    self.images[tile].draw(self.surface, pos)

            pygame.display.flip()
            self.clock.tick(30)

        pygame.quit()

scene = Scene()
scene.loop()
One good thing about low quality images. You can see how fast it program runs. Then see how much slow down with high quality images. In programming everything has it cost.
You gave yourself a lot of work. Try with a sprite of an hospital, a tree now Rolleyes
(Dec-11-2018, 06:28 PM)ThePhi Wrote: [ -> ]You gave yourself a lot of work.
Confused

Example with a trees
import pygame

BRED = pygame.Color(200, 110, 110)

def darken_color(color, darken=0.75):
    c = color.hsla
    color.hsla = c[0], c[1], c[2] * darken, c[3]

def lower_points(points, by=32):
    return tuple([(p[0], p[1] + by) for p in points])

def top_points(x=0, y=0, w=64, h=32):
    if w < 0:
        w = 64 + w

    if h < 0:
        h = 32 + h

    w -= x
    h -= y

    topleft     = x,            y + h * 0.5
    topright    = x + w * 0.5,  y + x * 0.5
    bottomleft  = x + w * 0.5,  y + h - x * 0.5
    bottomright = x + w,        y + h * 0.5
    return topleft, topright, bottomright, bottomleft

def side_points(top_points, height=32):
    return ((top_points[0],
             top_points[3],
            (top_points[3][0],  top_points[3][1] + height),
            (top_points[0][0],  top_points[0][1] + height)),

            (top_points[3],
             top_points[2],
            (top_points[2][0],  top_points[2][1] + height),
            (top_points[3][0],  top_points[3][1] + height)))

class Square:
    def __init__(self, color):
        self.surface = pygame.Surface((64, 64)).convert_alpha()
        self.surface.fill((0,0,0,0))

        pygame.draw.polygon(self.surface, color, [(0,48), (32,32), (64,48), (32,64)])
        pygame.draw.polygon(self.surface, BRED, [(0,48), (32,32), (66,48), (32,64)], 1)

    def draw(self, surface, pos):
        surface.blit(self.surface, pos)

class Block:
    def __init__(self, color):
        self.surface = pygame.Surface((64, 64)).convert_alpha()
        self.surface.fill((0,0,0,0))
        self.create_image(color)

    def create_image(self, color):
        top = top_points()
        left, right = side_points(top)
        # top
        pygame.draw.polygon(self.surface, color, top)

        # left
        darken_color(color)
        pygame.draw.polygon(self.surface, color, left)

        # right
        darken_color(color)
        pygame.draw.polygon(self.surface, color, right)
        #pygame.draw.polygon(self.surface, BRED, [(32,32), (0,16), (32,0), (64,16)], 1)
        #pygame.draw.polygon(self.surface, BRED, [(0,16), (32,32), (32,64), (0,48)], 1)
        #pygame.draw.polygon(self.surface, BRED, [(32,32), (64,16), (64,48), (32,64)], 1)

    def draw(self, surface, pos):
        surface.blit(self.surface, pos)

class Tree:
    def __init__(self, color, trunk_color, ground_color):
        self.tree_top = pygame.Surface((64, 64)).convert_alpha()
        self.tree_top.fill((0,0,0,0))
        self.trunk = pygame.Surface((64, 64)).convert_alpha()
        self.trunk.fill((0,0,0,0))
        self.create_image(color, trunk_color, ground_color)

    def create_image(self, color, trunk_color, ground_color):
        # Tree Top
        top, left, right = self.layer(top_points(), 24, 8)
        self.draw_polygons(self.tree_top, top, left, right, pygame.Color(*color))
        top, left, right = self.layer(top_points(8, w=-8), 16, 8)
        self.draw_polygons(self.tree_top, top, left, right, pygame.Color(*color))
        top, left, right = self.layer(top_points(16, w=-16), 8, 8)
        self.draw_polygons(self.tree_top, top, left, right, pygame.Color(*color))
        top, left, right = self.layer(top_points(24, w=-24), 0, 8)
        self.draw_polygons(self.tree_top, top, left, right, pygame.Color(*color))
        # Trunk
        top = lower_points(top_points())
        pygame.draw.polygon(self.trunk, ground_color, top)
        top, left, right = self.layer(top_points(20, w=-20), 0, 32)
        self.draw_polygons(self.trunk, top, left, right, trunk_color)

    def draw_polygons(self, surface, top, left, right, color):
        # top
        pygame.draw.polygon(surface, color, top)

        # left
        darken_color(color)
        pygame.draw.polygon(surface, color, left)

        # right
        darken_color(color)
        pygame.draw.polygon(surface, color, right)

    def layer(self, toptop, height, diff):
        top = lower_points(toptop, height)
        left, right = side_points(top, diff)
        return top, left, right

    def draw(self, surface, pos):
        surface.blit(self.trunk, pos)
        position = pos[0], pos[1] - 16
        surface.blit(self.tree_top, position)

class Scene:
    def __init__(self):
        self.rect = pygame.Rect(0, 0, 800, 600)
        pygame.display.set_caption('Example')
        self.surface = pygame.display.set_mode(self.rect.size)
        self.clock = pygame.time.Clock()

        self.images = [Square(pygame.Color('lawngreen')),
                       Block(pygame.Color('cyan')),
                       Block(pygame.Color('firebrick')),
                       Tree(pygame.Color('forestgreen'), pygame.Color('brown'), pygame.Color('lawngreen'))
        ]

        self.map = [[3, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                    [0, 1, 0, 0, 1, 0, 2, 2, 2, 0],
                    [0, 1, 0, 0, 1, 0, 0, 2, 0, 0],
                    [0, 1, 1, 1, 1, 0, 0, 2, 0, 0],
                    [0, 1, 0, 0, 1, 0, 0, 2, 0, 3],
                    [0, 1, 0, 0, 1, 0, 2, 2, 2, 0],
                    [3, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

    def loop(self):
        self.running = True
        while self.running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.running = False

            self.surface.fill((0,0,0))

            cx = self.rect.centerx // 2 + len(self.map) * 32 + 16
            cy = self.rect.centery // 2 - len(self.map[0]) * 4
            w, h = self.rect.size
            for row, line in enumerate(self.map):
                for col, tile in enumerate(line):
                    pos = w - (row * 32 + cx) + col * 32, (col + row) * 16 + cy
                    self.images[tile].draw(self.surface, pos)

            pygame.display.flip()
            self.clock.tick(30)

        pygame.quit()

scene = Scene()
scene.loop()
(Dec-10-2018, 03:19 PM)Windspar Wrote: [ -> ]Creating image in game and/or loading image is just a personal preference.
Loading image have higher quality. If you are going that way.
Creating image I can program to have different colors quickly.
So I can test out different task quickly.
Then if I want higher quality images. I can just replace it.
In my opinion the opposite is true. I think it is much more faster to throw an image in GIMP (or PhotoShop Tongue ) to change it than to program it. If your planning on replacing your placeholder images anyways, then it was a complete waste of time writing the code to make trees, rather than just using the actual image you would be using in the first place.
It's probably just me, but I like programming image code. I always use blender over gimp when I can. I can do some math in blender. I like dealing objects over layers. I use gimp for normals and diffuse maps.

I believe I can have 50 colors of every image before you can do it gimp.

It all comes down to how fancy you want your images.
Since I not very good at make fancy images.
Pages: 1 2