Python, Pygame, Image manipulation: Restretch a loaded png, to be the texture for an isometric Tile

2024/10/7 18:32:09

I'm a 17 year old programmer, trying to program an isometric game in python, with pygame. After finishing a tile engine, working with not good looking, gimp-drawn PNG's, I wondered, if it would be possible to render some Tiles by texture. I hope I provided all what's needed to understand, what's my issue and please excuse my not perfect English.

Simply what I want to do, is to generate a 128 by 128 Pixel width Image of an Isometric Tile, using the following picture as texture for all three sides of the Block:

texture

(Links here because I'm not yet allowed to put pictures in, due to it's my first post)

To explain better, what I'm trying to do, I have drawn this little picture: desired output

I have already searched the Internet for about 2 hours and didn't come to a solution, except for the top part of the Tile, here is what I already got in Code:

This is the Image Manipulation Module, the transformToRightPart() is the method where I need help:

import pygameclass Image(object):'''Use this Module to create Tiles by Texture to use them later in the Tileengine.It is important to run pygame.init() before creating objects of this class!Contains unfinished Elements!'''def __init__(self, path):self.loadFromPath(path)def getIMG(self):assert self.originalIMG is not None, "No picture to return"if not self.IMG == None:return self.IMGelse:return self.originalIMGdef loadFromPath(self, path):'''Don't do convert() or convert_alpha() here,as Objects of this class are created during the loading process,with no pygame.display() created.'''self.originalIMG = pygame.image.load(path)self.IMG = Nonedef transformToTopPart(self):'''Transforms the loaded Image to the Top Part of an Isometric Tile, with the Dimensions 2:1,said in Pixels: 128 px Width by 64 px Height.'''self.IMG = pygame.transform.rotate(self.originalIMG, 45)self.IMG = pygame.transform.scale(self.IMG, (128, 64))def transformToRightPart(self):'''TODO!! Don't ask how (X.X)Transforms the loaded Image to the right Part of an Isometric Tile.'''assert False, "This method isn't finished, try something different ;)"def transformToLeftPart(self):'''Transforms the loaded Image to the left Part of an Isometric Tile.Due to the nice geometric fact, that the shape of the left part,is just the flipped right part shape and we don't lose quality by flipping,we do this little trick, to enshorten the code.'''self.originalIMG = pygame.transform.flip(self.originalIMG, True, False)self.transformToRightPart()self.IMG = pygame.transform.flip(self.IMG, True, False)self.originalIMG = pygame.transform.flip(self.originalIMG, True, False)

And this is the Module, which creates a window with the tile to render:

import pygame, sysfrom ImageManipulation import Image
from pygame.locals import *if __name__ == '__main__':pygame.init()FPS=20fpsClock = pygame.time.Clock()picture = Image("Stone_Floor_texture.png")picture.transformToTopPart()DISPLAY = pygame.display.set_mode((400,400),0,32)while True:for event in pygame.event.get():if event.type == QUIT:pygame.quit()sys.exit()DISPLAY.blit(picture.getIMG(),(0,0))pygame.display.update()fpsClock.tick(FPS)

The output of the code looks like this:

my output

What I'm trying to achieve is, that it looks, something like this:

desired output

Answer

Big thanks to Spektre for all the effort he made, trying to help me, but all in all, after two days of over-thinking the problem and bug-fixing, I came up with a solution myself. It might not be as fast or efficient as targeting the pixels directly in an array, like Spektre did in his c++ example, but it is a way, you're only dependencies are pygame, and it is easy to understand.

What did I do? - I wrote two functions, the first getting a surface containing only a single column of another surface, with an index, referring to the x position of the column. And the second, calculating a coefficient, how far down each row should get moved, if the last row should get shifted down a certain amount of pixels and then returning a surface with the shifted picture.

Here is the magic Code:

import pygamefrom pygame.locals import *
from pygame import Surfacedef getColumn(surface, index):assert index <= surface.get_width(), "index can't be bigger, than surface width"height = surface.get_height()subsurf = Surface((1,height)) # Create Surface 1 px by picture-height high, to store the output insubsurf.blit(surface.subsurface(pygame.Rect( (index,0),(1,height) )),(0,0)) # Blit a one pixel width subsurface with x Position at index of the image to subsurfreturn subsurfdef shiftRightDown(surface, pixels):size = surface.get_size()newSize = (size[0], size[1]+pixels)coeff = pixels / size[0]returnSurface = Surface(newSize)for i in range(size[1]): # here happens the magicreturnSurface.blit(getColumn(surface, i), (i,0+int(i*coeff)))return returnSurface

After all, big respect to Spektres coding skills, even though I'm to dumb to understand anything from the c plus plus example, as I'm a total beginner.

https://en.xdnf.cn/q/118788.html

Related Q&A

TypeError: list object is not callable [duplicate]

This question already has answers here:TypeError: list object is not callable while trying to access a list(9 answers)Closed 10 years ago.I cant find the problem im facing... this is exactly what the …

Tokenise text and create more rows for each row in dataframe

I want to do this with python and pandas.Lets suppose that I have the following:file_id text 1 I am the first document. I am a nice document. 2 I am the second document. I am an even …

Is the example of the descriptor protocol in the Python 3.6 documentation incorrect?

I am new to Python and looking through its documentation I encountered the following example of the descriptor protocol that in my opinion is incorrect. .It looks like class IntField:def __get__(self, …

How to clean a string to get value_counts for words of interest by date?

I have the following data generated from a groupby(Datetime) and value_counts()Datetime 0 01/01/2020 Paul 803 2 01/02/2020 Paul 210982360967 1 …

Folium - Map doesnt appear

I try to get map through Folium but only thing I can see is marker on blank page. Id like to know where is problem lies, in explorer or coding. map.py import foliummap = folium.Map(location = [46.20, 6…

python tkinter exe built with cx_Freeze for windows wont show GUI

PROBLEM SOLVED. the issue was with jaraco module, that i used for clipboard manipulation, i used pyperclip instead.I made a python app with tkinter that works fine, but I wanted to make an exe from it …

lxml tree connection and properties

I have a .dtsx file so, I have multiple components with connections, so I need to extract component that have especific connection, but I can not handle that, example: <components><component r…

Python recursive function call with if statement

I have a question regarding function-calls using if-statements and recursion. I am a bit confused because python seems to jump into the if statements block even if my function returns "False"…

How can I list all 1st row values in an Excel spreadsheet using OpenPyXL?

Using the OpenPyXL module with Python 3.5, I was able to figure out how many columns there are in a spreadsheet with:In [1]: sheet.max_column Out [1]: 4Then I was able to list the values in each of the…

Using matplotlib on non-0 MPI rank causes QXcbConnection: Could not connect to display

I have written a program that uses mpi4py to do some job (making an array) in the node of rank 0 in the following code. Then it makes another array in the node of rank 1. Then I plot both the arrays. T…