This is different to the other questions as it uses another method. I have the following code and need to change it so that it produces a grid (all rows and columns filled in) as per Figure 16.7 on this link: http://programarcadegames.com/index.php?chapter=array_backed_grids
The following code produces a full row and a full column, but I can't quite work out how to extend it to fill the whole screen with rectangles with the appropriate margin built in.
Code:
"""
Create a grid with rows and colums
"""
import pygame
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
pygame.init()
# Set the width and height of the screen [width, height]
size = (255, 255)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
width=20
height=20
margin=5
# -------- Main Program Loop -----------
while not done:
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# --- Game logic should go here
# --- Screen-clearing code goes here
# Here, we clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
# If you want a background image, replace this clear with blit'ing the
# background image.
screen.fill(BLACK)
# --- Drawing code should go here
#for column (that is along the x axis) in range (0 = starting position, 100=number to go up to, width+margin =step by (increment by this number)
#adding the 255 makes it fill the entire row, as 255 is the size of the screen (both ways)
for column in range(0+margin,255,width+margin):
pygame.draw.rect(screen,WHITE, [column,0+margin,width,height])
for row in range(0+margin,255,width+margin):
pygame.draw.rect(screen,WHITE,[0+margin,row,width,height])
#This simply draws a white rectangle to position (column)0,(row)0 and of size width(20), height(20) to the screen
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(60)
# Close the window and quit.
pygame.quit()
The problem lies in the inner loop (for row in...),
where the rect is drawn with:
pygame.draw.rect(screen,WHITE,[0+margin,row,width,height])
Note that the x coordinate always is 0+margin,
no matter which column is currently drawn. So
the code draws 10 columns on top of each other.
As a simple fix, change the line to:
pygame.draw.rect(screen,WHITE,[column,row,width,height])
You might then notice that the other call of the draw method in the outer loop is completely unnecessary. After all, the inner call now draws a rectangle for each row in each column. So you can reduce the loop code to:
for column in range(0+margin, 255, width+margin):
for row in range(0+margin, 255, height+margin):
pygame.draw.rect(screen, WHITE, [column,row,width,height])
Related
I am trying to make a game where if someone press left-click, pygame draws a circle, then a line connecting the circle to the upper left corner. If he/she press right-click, it removes everything created from the screen. I thought about just covering everything with a big black square, but that is not really clearing the screen, just covering it. My code is as follow:
from pygame import *
init()
size = width, height = 650, 650
screen = display.set_mode(size)
button = 0
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
def drawScene(screen, button):
# Draw circle if the left mouse button is down.
if button==1:
draw.circle(screen,GREEN,(mx,my), 10)
draw.line(screen,GREEN, (0,0),(mx,my))
if button == 3:
mouse.set_visible(False)
display.flip()
running = True
myClock = time.Clock()
# Game Loop
while running:
for e in event.get(): # checks all events that happen
if e.type == QUIT:
running = False
if e.type == MOUSEBUTTONDOWN:
mx, my = e.pos
button = e.button
drawScene(screen, button)
myClock.tick(60) # waits long enough to have 60 fps
quit()
Kindly guide me in this situation. Thanks in advance.
I thought about just covering everything with a big black square, but that is not really clearing the screen, just covering it.
There is not any difference between cover and clear. The screen consist of pixels. Drawing an object just changes the color of the pixels. Drawing a black square changes the color of the pixel again.
Note, operations like pygame.draw.circle() and pygame.draw.line() do not create any object. They just change the colors of some pixels of the surface which is passed to the operation.
The easiest way to clear the entire window is pygame.Surface.fill():
screen.fill((0, 0, 0))
respectively
screen.fill(BLACK)
In computer graphics, there is no such thing as "clearing" a screen. you can only overwrite the previous drawing with new pixels. your idea of drawing a big black rectangle would work perfectly but I may be more efficient to use screen.fill(0)
In a pygame project I'm working on, sprites of characters and objects cast a shadow onto the terrain. Both the shadow and the terrain are normal pygame surfaces so, to show them, the shadow is blitted onto the terrain. When there's no other shadow (only one shadow and the terrain) everything works fine, but when the character walks into the area of a shadow, while casting its own shadow, both shadows combine their alpha values, obscuring the terrain even more.
What I want is to avoid this behaviour, keeping the alpha value stable. Is there any way to do it?
EDIT: This is an image, that I made in Photoshop, to show the issue
EDIT2: #sloth's answer is ok, but I neglected to comment that my project is more complicated than that. The shadows are not whole squares, but more akin to “stencils”. Like real shadows, they are silhouettes of the objects they are cast from, and therefore they need per pixel alphas which are not compatible with colorkey and whole alpha values.
Here is a YouTube video that shows the issue a bit more clearly.
An easy way to solve this is to blit your shadows on another Surface first which has an alpha value, but no per pixel alpha. Then blit that Surface to your screen instead.
Here's a simple example showing the result:
from pygame import *
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
# we create two "shadow" surfaces, a.k.a. black with alpha channel set to something
# we use these to illustrate the problem
shadow = pygame.Surface((128, 128), pygame.SRCALPHA)
shadow.fill((0, 0, 0, 100))
shadow2 = shadow.copy()
# a helper surface we use later for the fixed shadows
shadow_surf = pygame.Surface((800, 600))
# we set a colorkey to easily make this surface transparent
colorkey_color = (2,3,4)
shadow_surf.set_colorkey(colorkey_color)
# the alpha value of our shadow
shadow_surf.set_alpha(100)
# just something to see the shadow effect
test_surface = pygame.Surface((800, 100))
test_surface.fill(pygame.Color('cyan'))
running = True
while running:
for e in pygame.event.get():
if e.type == pygame.QUIT:
running = False
screen.fill(pygame.Color('white'))
screen.blit(test_surface, (0, 150))
# first we blit the alpha channel shadows directly to the screen
screen.blit(shadow, (100, 100))
screen.blit(shadow2, (164, 164))
# here we draw the shadows to the helper surface first
# since the helper surface has no per-pixel alpha, the shadows
# will be fully black, but the alpha value for the full Surface image
# is set to 100, so we still have transparent shadows
shadow_surf.fill(colorkey_color)
shadow_surf.blit(shadow, (100, 100))
shadow_surf.blit(shadow2, (164, 164))
screen.blit(shadow_surf, (400, 0))
pygame.display.update()
You could create a function that tests for shadow collision and adjust the blend values of the shadows accordingly.
You can combine per-pixel alpha shadows by blitting them onto a helper surface and then fill this surface with a transparent white and pass the pygame.BLEND_RGBA_MIN flag as the special_flags argument. The alpha value of the fill color should be equal or lower than the alphas of the shadows. Passing the pygame.BLEND_RGBA_MIN flag means that for each pixel the lower value of each color channel will be taken, so it will reduce the increased alpha of the overlapping shadows to the fill color alpha.
import pygame as pg
pg.init()
screen = pg.display.set_mode((800, 600))
clock = pg.time.Clock()
shadow = pg.image.load('shadow.png').convert_alpha()
# Shadows will be blitted onto this surface.
shadow_surf = pg.Surface((800, 600), pg.SRCALPHA)
running = True
while running:
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
screen.fill((130, 130, 130))
screen.blit(shadow, (100, 100))
screen.blit(shadow, (154, 154))
shadow_surf.fill((0, 0, 0, 0)) # Clear the shadow_surf each frame.
shadow_surf.blit(shadow, (100, 100))
shadow_surf.blit(shadow, (154, 154))
# Now adjust the alpha values of each pixel by filling the `shadow_surf` with a
# transparent white and passing the pygame.BLEND_RGBA_MIN flag. This will take
# the lower value of each channel, therefore the alpha should be lower than
# the shadow alphas.
shadow_surf.fill((255, 255, 255, 120), special_flags=pg.BLEND_RGBA_MIN)
# Finally, blit the shadow_surf onto the screen.
screen.blit(shadow_surf, (300, 0))
pg.display.update()
clock.tick(60)
Here's the shadow.png.
Im trying to make a rectangle bounce, without going off limits.
I want my rectangle to bounce depending on the wall it touched.
In this code im trying to bounce the rectangle in a 90º angle, but it isn't working.
Im using this to calculate each advance:
rect_x += rectxSpeed
rect_y += rectySpeed
When it reachs the limit
if rect_y>450 or rect_y<0:
rectySpeed=5
rect_y=rectySpeed*-(math.pi/2)
if rect_x>650 or rect_x<0:
rectxSpeed=5
rectx_y=rectxSpeed*-(math.pi/2)
Whole code here:
import pygame
import random
import math
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
rect_x= 50.0
rect_y = 50.0
rectxSpeed=5
rectySpeed=5
pygame.init()
# Set the width and height of the screen [width, height]
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# --- Game logic should go here
# --- Screen-clearing code goes here
# Here, we clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
# If you want a background image, replace this clear with blit'ing the
# background image.
screen.fill(BLACK)
string=str(rect_x)
string2=str(rect_y)
string3="["+string+"]"+"["+string2+"]"
font = pygame.font.SysFont('Calibri', 25, True, False)
text = font.render(string3,True,RED)
screen.blit(text, [0, 0])
#Main rectangle
pygame.draw.rect(screen, WHITE, [rect_x, rect_y, 50, 50])
#Second rectangle inside the rectangle 1
pygame.draw.rect(screen, RED, [rect_x+10, rect_y+10, 30, 30])
rect_x += rectxSpeed
rect_y+=rectySpeed
if rect_y>450 or rect_y<0:
rectySpeed=5
rect_y=rectySpeed*-(math.pi/2)
if rect_x>650 or rect_x<0:
rectxSpeed=5
rect_x=rectxSpeed*-(math.pi/2)
# --- Drawing code should go here
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(20)
# Close the window and quit.
pygame.quit()
¿How can i adjust the advance?
This code produce this:
By Changing the reach limit code with:
if rect_y>450 or rect_y<0:
rectySpeed=rectySpeed*-(math.pi/2)
if rect_x>650 or rect_x<0:
rectxSpeed=rectxSpeed*-(math.pi/2)
Produces this:
I think it's important to recognize here that the speed of the rectangle object here is a scalar value, not it's vector counterpart velocity. You are attempting to multiply the rectySpeed (a scalar value) by -(math/pi)/2, which is a value that will be returned in radians as #0x5453 mentioned. As far as the rectangle bouncing differently depending on the wall that it contacted, you have not specified the differing constraints that you intend to impose. I think you may want to consider why you want the rectangle to always bounce at a 90° angle. Note that a rectangle that always bounces at a 90° angle would yield some very odd functionality to the player/user.
The angle that the rectangle is approaching the wall measured from the horizontal will be equal to the angle that the rectangle will rebound off the wall measured from the vertical line of the wall to it's new path (in the case of an x-directional bounce).
In terms of an accurate physics engine, you may want to consider just simplifying your mechanics to the following in the case that the rectangle contacts a wall:
if rect_y>450 or rect_y<0:
rectySpeed=rectySpeed*-1
if rect_x>650 or rect_x<0:
rectxSpeed=rectxSpeed*-1
The above ensures that the rectangle object simply changes direction, therefore the magnitude of the rectangle's speed does not change, however the velocity indeed does since it is a vector quantity.
I have the general outline code. But i need a background which can change color once you run the program at an reasonable speed between the colors red, green, blue, black and white. I know it has to do with the while loop, i just do not know how to incorporate it.
from __future__ import division
import pygame
pygame.init()
width = 640
height = 480
size = (width, height)
screen = pygame.display.set_mode(size)
background = (0,0,0)
fps = 60
clock = pygame.time.Clock()
while True:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
screen.blit(background)
pygame.display.flip()
clock.tick(1)
If you already know that colors are composite of red, green and blue that will help you already, those are called color channels and change between 0 and 255. I would first take a paper and draw how would change each of the channels with time. So you'll have 3 functions on the same time scale. Then I would brake the time axis in sections, where the functions are linear (or some other standard function), and define the function depending on in which section I am now. I gave just a general approach, since it's quite a big amount of job to do.
Another approach is to set up the table will the sequence of all colors that are to be shown and just cycle through them in a loop and filling the display.
quite new here and to programming in general I suppose, deciding to ask other people for help.
import sys,os
import pygame
black = ( 0, 0, 0)
white = ( 255, 255, 255)
green = ( 0, 255, 0)
red = ( 255, 0, 0)
blue = ( 0, 0, 255 )
pygame.init()
# Set the width and height of the screen [width,height]
size=[700,500]
screen=pygame.display.set_mode(size)
pygame.display.set_caption("DN[A]")
#Loop until the user clicks the close button.
done=False
# Used to manage how fast the screen updates
clock=pygame.time.Clock()
FPS=60
#Loading images below.
n=1
z=1
maxint=10
minint=-maxint
# -------- Main Program Loop -----------
while done==False:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT:
done=True
# above this, or they will be erased with this command.
screen.fill(black)
x,y=pygame.mouse.get_pos()
for i in range(size[1]):
screen.set_at((x,y),blue)
x+=1
y+=n
n+=z
if n==maxint or n==minint:
z=-z
pygame.display.flip()
clock.tick(FPS)
pygame.quit ()
So basically if maxint is 10 it gets a reflection. What I'm aiming for is the result when maxint is 5. Anyone knows why it does that?
Also when it's 6 or any other number it gets even stranger.
The reason why you see two sines, is because of our vision. We only see an image every few ms, so we see both sines, instead of them alternating.
When you have 10 as your maxint will end with a negative z, so the next time we draw we will draw the bottom half. You can fix this by putting n and z inside the while loop.
Also, its nicer to use not done instead of done==False.