I am just getting started with Pygame, and I did a little test of just printing pixels in random spots. However, I noticed that the pixels don't seem to be single pixels at all, but 'fuzzy' blobs of a few pixels, as shown in the image. Here's the code I used to draw the pixels:
Is there any way to just display single pixels?
Edit: Here's the whole code I used:
import pygame.gfxdraw
import pygame
import random
width = 1000
height = 1000
screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
running = True
while running:
x = random.randint(0,1000)
y = random.randint(0,1000)
pygame.gfxdraw.pixel(screen, x, y, (225,225,225))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.flip()
clock.tick(240)
more fuzzy pixels
pygame.gfxdraw.pixel(surface, x, y, color) will draw a single pixel on the given surface.
Also you will need to add import pygame.gfxdraw.
EDIT: Full code:
import pygame.gfxdraw
import pygame
import random
width = 1680
height = 1050
screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
running = True
x = [i for i in range(width - 10)]
x_full = [i for i in range(width)]
y = 100
y_full = [i for i in range(height // 2)]
while running:
for i in x:
for j in y_full:
pygame.gfxdraw.pixel(screen, i, j, pygame.Color("red"))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.flip()
clock.tick(1)
Try to test it this way, I set the window size to fit my monitor resolution so it goes fullscreen. x_full and y should give you horizontal line. And if you subtract, for example, 10 you will get slightly shorter line, and vice-versa with y_full and some random x. Also using (width//2, height//2) will cover exactly quarter of the screen. I think it is accurate and that pygame.gfxdraw.pixel(screen, i, j, pygame.Color("red")) displays only single pixel as it should.
In your code you are using random to display pixels and it adds them 240 per second so you are very fast ending up with bunch of pixels at random positions resulting to have pixels close to each other looking as a "bigger one". I think this is what was happening here. Please someone correct me if I am wrong.
Also make small window e.g. (100, 100) and draw one pixel at (50, 50) this way it can be more easily seen. If you are on windows use magnifier to test it.
IMPORTANT:
While testing this with huge number of pixels do it OUTSIDE of the loop because it will consume much processor power to display them.
Hope this answers your question
Related
I just started playing around with python a bit and tried to do some silly grafix stuff to see how it worked. Now I got stuck with one precise problem: I am trying to read the color value of a pixel from a pygame surface - but I can't. The below code - which I found in several (perhaps outdated) manuals and samples - throws an error I don't understand:
(Line 38 is the one containing the "screen.get_at()" part)
File "/home/mark/devel/python/./test.py", line 38, in
color = screen.get_at((x, y))
TypeError: 'list' object cannot be interpreted as an integer
What I guess from the stuff I found online: pygame.surface changed the type of the return value for get_at() a short while ago. Now it doesn't return four integers for R, G, B and alpha. but it returns a type "color". However, I was unable to find an explanation what this type "color" actually is or how it works, resp. how I get just the RGB values out of it.
A shortened sample of my code which throws the above error is as follows:
#!/usr/bin/python3
import pygame
from pygame.locals import *
import numpy as np
WIDTH = 1200
HEIGHT = 800
WHITE = (255, 255, 255)
pygame.init()
# Set width and height of the screen
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("Ant")
pygame.draw.rect(screen, WHITE, (0,0,WIDTH,HEIGHT))
pos = ([0],[0])
# Loop until the user clicks the close button.
done = False
clock = pygame.time.Clock()
# Loop as long as done == False
while not done:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: # If user wants to exit
done = True # Flag that we are done so we exit this loop
x = pos[0] # horizontal position
y = pos[1] # vertical position
color = screen.get_at((x, y))
print (color)
pygame.display.flip()
# This limits the while loop to a max of 60 times per second.
# Leave this out and we will use all CPU we can.
clock.tick(600)
# Be IDLE friendly
pygame.quit()
I'd really appreciate if someone could give me a hint how to get the RGB (integer) values from this "color" type get_at() returns.
thx,
Mark
I'm trying to make a visualisation for various sorting algorithms and I was playing around with Pygame to try and draw the rectangles that I need.
In the below code, the user is given multiples inputs: the lowest value of the list to be sorted, the highest value, and the number of elements the list is going to have. The elements are going to be randomly generated.
Then I'm getting the user's screen size so that I can have an appropriate window for the visualisation. Based on the visualisation window and the user's input, I'm setting up the width and height of the rectangles, so that each rectangle has the same width and that they are scaled based on the highest value.
Almost everything is nice and fine with this approach, but there's one thing that I can't figure out. It seems that setting the number of elements (n, in the code below) too high, the rectangles are not being drawn.
My asumption is that after a specific threshold, RECT_W, which is the width of the rectangles, becomes to small for Pygame to draw it.
What options do I have to solve it, except of having the number of elements smaller than a specific value?
import random
import pygame
import color_constants as colors
import ctypes
import copy
from pygame.locals import *
# Read data based on user's input
def readData():
listOfNumbers = []
data = dict()
print("Lowest Value: ")
numLow = int(input())
print("Highest Value: ")
numHigh = int(input())
print("Length of list: ")
n = int(input())
for i in range(0, n):
listOfNumbers.append(random.randint(numLow, numHigh))
origLst = copy.copy(listOfNumbers)
data.update({'lst': origLst})
data.update({'numLow': numLow})
data.update({'numHigh': numHigh})
data.update({'n': n})
data.update({'sorted': listOfNumbers})
return data
if __name__ == "__main__":
data = readData()
# Getting the user's screen size
user32 = ctypes.windll.user32
SCREENSIZE = user32.GetSystemMetrics(0)-100, user32.GetSystemMetrics(1)-100
SCREEN_W = SCREENSIZE[0]
SCREEN_H = SCREENSIZE[1]
# Setting and scaling the size of rectangle based on the number of elements (n)
# and the highest number (numHigh)
RECT_W = SCREEN_W // data['n']
RECT_H = SCREEN_H / (data['numHigh'])
# Setting up the color literals
RED = (255, 255, 255)
GRAY = (0, 0, 0)
pygame.init()
screen = pygame.display.set_mode(SCREENSIZE)
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
screen.fill(GRAY)
for i in range(data['n']):
rect = Rect(i*RECT_W, 0, RECT_W, RECT_H * data['lst'][i])
rect.bottom = SCREEN_H
pygame.draw.rect(screen, RED, rect)
pygame.display.flip()
If data['n'] is greater than SCREEN_W, RECT_W is 0. A coordinate is truncated when drawing. You cannot draw a fraction of a pixel. The size of the rectangle can only be integral (0, 1, 2 ...). Hence, you cannot draw a rectangle with a size less than 1.
You can draw the rectangles on a large surface and scale down the surface. However, the rectangles get blurred. So, this is no good option.
I'm new one in coding, so I expect that this is easy one, but I still can't figure this out.
So I'm trying to make a program that animates a diagram, but the problem is when am making animation with equation (0,0) obviously in upper left corner.
I need to make a grid that will represent this, so I cant input my equation and get right animation depends on this grid's numbers Grid here
UPD:
Sorry for being less specific than I should.
The goal is to make a program that animates HR diagram, outputs luminosity and temperature after you inputs solar mass.
I didn't input equation so far because I'm trying to figure out how pygame animation works.
What I got so far trying to animate diagonal line:
import pygame
from pygame.locals import *
pygame.init()
width = 600
height = 600
screen = pygame.display.set_mode((width, height))
background = pygame.image.load("background.png")
point = pygame.image.load("point.png")
clock = pygame.time.Clock()
speed = 100
x = 0
y = 0
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
quit()
screen.blit(background, (0,0))
screen.blit(point, (x,y),)
milli = clock.tick()
second = milli/1000.
dm=second * speed
x += dm
y = x
print (x, y)
if x > 600 or y > 600:
x = 0
y = 0
pygame.display.update()
So I need to make axis like in diagram, so I can just type down the equation and make correct animation and correct outputs
Use a 2 dimensional array to represent a grid structure in python.
w, h = 10000, 50000;
grid = [[0 for x in range(w)] for y in range(h)]
Im currently using the random import to create five random x, y values and taking those values and drawing a polygon with the pygame.draw.polygon () command. If I had a texture square I wanted to apply over top of that shape instead of having just on rgb value what would be the most efficient way to do that? i want to take the generated polygon below and with out hard coding its shape, taking a general texture square and making all that green that new texture as if that shape was cut out of the texture square.
import pygame,random
from pygame import*
height = 480
width = 640
#colors
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
white = (255,255,255)
black = (0,0,0)
pygame.init()
points = [ ]
screen = pygame.display.set_mode((width,height))
pygame.display.set_caption("PlayBox")
r = random
for i in range(0,5):
x = r.randrange(0,640)
y = r.randrange(0,480)
points.append([x,y])
running = True
while running == True:
screen.fill(white)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
break
pygame.draw.polygon(screen,green,points,0)
pygame.display.update()
pygame.display.update()
One option, of course, would be to re-implement the "bucket fill" algorithm yourself,
and copy pixels inside the polygon. That would be a lot of work, and wouldget slow done in pure Python - still, it would launch you into the basic foundations of image manipulation http://en.wikipedia.org/wiki/Flood_fill
Since Pygame already does the heavy lifting, but provides just solid color fills,
the way to go is to use pygame's results as a clipping mask to your texture. Unfortunatelly that is probably more difficult than it should. I hope my sample here
can be useful for others having the same needs.
Pygame gives us some primitives to manipulate the color planes in the surfaces,
but they are definitely low level. Another thing is that these primitives require
numpy to be installed - I am not certain if Window's pyagames installer include it -
otherwise people running your project have to be told to install numpy themselves.
So, teh way to go is:
Load your desired texture in a surface (for less headache, one of the same size
of the final image), to draw the shape you want to be painted with the texture
in a mask surface, with 8bpp (B&W) - which works as a transparency map to the
texture -
them use pygame's surfarray utilities to blit everything together:
# coding: utf-8
import random
import pygame
SIZE = 800,600
def tile_texture(texture, size):
result = pygame.Surface(size, depth=32)
for x in range(0, size[0], texture.get_width()):
for y in range(0, size[1], texture.get_height()):
result.blit(texture,(x,y))
return result
def apply_alpha(texture, mask):
"""
Image should be a 24 or 32bit image,
mask should be an 8 bit image with the alpha
channel to be applied
"""
texture = texture.convert_alpha()
target = pygame.surfarray.pixels_alpha(texture)
target[:] = pygame.surfarray.array2d(mask)
# surfarray objets usually lock the Surface.
# it is a good idea to dispose of them explicitly
# as soon as the work is done.
del target
return texture
def stamp(image, texture, mask):
image.blit(apply_alpha(texture, mask), (0,0))
def main():
screen = pygame.display.set_mode(SIZE)
screen.fill((255,255,255))
texture = tile_texture(pygame.image.load("texture.png"), SIZE)
mask = pygame.Surface(SIZE, depth=8)
# Create sample mask:
pygame.draw.polygon(mask, 255,
[(random.randrange(SIZE[0]), random.randrange(SIZE[1]) )
for _ in range(5)] , 0)
stamp(screen, texture, mask)
pygame.display.flip()
while not any(pygame.key.get_pressed()):
pygame.event.pump()
pygame.time.delay(30)
if __name__ == "__main__":
pygame.init()
try:
main()
finally:
pygame.quit()
I've been going through some Python tutorials using Python 2.7 and Pygame and I decided to challenge myself. The tutorial showed how to make a ball move (right) across the screen, then pop back to the other (left) side of the screen at a specific speed. I wanted to make the ball bounce back and forth from left to right, so I wrote this:
bif = "bg.jpg"
mif = "ball1.png"
import pygame, sys
from pygame import *
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((816,460),0,32)
background = pygame.image.load(bif).convert()
ball = pygame.image.load(mif).convert_alpha()
x = 0
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
screen.blit(background, (0,0))
screen.blit(ball, (x, 160))
speed = 500
milli = clock.tick() #A tick is 1 millisecond
seconds = milli/1000.000000
dm = seconds * speed
if x == 0:
a = dm
elif x == 770:
a = -dm
x += a
pygame.display.update()
"bg.jpg" is a jpeg image that is 816 x 460 pixels and "bif.png" is a png image of a ball with a 50 pixel radius. Instead of moving back and forth at 500 pixels per second, the ball moves at a random speed to the right, then bounces off of the right side of the screen at a random speed to the left, and repeats this a random number of times. Then the ball keeps going in one direction and doesn't come back. I can't figure out why it's doing this. It behaves differently every time I run it. If anybody can figure out why, I'd be really thankful.
tick(), without arguments returns time which passed since last call. In your use it depends on rendering speed which will always be different that is why you get different speed each time.
Replace from speed = 500 to the end with:
speed = 1
if x == 0 or x == 770:
speed = -speed
x += speed
pygame.display.update()
clock.tick(60)