[Pygame]: Move surface towards position - python

Is there an algorithm to change a set of coordinates to make it move towards another set of coordinates?
Like, if I have ax,ay=(20,30) a
#fonctions
import pygame, sys
from pygame.locals import *
pygame.init()
fpsClock = pygame.time.Clock()
windows= pygame.display.set_mode((1200,500), 0, 32)
pygame.display.set_caption('testing')
size = width, height = (32, 32)
PNGImg = pygame.Surface(size)
sob_X=575
sob_Y=250
FPS = 15 # frames per second setting
RED= (255, 0, 0) #red color
while True:
windows.fill((54, 141, 197))
pygame.draw.circle(windows, RED, (70, 80), 20, 0)
windows.blit(PNGImg, (sob_X,sob_Y))
dis_X=sob_X-600 #cicle X_Cordinate
dis_Y=sob_X-870 #cicle Y_Cordinate
if dis_X<0:
sob_X=sob_X+ dis_X
if sob_X==70 and dis_Y<0:
sob_Y=sob_X+dis_Y
elif sob_X==70 and dis_Y>0:
sob_Y=sob_Y-dis_Y
elif dis_X>0:
sob_X=sob_X -dis_X
if sob_X==70 and dis_Y<0:
sob_Y=sob_Y+dis_Y
elif sob_X==70 and dis_Y>0:
sob_Y=sob_Y-dis_Y
windows.blit(PNGImg, (sob_X,sob_Y))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
fpsClock.tick(FPS)
pygame.quit()
nd bx,by=(40,60)
How can I change ax and ay (coordinate of the image"surface") to equal bx and by? (Preferably an algorithm achievable in python.)
i tried to make algorithme but in the end don't work
thanks you

Replying here as I can't comment yet, but from the question itself, do you mean to do ax, ay = bx, by ? You can simply do that, or even individual ones like ax = by.
With an example from the terminal:
>>> ax,ay=(20,30)
>>> bx,by=(40,60)
>>> ax, ay = bx, by
>>> ax, ay
(40, 60)

Related

How can I improve my color change programm?

A few days ago I found a couple of dead pixels on my laptop screen. Googled how to remove them without going to the service center, but nothing helped. I decided to create a simple code myself to go through all possible colors in order to finally make a verdict on whether I should go to a service center or not.
I decided to write code in Python, because on I can quickly create an algorithm that would solve my problem, but I met with a problem in speed.
Walking through one color (blue in my case) takes about 1.64 seconds, then it takes about 29 hours to walk through all the colors, which is quite a long time. Is there any way to speed up the process? Or should I choose some other method?
import pygame
WIDTH = 200
HEIGHT = 200
FPS = 144
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
running = True
r = 0
g = 0
b = 0
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
b += 1
if b % 256 == 0:
b = 0
g += 1
if g % 256 == 0:
g = 0
r += 1
if r % 256 == 0:
break
screen.fill((r, g, b))
pygame.display.flip()
Here's your script modified to randomly cycle through RGB on/off permutations:
import pygame
import random
WIDTH = 200
HEIGHT = 200
FPS = 144
# permutations of on/off for R, G & B
colours = ((0, 0, 0),
(255, 0, 0),
(0, 255, 0),
(0, 0, 255),
(255, 255, 0),
(0, 255, 255),
(255, 0, 255),
(255, 255, 255))
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# testing out the walrus operator
while (colour := random.choice(colours)) == screen.get_at((0, 0))[:3]:
# print(f"dupe: {colour} {screen.get_at((0,0))}")
pass
# colour = random.choice(colours)) # no dupe check
screen.fill(colour)
# print(colour)
pygame.display.flip()
clock.tick(FPS)
The duplicate colour prevention is a little ugly but I was testing out an assignment expression.
Enable the print statements to confirm that you're not getting duplicate colours although it probably doesn't matter. You can get rid of the duplicate check and uncomment the original colour assignment if you don't like the :=.

How to get mouse coordinates on a grid [duplicate]

This question already has answers here:
Is it possible to update a pygame drawing attribute when a event occurs?
(1 answer)
Python: How to make drawn elements snap to grid in pygame
(1 answer)
Closed 5 months ago.
I have a function to get a position on a grid (the size of the grid is flexible) based on the mouse position
def get_coords_from_mouse_pos(self, mx, my):
return mx // self.item_width, my // self.item_height
self.item_width and self.item_height are the width and height of one tile on the grid. mx and my are the mouse x and y positions. This probably exists somewhere else but I can't find it.
I probably just have the math wrong, but I would appreciate it if someone could help.
Here's a minimal example that shows your logic working, the left and top grid borders are considered as part of the cell below.
import pygame
# Configuration
width, height = 320, 240
cell_width, cell_height = 32, 32
pygame.init()
sys_font = pygame.font.SysFont(None, 60)
text = sys_font.render(" ", True, "turquoise")
clock = pygame.time.Clock()
screen = pygame.display.set_mode((width, height))
# create transparent background grid
grid = pygame.Surface((width, height), flags=pygame.SRCALPHA)
for y in range(0, height, cell_height):
pygame.draw.aaline(grid, "green", (0, y), (width, y)) # horizontal lines
for x in range(0, width, cell_width):
pygame.draw.aaline(grid, "green", (x, 0), (x, height)) # vertical lines
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
mx, my = pygame.mouse.get_pos()
pygame.display.set_caption(f"Mouse: {mx}, {my}")
if mx > 0 and my > 0:
cellx = mx // cell_width
celly = my // cell_height
text = sys_font.render(f"Cell: {cellx}, {celly}", True, "turquoise")
# Graphics
screen.fill("grey25")
screen.blit(grid, (0, 0))
# Draw Text in the center
screen.blit(text, text.get_rect(center=screen.get_rect().center))
# Update Screen
pygame.display.update()
clock.tick(30)
pygame.quit()
This will look something like this:

Modify alpha of Surface pixels directly in pygame

I have a Surface in PyGame. I want to modify the alpha values of pixels directly. I've tried doing it with the various methods that access the alpha values, but they don't seem to work.
from screeninfo import get_monitors
import pygame, os, numpy.random, pygame.surfarray
pygame.init()
FPS = 60
CLOCK = pygame.time.Clock()
monitor_info = get_monitors()
x = 0
y = 0
width = monitor_info[0].width
height = monitor_info[0].height
if len(monitor_info) > 1:
if monitor_info[0].x < 0:
x = 0
else:
x = monitor_info[0].width
width = monitor_info[1].width
height = monitor_info[1].height
os.environ['SDL_VIDEO_WINDOW_POS'] = "{},0".format(x)
pygame.display.init()
pygame.mouse.set_visible(False)
screen_info = pygame.display.Info()
screen_size = width, height
base_screen = pygame.display.set_mode(screen_size, pygame.NOFRAME)
base_screen.fill([100, 100, 100])
board_size = (int(min(width, height)*0.75), int(min(width, height)*0.75))
surface = pygame.Surface(board_size, pygame.SRCALPHA)
surface.fill([255, 255, 255, 255])
base_screen.blit(surface, (0,0))
pygame.display.flip()
pixels = numpy.random.uniform(low=0, high=255, size=(board_size[0], board_size[1], 3))
transparency = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
while True:
events = pygame.event.get()
ms = CLOCK.tick(FPS)
print('\r {} '.format(ms), end='')
# pygame.surfarray.blit_array(surface, pixels)
aa = pygame.surfarray.pixels_alpha(surface)
aa = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
del aa
# for i in range(board_size[0]):
# for j in range(board_size[1]):
# a = surface.get_at((i,j))
# a[3] = 0
# surface.set_at((i,j), a)
base_screen.blit(surface, (0,0))
pygame.display.flip()
I've tried both things in the loop (pixels_array, and get_at/set_at) but neither works--the image just stays white (if I set the initial alpha to 0, it stays transparent). Does anyone know how to set per-pixel alpha values for a Surface?
I found your problem!! The reason why you can't see alpha is:
a) you first set surface alpha to 255, surface.fill([255, 255, 255, 255])
b) I believe aa = pygame.surfarray.pixels_alpha(surface) aa = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8') aren't working, however pygame.surfarray.blit_array(surface, pixels) do work (produce colours) but I don't think they have any actual Alpha.
c) you need to fill the base_screen and THEN blit you surface. Such a common mistake but this is the main the problem.
And finally, Tim Robert's comment about the for loop, will definitely get you your alpha!
Here is it re-written to work (without screeninfo as I don't have that library currently):
import pygame, os, numpy.random, pygame.surfarray
from random import randint
pygame.init()
FPS = 60
CLOCK = pygame.time.Clock()
x = 50
y = 50
width = 500
height = 500
os.environ['SDL_VIDEO_WINDOW_POS'] = "{},0".format(x)
#pygame.display.init(), don't actually need this
pygame.mouse.set_visible(False)
screen_info = pygame.display.Info()
screen_size = width, height
base_screen = pygame.display.set_mode(screen_size, pygame.NOFRAME)
base_screen.fill([100, 100, 100])
board_size = (int(min(width, height)*0.75), int(min(width, height)*0.75))
surface = pygame.Surface(board_size, pygame.SRCALPHA)
surface.fill([255, 0, 0]) ###could also be surface.fill([255,0,0,255]) to set the whole surface's alpha straight up if you didn't want to change each pixel later
while True:
#just so you can quit this program
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
raise SystemExit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
pygame.quit()
raise SystemExit()
ms = CLOCK.tick(FPS)
for i in range(board_size[0]):
for j in range(board_size[1]):
a = surface.get_at((i,j))
a[3] = randint(0, 128)#OR SET TO REQUIRED ALPHA VALUE
surface.set_at((i,j), a)
##################################################
base_screen.fill([100, 100, 100]) #NEED TO DO THIS
##################################################
base_screen.blit(surface, (0,0))
pygame.display.flip()
(by the way, I used red as the second surface colour as I thought it would stand out better)
Edit
As Eternal Ambiguity stated in the comments, here is the much, much faster version, in place of the for loops:
aa = pygame.surfarray.pixels_alpha(surface)
aa[:] = numpy.random.uniform(low=0, high=255, size=board_size).astype('uint8')
del aa
pygame.Surface.blit() does not replace the pixels in the target surface with the source surface. It mixes (blends) the pixels of the surfaces. Actually you are blending the new surface with the old previous surface every frame. This means that the area of the surface appears uniformly colored within milliseconds. You have to clear the screen in every frame:
while True:
# [...]
base_screen.fill((0, 0, 0))
base_screen.blit(surface, (0,0))
pygame.display.flip()
Minimal example:
import pygame
pygame.init()
width, height = 200, 200
base_screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
board_size = (int(min(width, height)*0.75), int(min(width, height)*0.75))
surface = pygame.Surface(board_size, pygame.SRCALPHA)
surface.fill([255, 0, 0])
for x in range(board_size[0]):
for y in range(board_size[1]):
a = surface.get_at((x, y))
a[3] = round(y / board_size[1] * 255)
surface.set_at((x, y), a)
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
base_screen.fill((100, 100, 100))
base_screen.blit(surface, surface.get_rect(center = base_screen.get_rect().center))
pygame.display.flip()

Python PyMunk acts weirdly

here is the problem :
My pymunk code is from https://pymunk-tutorial.readthedocs.io/en/latest/shape/shape.html
But when i launch the program, a weird force acts on the segment.
See the result : https://youtu.be/s4a0RLb6Y6k
See the code : (without useless part about dependencies)
import pymunk
import pymunk.pygame_util
import pygame
from pygame.locals import *
pygame.init()
width, height = 1280, 720
window = pygame.display.set_mode((width, height), FULLSCREEN)
draw_options = pymunk.pygame_util.DrawOptions(window)
window.fill((0,0,0))
run = True
space = pymunk.Space()
space.gravity = 0, -1000
b0 = space.static_body
sol = pymunk.Segment(b0, (0, 30), (width, 30), 10)
sol.elasticity = 1
body = pymunk.Body(mass=1, moment=1000)
body.position = (width/2, 50)
segment = pymunk.Segment(body, (width/2-20,50), (width/2+20,50), 1)
segment.elasticity = 0.95
space.add(sol, body, segment)
while run == True:
space.step(0.01)
window.fill((0,0,0))
pygame.draw.line(window, (0, 255, 0), (0, height-30), (width, height-30), 1)
space.debug_draw(draw_options)
pygame.display.flip()
pygame.time.Clock().tick(60)
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
run = False
if event.type == QUIT:
run = False
mouse_x, mouse_y = pygame.mouse.get_pos()
pass
continue
I don't see where is the problem..
Thanks by advance
One common reason why strange behavior like that in the video happens is because center of gravity of the shape is not in the actual center. Try changing so that you make the Segment around the its center (0,0), where the body is.
Something like this maybe
segment = pymunk.Segment(body, (-20,0), (20,0), 1)
If you want to move it you can adjust the position of the body instead.
So the a an b values are relative from the center of mass of the body precited.
(with a and b from shape = pymunk.Segment(body, a, b, thickness) )
Thanks very much !

How do I increase the size of a rectangle if a key is pressed?

Using pygame, I'm trying to create a simple mechanic which will increase a rectangle in the top right of my code, in this case it is a health bar. For now I want to make the bar increase everytime the button 'x' is clicked. Here is my code:
DISPLAYSURF = DISPLAYSURF = pygame.display.set_mode((900, 550), 0, 32)
heatBar = [45, 30]
hbPosition = [45, 30]
# Main game loop
while True:
heatBar.insert(0, list(hbPosition))
for event in pygame.event.get():
#Heat Bar (Tap x to increase)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_x:
for pos in heatBar:
pygame.draw.rect(DISPLAYSURF, GREEN,
pygame.Rect(pos[0],pos[1],10,50))
The pygame.Rect on the last line is part of the line previous to it.
Anyway, I've tried to add various things and comment out things but I just can't seem to get it to work. Any idea on what I'm doing wrong or how to fix it?
Here's an example of a health bar:
import pygame
pygame.init()
w, h = 400, 400
screen = pygame.display.set_mode((w, h))
health = 0
while True:
screen.fill((0, 0, 0))
if pygame.event.poll().type == pygame.QUIT: pygame.quit(); break
keys = pygame.key.get_pressed()
if keys[pygame.K_x]:
health += 0.1
pygame.draw.rect(screen,
(100, 240, 100),
pygame.Rect(0, 0, health, 35
))
pygame.display.flip()
EDIT(added extra features):
import pygame
pygame.init()
w, h = 400, 400
screen = pygame.display.set_mode((w, h))
# I decided to go for a maxhealth type thing here,
health = 100
while True:
screen.fill((0, 0, 0))
# VVV This line polls pygames events and checks if it a QUIT event,
if pygame.event.poll().type == pygame.QUIT: pygame.quit(); break
# This relies on the previous line being called, or else it won't update,
keys = pygame.key.get_pressed()
# I added `Z` for adding to the health too,
if keys[pygame.K_x] and health > 0:
health -= 0.1
if keys[pygame.K_z] and health < 100:
health += 0.1
# The tint value is multiplied by 2.55 to map 0-100 to 0-255. Try it yourself(algebra): 255/100 = 2.55,
tint = 255 - (health * 2.55)
pygame.draw.rect(screen,
(tint, 255 - tint, 0),
pygame.Rect(0, 0, health, 35
))
pygame.display.flip()
Unfortunently because of how tint works, the middle range looks like a ugly brownish colour.
Also I would highly recommend you make your game with classes, they are much more uniform, and they are great for making large scale projects.
Here's a nice link: https://www.youtube.com/watch?v=ZDa-Z5JzLYM
EDIT(fixing brownish colour):
To fix the brownish colour, change this line:
pygame.draw.rect(screen,
(tint, 255 - tint, 0),
pygame.Rect(0, 0, health, 35
))
To,
pygame.draw.rect(screen,
(min(255, tint * 2), min(255, 335 - tint), 0),
pygame.Rect(0, 0, health, 35
))
NOTE: Using min(255, ...) will effectively make sure that the value does not exceed 255, because as long as the number is less than 255 it will return the number, otherwise it will return 255. Multiplying the tint by two is basically offsetting it, and the 335 - tint is to offset the other one too, you can change 335 to another number to change where the yellow is in the health bar :)

Categories