[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Background ghosts



I don't usually respond to myself. :-) I thought some more about it and thought that maybe the source code would be helpful. The game needs a lot of spit and polish - the graphics are pretty ugly, the title screen is very basic, and ... oh - the game doesn't end when the tiles pile up over the top. Not to mention that the block sequence is always the same (this is for debugging).

Anyway, if someone wants to take a look, the code is attached...




-----Original Message-----
From: "Michael Phipps" [michael.phipps@xxxxxxxxxxx]
Date: 01/01/2009 13:14
To: pygame-users@xxxxxxxx
Subject: Re: [pygame] Background ghosts

Hi Jake!

Thanks for responding.

The background that I blit in is the same size as the display surface, so I really am clearing the screen. :-/ I can see this - when I complete a row, I redraw the screen and everything looks fine. Then a new sprite starts making its  way down the board (imagine tetris) and, as soon as it is over top of the highest point where a block had been (even though it isn't there because rows disappeared), that old block  "shows through".

As for the splitting the sprites, I considered that. The problem is that when a row is complete (just like in Tetris), a whole piece that fell wouldn't necessarily disappear, but only part of one. I guess I could separate each piece into multiple sprites, but that would involve dozens of sprites and I don't think that the tracking of it would be any better than what I have right now.

Michael




-----Original Message-----
From: "Jake b" [ninmonkeys@xxxxxxxxx]
Date: 12/31/2008 23:12
To: pygame-users@xxxxxxxx
Subject: Re: [pygame] Background ghosts

It looks like you never clear the screen. try something like:
def drawBoard():
   self.screen.fill( (128,128,128) )
   blit background to display
   for piece in fallenPieces:
        blit piece to display
  display.flip()

Why do you split sprites into two groups? ( stopped, and moving )

(Not sure if that will exactly integrate into how your code, is, but
this is what I mean):

class TetrisMain():
	def __init__(self):
		"""init pygame, surfaces, sprite groups"""
		self.screen = #pygame screen
		self.pieces_list = #sprite group filled with pieces
		
	def draw(self):
		"""clear, blit background, blit pieces, flip."""
		self.screen.fill((128,128,128))
		self.screen.blit( self.background, (0,0))
		self.pieces_list.draw(self.screen)
		pygame.display.flip()
		
	def loop(self):
		"""main loop"""
		self.pieces_list.update() # update using sprite group
		self.draw()

On Wed, Dec 31, 2008 at 8:47 PM, Michael Phipps
<michael.phipps@xxxxxxxxxxx> wrote:
> I am finishing up my first pygame; everything has been fun and easy except this:
>
> The game is a tetris-like game (with a twist). I have the falling piece as a sprite. The background is just a bitmap. The pieces that have already fallen, I blit into place. So I have something like (in pseudo code):
>
> def drawBoard():
>    blit background to display
>    for piece in fallenPieces:
>         blit piece to display
>   display.flip()
>
> while 1: # game loop
>    moveSprite()
>    if sprite.nextLocation == taken
>        fallenPieces.Append(sprite.asPiece())
>        sprite = None
>        removeSolidRows() # This removes fallen pieces that have formed complete rows
>        drawboard()
>
> The problem that I have is that as the sprite is falling, I can see rows that have been removed. I have confirmed that drawBoard() is doing the right thing - when the sprite hits the bottom and the screen redraws, the ghosts disappear. They are only there when the sprite floats over them. It looks like the sprite is getting the data from the old version of the screen (i.e. before the last piece fell and rows were removed) to redraw the screen's dirty regions.
>
> Help!
>
> Michael
>



-- 
Jake



import sys, pygame, random
		
class scoreClass:
	value = 100
	def get(self):
		return self.value
	def increment(self,blocks,multiplier):
		self.value+=(100*blocks)*multiplier

class rastras:
	size = width, height = 640, 768
	playfieldSize = 5,12
	blockWidth,blockHeight = 48,48
	playfieldOffset = 60,50
	normalSpeed = 2
	acceleratedSpeed = 8
	score = scoreClass()
	colors = ( (255,0,0), (0,255,0), (0,0,255), (0,255,255), (255,0,255), (255,255,0))
	waysToScore = ((1,0),(0,-1),(-1,-1),(1,-1))

	playfield = blockWidth*playfieldSize[0],blockHeight*playfieldSize[1]
	playfieldBottom = playfield[1]+playfieldOffset[1]
	scoreLocation = width/2 + (playfield[0]+playfieldOffset[0])/2, height/3 

	pygame.init()
	screen = pygame.display.set_mode(size)
	clock = pygame.time.Clock()
	font = pygame.font.Font(None, 24)

	light = pygame.Surface((blockWidth,blockHeight)).convert()
	light.set_alpha(180,pygame.RLEACCEL)
	light.fill((255,255,255),(0,0,blockWidth-1,blockHeight-1))
	dark = pygame.Surface((blockWidth,blockHeight)).convert()
	dark.set_alpha(75,pygame.RLEACCEL)
	dark.fill((0,0,0,128),(0,0,blockWidth-1,blockHeight-1))
	white = pygame.Surface((blockWidth,blockHeight)).convert()
	white.fill((255,255,255),(0,0,blockWidth-1,blockHeight-1))
	black = pygame.Surface((blockWidth,blockHeight)).convert()
	black.fill((0,0,0,0),(0,0,blockWidth-1,blockHeight-1))
	flashSurfaces = (None,dark,black,dark,None,light,white,light)
	blocks = []
	background = None

	def loadblocks(self):
		for block in range(len(self.colors)):
			self.blocks.append(pygame.Surface((self.blockWidth,self.blockHeight)).convert())
			self.blocks[block].fill(self.colors[block],(1,1,self.blockWidth-1,self.blockHeight-1))

	def loadbackground(self):
		self.background = pygame.Surface(self.size)
		self.background.fill((80,90,240))
		self.background.fill((220,220,220),(self.playfieldOffset,self.playfield))

	def makenewblocksprite(self,group):
		blocksprite = pygame.sprite.Sprite(group)
		blockspriteImage = pygame.Surface((self.blockWidth,3*self.blockHeight))
		blocksprite.image=blockspriteImage
		blocksprite.rect = pygame.Rect(self.playfieldOffset,(self.blockWidth,3*self.blockHeight))
		self.orderblocksprite(blocksprite, (0,1,2))
		#orderblocksprite(blocksprite, (random.randint(0,0),random.randint(0,0),random.randint(0,0)))
		#orderblocksprite(blocksprite, (random.randint(0,5),random.randint(0,5),random.randint(0,5)))
		return blocksprite

	def orderblocksprite(self,blocksprite, order):
		blocksprite.order = order
		blocksprite.image.blit(self.blocks[order[0]],(0,0 ))
		blocksprite.image.blit(self.blocks[order[1]],(0,self.blockHeight))
		blocksprite.image.blit(self.blocks[order[2]],(0,2*self.blockHeight))

	def rotateblocksprite(self,blocksprite):
		order=(blocksprite.order[1],blocksprite.order[2],blocksprite.order[0])
		orderblocksprite(blocksprite, order)
		
	def heightToBlock(self,height):
		return (height-self.playfieldOffset[1])/self.blockHeight

	def updateBoard(self,sprite,position): # Add stuff to the board
		bottomMost = self.heightToBlock(sprite.rect.bottom)-1
		self.board[bottomMost][position] = sprite.order[2]
		self.board[bottomMost-1][position] = sprite.order[1]
		self.board[bottomMost-2][position] = sprite.order[0]
		multiplier = 1
		while (self.cullBoard2(multiplier)):
			multiplier*=2

	def flashSquare(self,locations,frame):
		surface = self.flashSurfaces[frame%8]
		self.drawBoard(False)
		if surface != None:
			for location in locations:
				self.screen.blit(surface, (self.playfieldOffset[0]+self.blockWidth*location[0],self.playfieldOffset[1]+self.blockHeight*location[1]))
		pygame.display.flip()

	def cullBoard2(self,multiplier):
		for y in range (self.playfieldSize[1]-1,0,-1):
			for x in range (0,self.playfieldSize[0] ):
				for way in self.waysToScore:
					thisscore = self.findGroup(x,y,way[0],way[1])
					if (thisscore>=3):
						self.score.increment(thisscore,multiplier)
						return True
		return False

	def findGroup(self,x,y,deltax,deltay):
		lookingFor = self.board[y][x]
		if (lookingFor == -1):
			return 0
		for blockToTry in range(0,max (self.playfieldSize[0],self.playfieldSize[1])):
			newx = x + deltax*blockToTry 
			newy = y + deltay*blockToTry 

			if newx<0 or newx>=self.playfieldSize[0] or newy<0 or newy>=self.playfieldSize[1] or self.board[newy][newx]!=lookingFor:
				if blockToTry >= 3:
					locations = []
					for offset in range (blockToTry):	
						locations.append((x+deltax*offset,y+deltay*offset))

					locations.sort(None,lambda x:x[1],False) #sort locations by y to prevent out of order removals which will corrupt...

					for frame in range (0,24):
						self.flashSquare(locations,frame)
						self.clock.tick(15)

					for location in locations:
						for deltay in range (location[1],1,-1):
								self.board[deltay][location[0]]=self.board[deltay-1][location[0]]
				return blockToTry

		return 0
		
	def drawBoard(self,done): 
		self.screen.blit(self.background,self.screen.get_rect())
		for x in range(self.playfieldSize[0]):
			for y in range(self.playfieldSize[1]):
				if (self.board[y][x]==-1):
	#				screen.blit(playfieldBackground, (playfieldOffset[0]+blockWidth*x,playfieldOffset[1]+blockHeight*y), (blockWidth*x,blockHeight*y,blockWidth,blockHeight))
					pass
				else:
					self.screen.blit(self.blocks[self.board[y][x]],
							(self.playfieldOffset[0]+self.blockWidth*x,self.playfieldOffset[1]+self.blockHeight*y))

		# Display the score
		text = self.font.render(str(self.score.get()), True, (255, 255, 255), (200, 50, 60))
		textRect = text.get_rect()
		textRect.centerx = self.scoreLocation[0]
		textRect.centery = self.scoreLocation[1]
		self.screen.blit(text, textRect)

		if (done == True):
			pygame.display.flip()
		
	def playgame(self):
		receiveLR=True
		position = 0
		self.loadblocks()
		group = pygame.sprite.Group()
		blocksprite = self.makenewblocksprite(group)
		updateRect = pygame.Rect(0,0,self.blockWidth,self.blockHeight*3+self.acceleratedSpeed+1)

		self.loadbackground()

		# Setup the board; -1 == empty
		self.board = [[-1 for col in range(self.playfieldSize[0])] for row in range(self.playfieldSize[1])] 

		self.drawBoard(True)


		while 1:
			receiveLR = not receiveLR
			for event in pygame.event.get():
				if event.type == pygame.QUIT: sys.exit()
			keys = pygame.key.get_pressed()
			if (keys[pygame.K_RIGHT] and position < 4 and receiveLR):
					position+=1

			if (keys[pygame.K_LEFT] and position > 0 and receiveLR):
				position -=1

			if (keys[pygame.K_UP] and receiveLR):
				self.rotateblocksprite(blocksprite)

			group.clear(self.screen,self.background)
			updateRect.top, updateRect.left = blocksprite.rect.top, blocksprite.rect.left 
			blocksprite.rect.top +=  self.acceleratedSpeed if (keys[pygame.K_DOWN]) else self.normalSpeed
			blocksprite.rect.left = position*self.blockWidth+self.playfieldOffset[0]

			if blocksprite.rect.top < 0 or blocksprite.rect.bottom >= self.playfieldBottom or \
					self.board[self.heightToBlock(blocksprite.rect.bottom)][position]!=-1:
				self.updateBoard(blocksprite,position)
				blocksprite = self.makenewblocksprite(group)
				self.drawBoard(True)
			else:
				group.draw(self.screen)
				pygame.display.update([updateRect])

			self.clock.tick(20)

def titlescreen():
	game = rastras()
	font = pygame.font.Font(None, game.width/10)
	text = font.render("Apelsinas Software", True, (255, 90, 25), (0, 0, 0))
	textRect = text.get_rect()
	textRect.centerx = game.width/2
	textRect.top = 10
	game.screen.blit(text, textRect)
	text = font.render("presents...", True, (40, 60, 255), (0, 0, 0))
	textRect2 = text.get_rect()
	textRect2.centerx = game.width/2
	textRect2.top = textRect.bottom + 10
	game.screen.blit(text, textRect2)
	font = pygame.font.Font(None, game.width/3)
	text = font.render("Rastras", True, (40, 255, 60), (0, 0, 0))
	textRect3 = text.get_rect()
	textRect3.centerx = game.width/2
	textRect3.top = textRect2.bottom + 10
	game.screen.blit(text, textRect3)
	pygame.display.flip()
	for i in range (1, 100):
		game.clock.tick(20)
	game.playgame()

titlescreen()