Managing a Grid of Objects by their Properties

Started by
-1 comments, last by PaladinJohn 12 years ago
First off, apologies for posting a request for help on this same project again, but I'm determined to see it through to it's conclusion no matter how many obstacles get in my way. I've made a personal promise not to ask for outside help unless I've been stuck on the same problem for more than a week, but once again I've hit a brick wall. In my previous threads I didn't recieve any responses and eventually figured out how to solve the problem, but this time I can say with confidence that I've hit the biggest one yet. So, for that, any insight or advice would be very much greatly appreciated. Even if I do not recieve an answer to my problem, even just a different perspective on trying to solve it might help me figure things out on my own. Here's a little background and the problem:

After reading several books on Python cover to cover, I decided that I would attempt to apply my knowledge in creating a game from scratch on my own. Every thing I read suggested Tetris as a baseline, but rather than listen I went with a game I didn't think would be much different in remaking Dr. Mario. I have almost all of the basic game elements finished, with the exception of perhaps the most important: Detecting and clearing lines. I thought I would pass objects onto a grid with an element property that detected what color each game piece was, then search the columns and rows for any sequences of objects with the same element greater than 3, and then clear them. Unfortunately, in troubleshooting my program, I realized that all of the elements in the list are inheriting the current game piece's elements and not retaining their own. This leads me to believe that the method I am using for putting them on the grid is faulty. I can't tell where I messed up, or how I could have done it better since everything graphically is working as it should. Below are the problem areas of the program I believe have a problem somewhere:

def draw(self, occupiedGrid):
for x in range(0, NUM_COLUMNS):
for y in range (0, NUM_ROWS):
if self.occupiedGrid[x][y] != 0:
self.element = Element(self.occupiedGrid[x][y].element, self.occupiedGrid[x][y].linked, self.occupiedGrid[x][y].dir)
self.element.x = self.occupiedGrid[x][y].x
self.element.y = self.occupiedGrid[x][y].y
self.element.populate()
self.inactiveSprites.add(self.element)


and:

def clearObjects(self, occupiedGrid):
self.matchedElements = []

for x in range (0, NUM_COLUMNS):
self.temp_list = []
for i in range(0, NUM_ROWS):
if self.occupiedGrid[x] != 0:
self.temp_list.append(self.occupiedGrid[x])
if len(self.temp_list) >= 4:
self.matchedElements = self.matchedElements + self.temp_list
print self.matchedElements[0].element


Please note that clearObjects() is currently written as a debug method and not as what I intend for it to be in the final program. It was at this point that I discovered the grid elements were not appearing as they were supposed to.

Once again, thank you for any one who took a look at this. I know that after I get proper clearing and bpard state settling implemented, everything left is all down hill from there and will take me very little time to finish off the program. If my technique or ideas in implementing this game are completely off as well, feel free to let me know. I would rather be shown new ideas and methods at this early stage in my programming journey than develop bad habits that are hard to get out of later on down the road. I have been demoralized by this project since I started it in late January and still haven't made decent progress all these months later and keep running into problem after problem with my now very apparent limited understanding of programming. For that, I would appreciate any and all insight I can recieve to save me weeks from staring at my computer screen, randomly punching in new code until something clicks by happenstance.

The full code is below in case the problem is contained somewhere outside of these two functions:


import pygame, random
pygame.init()

NUM_COLUMNS = 8
NUM_ROWS = 16

DOWN = 1
LEFT = 2
RIGHT = 3
ROTATE = 4

screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()

class Element(pygame.sprite.Sprite):
def __init__(self, element, linked, direction):
self.element = element
self.dir = direction
self.linked = linked
pygame.sprite.Sprite.__init__(self)
self.imageMaster = pygame.image.load("WMana.xcf")
self.generateElements()
self.image = self.imageMaster
self.rect = self.image.get_rect()
self.image.set_colorkey((255, 255, 255))
self.x = 0
self.y = 0

def generateElements(self):
#1 = W, 2 = G, 3 = Y
if self.element == 0:
self.element = random.randrange(1, 4)
if self.linked == True:
if self.element ==1:
self.imageMaster = pygame.image.load("piece_white.png")
elif self.element == 2:
self.imageMaster = pygame.image.load("piece_green.png")
elif self.element == 3:
self.imageMaster = pygame.image.load("piece_yellow.png")
if self.linked == False:
if self.element == 1:
self.imageMaster = pygame.image.load("WMana.xcf")
elif self.element == 2:
self.imageMaster = pygame.image.load("GMana.xcf")
elif self.element == 3:
self.imageMaster = pygame.image.load("YMana.xcf")
self.imageMaster = self.imageMaster.convert()

def resetElement(self):
self.element = random.randrange(1,4)
self.generateElements()

def populate(self):
self.image = pygame.transform.rotate(self.imageMaster, self.dir)
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y - 20)

class Mana(pygame.sprite.Sprite):
def __init__(self, pelement, selement):
self.pelement = pelement
self.selement = selement
pygame.sprite.Sprite.__init__(self)
self.imageMaster = pygame.image.load("testWW.xcf")
self.reset()
self.wait = 0
self.drop = 12
self.moving = 0

def update(self):
self.rotate()
self.rect.bottomleft = (self.x, self.y)
self.wait += 1
self.checkPos()

def elements(self):
if self.pelement.element == 1:
if self.selement.element == 1:
self.imageMaster = pygame.image.load("testWW.xcf")
elif self.selement.element == 2:
self.imageMaster = pygame.image.load("testWG.xcf")
elif self.selement.element == 3:
self.imageMaster = pygame.image.load("testWY.xcf")
elif self.pelement.element == 2:
if self.selement.element == 1:
self.imageMaster = pygame.image.load("testGW.xcf")
elif self.selement.element == 2:
self.imageMaster = pygame.image.load("testGG.xcf")
elif self.selement.element == 3:
self.imageMaster = pygame.image.load("testGY.xcf")
elif self.pelement.element == 3:
if self.selement.element == 1:
self.imageMaster = pygame.image.load("testYW.xcf")
elif self.selement.element == 2:
self.imageMaster = pygame.image.load("testYG.xcf")
elif self.selement.element == 3:
self.imageMaster = pygame.image.load("testYY.xcf")
self.imageMaster = self.imageMaster.convert()

def rotate(self):
oldBL = self.rect.bottomleft
self.image = pygame.transform.rotate(self.imageMaster, self.dir)
self.rect = self.image.get_rect()
self.rect.bottomleft = oldBL

def checkPos(self):
if self.dir == 0 or self.dir == 360:
self.pelement.x = (self.x + 10)
self.pelement.y = (self.y + 10)
self.pelement.dir = 0
self.selement.x = (self.x + 30)
self.selement.y = (self.y + 10)
self.selement.dir = 180
elif self.dir == 90:
self.pelement.x = (self.x + 10)
self.pelement.y = (self.y + 10)
self.pelement.dir = 90
self.selement.x = (self.x + 10)
self.selement.y = (self.y - 10)
self.selement.dir = 270
elif self.dir == 180:
self.pelement.x = (self.x + 30)
self.pelement.y = (self.y + 10)
self.pelement.dir = 180
self.selement.x = (self.x + 10)
self.selement.y = (self.y + 10)
self.selement.dir = 0
elif self.dir == 270:
self.pelement.x = (self.x + 10)
self.pelement.y = (self.y - 10)
self.pelement.dir = 270
self.selement.x = (self.x + 10)
self.selement.y = (self.y + 10)
self.selement.dir = 90

def land(self, occupiedGrid):
occupiedGrid[ xToGrid(self.pelement.x) ][ yToGrid(self.pelement.y) ] = self.pelement
occupiedGrid[ xToGrid(self.selement.x) ][ yToGrid(self.selement.y) ] = self.selement

def reset(self):
self.pelement.resetElement()
self.selement.resetElement()
self.elements()
self.image = self.imageMaster
self.rect = self.image.get_rect()
self.image.set_colorkey((255, 255, 255))
self.x = 300
self.y = 100
self.dir = 0

def checkCollision(self, inactiveSprites, occupiedGrid):
if self.moving == DOWN:
if self.rect.bottom > 380:
return True
if self.moving == LEFT:
if self.rect.left < 260:
return True
if self.moving == RIGHT:
if self.rect.right > 400:
return True

for x in range(0,NUM_COLUMNS):
for y in range(0,NUM_ROWS):
if self.moving == DOWN:
if occupiedGrid[xToGrid(self.pelement.x)][yToGrid(self.pelement.y + 20)]:
return True
elif occupiedGrid[xToGrid(self.selement.x)][yToGrid(self.selement.y + 20)]:
return True
if self.moving == LEFT:
if occupiedGrid[xToGrid(self.pelement.x - 20)][yToGrid(self.pelement.y)]:
return True
elif occupiedGrid[xToGrid(self.selement.x - 20)][yToGrid(self.selement.y)]:
return True
if self.moving == RIGHT:
if occupiedGrid[xToGrid(self.pelement.x + 20)][yToGrid(self.pelement.y)]:
return True
elif occupiedGrid[xToGrid(self.selement.x + 20)][yToGrid(self.selement.y)]:
return True
if self.moving == ROTATE:
if occupiedGrid[xToGrid(self.pelement.x)][yToGrid(self.pelement.y)]:
return True
if occupiedGrid[xToGrid(self.selement.x)][yToGrid(self.selement.y)]:
return True

return False

class Backdrop(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("Border.xcf")
self.image = self.image.convert()
self.rect = self.image.get_rect()

def update(self):
self.rect.center = (320, 240)

class Game():
def __init__(self):
pygame.display.set_caption("Mana Clash!")

self.background = pygame.Surface(screen.get_size())
self.background.fill((100, 100, 100))
screen.blit(self.background, (0, 0))

self.getNewMana()
self.backdrop = Backdrop()

self.occupiedGrid = []
for x in range(0, NUM_COLUMNS):
self.occupiedGrid.append([])
for y in range(0, NUM_ROWS):
self.occupiedGrid[x].append(0)

self.allSprites = pygame.sprite.OrderedUpdates(self.backdrop, self.mana)
self.inactiveSprites = pygame.sprite.OrderedUpdates()

def getNewMana(self):
self.pelement = Element(0, True, 0)
self.selement = Element(0, True, 0)
self.mana = Mana(self.pelement, self.selement)

def debug(self, occupiedGrid):
for x in range(0, NUM_COLUMNS):
for y in range (0, NUM_ROWS):
if self.occupiedGrid[x][y] != 0:
print self.occupiedGrid[x][y].element

def draw(self, occupiedGrid):
for x in range(0, NUM_COLUMNS):
for y in range (0, NUM_ROWS):
if self.occupiedGrid[x][y] != 0:
self.element = Element(self.occupiedGrid[x][y].element, self.occupiedGrid[x][y].linked, self.occupiedGrid[x][y].dir)
self.element.x = self.occupiedGrid[x][y].x
self.element.y = self.occupiedGrid[x][y].y
self.element.populate()
self.inactiveSprites.add(self.element)

def settle(self):
self.mana.land(self.occupiedGrid)
self.draw(self.occupiedGrid)
self.mana.reset()

def checkKeys(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.mana.moving = 2
self.mana.checkPos()
if self.mana.checkCollision(self.inactiveSprites, self.occupiedGrid) == False:
self.mana.x -= 20
if keys[pygame.K_RIGHT]:
self.mana.moving = 3
if self.mana.dir == 0 or self.mana.dir == 180 or self.mana.dir == 360:
if self.mana.x <= 340:
self.mana.checkPos()
if self.mana.checkCollision(self.inactiveSprites, self.occupiedGrid) == False:
self.mana.x += 20
elif self.mana.dir == 90 or self.mana.dir == 270:
if self.mana.rect.right <= 380:
self.mana.checkPos()
if self.mana.checkCollision(self.inactiveSprites, self.occupiedGrid) == False:
self.mana.x += 20
if keys[pygame.K_DOWN]:
self.mana.moving = 1
self.mana.checkPos()
if self.mana.checkCollision(self.inactiveSprites, self.occupiedGrid) == False:
self.mana.y += 20
self.mana.wait = 0
elif self.mana.checkCollision(self.inactiveSprites, self.occupiedGrid) == True:
self.settle()

def fall(self):
if self.mana.wait >= self.mana.drop:
self.mana.wait = 0
self.mana.moving = 1
self.mana.checkPos()
if self.mana.checkCollision(self.inactiveSprites, self.occupiedGrid) == False:
self.mana.y += 20
elif self.mana.checkCollision(self.inactiveSprites, self.occupiedGrid) == True:
self.settle()

def clearObjects(self, occupiedGrid):
self.matchedElements = []

for x in range (0, NUM_COLUMNS):
self.temp_list = []
for i in range(0, NUM_ROWS):
if self.occupiedGrid[x] != 0:
self.temp_list.append(self.occupiedGrid[x])
if len(self.temp_list) >= 4:
self.matchedElements = self.matchedElements + self.temp_list
print self.matchedElements[0].element


def mainLoop(self):
keepGoing = True
while keepGoing:
clock.tick(10)
pygame.mouse.set_visible(False)
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RCTRL:
if self.mana.dir == 90 or self.mana.dir == 270:
if self.mana.x == 380:
self.mana.x -= 20
self.mana.moving = 4
self.mana.dir += 90
self.mana.checkPos()
if self.mana.checkCollision(self.inactiveSprites, self.occupiedGrid) == True:
self.mana.dir -= 90
if self.mana.dir > 360:
self.mana.dir = 90
elif event.key == pygame.K_RALT:
if self.mana.dir == 90 or self.mana.dir == 270:
if self.mana.x == 380:
self.mana.x -= 20
self.mana.moving = 4
self.mana.dir -= 90
self.mana.checkPos()
if self.mana.checkCollision(self.inactiveSprites, self.occupiedGrid) == True:
self.mana.dir += 90
if self.mana.dir < 0:
self.mana.dir = 270

if event.key == pygame.K_d:
self.debug(self.occupiedGrid)
if event.key == pygame.K_s:
self.clearObjects(self.occupiedGrid)

self.checkKeys()
self.fall()

self.allSprites.clear (screen, self.background)
self.inactiveSprites.clear (screen, self.background)
self.allSprites.update()
self.inactiveSprites.update()
self.allSprites.draw(screen)
self.inactiveSprites.draw(screen)

pygame.display.update()

pygame.mouse.set_visible(True)

def main():
game = Game()
game.mainLoop()

def xToGrid(pixel_coordinate):
return ((pixel_coordinate - 10) - 240) / 20

def yToGrid(pixel_coordinate):
return ((pixel_coordinate - 10) - 100) / 20

if __name__ == "__main__":
main()

This topic is closed to new replies.

Advertisement