Is there a way to use for loops to make a game map in pygame? - python

So I want to make a gamemap in my pygame using for loops, but apparently the way I am doing it does not work. The code is below and if you can take a look at it, that would be nice!
Pygame
import pygame
import sys
import random
import subprocess
# _______initiate Game______________ #
class Game:
pygame.init()
width = 800
height = 800
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Maze Game")
pygame.draw.circle(screen, (0, 0, 255), (250, 250), 75)
white = [255, 255, 255]
black = [0, 0, 0]
lblue = [159, 210, 255]
background = input(
"What color background would you like? (White, Black, or Light Blue): ")
if background == "White":
screen.fill(white)
pygame.display.flip()
elif background == "Black":
screen.fill(black)
pygame.display.update()
elif background == "Light Blue":
screen.fill(lblue)
pygame.display.update()
else:
screen.fill(black)
pygame.display.update()
for "." in "map1.txt":
pygame.image.load("winter.Wall.png")
# ___________________TO RUN___________________________ #
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
command = "python JakeGame.py"
subprocess.call(command)
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.type == pygame.K_ESCAPE:
pygame.quit()
# _______________________________________________ #
pygame.quit()
This is the map txt file and the error I am getting
...1...........................................
...11111111111111..............................
1111............11111111111111.................
1............................111...............
111............................................
1..............................................
111111111111111111111111111....................
..................1............................
1111111111111111111............................
..................1............................
..................11111111.....................
..........111111111......111111111.............
.................................1.............
So basically, what I am trying to do is convert all those periods to be loaded with an image called winterWall.png .
The error I am getting is "can't assign literal" Thank you guys for helping :p

It's a bit more complicated than just what you propose (which is invalid syntax).
The code needs to open the file, then iterate over the rows and columns of map data. Then, for each type of letter it finds, render some kind of tile-based representation - here I've just used red and green blocks. An alternate version could just as easily render bitmaps.
The first thing you need to do is open the file and read the text into a list of strings - one for each line:
map_data = open( map_filename, "rt" ).readlines()
One caveat to this method, is that each line still has its end-of-line on the end. And it would be better to handle errors (like the file being missing), rather than crashing.
Then we create a Surface, which is just an off-screen image. It needs to be as big as the map is, times the size of the tiles. Since this is created inside the TileMap class, this gets stored in TileMap.image (i.e: self.image).
Next the code iterates through each line, and then each letter drawing a rectangle. The code just uses the constant TILE_SIZE for this. You need to decide if this is going to work with coloured squares, or bitmaps, etc. - but obviously all your tiles need to use the same size.
# iterate over the map data, drawing the tiles to the surface
x_cursor = 0 # tile position
y_cursor = 0
for map_line in map_data: # for each row of tiles
x_cursor = 0
for map_symbol in map_line: # for each tile in the row
tile_rect = pygame.Rect( x_cursor, y_cursor, TileMap.TILE_SIZE, TileMap.TILE_SIZE )
if ( map_symbol == '.' ):
pygame.draw.rect( self.image, RED, tile_rect )
elif ( map_symbol == '1' ):
pygame.draw.rect( self.image, GREEN, tile_rect )
else:
pass # ignore \n etc.
x_cursor += TileMap.TILE_SIZE
y_cursor += TileMap.TILE_SIZE
Note that we make an x_cursor and y_cursor. This is the top-left corner of the map-tile about to be drawn. As we step through each character, we update this to the next position on the map.
At each point, the map has a TILE_SIZE by TILE_SIZE (16x16) "cell" into which we draw a coloured square, depending on the type of map item.
At the end of the operation, we have loaded in all the map tiles, and draw the map to an off-screen Surface (self.image), which can be draw to the screen quickly and easily.
The TileMap class, simply wraps all this together.
Reference Code:
import pygame
WINDOW_WIDTH = 800
WINDOW_HEIGHT= 600
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
#define colours
BLACK = (0,0,0)
RED = ( 200, 0, 0 )
GREEN = (0,255,0)
### Class to render map-data to a surface image
class TileMap:
TILE_SIZE=16 # size of map elements
def __init__( self, map_filename ):
""" Load in the map data, generating a tiled-image """
map_data = open( map_filename, "rt" ).readlines() # Load in map data TODO: handle errors
map_width = len( map_data[0] ) - 1
map_length = len( map_data )
# Create an image to hold all the map tiles
self.image = pygame.Surface( ( map_width * TileMap.TILE_SIZE, map_length * TileMap.TILE_SIZE ) )
self.rect = self.image.get_rect()
# iterate over the map data, drawing the tiles to the surface
x_cursor = 0 # tile position
y_cursor = 0
for map_line in map_data: # for each row of tiles
x_cursor = 0
for map_symbol in map_line: # for each tile in the row
tile_rect = pygame.Rect( x_cursor, y_cursor, TileMap.TILE_SIZE, TileMap.TILE_SIZE )
if ( map_symbol == '.' ):
pygame.draw.rect( self.image, RED, tile_rect )
elif ( map_symbol == '1' ):
pygame.draw.rect( self.image, GREEN, tile_rect )
else:
pass # ignore \n etc.
x_cursor += TileMap.TILE_SIZE
y_cursor += TileMap.TILE_SIZE
def draw( self, surface, position=(0,0) ):
""" Draw the map onto the given surface """
self.rect.topleft = position
surface.blit( self.image, self.rect )
### initialisation
pygame.init()
pygame.mixer.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
pygame.display.set_caption("Render Tile Map")
### Load the map
tile_map = TileMap( "map1.txt" )
### Main Loop
clock = pygame.time.Clock()
done = False
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
# Update the window, but not more than 60fps
window.fill( BLACK )
# Draw the map to the window
tile_map.draw( window )
pygame.display.flip()
clock.tick_busy_loop(60)
pygame.quit()

Related

Mask acts as it if it was a solid box

How can I make a mask that's alpha pixels don't collide?
I've tried everything, following tutorials, viewing other stackoverthrow questions/answers, nothing works. PLEASE SPECIFY THE PROBLEM AND THE SOLUTION.
Here's my code:
level = pygame.image.load(r'data\test lvl.png').convert_alpha()
rect = level.get_rect(center = (400,400))
levelmask = pygame.mask.from_surface(image)
This mask is just a solid box, drawing it yields a solid box. Here's the collision between the level and the player.
offset = (X2, Y2)
collide = levelmask.overlap(self.rect_mask, offset)
print(offset)
print(collide)
if collide == None:
collide = -1
else:
collide = 0
return collide
And here's the code for the initialization of self.rect_mask.
self.rect_mask = pygame.mask.Mask((75, 160))
self.rect_mask.fill()
There seems to be nothing wrong with your code. I have incorporated elements of it into an example below.
So where could the issue be:
The "level" image has weird transparency (probably not, see comment above)
The levelmask used in the overlap() test is somehow different to the one created in the OP's example.
The offset is wrong somehow.
The 75 x 160 filled comparison mask is always too big to be "inside" the levelmask.
The example below uses the exact operations presented in the OP's example code. It works. A mask is created for the maze, where the non-wall parts are transparent. Another mask is created for the moving object (alien_*), also based on transparency.
Demo:
Code:
import pygame
# Window size
WINDOW_WIDTH = 612
WINDOW_HEIGHT = 612
FPS = 60
# background colours
INKY_BLACK = ( 0, 0, 0 )
FIREY_RED = ( 203, 49, 7 )
class Coordinate:
def __init__( self, x, y=None ):
if ( type(x) is tuple ):
self.x = x[0]
self.y = x[1] # Pygame.Rect corner
else:
self.x = x
self.y = y
### MAIN
pygame.init()
pygame.font.init()
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
pygame.display.set_caption("Mask Example")
# Make some bitmaps with masks for collision
maze_image = pygame.image.load( "square_maze_10x10.png" ).convert_alpha()
maze_rect = maze_image.get_rect()
maze_mask = pygame.mask.from_surface( maze_image )
alien_image = pygame.image.load( "green_guy.png" ).convert_alpha()
alien_rect = alien_image.get_rect()
alien_rect.topleft = ( 20, 20 )
alien_mask = pygame.mask.from_surface( alien_image )
clock = pygame.time.Clock()
done = False
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
# Handle continuous-keypresses
keys = pygame.key.get_pressed()
delta = Coordinate( 0,0 )
if ( keys[pygame.K_UP] ):
delta.y = -1
elif ( keys[pygame.K_DOWN] ):
delta.y = 1
elif ( keys[pygame.K_LEFT] ):
delta.x = -1
elif ( keys[pygame.K_RIGHT] ):
delta.x = 1
# move according to keys
alien_rect.x += delta.x
alien_rect.y += delta.y
# has the alien hit the walls use a Mask Check?
background = INKY_BLACK
if ( None != maze_mask.overlap( alien_mask, alien_rect.topleft ) ): # <<-- Mask check here
background = FIREY_RED
# Repaint the screen
window.fill( background )
window.blit( maze_image, maze_rect )
window.blit( alien_image, alien_rect )
pygame.display.flip()
clock.tick_busy_loop( FPS )
pygame.quit()
Resources:

Assigning Variables to newly added Sprites

I'm trying to let the user press and hold the right mouse button to make squares, then move them around with the mouse by left clicking. I was able to make a sprite that could be moved around with left click and to make new sprites when the user right clicks:
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
elif event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
quit()
elif event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
if x <= m_x <= x + tilesize_w and y <= m_y <= y + tilesize_h:
m_xrom = m_x - x
m_yrom = m_y - y
down = True
elif event.button == 3:
m_xrom = m_x
m_yrom = m_y
elif event.type == pg.MOUSEBUTTONUP:
if event.button == 1:
down = False
elif event.button == 3:
tiles.add(Player((m_xrom,m_yrom), 876567, abs(m_x - m_xrom), abs(m_y - m_yrom))
m_x,m_y = pg.mouse.get_pos()
if down:
x = m_x - m_xrom
y = m_y - m_yrom
color = 279348
lvl = Level((x,y), color, tilesize_w, tilesize_h)
lvl.run()
However I don't know how to the move the sprites that the user makes. I would like to be able to make several different user-made sprite that can move independently.
This is a somewhat simple process once the code "saves" the newly drawn boxes somehow. I think a good way to do this is to create a PyGame sprite object for each new box, and keep them in a sprite Group.
At the end of a "mouse drag" operation, we have a start-position - the mouse-xy of the MOUSEBUTTONDOWN event, and the end-position is the mouse-xy of the MOUSEBUTTONUP event. With a bit of fiddling to handle negative-ranges, we calculate a PyGame rectangle object (Rect), using it as the basis for a BoxSprite:
class BoxSprite( pygame.sprite.Sprite ):
""" Rectangular, coloured box-sprite """
def __init__( self, drag_rect ):
super().__init__()
self.image = pygame.Surface( ( drag_rect.width, drag_rect.height ) )
self.rect = drag_rect.copy()
self.image.fill( GREEN )
Looking at the BoxSprite, it's really not much more than a coloured Surface, sized and positioned over the original drag_rect.
Once we have a Sprite to hold the box, PyGame has the super-useful Sprite Group class. This can be used to hold all the BoxSprites, and provides easy drawing, membership and collision functions.
So now the code can "remember" every box, how can we determine if the user clicked on one? An easy way to do this is to test if the click mouse-position is inside any of the group members. A simple approach would be to iterate through every sprite in the group, checking each sprite's Rect. Or if we can somehow treat the mouse-click as a sprite-object, we can use the existing Sprite Group's "Sprite Vs Sprite-Group" collision-test function. This operation returns a handy list of collided sprites from the group. Nice.
Once you have this list, how you treat them is up to you. In the example below I implemented a drag-existing sprite, so clicking on an existing Box "grabs" it until the mouse button is released.
import pygame
# window sizing
WIDTH = 500
HEIGHT = 500
MAX_FPS = 60
BLACK = ( 0, 0, 0)
RED = (255, 0, 0)
GREEN = ( 20, 200, 20)
YELLOW= ( 255,255, 0)
pygame.init()
window = pygame.display.set_mode( ( WIDTH, HEIGHT ) )
pygame.display.set_caption( "Box Dragging Demo" )
###
### This is a sprite we use to hold each rectangular box the User creates.
### Once the user completes an on-screen draw operation, the box gets stored in
### an instance of a BoxSprite
###
class BoxSprite( pygame.sprite.Sprite ):
""" Rectangular, coloured box-sprite """
def __init__( self, drag_rect ):
super().__init__()
self.image = pygame.Surface( ( drag_rect.width, drag_rect.height ) )
self.rect = drag_rect.copy()
self.image.fill( GREEN )
def moveBy( self, dx, dy ):
""" Reposition the sprite """
self.rect.x += dx
self.rect.y += dy
def setColour( self, c ):
self.image.fill( c )
###
### Sprite Groups have no function to test collision against a point
### So this object holds a position as a "dummy" 1x1 sprite, which
### can be used efficiently in collision functions.
###
class CollidePoint( pygame.sprite.Sprite ):
""" Simple single-point Sprite for easy collisions """
def __init__( self, point=(-1,-1) ):
super().__init__()
self.image = None # this never gets drawn
self.rect = pygame.Rect( point, (1,1) )
def moveTo( self, point ):
""" Reposition the point """
self.rect.topleft = point
# Sprite Group to hold all the user-created sprites
user_boxes_group = pygame.sprite.Group() # initially empty
rect_start = ( -1, -1 ) # start position of drawn rectangle
drag_start = ( -1, -1 ) # start position of a mouse-drag
mouse_click = CollidePoint() # create a sprite around the mouse-click for easier collisions
clicked_boxes = [] # the list of sprites being clicked and/or dragged
clock = pygame.time.Clock() # used to govern the max MAX_FPS
### MAIN
exiting = False
while not exiting:
# Handle events
mouse_pos = pygame.mouse.get_pos()
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
exiting = True
elif ( event.type == pygame.MOUSEBUTTONDOWN ):
# MouseButton-down signals beginning a drag or a draw
# Did the user click on an existing sprite?
mouse_click.moveTo( mouse_pos )
clicked_boxes = pygame.sprite.spritecollide( mouse_click, user_boxes_group, False ) # get the list of boxes clicked (if any)
# was anything clicked?
if ( len( clicked_boxes ) > 0 ):
drag_start = mouse_pos # yes, begin a drag operation
for box in clicked_boxes:
box.setColour( YELLOW )
else:
# Nothing clicked, not already drawing, start new rectangle-draw
rect_start = pygame.mouse.get_pos()
elif ( event.type == pygame.MOUSEBUTTONUP ):
# MouseButton-up signals both drag is complete, and draw is complete
# Was the user dragging any sprites?
if ( len( clicked_boxes ) > 0 ):
# drag is over, drop anything we were dragging
for box in clicked_boxes:
box.setColour( GREEN )
drag_start = ( -1, -1 )
clicked_boxes = []
# Was the user drawing a rectangle?
elif ( rect_start != ( -1, -1 ) ):
# Rects are always defined from a top-left point
# So swap the points if the user dragged up
if ( rect_start > mouse_pos ):
swapper = ( mouse_pos[0], mouse_pos[1] )
mouse_pos = rect_start
rect_start = swapper
# create a new sprite from the drag
new_width = abs( mouse_pos[0] - rect_start[0] )
new_height = abs( mouse_pos[1] - rect_start[1] )
if ( new_width > 0 and new_height > 0 ):
new_sprite = BoxSprite( pygame.Rect( rect_start, ( new_width, new_height ) ) )
user_boxes_group.add( new_sprite )
rect_start = ( -1, -1 ) # done drawing
elif ( event.type == pygame.MOUSEMOTION ):
# The mouse is moving, so move anything we're dragging along with it
# Note that we're moving the boxes bit-by-bit, not a start->final move
if ( len( clicked_boxes ) > 0 ):
x_delta = mouse_pos[0] - drag_start[0]
y_delta = mouse_pos[1] - drag_start[1]
for box in clicked_boxes:
box.moveBy( x_delta, y_delta )
drag_start = mouse_pos
# Handle keys
keys = pygame.key.get_pressed()
if ( keys[pygame.K_ESCAPE] ):
exiting = True
# paint the window
window.fill( BLACK ) # paint background
user_boxes_group.draw( window ) # paint the sprites
# If we're already dragging a box, paint a target-rectangle
if ( rect_start != ( -1, -1 ) ):
# Use a lines instead of a Rect, so we don't have to handle width/height co-ordinate position issues
box = [ rect_start, ( mouse_pos[0], rect_start[1] ), mouse_pos, ( rect_start[0], mouse_pos[1] ) ]
pygame.draw.lines( window, RED, True, box, 1 )
pygame.display.flip()
clock.tick( MAX_FPS )
pygame.quit()

screen.blit image giving a black screen and drawing shows up when i close the pygame window

I want to load game pieces for my game but when i try to blit them the entire screen goes black. While closing the window the entire drawing shows up for a second.
the code so far:
import pygame
import math
board_lines = [
( 13,15,462,15 ), ( 13,469,462,469 ), #lin1 and line2,outer rect
( 62,86,409,86 ), ( 62,389,409,389 ), #line3 and l4,mid reect
( 114,186,360,186 ), ( 114,318,360,318 ), #line5,l6,internl rect
( 13,15,13,469 ), ( 462,12,462,469 ), #line9,l10,left and right sides
( 62,86,62,389 ), ( 409,85,409,389 ), #l7,l8left and right sides
( 114,186,114,316), ( 360,187,360,318 ), #l11,lin12left and right sides
( 237,15,237,186 ), ( 237,469,237,320 ), #upper V.line,lowerV
( 13,242,113,242 ), ( 360,242,462,242 ) #rIGHT LEFT hoRIZONTAL LINE
]
pygame.init()
intersectionPoints = []
for i, line1 in enumerate(board_lines):
for line2 in board_lines[i:]:
isectP = lineLineIntersect(line1[:2], line1[2:], line2[:2], line2[2:])
if isectP:
intersectionPoints.append(isectP)
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW_P = pygame.image.load('yellowgoti.png')
BLUE_P = pygame.image.load('bluegoti.png')
# This sets the WIDTH and HEIGHT of each grid location
WIDTH = 20
HEIGHT = 20
# This sets the margin between each cell
MARGIN = 5
# Create a 2 dimensional array. A two dimensional
# array is simply a list of lists.
grid = []
for row in range(19):
# Add an empty array that will hold each cell
# in this row
grid.append([])
for column in range(19):
grid[row].append(0) # Append a cell
# Set row 1, cell 5 to one. (Remember rows and
# column numbers start at zero.)
grid[1][5] = 1
WINDOW_SIZE = [800, 600]
screen = pygame.display.set_mode(WINDOW_SIZE)
pygame.display.set_caption("Array Backed Grid")
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Set the screen background
screen.fill(BLACK)
#screen.background(YELLOW_P,,600)
# Draw the grid
for row in range(19):
for column in range(19):
color = WHITE
if grid[row][column] == 1:
color = GREEN
for line in board_lines:
pygame.draw.line(screen, RED, line[:2], line[2:], 3)
for isectP in intersectionPoints:
pygame.draw.circle(screen, GREEN, isectP, 5)
screen.blit(BLUE_P,(400,200))
# Limit to 60 frames per second
clock.tick(60)
pygame.display.flip()
pygame.quit()
is it the correct position to use blit in the code.
if not so then at which position i can blit the screen in code.
thanks in advance for the help.omitted some part of code:
by indenting the main loop as suggested by #Kingsley resolved the problem:
WINDOW_SIZE = [800, 600]
screen = pygame.display.set_mode(WINDOW_SIZE)
pygame.display.set_caption("Array Backed Grid")
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(BLACK)
screen.blit(BLUE_P,(400,200))
for line in board_lines:
pygame.draw.line(screen, RED, line[:2], line[2:], 3)
for isectP in intersectionPoints:
pygame.draw.circle(screen, GREEN, isectP, 5)
clock.tick(60)
pygame.display.flip()
pygame.quit()

Drawing a line after forming 2d array in python using pygame or any other tool

I am creating a game using python and pygame. Firstly, I tried to create the game the using pygame.draw tool but then i realize that its hard to call points and train data set using this approach.the code for my first try is
import pygame
import sys
WINDOW_WIDTH = 800
WINDOW_HEIGHT= 600
#define colour
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,255,0)
blue = (121,202,255)
yellow= (255,255,0)
def lineRectIntersectionPoints( line, rect ):
""" Get the list of points where the line and rect
intersect, The result may be zero, one or two points.
BUG: This function fails when the line and the side
of the rectangle overlap """
def linesAreParallel( x1,y1, x2,y2, x3,y3, x4,y4 ):
""" Return True if the given lines (x1,y1)-(x2,y2) and
(x3,y3)-(x4,y4) are parallel """
return (((x1-x2)*(y3-y4)) - ((y1-y2)*(x3-x4)) == 0)
def intersectionPoint( x1,y1, x2,y2, x3,y3, x4,y4 ):
""" Return the point where the lines through (x1,y1)-(x2,y2)
and (x3,y3)-(x4,y4) cross. This may not be on-screen """
#Use determinant method, as per
#Ref: https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
Px = ((((x1*y2)-(y1*x2))*(x3 - x4)) - ((x1-x2)*((x3*y4)-(y3*x4)))) / (((x1-x2)*(y3-y4)) - ((y1-y2)*(x3-x4)))
Py = ((((x1*y2)-(y1*x2))*(y3 - y4)) - ((y1-y2)*((x3*y4)-(y3*x4)))) / (((x1-x2)*(y3-y4)) - ((y1-y2)*(x3-x4)))
return Px,Py
### Begin the intersection tests
result = []
line_x1, line_y1, line_x2, line_y2 = line # split into components
pos_x, pos_y, width, height = rect
### Convert the rectangle into 4 lines
rect_lines = [ ( pos_x, pos_y, pos_x+width, pos_y ), ( pos_x, pos_y+height, pos_x+width, pos_y+height ), # top & bottom
( pos_x, pos_y, pos_x, pos_y+height ), ( pos_x+width, pos_y, pos_x+width, pos_y+height ) ] # left & right
### intersect each rect-side with the line
for r in rect_lines:
rx1,ry1, rx2,ry2 = r
if ( not linesAreParallel( line_x1,line_y1, line_x2,line_y2, rx1,ry1, rx2,ry2 ) ): # not parallel
pX, pY = intersectionPoint( line_x1,line_y1, line_x2,line_y2, rx1,ry1, rx2,ry2 ) # so intersecting somewhere
# Lines intersect, but is it on-screen?
if ( pX >= 0 and pY >= 0 and pX < WINDOW_WIDTH and pY < WINDOW_HEIGHT ): # yes! on-screen
result.append( ( round(pX), round(pY) ) ) # keep it
if ( len( result ) == 2 ):
break # Once we've found 2 intersection points, that's it
return result
#opening window
pygame.init()
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
#pygame.draw.rect(screen, red, (200,100,250,250), 2)
#pygame.draw.rect(screen, green, (150,75,350,300), 2)
#pygame.draw.rect(screen, red, (100,50,450,350), 2)
##draw lines
##upper line
#pygame.draw.line(screen,white,(325,50),(325,100),3)
##lower line
#pygame.draw.line(screen,white,(325,350),(325,400),3)
##left line
#pygame.draw.line(screen,white,(100,200),(200,200),3)
##right line
#pygame.draw.line(screen,white,(450,200),(550,200),3)
##kingsley correction of the code
board_rects = [ ( 200,100,250,250, red ), ( 150,75,350,300, green ), ( 100,50,450,350, red ) ]
for rect in board_rects:
x_pos, y_pos = rect[0], rect[1]
width, height = rect[2], rect[3]
colour = rect[4]
pygame.draw.rect( screen, colour, ( x_pos, y_pos, width, height ), 2 )
board_lines = [ ( 325,50,325,100 ), ( 325,350,325,400 ), ( 100,200,200,200 ), ( 450,200,550,200 ) ]
for line in board_lines:
line_from = ( line[0], line[1] )
line_to = ( line[2], line[3] )
pygame.draw.line( screen, white, line_from, line_to, 3)
for line in board_lines:
for rect in board_rects:
rect = rect[ 0: -1 ] # trim off the colour
intersection_points = lineRectIntersectionPoints( line, rect )
for p in intersection_points:
pygame.draw.circle( screen, blue, p, 10 ) # Draw a circle at the intersection point
#updating window
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
pygame.display.update()
after that i tried to use the 2d array for creation of board. In this i want to draw line on specific high lighted boxes only and i want to remove/delete all other boxes. i used the following code:
import pygame
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
WIDTH = 20
HEIGHT = 20
MARGIN = 5
#set the array
grid = []
for row in range(19):
grid.append([])
for column in range(19):
grid[row].append(0)
# Set row 1, cell 5 to one. (Remember rows and
# column numbers start at zero.)
grid[0][0] = 1
pygame.init()
# Set the width and height of the screen [width, height]
size = [600, 600]
screen = pygame.display.set_mode(size)
#set the tittle of the game
pygame.display.set_caption("My Array 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
while not done:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done = True # Flag that we are done so we exit this loop
elif event.type == pygame.MOUSEBUTTONDOWN:
# User clicks the mouse. Get the position
pos = pygame.mouse.get_pos()
# Change the x/y screen coordinates to grid coordinates
column = pos[0] // (WIDTH + MARGIN)
row = pos[1] // (HEIGHT + MARGIN)
# Set that location to one
grid[row][column] = 1
print("Click ", pos, "Grid coordinates: ", row, column)
# --- 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
# Draw the grid
for row in range(19):
for column in range(19):
color = WHITE
if grid[row][column] == 1:
color = GREEN
pygame.draw.rect(screen,
color,
[(MARGIN + WIDTH) * column + MARGIN,
(MARGIN + HEIGHT) * row + MARGIN,
WIDTH,
HEIGHT])
# --- 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 boxes which i want to retain
i want to draw lins on the selected boxes
coords of the boxes
You can't "delete" boxes which are drawn on the display surface, don't draw them:
while not done:
# [...]
for row in range(19):
for column in range(19):
if grid[row][column] == 1:
color = GREEN
box_rect = [(MARGIN + WIDTH) * column + MARGIN,
(MARGIN + HEIGHT) * row + MARGIN,
WIDTH,
HEIGHT]
pygame.draw.rect(screen, color, box_rect)
TO d raw the lines, you've to find the center of the box. Use a pygame.Rect object to find the center point of a box. The center point of the box with the index (row, column) can be computed by:
box_rect = pygame.Rect((MARGIN + WIDTH) * column + MARGIN,
(MARGIN + HEIGHT) * row + MARGIN,
WIDTH,
HEIGHT)
box_center = box_rect.center

Working with classes (creating a class efficiently, drawing and updating all instances of the class every frame)

I've been working on a "bullet hell" game of my own, but I am struggling very much with working with classes (im new to python), below i've enclosed my code(I wouldnt include so much but i dont know howo to go about the problem). At the moment what i've been attempting to
1. Create different instances of the class
2. Draw them every frame
3. Update their position every frame according to the x and y speed
import pygame
# Define colors needed
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
bulletArray = []
BulletSprite = ("Bullet4.png")
pygame.init()
class Bullet:
def __init__(self, sprite, x, y, xSpeed, ySpeed):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.xSpeed = xSpeed
self.ySpeed = ySpeed
bulletArray.append(self)
def update(self):
pass
def draw(screen):
self.screen = screen
screen.blit(screen, (x, y))
#Set the width and height of the game screen
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Bullet stuff")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
testBullet = Bullet(BulletSprite, 200, 200, 2, 2)
#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
print(bulletArray)
# --- background image.
screen.fill(WHITE)
# --- Drawing code should go here
# --- Updates the screen every frame with whats been drawn
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(60)
# Close the window and quit.
pygame.quit()
Much of the this mechanism is already handled automatically if you use the PyGame Sprite Class.
A PyGame sprite is essentially made of:
An Image to draw to represent the object
A rectangle around the object to remember the location and check for collisions
An update() function to handle any movement of the sprite
It's handy to work with the existing PyGame Sprite layout because a lot of functionality is already provided by the library code.
So let's make a BulletSprite:
class BulletSprite( pygame.sprite.Sprite ):
def __init__( self, bitmap, x, y ):
pygame.sprite.Sprite.__init__( self )
self.image = bitmap # How the sprite looks
self.rect = bitmap.get_rect() # Bounding box the size of the image
self.rect.centerx = x # position the bullet
self.rect.centery = y # about its centre
And that's it. This will give you a stationary sprite, painted as the given bitmap at (x,y) on-screen.
So let's now use it:
# Create a group of 100 bullets
sprite_image = pygame.image.load( "bullet.png" )
all_bullets = pygame.sprite.Group() # Group to hold the sprites
for i in range( 100 ):
random_x = 50 + random.randrange( 950 ) # TODO: use proper screen size
random_y = 50 + random.randrange( 950 )
new_sprite = BulletSprite( sprite_image, random_x, random_y )
all_bullets.add( new_sprite )
# Main Window loop
while True:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
break
# Paint the window
window.fill( ( 0, 0, 0 ) ) # Paint it Black
all_bullets.update() # move all the bullets
all_bullets.draw( window ) # Paint all the bullets
pygame.display.flip()
pygame.quit()
And that's it. After the sprites are created, it takes two lines of code to move them all, and draw them all.
But they wont move yet. For them to move, the BulletSprite needs to have an update() function. This function does whatever is necessary to move the sprite - apply velocity, gravity, whatever. The net effect is the sprite's rectangle's (x,y) is changed.
So adding some changes to the sprite - first an x and y velocity, and then the movement code.
class BulletSprite( pygame.sprite.Sprite ):
def __init__( self, bitmap, x, y ):
pygame.sprite.Sprite.__init__( self )
self.image = bitmap # How the sprite looks
self.rect = bitmap.get_rect() # Bounding box the size of the image
self.rect.centerx = x # position the bullet
self.rect.centery = y # about its centre
self.x_move = random.randrange( -3, 3 ) # simple random velocity
self.y_move = random.randrange( -3, 3 )
def update( self ):
x = self.rect.centerx + self.x_move # calculate the new position
y = self.rect.centerx + self.y_move # by applying an offset
# has the sprite gone off-screen
if ( x < 0 or x > 1000 or y < 0 or y > 1000 )
self.kill() # remove from the group
else:
self.rect.centerx = x # RE-position the bullet
self.rect.centery = y
Every time the update() is called on your sprite group (all_bullets), the sprite library will go and call the update() function on every sprite in the group. The code checks to see if the bullet is off-screen (I lazily used 1000 as a placeholder for screen width & height), and if-so, the sprite.kill() function handles the removing from the group and cleaning up. It's very easy.

Categories