Hi I want to add a score system in this Memory game, but i don't how to add it or how it update. I want it when the user finds two pairs that matches it will give you a score of 1 and if you find more pairs it will add 1 to the score.
This is my first time here so I don't if I should paste all the code, but here it is anyways
If you want to run it on python, you have to dedent all by 4
## MemoryPuzzle.py
import random, pygame, sys
from pygame.locals import*
FPS = 20 ## frames per second, the general speed of the game
WINDOWWIDTH = 640 ##size of height in pixels
WINDOWHEIGHT = 480 ##size of height in pixels
REVEALSPEED = 8 ## speed of boxes sliding reveals and covers
BOXSIZE= 40 ## Size of box, width and height in pixels
GAPSIZE = 10 ##spaces between the box
BOARDWIDTH = 10 ## number of columns of icons
BOARDHEIGHT = 7 ## numbers of rows of icons
assert (BOARDWIDTH * BOARDHEIGHT) % 2==0, "Board needs to have an evem number of boxes for pairs to match."
XMARGIN = int((WINDOWWIDTH - (BOARDWIDTH * (BOXSIZE + GAPSIZE))) / 2)
YMARGIN = int((WINDOWHEIGHT - (BOARDHEIGHT * (BOXSIZE + GAPSIZE))) / 2)
# R G B
GRAY = (100, 100, 100)
NAVYBLUE = ( 60, 60, 100)
WHITE = (125, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
YELLOW = (255, 255, 0)
ORANGE = (255, 128, 0)
PURPLE = (255, 0, 255)
CYAN = ( 0, 255, 255)
BGCOLOR= NAVYBLUE
LIGHTBGCOLOR = GRAY
BOXCOLOR = WHITE
HIGHLIGHTCOLOR = BLUE
DONUT = "donut"
SQUARE = "square"
DIAMOND = "diomond"
LINES = "lines"
OVAL = "oval"
ALLCOLORS = (RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, CYAN)
ALLSHAPES = (DONUT, SQUARE, DIAMOND, LINES, OVAL)
assert len(ALLCOLORS) * len(ALLSHAPES) * 2 >= BOARDWIDTH * BOARDHEIGHT, "Board is too big for the number of shapes/colors defined."
def main():
global FPSCLOCK, DISPLAYSURF
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF =pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
mousex = 0# used to store x cooridinate of mouse event
mousey = 0# used to store y cooridinate of mouse event
pygame.display.set_caption("MemoryGame")
mainBoard = getRandomizedBoard()
revealedBoxes = generateRevealedBoxesData(False)
firstSelection = None #stores the (x, y) of the first box clicked
DISPLAYSURF.fill(BGCOLOR)
startGameAnimation(mainBoard)
while True: #main game loop
mouseClicked = False
DISPLAYSURF.fill(BGCOLOR)
drawBoard(mainBoard, revealedBoxes)
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
elif event.type == MOUSEMOTION:
mousex, mousey = event.pos
elif event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
mouseClicked = True
boxx, boxy = getBoxAtPixel(mousex, mousey)
if boxx != None and boxy != None:
## the mouse is over a box
if not revealedBoxes[boxx][boxy]:
drawHighlightBox(boxx, boxy)
if not revealedBoxes[boxx][boxy] and mouseClicked:
revealBoxesAnimation(mainBoard, [(boxx, boxy)])
revealedBoxes[boxx][boxy] = True #set the box as revealed
if firstSelection == None: #the current box was the first
firstSelection = (boxx, boxy)
else: # the current box was the second box clicked
#checks if theres is a match between the two icons.
icon1shape, icon1color = getShapeAndColor(mainBoard, firstSelection[0], firstSelection[1])
icon2shape, icon2color = getShapeAndColor(mainBoard, boxx, boxy)
if icon1shape != icon2shape or icon1color != icon2color:
#Icons dont match. Re_cover up Both Selections.
pygame.time.wait(1000) #1000 milliseconds = 1sec
coverBoxesAnimation(mainBoard, [(firstSelection[0], firstSelection[1]), (boxx, boxy)])
revealedBoxes[firstSelection[0]][firstSelection[1]] = False
revealedBoxes[boxx][boxy] = False
elif hasWon(revealedBoxes): #check if all pairs found
gameWonAnimation(mainBoard)
pygame.time.wait(2000)
#reset the board
mainBoard = getRandomizedBoard()
revealedBoxea = generateRevealedBoxesData(False)
#Show the fully unrevealed board for a second.
drawBoard(mainBoard, revealedBoxes)
pygame.display.update()
pygame.time.wait(1000)
#replay the start game animation
startGameAnimation(mainBoard)
firstSelection = None # reset first selection variable
#redraw the screen and wait a clock tick
pygame.display.update()
FPSCLOCK.tick(FPS)
def generateRevealedBoxesData(val):
revealedBoxes = []
for i in range(BOARDWIDTH):
revealedBoxes.append([val] * BOARDHEIGHT)
return revealedBoxes
def getRandomizedBoard():
# Get a list of every possible shape with every possible color
icons =[]
for color in ALLCOLORS:
for shape in ALLSHAPES:
icons.append( (shape, color) )
random.shuffle(icons) #Randomize the order of the icons
numIconsUsed = int (BOARDWIDTH * BOARDHEIGHT / 2) # Calculate how many icons needed
icons = icons [:numIconsUsed] *2 #make 2 of each
random.shuffle(icons)
#create the board data structure, with randomly placed icons.
board =[]
for x in range(BOARDWIDTH):
column = []
for y in range(BOARDHEIGHT):
column.append(icons[0])
del icons[0] #removes the icons as we assigned them
board.append(column)
return board
def splitIntoGroupsOf(groupSize, theList):
# splits a list into a list of lists, where the inner lists have at
# most groupsize number of items.
result = []
for i in range(0, len(theList), groupSize):
result.append(theList[i:i + groupSize])
return result
def leftTopCoordsOfBox(boxx, boxy):
#convert board cooridinates to pixel cooridinates
left = boxx *(BOXSIZE + GAPSIZE) + XMARGIN
top = boxy * (BOXSIZE + GAPSIZE) + YMARGIN
return (left, top)
def getBoxAtPixel(x, y):
for boxx in range(BOARDWIDTH):
for boxy in range(BOARDHEIGHT):
left, top = leftTopCoordsOfBox(boxx, boxy)
boxRect = pygame.Rect(left, top, BOXSIZE, BOXSIZE)
if boxRect.collidepoint(x, y):
return (boxx, boxy)
return (None, None)
def drawIcon(shape, color, boxx, boxy):
quarter = int(BOXSIZE * 0.25) #syntactic sugar
half = int(BOXSIZE * 0.5)
left, top = leftTopCoordsOfBox(boxx, boxy) #get pixel corrds from board coords
#draw shapes
if shape == DONUT:
pygame.draw.circle(DISPLAYSURF, color, (left + half, top + half), half - 5)
pygame.draw.circle(DISPLAYSURF, BGCOLOR, (left +half, top + half), quarter - 5)
elif shape == SQUARE:
pygame.draw.rect(DISPLAYSURF, color, (left + quarter, top + quarter, BOXSIZE - half, BOXSIZE -half))
elif shape== DIAMOND:
pygame.draw.polygon(DISPLAYSURF, color, ((left + half, top), (left + BOXSIZE - 1, top + half), (left + half, top + BOXSIZE - 1), (left, top + half)))
elif shape == LINES:
for i in range(0, BOXSIZE, 4):
pygame.draw.line(DISPLAYSURF, color, (left, top+ i), (left + i, top))
pygame.draw.line(DISPLAYSURF, color, ( left + i, top + BOXSIZE - 1), (left + BOXSIZE -1, top + i ))
elif shape == OVAL:
pygame.draw.ellipse(DISPLAYSURF, color, (left, top + quarter, BOXSIZE, half))
def getShapeAndColor( board, boxx, boxy):
#color value for x, y spot is stored in board[x] [y] [1]
return board[boxx][boxy][0], board[boxx][boxy][1]
def drawBoxCovers(board, boxes, coverage):
#draws boxes being covered/revealed. "boxes" is a list
#of two item lists, which have the x & y "spot of the box.
for box in boxes:
left, top = leftTopCoordsOfBox(box[0], box[1])
pygame.draw.rect(DISPLAYSURF, BGCOLOR, (left, top, BOXSIZE, BOXSIZE))
shape, color = getShapeAndColor(board, box[0], box[1])
drawIcon(shape, color, box[0], box[1])
if coverage > 0: #only draw the cover if there is an coverage
pygame.draw.rect(DISPLAYSURF, BOXCOLOR, (left, top, coverage, BOXSIZE))
pygame.display.update()
FPSCLOCK.tick(FPS)
def revealBoxesAnimation(board, boxesToReveal):
#do the "box reveal" animation.
for coverage in range(BOXSIZE, (-REVEALSPEED) -1, - REVEALSPEED):
drawBoxCovers(board, boxesToReveal, coverage)
def coverBoxesAnimation(board, boxesToReveal):
#Do the "box cover" animation
for coverage in range(0, BOXSIZE + REVEALSPEED, REVEALSPEED):
drawBoxCovers(board, boxesToReveal, coverage)
def drawBoard(board, revealed):
for boxx in range(BOARDWIDTH):
for boxy in range(BOARDHEIGHT):
left, top = leftTopCoordsOfBox(boxx, boxy)
if not revealed[boxx][boxy]:
#Draw a covered box.
pygame.draw.rect(DISPLAYSURF, BOXCOLOR, (left, top, BOXSIZE, BOXSIZE))
else:
#draw the (revealed) icon
shape, color = getShapeAndColor(board, boxx, boxy)
drawIcon(shape, color, boxx, boxy)
def drawHighlightBox(boxx, boxy):
left, top = leftTopCoordsOfBox(boxx, boxy)
pygame.draw.rect(DISPLAYSURF, HIGHLIGHTCOLOR, (left - 5, top - 5, BOXSIZE + 10, BOXSIZE + 10), 4)
def startGameAnimation(board):
#Randomly reval boxes 8 at a time.
coveredBoxes = generateRevealedBoxesData(False)
boxes = []
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
boxes.append( (x, y) )
random.shuffle(boxes)
boxGroups = splitIntoGroupsOf(8, boxes)
drawBoard(board, coveredBoxes)
for boxGroup in boxGroups:
revealBoxesAnimation(board, boxGroup)
coverBoxesAnimation(board, boxGroup)
def gameWonAnimation(board):
#flash the background color when teh player has won
coveredBoxes = generateRevealedBoxesData(True)
color1 = LIGHTBGCOLOR
color2 = BGCOLOR
for i in range (13):
color1, color2= color2, color1 #swap colors
DISPLAYSURF.fill(color1)
drawBoard(board, coveredBoxes)
pygame.display.update()
pygame.time.wait(300)
def hasWon(revealedBoxes):
#Return True if all the boxes have been revealed, otherwise False
for i in revealedBoxes:
if False in i:
return False # return False if any boxes are covered
return True
if __name__== "__main__":
main()
If I understood you correctly, It's just add a score = 0 variable outside the while True loop and keep manipulating the score inside this loop in these locations:
Here:
if firstSelection == None: #the current box was the first
firstSelection = (boxx, boxy)
score += 1
And here:
if icon1shape != icon2shape or icon1color != icon2color:
#Icons dont match. Re_cover up Both Selections.
pygame.time.wait(1000) #1000 milliseconds = 1sec
coverBoxesAnimation(mainBoard, [(firstSelection[0], firstSelection[1]), (boxx, boxy)])
revealedBoxes[firstSelection[0]][firstSelection[1]] = False
revealedBoxes[boxx][boxy] = False
score -= 1
Inside hasWon() you can reset the score.
I did in this way, trying to follow your logic of keeping the boxes revealed.
EDIT:
#create font obj outside loop
font_path = "./fonts/newfont.ttf"
font=pygame.font.Font(font_path, font_size)
#other option:
#font=pygame.font.SysFont("Arial", font_size)
Inside the loop:
scoretext = font.render(str(score), 1,(255,255,255))
screen.blit(scoretext, (x, y))
Not a good solution, but works...
Related
I am creating a battleship-type game. I am using .blit to display images that I load using the function pygame.image.load. I was wondering, is it possible to make images like this appear/disappear at different points?
My code is as follows:
import random, sys, pygame
from pygame.locals import *
# Set variables, like screen width and height
# globals
FPS = 60 #Determines the number of frames per second
REVEALSPEED = 2 #Determines the speed at which the squares reveals after being clicked
WINDOWWIDTH = 800 #Width of game window
WINDOWHEIGHT = 600 #Height of game window
TILESIZE = 40 #Size of the squares in each grid(tile)
MARKERSIZE = 40 #Size of the box which contatins the number that indicates how many ships in this row/col
BUTTONHEIGHT = 20 #Height of a standard button
BUTTONWIDTH = 40 #Width of a standard button
TEXT_HEIGHT = 25 #Size of the text
TEXT_LEFT_POSN = 10 #Where the text will be positioned
BOARDWIDTH = 6 #Number of grids horizontally
BOARDHEIGHT = 6 #Number of grids vertically
DISPLAYWIDTH = 200 #Width of the game board
EXPLOSIONSPEED = 10 #How fast the explosion graphics will play
XMARGIN = int((WINDOWWIDTH - (BOARDWIDTH * TILESIZE) - DISPLAYWIDTH - MARKERSIZE) / 2) #x-position of the top left corner of board
YMARGIN = int((WINDOWHEIGHT - (BOARDHEIGHT * TILESIZE) - MARKERSIZE) / 2) #y-position of the top left corner of board
#Colours which will be used by the game
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
GREEN = ( 0, 204, 0)
GRAY = ( 60, 60, 60)
BLUE = ( 0, 50, 255)
YELLOW = (255, 255, 0)
DARKGRAY =( 40, 40, 40)
transparent = (0, 0, 0, 0)
#Determine what to colour each element of the game
BGCOLOR = GRAY
BUTTONCOLOR = GREEN
TEXTCOLOR = WHITE
TILECOLOR = GREEN
BORDERCOLOR = BLUE
TEXTSHADOWCOLOR = BLUE
SHIPCOLOR = YELLOW
HIGHLIGHTCOLOR = BLUE
def main():
"""
The main function intializes the variables which will be used by the game.
"""
global DISPLAYSURF, FPSCLOCK, BASICFONT, HELP_SURF, HELP_RECT, NEW_SURF, \
NEW_RECT, SHOTS_SURF, SHOTS_RECT, BIGFONT, COUNTER_SURF, \
COUNTER_RECT, HBUTTON_SURF, EXPLOSION_IMAGES
pygame.init()
FPSCLOCK = pygame.time.Clock()
#Fonts used by the game
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
BASICFONT = pygame.font.Font('freesansbold.ttf', 20)
BIGFONT = pygame.font.Font('freesansbold.ttf', 50)
# Create and label the buttons
HELP_SURF = BASICFONT.render("HELP", True, WHITE)
HELP_RECT = HELP_SURF.get_rect()
HELP_RECT.topleft = (WINDOWWIDTH - 180, WINDOWHEIGHT - 350)
NEW_SURF = BASICFONT.render("NEW GAME", True, WHITE)
NEW_RECT = NEW_SURF.get_rect()
NEW_RECT.topleft = (WINDOWWIDTH - 200, WINDOWHEIGHT - 200)
# The 'Shots:' label at the top
SHOTS_SURF = BASICFONT.render("Shots: ", True, WHITE)
SHOTS_RECT = SHOTS_SURF.get_rect()
SHOTS_RECT.topleft = (WINDOWWIDTH - 750, WINDOWHEIGHT - 570)
# Load the explosion graphics from the /img folder
EXPLOSION_IMAGES = [
pygame.image.load("blowup1.png"), pygame.image.load("blowup2.png"),
pygame.image.load("blowup3.png"),pygame.image.load("blowup4.png"),
pygame.image.load("blowup5.png"),pygame.image.load("blowup6.png")]
# Set the title in the menu bar to 'Battleship'
pygame.display.set_caption('Battleship')
# Keep the game running at all times
while True:
shots_taken = run_game() #Run the game until it stops and save the result in shots_taken
show_gameover_screen(shots_taken) #Display a gameover screen by passing in shots_taken
def run_game():
greenButton = pygame.image.load('green-button-icon-png-13.png')
greenButton = pygame.transform.scale(greenButton, (75,75))
rect = greenButton.get_rect()
rect = rect.move((150, 475))
redButton = pygame.image.load('red-button-1426817_960_720.png')
redButton = pygame.transform.scale(redButton, (85,85))
rect2 = redButton.get_rect()
rect2 = rect2.move((400, 475))
"""
Function is executed while a game is running.
returns the amount of shots taken
"""
revealed_tiles = generate_default_tiles(False) #Contains the list of the tiles revealed by user
# main board object,
main_board = generate_default_tiles(None) #Contains the list of the ships which exists on board
ship_objs = ['raft'] # List of the ships available
main_board = add_ships_to_board(main_board, ship_objs) #call add_ships_to_board to add the list of ships to the main_board
mousex, mousey = 0, 0 #location of mouse
counter = [] #counter to track number of shots fired
while True:
# counter display (it needs to be here in order to refresh it)
COUNTER_SURF = BASICFONT.render(str(len(counter)), True, WHITE)
COUNTER_RECT = SHOTS_SURF.get_rect()
COUNTER_RECT.topleft = (WINDOWWIDTH - 680, WINDOWHEIGHT - 570)
# Fill background
DISPLAYSURF.fill(BGCOLOR)
# draw the buttons
DISPLAYSURF.blit(HELP_SURF, HELP_RECT)
DISPLAYSURF.blit(NEW_SURF, NEW_RECT)
DISPLAYSURF.blit(SHOTS_SURF, SHOTS_RECT)
DISPLAYSURF.blit(COUNTER_SURF, COUNTER_RECT)
DISPLAYSURF.blit(greenButton, rect)
DISPLAYSURF.blit(redButton, rect2)
greenButton.fill(transparent)
DISPLAYSURF.blit(greenButton, rect)
# Draw the tiles onto the board and their respective markers
draw_board(main_board, revealed_tiles)
mouse_clicked = False
check_for_quit()
#Check for pygame events
for event in pygame.event.get():
if event.type == MOUSEBUTTONUP:
if HELP_RECT.collidepoint(event.pos): #if the help button is clicked on
DISPLAYSURF.fill(BGCOLOR)
show_help_screen() #Show the help screen
elif NEW_RECT.collidepoint(event.pos): #if the new game button is clicked on
main() #goto main, which resets the game
else: #otherwise
mousex, mousey = event.pos #set mouse positions to the new position
mouse_clicked = True #mouse is clicked but not on a button
elif event.type == MOUSEMOTION: #Detected mouse motion
mousex, mousey = event.pos #set mouse positions to the new position
#Check if the mouse is clicked at a position with a ship piece
tilex, tiley = get_tile_at_pixel(mousex, mousey)
if tilex != None and tiley != None:
if not revealed_tiles[tilex][tiley]: #if the tile the mouse is on is not revealed
draw_highlight_tile(tilex, tiley) # draws the hovering highlight over the tile
if not revealed_tiles[tilex][tiley] and mouse_clicked: #if the mouse is clicked on the not revealed tile
reveal_tile_animation(main_board, [(tilex, tiley)])
revealed_tiles[tilex][tiley] = True #set the tile to now be revealed
if check_revealed_tile(main_board, [(tilex, tiley)]): # if the clicked position contains a ship piece
left, top = left_top_coords_tile(tilex, tiley)
blowup_animation((left, top))
if check_for_win(main_board, revealed_tiles): # check for a win
counter.append((tilex, tiley))
return len(counter) # return the amount of shots taken
counter.append((tilex, tiley))
pygame.display.update()
FPSCLOCK.tick(FPS)
def generate_default_tiles(default_value):
"""
Function generates a list of 10 x 10 tiles. The list will contain tuples
('shipName', boolShot) set to their (default_value).
default_value -> boolean which tells what the value to set to
returns the list of tuples
"""
default_tiles = [[default_value]*BOARDHEIGHT for i in range(BOARDWIDTH)]
return default_tiles
def blowup_animation(coord):
"""
Function creates the explosition played if a ship is shot.
coord -> tuple of tile coords to apply the blowup animation
"""
for image in EXPLOSION_IMAGES: # go through the list of images in the list of pictures and play them in sequence
#Determine the location and size to display the image
image = pygame.transform.scale(image, (TILESIZE+10, TILESIZE+10))
DISPLAYSURF.blit(image, coord)
pygame.display.flip()
FPSCLOCK.tick(EXPLOSIONSPEED) #Determine the delay to play the image with
def check_revealed_tile(board, tile):
"""
Function checks if a tile location contains a ship piece.
board -> the tiled board either a ship piece or none
tile -> location of tile
returns True if ship piece exists at tile location
"""
return board[tile[0][0]][tile[0][1]] != None
def reveal_tile_animation(board, tile_to_reveal):
"""
Function creates an animation which plays when the mouse is clicked on a tile, and whatever is
behind the tile needs to be revealed.
board -> list of board tile tuples ('shipName', boolShot)
tile_to_reveal -> tuple of tile coords to apply the reveal animation to
"""
for coverage in range(TILESIZE, (-REVEALSPEED) - 1, -REVEALSPEED): #Plays animation based on reveal speed
draw_tile_covers(board, tile_to_reveal, coverage)
def draw_tile_covers(board, tile, coverage):
"""
Function draws the tiles according to a set of variables.
board -> list; of board tiles
tile -> tuple; of tile coords to reveal
coverage -> int; amount of the tile that is covered
"""
left, top = left_top_coords_tile(tile[0][0], tile[0][1])
if check_revealed_tile(board, tile):
pygame.draw.rect(DISPLAYSURF, SHIPCOLOR, (left, top, TILESIZE,
TILESIZE))
else:
pygame.draw.rect(DISPLAYSURF, BGCOLOR, (left, top, TILESIZE,
TILESIZE))
if coverage > 0:
pygame.draw.rect(DISPLAYSURF, TILECOLOR, (left, top, coverage,
TILESIZE))
pygame.display.update()
FPSCLOCK.tick(FPS)
def check_for_quit():
"""
Function checks if the user has attempted to quit the game.
"""
for event in pygame.event.get(QUIT):
pygame.quit()
sys.exit()
def check_for_win(board, revealed):
"""
Function checks if the current board state is a winning state.
board -> the board which contains the ship pieces
revealed -> list of revealed tiles
returns True if all the ships are revealed
"""
for tilex in range(BOARDWIDTH):
for tiley in range(BOARDHEIGHT):
if board[tilex][tiley] != None and not revealed[tilex][tiley]: # check if every board with a ship is revealed, return false if not
return False
return True
def draw_board(board, revealed):
"""
Function draws the game board.
board -> list of board tiles
revealed -> list of revealed tiles
"""
#draws the grids depending on its state
for tilex in range(BOARDWIDTH):
for tiley in range(BOARDHEIGHT):
left, top = left_top_coords_tile(tilex, tiley)
if not revealed[tilex][tiley]:
pygame.draw.rect(DISPLAYSURF, TILECOLOR, (left, top, TILESIZE,
TILESIZE))
else:
if board[tilex][tiley] != None:
pygame.draw.rect(DISPLAYSURF, SHIPCOLOR, (left, top,
TILESIZE, TILESIZE))
else:
pygame.draw.rect(DISPLAYSURF, BGCOLOR, (left, top,
TILESIZE, TILESIZE))
#draws the horizontal lines
for x in range(0, (BOARDWIDTH + 1) * TILESIZE, TILESIZE):
pygame.draw.line(DISPLAYSURF, DARKGRAY, (x + XMARGIN + MARKERSIZE,
YMARGIN + MARKERSIZE), (x + XMARGIN + MARKERSIZE,
WINDOWHEIGHT - YMARGIN))
#draws the vertical lines
for y in range(0, (BOARDHEIGHT + 1) * TILESIZE, TILESIZE):
pygame.draw.line(DISPLAYSURF, DARKGRAY, (XMARGIN + MARKERSIZE, y +
YMARGIN + MARKERSIZE), (WINDOWWIDTH - (DISPLAYWIDTH + MARKERSIZE *
2), y + YMARGIN + MARKERSIZE))
def add_ships_to_board(board, ships):
"""
Function goes through a list of ships and add them randomly into a board.
board -> list of board tiles
ships -> list of ships to place on board
returns list of board tiles with ships placed on certain tiles
"""
new_board = board[:]
ship_length = 0
for ship in ships: #go through each ship declared in the list
#Randomly find a valid position that fits the ship
valid_ship_position = False
while not valid_ship_position:
xStartpos = random.randint(0, (BOARDHEIGHT-1))
yStartpos = random.randint(0, (BOARDHEIGHT-1))
isHorizontal = random.randint(0, 1) #vertical or horizontal positioning
#Type of ship and their respective length
if 'battleship' in ship:
ship_length = 5
elif 'destroyer' in ship:
ship_length = 4
elif 'cruiser'in ship:
ship_length = 3
elif 'submarine' in ship:
ship_length = 2
elif 'raft' in ship:
ship_length = 1
#check if position is valid
valid_ship_position, ship_coords = make_ship_position(new_board,
xStartpos, yStartpos, isHorizontal, ship_length, ship)
#add the ship if it is valid
if valid_ship_position:
for coord in ship_coords:
new_board[coord[0]][coord[1]] = ship
return new_board
def make_ship_position(board, xPos, yPos, isHorizontal, length, ship):
"""
Function makes a ship on a board given a set of variables
board -> list of board tiles
xPos -> x-coordinate of first ship piece
yPos -> y-coordinate of first ship piece
isHorizontal -> True if ship is horizontal
length -> length of ship
returns tuple: True if ship position is valid and list ship coordinates
"""
ship_coordinates = [] #the coordinates the ship will occupy
if isHorizontal:
for i in range(length):
if (i+xPos > (BOARDHEIGHT-1)) or (board[i+xPos][yPos] != None) or \
hasAdjacent(board, i+xPos, yPos, ship): #if the ship goes out of bound, hits another ship, or is adjacent to another ship
return (False, ship_coordinates) #then return false
else:
ship_coordinates.append((i+xPos, yPos))
else:
for i in range(length):
if (i+yPos > (BOARDHEIGHT-1)) or (board[xPos][i+yPos] != None) or \
hasAdjacent(board, xPos, i+yPos, ship): #if the ship goes out of bound, hits another ship, or is adjacent to another ship
return (False, ship_coordinates) #then return false
else:
ship_coordinates.append((xPos, i+yPos))
return (True, ship_coordinates) #ship is successfully added
def hasAdjacent(board, xPos, yPos, ship):
"""
Funtion checks if a ship has adjacent ships
board -> list of board tiles
xPos -> x-coordinate of first ship piece
yPos -> y-coordinate of first ship piece
ship -> the ship being checked for adjacency
returns true if there are adjacent ships and false if there are no adjacent ships
"""
for x in range(xPos-1,xPos+2):
for y in range(yPos-1,yPos+2):
if (x in range (BOARDHEIGHT)) and (y in range (BOARDHEIGHT)) and \
(board[x][y] not in (ship, None)):
return True
return False
def left_top_coords_tile(tilex, tiley):
"""
Function calculates and returns the pixel of the tile in the top left corner
tilex -> int; x position of tile
tiley -> int; y position of tile
returns tuple (int, int) which indicates top-left pixel coordinates of tile
"""
left = tilex * TILESIZE + XMARGIN + MARKERSIZE
top = tiley * TILESIZE + YMARGIN + MARKERSIZE
return (left, top)
def get_tile_at_pixel(x, y):
"""
Function finds the corresponding tile coordinates of pixel at top left, defaults to (None, None) given a coordinate.
x -> int; x position of pixel
y -> int; y position of pixel
returns tuple (tilex, tiley)
"""
for tilex in range(BOARDWIDTH):
for tiley in range(BOARDHEIGHT):
left, top = left_top_coords_tile(tilex, tiley)
tile_rect = pygame.Rect(left, top, TILESIZE, TILESIZE)
if tile_rect.collidepoint(x, y):
return (tilex, tiley)
return (None, None)
def draw_highlight_tile(tilex, tiley):
"""
Function draws the hovering highlight over the tile.
tilex -> int; x position of tile
tiley -> int; y position of tile
"""
left, top = left_top_coords_tile(tilex, tiley)
pygame.draw.rect(DISPLAYSURF, HIGHLIGHTCOLOR,
(left, top, TILESIZE, TILESIZE), 4)
def show_help_screen():
"""
Function display a help screen until any button is pressed.
"""
line1_surf, line1_rect = make_text_objs('Press a key to return to the game',
BASICFONT, TEXTCOLOR)
line1_rect.topleft = (TEXT_LEFT_POSN, TEXT_HEIGHT)
DISPLAYSURF.blit(line1_surf, line1_rect)
line2_surf, line2_rect = make_text_objs(
'This is a battleship puzzle game. Your objective is ' \
'to sink all the ships in as few', BASICFONT, TEXTCOLOR)
line2_rect.topleft = (TEXT_LEFT_POSN, TEXT_HEIGHT * 3)
DISPLAYSURF.blit(line2_surf, line2_rect)
line3_surf, line3_rect = make_text_objs('shots as possible. The markers on'\
' the edges of the game board tell you how', BASICFONT, TEXTCOLOR)
line3_rect.topleft = (TEXT_LEFT_POSN, TEXT_HEIGHT * 4)
DISPLAYSURF.blit(line3_surf, line3_rect)
line4_surf, line4_rect = make_text_objs('many ship pieces are in each'\
' column and row. To reset your game click on', BASICFONT, TEXTCOLOR)
line4_rect.topleft = (TEXT_LEFT_POSN, TEXT_HEIGHT * 5)
DISPLAYSURF.blit(line4_surf, line4_rect)
line5_surf, line5_rect = make_text_objs('the "New Game" button.',
BASICFONT, TEXTCOLOR)
line5_rect.topleft = (TEXT_LEFT_POSN, TEXT_HEIGHT * 6)
DISPLAYSURF.blit(line5_surf, line5_rect)
while check_for_keypress() == None: #Check if the user has pressed keys, if so go back to the game
pygame.display.update()
FPSCLOCK.tick()
def check_for_keypress():
"""
Function checks for any key presses by pulling out all KEYDOWN and KEYUP events from queue.
returns any KEYUP events, otherwise return None
"""
for event in pygame.event.get([KEYDOWN, KEYUP, MOUSEBUTTONDOWN, MOUSEBUTTONUP, MOUSEMOTION]):
if event.type in (KEYDOWN, MOUSEBUTTONUP, MOUSEBUTTONDOWN, MOUSEMOTION):
continue
return event.key
return None
def make_text_objs(text, font, color):
"""
Function creates a text.
text -> string; content of text
font -> Font object; face of font
color -> tuple of color (red, green blue); colour of text
returns the surface object, rectangle object
"""
surf = font.render(text, True, color)
return surf, surf.get_rect()
def show_gameover_screen(shots_fired):
"""
Function display a gameover screen when the user has successfully shot at every ship pieces.
shots_fired -> the number of shots taken before game is over
"""
DISPLAYSURF.fill(BGCOLOR)
titleSurf, titleRect = make_text_objs('Congrats! Puzzle solved in:',
BIGFONT, TEXTSHADOWCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2))
DISPLAYSURF.blit(titleSurf, titleRect)
titleSurf, titleRect = make_text_objs('Congrats! Puzzle solved in:',
BIGFONT, TEXTCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3)
DISPLAYSURF.blit(titleSurf, titleRect)
titleSurf, titleRect = make_text_objs(str(shots_fired) + ' shots',
BIGFONT, TEXTSHADOWCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2 + 50))
DISPLAYSURF.blit(titleSurf, titleRect)
titleSurf, titleRect = make_text_objs(str(shots_fired) + ' shots',
BIGFONT, TEXTCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2 + 50) - 3)
DISPLAYSURF.blit(titleSurf, titleRect)
pressKeySurf, pressKeyRect = make_text_objs(
'Press a key to try to beat that score.', BASICFONT, TEXTCOLOR)
pressKeyRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 100)
DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
while check_for_keypress() == None: #Check if the user has pressed keys, if so start a new game
pygame.display.update()
FPSCLOCK.tick()
if __name__ == "__main__": #This calls the game loop
main()
Generally there's two ways of doing this.
The more common way is to re-paint the entire screen on each iteration of the main loop.
For example:
### Main Loop
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == pygame.MOUSEBUTTONUP ):
mouse_position = pygame.mouse.get_pos() # Location of mouse-click
player_moves.append ( PlayerMove( mouse_position ) ) # Make a new move
# Re-paint the screen
window.fill( OCEAN_BLUE_COLOUR ) # clear the screen
# Paint each of the players turns
for m in player_moves:
m.draw( window ) # paints a hit or miss icon
pygame.display.flip()
Alternatively, instead of re-painting everything, only change the items that have updated, or when events happen. This is close to the "dirty-rectangles" method of updating.
# Initially paint the screen
window.fill( OCEAN_BLUE_COLOUR ) # clear the screen
### Main Loop
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == pygame.MOUSEBUTTONUP ):
mouse_position = pygame.mouse.get_pos() # Location of mouse-click
move = playerMove( mouse_position )
move.draw( window )
pygame.display.flip()
The difficulty of the second method, is that the program needs to clean up after the movement of on-screen images (otherwise they will leave a trail). Obviously in a battleship game, no on-screen elements move - but things like re-drawing scores or starting a new game will need to somehow erase the background. I'm not sure if this will also re-paint the window after it has been occluded by another window.
If you are a beginner programmer, I would use the first method. It's much simpler, and a lot of games are written this way.
I am currently trying to make conways game of life in python, I am trying to figure out how to make the program read the black squares as on, however I am having no luck, could anyone help. The onoff print currently just prints everything as off (0's) and I want it to print 1's where there is black squares, in order.
import pygame
import random
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
GREY = (0, 210, 230)
WIDTH = 20
HEIGHT = 20
MARGIN = 1
gridsize = 20
onoff = []
grid = []
for row in range(gridsize):
grid.append([])
for column in range(gridsize): # grid
grid[row].append([])
grid[row][column] = 0 # setting value of pixel to off
for x in range(gridsize*gridsize): #onoff update
onoff.append(grid[row][column])
print(onoff)
pygame.init()
WINDOW_SIZE = [21*gridsize, 21* gridsize]
screen = pygame.display.set_mode(WINDOW_SIZE) # screen size
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:# mosue click detection
pos = pygame.mouse.get_pos()
column = pos[0] // (WIDTH + MARGIN)
row = pos[1] // (HEIGHT + MARGIN)
grid[row][column] = 1
print(onoff)
print("Grid coordinates: ", row, column)
for row in range(gridsize):
for column in range(gridsize):
color = WHITE #grid creation
if grid[row][column] == 1:
color = BLACK
pygame.draw.rect(screen,
color,
[(MARGIN + WIDTH) * column + MARGIN, # black rect
(MARGIN + HEIGHT) * row + MARGIN,
WIDTH,
HEIGHT])
clock.tick(60)
pygame.display.flip()
pygame.quit()
onoff = []
grid = []
for row in range(gridsize):
grid.append([])
for column in range(gridsize): # grid
grid[row].append([])
grid[row][column] = 0 # setting value of pixel to off
onoff.append(grid[row][column])
for x in range(len(grid)):
print(grid[x])
its ok i solved it, thanks anyways
I keep on getting this error message every time I run my game that I wrote in Python using Pygame. The error message is:
Traceback (most recent call last):
File "/home/pi/Memory Puzzle_20171029.py", line 248, in <module>
main()
File "/home/pi/Memory Puzzle_20171029.py", line 58, in main
startGameAnimation(mainBoard)
File "/home/pi/Memory Puzzle_20171029.py", line 226, in startGameAnimation
revealBoxesAnimation(board, boxGroups)
File "/home/pi/Memory Puzzle_20171029.py", line 192, in revealBoxesAnimation
drawBoxCovers(board, boxesToReveal, coverage)
File "/home/pi/Memory Puzzle_20171029.py", line 182, in drawBoxCovers
left, top = leftTopCoordsOfBox(box[0], box[1])
File "/home/pi/Memory Puzzle_20171029.py", line 144, in leftTopCoordsOfBox
left = boxx*(BOXSIZE + GAPSIZE) + XMARGIN
TypeError: can only concatenate tuple (not "int") to tuple
Please help, I am a beginner in programming and don't know all the errors in Python. I would be very grateful if you can offer your knowledge and help me fix this problem
Thanks!!!
Here is my script for my game
import random, pygame, sys
from pygame.locals import *
FPS = 30
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
REVEALSPEED = 8
BOXSIZE = 40
GAPSIZE = 10
BOARDWIDTH = 10
BOARDHEIGHT = 7
assert (BOARDWIDTH * BOARDHEIGHT) % 2 == 0,'Board needs to have an even number of boxes for pairs of matches.'
XMARGIN = int((WINDOWWIDTH - (BOARDWIDTH*(BOXSIZE + GAPSIZE)))/2)
YMARGIN = int((WINDOWWIDTH - (BOARDHEIGHT*(BOXSIZE + GAPSIZE)))/2)
GRAY = (100, 100, 100)
NAVYBLUE = (60, 60, 100)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = ( 0, 0,255)
YELLOW = (255, 255, 0)
ORANGE = (255, 255, 0)
PURPLE = (255, 0, 255)
CYAN = ( 0, 255, 255)
BGCOLOR = NAVYBLUE
LIGHTBGCOLOR = GRAY
BOXCOLOR = WHITE
HIGHLIGHTCOLOR = BLUE
DONUT = 'donut'
SQUARE = 'square'
DIAMOND = 'diamond'
LINES = 'lines'
OVAL = 'oval'
ALLCOLORS = (RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, CYAN)
ALLSHAPES = (DONUT, SQUARE, DIAMOND, LINES, OVAL)
assert len(ALLCOLORS) * len(ALLSHAPES)*2 >= BOARDWIDTH*BOARDHEIGHT, 'Board is too big for the number of shapes/colors defined.'
def main():
global FPSCLOCK, DISPLAYSURF
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
mousex = 0
mousey = 0
pygame.display.set_caption('Memory Game')
mainBoard = getRandomizedBoard()
revealedBoxes = generateRevealedBoxesData(False)
firstSelection = None
DISPLAYSURF.fill(BGCOLOR)
startGameAnimation(mainBoard)
while True:
mouseClicked = False
DISPLAYSURF.fill(BGCOLOR)
drawBoard(mainBoard, revealedBoxes)
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
elif event.type == MOUSEMOTION:
mousex, mousey = event.pos
elif event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
mouseClicked = True
boxx, boxy = getBoxAtPixel(mousex, mousey)
if boxx != None and boxy != None:
if not revealedBoxes[boxx][boxy]:
drawHighlightBox(boxx, boxy)
if not revealedBoxes[boxx, boxy] and mouseClicked:
revealBoxesAnimation(mainBoard, [(boxx, boxy)])
revealedBoxes [boxx, boxy] = True
if fisrtSelection == None:
fisrtSelection = (boxx, boxy)
else:
icon1shape, icon1color = getShapeAndColor(mainBoard, firstSelection[0], firstselection[1])
icon2shape, icon2color = getShapeAndColor(mainBoard, boxx, boxy)
if icon1shape != icon2shape or icon1color:
pygame.time.wait(1000)
coverBoxesAnimation(mainBoard, [(firstSelection[0], firstSelection[1]), (boxx, boxy)])
revealedBoxes[firstSelection[0]][firstSelection[1]] = False
revealedBoxes[boxx][boxy] = False
elif hasWon(revealedBoxes):
gameWonAnimation(mainBoard)
pygame.time.wait(2000)
mainBoard = getRandomizedBoard()
revealedBoxes = generateRevealedBoxesData(False)
drawBoard(mainBoard, revealedBoxes)
pygame.display.update()
pygame.time.wait(1000)
startGameAnimation(mainBoard)
firstSelection = None
pygame.display.update()
FPSCLOCK.tick(FPS)
def generateRevealedBoxesData(val):
revealedBoxes =[]
for i in range(BOARDWIDTH):
revealedBoxes.append([val] * BOARDHEIGHT)
return revealedBoxes
def getRandomizedBoard():
icons = [1]
for color in ALLCOLORS:
for shape in ALLSHAPES:
icons.append((shape, color))
random.shuffle(icons)
numIconsUsed = int(BOARDWIDTH * BOARDHEIGHT / 2)
icons = icons[:numIconsUsed] * 2
random.shuffle(icons)
board = [0]
for x in range(BOARDWIDTH):
column = []
for y in range(BOARDHEIGHT):
column.append(icons[0])
del icons[0]
board.append(column)
return board
def splitIntoGroupsOf(groupSize, theList):
result = []
for i in range (0, len(theList), groupSize):
result.append(theList[i:i +groupSize])
return result
def leftTopCoordsOfBox(boxx, boxy):
left = boxx*(BOXSIZE + GAPSIZE) + XMARGIN
top = boxy * (BOXSIZE + GAPSIZE) + YMARGIN
return (left, top)
return(left, top)
def getBoxAtPixel(x, y):
for boxx in range(BOARDWIDTH):
for boxy in range(BOARDHEIGHT):
left,top = leftTopCoordsOfBox(boxx, boxy)
boxRect = pygame.Rect(left, top, BOXSIZE, BOXSIZE)
if boxRect.collidepoint(x, y):
return (boxx, boxy)
return(None, None)
def drawIcon(shape, color, boxx, boxy):
quarter = int(BOXSIZE * 0.25)
half = int(BOXSIZE * 0.5)
left, top = leftTopCoordsOfBox(boxx, boxy)
if shape == DONUT:
pygame.draw.circle(DISPLAYSURF, color, (left + half, top + half), half - 5)
pygame.draw.circle(DISPLAYSURF, BGCOLOR, (left + half, top + half), quarter - 5)
elif shape == SQUARE:
pygame.draw.rect(DISPLAYSURF, color,(left + quarter, top + quarter, BOXSIZE - half, BOXSIZE - half))
elif shape == DIAMOND:
pygame.draw.polygon(DISPLAYSURF, color,((left + half, top), (left + BOXSIZE - 1, top + half), (left + half, top + BOXSIZE - 1), (left, top + half)))
elif shape == LINES:
for i in range(0, BOXSIZE, 4):
pygame.draw.line(DISPLAYSURF, color, (left, top + i), (left + i, top))
pygame.draw.line(DISPLAYSURF, color, (left + i, top + BOXSIZE - 1), (left + BOXSIZE - 1, top + i))
elif shape == OVAL:
pygame.draw.ellipse(DISPLAYSURF, color, (left, top + quarter, BOXSIZE, half))
def getShapeAndColor(board, boxx, boxy):
return board[boxx][boxy][0], board[boxx][boxy][1]
def drawBoxCovers(board, boxes, coverage):
for box in boxes:
left, top = leftTopCoordsOfBox(box[0], box[1])
pygame.draw.rect(DISPLAYSURF, BGCOLOR, (left, top, BOXSIZE, BOXSIZE))
shape, color = getShapeAndColor(board, box[0], box[1])
drawIcon(shape, color, box[0], box[1])
if coverage > 0:
pygame.draw.rect(DISPLAYSURF, BOXCOLOR, (left, top, coverage, BOXSIZE))
pygame.display.update()
FPSCLOCK.tick(FPS)
def revealBoxesAnimation(board, boxesToReveal):
for coverage in range(BOXSIZE, (-REVEALSPEED) - 1, - REVEALSPEED):
drawBoxCovers(board, boxesToReveal, coverage)
def coverBoxesAnimation(board, boxesToReveal):
for coverage in range(BOXSIZE, (-REVEALSPEED) - 1, -REVEALSPEED):
drawBoxCovers(board, boxesToReveal, coverage)
def drawBoard(board, revealed):
for boxx in range(BOARDWIDTH):
for boxy in range(BOARDHEIGHT):
left, top = leftTopCoordsOfBox(boxx, boxy)
if not revealed[boxx][boxy]:
pygame.draw.rect(DISPLAYSURF, BOXCOLOR, (left, top, BOXSIZE, BOXSIZE))
else:
shape, color = getShapeAndColor(board, boxx, boxy)
drawIcon(shape, color, boxx, boxy)
def drawHighlightBox(boxx, boxy):
left, top = leftTopCoordsOfBox(boxx, boxy)
pygame.draw.rect(DISPLAYSURF, HIGHLIGHTCOLOR, (left - 5, top - 5, BOXSIZE + 10, BOXSIZE + 10), 4)
def startGameAnimation(board):
coveredBoxes = generateRevealedBoxesData(False)
boxes = [0]
for x in range(BOARDHEIGHT):
for y in range(BOARDHEIGHT):
boxes.append( (x,y) )
random.shuffle(boxes)
boxGroups = splitIntoGroupsOf(8, boxes)
drawBoard(board, coveredBoxes)
for boxGroup in boxGroups:
revealBoxesAnimation(board, boxGroups)
coverBoxesAnimation(board, boxGroups)
def gameWonAnimation(board):
coveredBoxes = generateRevealedBoxesData(True)
color1 = LIGHTBGCOLOR
color2 = BGCOLOR
for i in range(13):
color1, color2 = color2, color1
DISPLAYSURF.fill(color1)
drawBoard(board, coveredBoxes)
pygame.display.update()
pygame.time.wait(300)
def hasWon(revealedBoxes):
for i in revealedboxes:
if False in i:
return False
return True
if __name__ == '__main__':
main()
You are trying to add/concatenate a tuple to a integer.
left = boxx*(BOXSIZE + GAPSIZE) + XMARGIN
If you want add XMARGIN to both the elements in tuple boxx*(BOXSIZE + GAPSIZE), then do it this way boxx*(BOXSIZE + GAPSIZE) + (XMARGIN, XMARGIN)
I want to add gradient to the ball in this program & also possibly the waves drawn to fade into the colour of the background (as if glowing) instead of one colour fills.
I've looked at tons of tutorials however none of them are making much sense to my syntax, the general idea to me is confusing as I have moving objects that draw the space I want to add gradient to quite slowly. Can anyone give an insight into how I can do this?
code:
import sys, pygame, math
from pygame.locals import *
# set up of constants
WHITE = (255, 255, 255)
DARKRED = (128, 0, 0)
RED = (255, 0, 0)
BLACK = ( 0, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
BGCOLOR = WHITE
screen = pygame.display.set_mode()
WINDOWWIDTH = 800 # width of the program's window, in pixels
WINDOWHEIGHT = 800 # height in pixels
WIN_CENTERX = int(WINDOWWIDTH / 2) # the midpoint for the width of the window
WIN_CENTERY = int(WINDOWHEIGHT / 2) # the midpoint for the height of the window
screen = pygame.display.get_surface()
FPS = 160 # frames per second to run at
AMPLITUDE = 80 # how many pixels tall the waves with rise/fall.
# standard pygame setup code
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), pygame.RESIZABLE)
pygame.display.set_caption('Window title')
fontObj = pygame.font.Font('freesansbold.ttf', 16)
# variables that track visibility modes
showSine = True
showSquare = True
pause = False
xPos = 0
step = 0 # the current input f
posRecord = {'sin': [], 'square': []} # keeps track of the ball positions for drawing the waves
yPosSquare = AMPLITUDE # starting position
# main application loop
while True:
# event handling loop for quit events
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
# fill the screen to draw from a blank state
DISPLAYSURF.fill(BGCOLOR)
# sine wave
yPos = -1 * math.sin(step) * AMPLITUDE
posRecord['sin'].append((int(xPos), int(yPos) + WIN_CENTERY))
if showSine:
# draw the sine ball and label
pygame.draw.circle(DISPLAYSURF, RED, (int(xPos), int(yPos) + WIN_CENTERY), 10)
sinLabelRect.center = (int(xPos), int(yPos) + WIN_CENTERY + 20)
DISPLAYSURF.blit(sinLabelSurf, sinLabelRect)
# draw the waves from the previously recorded ball positions
if showSine:
for x, y in posRecord['sin']:
pygame.draw.circle(DISPLAYSURF, DARKRED, (x,y), 4)
#drawing horizontal lines
# square
posRecord['square'].append((int(xPos), int(yPosSquare) + WIN_CENTERY))
if showSquare:
# draw the sine ball and label
pygame.draw.circle(DISPLAYSURF, GREEN, (int(xPos), int(yPosSquare) + WIN_CENTERY), 10)
squareLabelRect.center = (int(xPos), int(yPosSquare) + WIN_CENTERY + 20)
DISPLAYSURF.blit(squareLabelSurf, squareLabelRect)
# draw the waves from the previously recorded ball positions
if showSquare:
for x, y in posRecord['square']:
pygame.draw.circle(DISPLAYSURF, BLUE, (x, y), 4)
# draw the border
pygame.draw.rect(DISPLAYSURF, BLACK, (0, 0, WINDOWWIDTH, WINDOWHEIGHT), 1)
pygame.display.update()
FPSCLOCK.tick(FPS)
if not pause:
xPos += 1
#wave movement
if xPos > WINDOWWIDTH:
#sine
xPos = 0
posRecord['sin'] = []
step = 0
# square
yPosSquare = AMPLITUDE
posRecord['square'] = []
else:
#sine
step += 0.008
#step %= 2 * math.pi
# square
# jump top and bottom every 100 pixels
if xPos % 100 == 0:
yPosSquare *= -1
# add vertical line
for x in range(-AMPLITUDE, AMPLITUDE):
posRecord['square'].append((int(xPos), int(x) + WIN_CENTERY))
Use SPACE to change background color.
First line use only transparency - and has no problem with different background color.
Second line changes only circles color - and depends on background color.
Third and fourth line (it is the same line with different starting color) change circles color and transparency - and depends on background color.
Second and last line look good on one color background and need more work to find good-looking fading.
import pygame
pygame.init()
screen = pygame.display.set_mode((600,200))
#--------------------------------------
# circles positions and transparency (x,y, alpha)
circles = []
for x in range(100):
circles.append( [100+x*3, 200, x*2] )
#--------------------------------------
white = True # background color
#--------------------------------------
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
elif event.key == pygame.K_SPACE:
white = not white
#--------------------------------------
if white:
screen.fill((255,255,255))
else:
screen.fill((0,0,0))
#--------------------------------------
# first
circle_img = pygame.Surface((20,20))
pygame.draw.circle(circle_img, (255,0,0), (10,10), 10)
circle_img.set_colorkey(0)
for x in circles:
circle_img.set_alpha(x[2])
screen.blit(circle_img, (x[0],40))
#--------------------------------------
# second
circle_img = pygame.Surface((20,20))
for x in circles:
pygame.draw.circle(circle_img, (255,255-x[2],255-x[2]), (10,10), 10)
circle_img.set_colorkey(0)
screen.blit(circle_img, (x[0],90))
#--------------------------------------
# last
circle_img = pygame.Surface((20,20))
for x in circles:
pygame.draw.circle(circle_img, (255,255-x[2],255-x[2]), (10,10), 10)
circle_img.set_colorkey(0)
circle_img.set_alpha(x[2])
screen.blit(circle_img, (x[0],140))
#--------------------------------------
pygame.display.flip()
pygame.quit()
Here is a function from my program, it called when a key is pressed. What is supposed to happen is the key is pressed and a corresponding note is played, and a sine wave appears on the screen also. The sound plays fine, so I won't post any more code for the sound, but it is just the visual side of things that don't work, why won't this wave show?
WINDOWWIDTH = 640 # width of the program's window, in pixels
WINDOWHEIGHT = 480 # height in pixels
WIN_CENTERX = int(WINDOWWIDTH / 2) # the midpoint for the width of the window
WIN_CENTERY = int(WINDOWHEIGHT / 2) # the midpoint for the height of the window
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
fontObj = pygame.font.SysFont('freesansbold.ttf', 16)
FPSCLOCK = pygame.time.Clock()
# set up a bunch of constants
BLUE = ( 0, 0, 255)
WHITE = (255, 255, 255)
DARKRED = (128, 0, 0)
DARKBLUE = ( 0, 0, 128)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
DARKGREEN = ( 0, 128, 0)
YELLOW = (255, 255, 0)
DARKYELLOW = (128, 128, 0)
BLACK = ( 0, 0, 0)
BGCOLOR = WHITE
FPS = 160 # frames per second to run at
pause = False
# making text Surface and Rect objects for various labels
sinLabelSurf = fontObj.render('sine', True, RED, BGCOLOR)
squareLabelSurf = fontObj.render('square', True, BLUE, BGCOLOR)
sinLabelRect = sinLabelSurf.get_rect()
squareLabelRect = squareLabelSurf.get_rect()
def MakeSineWave(freq=1000):
#### visual part ####
xPos = 0
step = 0
AMPLITUDE = 80 # how many pixels tall the waves with rise/fall.
posRecord = {'sin': [], 'line': []}
yPos = -1 * math.sin(step) * AMPLITUDE
posRecord['sin'].append((int(xPos), int(yPos) + WIN_CENTERY))
# draw the sine ball and label
pygame.draw.circle(DISPLAYSURF, DARKRED, (int(xPos), int(yPos) + WIN_CENTERY), 10)
sinLabelRect.center = (int(xPos), int(yPos) + WIN_CENTERY + 20)
DISPLAYSURF.blit(sinLabelSurf, sinLabelRect)
# draw the waves from the previously recorded ball positions
for x, y in posRecord['sin']:
pygame.draw.circle(DISPLAYSURF, DARKRED, (x, y), 4)
# draw the border
pygame.draw.rect(DISPLAYSURF, BLACK, (0, 0, WINDOWWIDTH, WINDOWHEIGHT), 1)
pygame.display.update()
FPSCLOCK.tick(FPS)
if not pause:
xPos += 0.5
if xPos > WINDOWWIDTH:
xPos = 0
posRecord = {'sin': []}
step = 0
else:
step += 0.008
#### audial part ####
return MakeSound(SineWave(freq))
You run MakeSineWave only once - when button is pressed - but code which draws wave have to be run all the time in all loop. It draws longer wave in every loop.
It seems you ask in another question how to draw all wave and move only red ball - and answer need differen changes in MakeSineWave then changes for this question.
EDIT: It is working code - but there is a mess - it needs less code directly in mainloop but more code in some new functions.
import pygame
from pygame.locals import *
import math
import numpy
#----------------------------------------------------------------------
# functions
#----------------------------------------------------------------------
def SineWave(freq=1000, volume=16000, length=1):
num_steps = length * SAMPLE_RATE
s = []
for n in range(num_steps):
value = int(math.sin(n * freq * (6.28318/SAMPLE_RATE) * length) * volume)
s.append( [value, value] )
return numpy.array(s)
#-------------------
def SquareWave(freq=1000, volume=100000, length=1):
num_steps = length * SAMPLE_RATE
s = []
length_of_plateau = int( SAMPLE_RATE / (2*freq) )
print num_steps, length_of_plateau
counter = 0
state = 1
for n in range(num_steps):
value = state * volume
s.append( [value, value] )
counter += 1
if counter == length_of_plateau:
counter = 0
state *= -1
return numpy.array(s)
#-------------------
def MakeSound(arr):
return pygame.sndarray.make_sound(arr)
#-------------------
def MakeSquareWave(freq=1000):
return MakeSound(SquareWave(freq))
#-------------------
def MakeSineWave(freq=1000):
return MakeSound(SineWave(freq))
#-------------------
def DrawSineWave():
# sine wave
yPos = -1 * math.sin(step) * AMPLITUDE
posRecord['sin'].append((int(xPos), int(yPos) + WIN_CENTERY))
if showSine:
# draw the sine ball and label
pygame.draw.circle(screen, RED, (int(xPos), int(yPos) + WIN_CENTERY), 10)
sinLabelRect.center = (int(xPos), int(yPos) + WIN_CENTERY + 20)
screen.blit(sinLabelSurf, sinLabelRect)
# draw the waves from the previously recorded ball positions
if showSine:
for x, y in posRecord['sin']:
pygame.draw.circle(screen, DARKRED, (x, y), 4)
#-------------------
def DrawSquareWave():
# square wave
posRecord['square'].append((int(xPos), int(yPosSquare) + WIN_CENTERY))
if showSquare:
# draw the square ball and label
pygame.draw.circle(screen, GREEN, (int(xPos), int(yPosSquare) + WIN_CENTERY), 10)
squareLabelRect.center = (int(xPos), int(yPosSquare) + WIN_CENTERY + 20)
screen.blit(squareLabelSurf, squareLabelRect)
# draw the waves from the previously recorded ball positions
if showSquare:
for x, y in posRecord['square']:
pygame.draw.circle(screen, BLUE, (x, y), 4)
#----------------------------------------------------------------------
# constants - (uppercase name)
#----------------------------------------------------------------------
# set up a bunch of constants
WHITE = (255, 255, 255)
DARKRED = (128, 0, 0)
RED = (255, 0, 0)
BLACK = ( 0, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
BGCOLOR = WHITE
WINDOWWIDTH = 1200 # width of the program's window, in pixels
WINDOWHEIGHT = 720 # height in pixels
WIN_CENTERX = int(WINDOWWIDTH / 2) # the midpoint for the width of the window
WIN_CENTERY = int(WINDOWHEIGHT / 2) # the midpoint for the height of the window
FPS = 160 # frames per second to run at
AMPLITUDE = 80 # how many pixels tall the waves with rise/fall.
#-------------------
SAMPLE_RATE = 22050 ## This many array entries == 1 second of sound.
SINE_WAVE_TYPE = 'Sine'
SQUARE_WAVE_TYPE = 'Square'
#----------------------------------------------------------------------
# main program
#----------------------------------------------------------------------
#-------------------
# variables (which don't depend on pygame)
#-------------------
sound_types = {SINE_WAVE_TYPE:SQUARE_WAVE_TYPE, SQUARE_WAVE_TYPE:SINE_WAVE_TYPE}
current_type = SINE_WAVE_TYPE
current_played = { 'z': None, 'c': None }
current_drawn = None
#-------------------
# variables that track visibility modes
showSine = True
showSquare = True
xPos = 0
step = 0 # the current input f
posRecord = {'sin': [], 'square': []} # keeps track of the ball positions for drawing the waves
yPosSquare = AMPLITUDE # starting position
#-------------------
# start program
#-------------------
pygame.init()
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), pygame.HWSURFACE | pygame.DOUBLEBUF)
pygame.display.set_caption('Nibbles!')
# making text Surface and Rect objects for various labels
pygame.display.set_caption('Trig Waves')
fontObj = pygame.font.Font('freesansbold.ttf', 16)
### HERE
squareLabelSurf = fontObj.render('square', True, BLUE, BGCOLOR)
squareLabelRect = squareLabelSurf.get_rect()
sinLabelSurf = fontObj.render('sine', True, RED, BGCOLOR)
sinLabelRect = sinLabelSurf.get_rect()
#-------------------
# mainloop
#-------------------
fps_clock = pygame.time.Clock()
_running = True
while _running:
#-------------------
# events
#-------------------
for event in pygame.event.get():
if event.type == pygame.QUIT:
_running = False
# some keys don't depend on `current_type`
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
_running = False
if event.key == K_RETURN:
current_type = sound_types[current_type] #Toggle
print 'new type:', current_type
# some keys depend on `current_type`
if current_type == SINE_WAVE_TYPE:
if event.type == KEYDOWN:
#lower notes DOWN
if event.key == K_z:
print current_type, 130.81
current_played['z'] = MakeSineWave(130.81)
current_played['z'].play()
current_drawn = DrawSineWave
elif event.key == K_c:
print current_type, 180.81
current_played['c'] = MakeSineWave(180.81)
current_played['c'].play()
current_drawn = DrawSineWave
elif event.type == KEYUP:
#lower notes UP
if event.key == K_z:
current_played['z'].fadeout(350)
current_drawn = None
#sine - reset data
xPos = 0
posRecord['sin'] = []
step = 0
elif event.key == K_c:
current_played['c'].fadeout(350)
current_drawn = None
#sine - reset data
xPos = 0
posRecord['sin'] = []
step = 0
elif current_type == SQUARE_WAVE_TYPE:
if event.type == KEYDOWN:
#lower notes DOWN
if event.key == K_z:
print current_type, 130.81
current_played['z'] = MakeSquareWave(130.81)
current_played['z'].play()
current_drawn = DrawSquareWave
elif event.key == K_c:
print current_type, 180.81
current_played['c'] = MakeSquareWave(180.81)
current_played['c'].play()
current_drawn = DrawSquareWave
elif event.type == KEYUP:
#lower notes UP
if event.key == K_z:
current_played['z'].fadeout(350)
current_drawn = None
# square - reset data
xPos = 0
yPosSquare = AMPLITUDE
posRecord['square'] = []
step = 0
elif event.key == K_c:
current_played['c'].fadeout(350)
current_drawn = None
# square - reset data
xPos = 0
yPosSquare = AMPLITUDE
posRecord['square'] = []
step = 0
#-------------------
# draws
#-------------------
# fill the screen to draw from a blank state
screen.fill(BGCOLOR)
if current_drawn:
current_drawn()
pygame.display.update()
#-------------------
# moves
#-------------------
if current_drawn:
xPos += 1.0 #0.5
if xPos > WINDOWWIDTH:
#sine ### HERE
xPos = 0
posRecord['sin'] = []
step = 0
# square ### HERE
yPosSquare = AMPLITUDE
posRecord['square'] = []
else:
#sine ### HERE
step += 0.008
#step %= 2 * math.pi
# square ### HERE
# jump top and bottom every 100 pixels
if xPos % 100 == 0:
yPosSquare *= -1
# add vertical line
for x in range(-AMPLITUDE, AMPLITUDE):
posRecord['square'].append((int(xPos), int(x) + WIN_CENTERY))
#-------------------
# FPS
#-------------------
fps_clock.tick(FPS)
#-------------------
# end program
#-------------------
pygame.quit()
#----------------------------------------------------------------------