How to get image position in Pygame - python

I am coding for a mouse drag and drop effect on images. Meanwhile, I want to take record of the upper-left point of image each time I dragged and dropped it, are there any ways to get it?

What methods are you using to draw the images? It's hard to answer this question without that.
If you aren't already doing this, you could use a class to hold data about your image, such as position and geometry.

If you derive your classes from pygame.sprite.Sprite , you can get the position by guy.rect. Depending on if you want center, or toplef, or the full rect:
guy.rect.topleft or guy.rect.center or guy.rect

Related

Is there a function in Pygame to save a portion of the screen as an image? [duplicate]

This question already has answers here:
How can I crop an image with Pygame?
(4 answers)
Closed 1 year ago.
I am working on making a drawing program in Pygame. All features are basically complete except for the ability to save your image. Is there any built in Pygame function that does this, or will I have to find some other way (E.G. taking a screenshot or something).
screen is a Surface object which has method subsurface(Rect) to get part of surface - and this part will be also a Surface object.
And there is function pygame.image.save(surface, filename)
Other method: at start create smaller Surface and draw on this surface (instead of drawing directly on screen) and blit() this surface on screen to display it and save() this surface to file.
You can even use many surfaces and keep them on list to create function Undo. When you use new tool then you duplicate surface and put it on list. When you use Undo then you get last surface from list.
If it's a drawing game, then you'll probably find it very easy to manually make the image.
I know it sounds scary, but it really isn't, especially in python.
You can use PyPng to convert a 2D array into an image, as I assume you already use a 2D array to store the drawing

How can I make a rectangle in pygame be able to check for other rectangles around it?

As part of my current pygame project (I am very new to pygame), I have created multiple rectangles that move at random around the screen. As one of the features of this game, I want to make it so if one rectangle is close enough to another one, it moves towards it. Another feature I want to add is that rectangles cannot collide with each other, but I don't want to just do the regular
if rectangle1.colliderect(rectangle2):
rectange.x -= 10 # That is, it's previous position
because it will make the animations look odd.
The main way I can see to solve these problems is to use some sort of function that could check if a rectangle.x - 30 is another rectangle (or something similar), but I am unaware of one that exists.
I have attempted to look through google, but I haven't found anything as all the posts are different problems that aren't quite the same.
Thank you for any responses!
Use inflate to create a rectangle that is larger than the original one and surrounds it. Use this rectangle to find other rectangles in range:
test_rect = rect1.inflate(dist, dist)
if test_rect.colliderect(rect2):
# [...]

Wrapping a pygame surface around a viewport

I'm coding a game where the viewport follows the player's ship in a finite game world, and I am trying to make it so that the background "wraps" around in all directions (you could think of it as a 2D surface wrapped around a sphere - no matter what direction you travel in, you will end up back where you started).
I have no trouble getting the ship and objects to wrap, but the background doesn't show up until the viewport itself passes an edge of the gameworld. Is it possible to make the background surface "wrap" around?
I'm sorry if I'm not being very articulate. It seems like a simple problem and tons of games do it, but I haven't had any luck finding an answer. I have some idea about how to do it by tiling the background, but it would be nice if I could just tell the surface to wrap.
I don't think so, I have an idea though. I'm guessing your background wraps horizontally and always to the right, then you could attach part of the beginning to the end of the background.
Example, if you have a 10,000px background and your viewport is 1000px, attach the first 1000px to the end of the background, so you'll have a 11,000px background. Then when the vieport reaches the end of the background, you just move it to the 0px position and continue moving right.
I was monkeying around with something similar to what you described that may be of use. I decided to try using a single map class which contained all of my Tiles, and I wanted only part of it loaded into memory at once so I broke it up into Sectors (32x32 tiles). I limited it to only having 3x3 Sectors loaded at once. As my map scrolled to an edge, it would unload the Sectors on the other side and load in new ones.
My Map class would have a Rect of all loaded Sectors, and my camera would have a Rect of where it was located. Each tick I would use those two Rects to find what part of the Map I should blit, and if I should load in new Sectors. Once you start to change what Sectors are loaded, you have to shift
Each sector had the following attributes:
1. Its Coordinate, with (0, 0) being the topleft most possible Sector in the world.
2. Its Relative Sector Coordinate, with (0, 0) being the topleft most loaded sector, and (2,2) the bottom right most if 3x3 were loaded.
3. A Rect that held the area of the Sector
4. A bool to indicate of the Sector was fully loaded
Each game tick would check if the bool to see if Sector was fully loaded, and if not, call next on a generator that would blit X tiles onto the Map surface. I
The entire Surface
Each update would unload, load, or update and existing Sector
When an existing Sector was updated, it would shift
It would unload Sectors on update, and then create the new ones required. After being created, each Sector would start a generator that would blit X amount of tiles per update
Thanks everyone for the suggestions. I ended up doing something a little different from the answers provided. Essentially, I made subsurfaces of the main surface and used them as buffers, displaying them as appropriate whenever the viewport included coordinates outside the world. Because the scrolling is omnidirectional, I needed to use 8 buffers, one for each side and all four corners. My solution may not be the most elegant, but it seems to work well, with no noticeable performance drop.

Python/Tkinter - cropping a canvas based on whitespace?

I'm tinkering around with tkinter, and have used it to make some dynamic graphics based on a dataset.
I started of with an arbitrary sized canvas of 1000x1000 pixels, and now I have my images made, I wondered if there is was anyway to crop the canvas around the unoccupied parts of the edges.
I think of a couple of ways to achieve this, one would be to trim each edge until an object is hit, however, I think this wouldn't work because as far as I can tell the objects are directly addressed onto the canvas location, so any changes to the canvas in the top RHS would just result in objects moving in concert, another would be to (somehow) group all the objects into a single named object, get the borders and a somehow redraw the lot on a newly sized canvas.
I wondered if anyone had any ideas or done this before?
The bbox method of the canvas gives you the bounding box (opposite corners) of an object or objects on the canvas. So, my_canvas.bbox("all") will return you a rectangle that encompasses all of the items on the canvas. According to the official Tk documentation, this method "may overestimate the actual bounding box by a few pixels"
I'm not sure exactly what you mean by "crop" in the context of this question, but since you know the x/y of the upper left corner of the objects, you can use the move method to move all objects by -x1/-y1 pixels to move everything to the upper left corner.

Native PyGame method for automatically scaling inputs to a surface resolution?

This question is related to this other one.
In my program (which uses pygame to draw objects on the video) I have two representation of my world:
A physical one that I use to make all the calculations involved in the simulation and in which objects are located on a 1000x1000 metres surface.
A visual one which I use to draw on the screen, in which my objects are located in a window measuring 100x100 pixels.
What I want to achieve is to be able to pass to my pygame drawing functions (which normally accept inputs in pixels) my physical/real-word coordinates. In other words, I would like to be able to say:
Draw a 20m radius circle at coordinates (200m, 500m)
using the precise pygame syntax:
pygame.draw.circle(surface, (255,255,255), (200,500), 20)
and get my circle of 2px radius at centred on pixels (20,50).
Please note that this question is about a native pygame way to do this, not some sort of workaround to achieve that result (if you want to answer that, you should take a look to the question I already mentioned) instead.
Thanks in advance for your time and support.
There is no native pygame way to do this.
You may be misunderstanding the function of pygame. It is not for drawing vector objects. It is for writing pixels into video surfaces.
Since you have vector objects, you must define how they will be converted into pixels. Doing this is not a workaround - it's how you are intended to use pygame.
Since it seems that PyGame developers do not hang around here too much, I brought the question to the Pygame mailing list where it originated a monster thread and the issue has been debated at large.
The summary would be:
At present there is not such a feature.
There is interest to implement it, or at least to try to implement it...
...although is not a priority of the core devs in any way
There is more than one way to skin a cat:
should be the scaling happen both ways (inputting coordinates and reading them)?
how to deal with lines that have no thickness but that should be visible?
how to deal with visibility of objects at the edge of the image? which of their points should be taken as reference to know if a pixel should be lit or not for them?
and more (see linked thread).

Categories