Got the basic grouping/dropping mechanism working. Would like to be able to support horizontal groups as well. Sometimes the selection doesn't turn off when dropping a group.

This commit is contained in:
2014-06-04 07:27:30 -07:00
parent 53b231a6b8
commit a0b3a2398b

View File

@@ -1,35 +1,27 @@
import pygame import pygame
import json import json
import copy import copy
import time
import random
maps = [ maps = [
[
[1,2,3,4,1,2,3,4,1,2,3,4],
[1,2,3,4,1,2,3,4,1,2,3,4],
[1,2,3,4,1,2,3,4,1,2,3,4],
[1,2,3,4,1,2,3,4,1,2,3,4]
],
[
[1,1,3,4,1,2,3,4,1,2,3,4],
[1,1,3,4,2,2,2,4,1,2,3,4],
[1,1,3,4,1,2,3,4,1,2,3,4],
[1,1,3,4,1,1,3,4,1,2,3,4]
],
[
[0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,3,0,0,3,3,0,0,0],
[0,0,0,4,2,0,0,4,1,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,1,0,0,0,0,0,0,3,0,0],
[0,0,0,3,0,0,0,0,1,0,0,0],
[0,0,0,0,4,2,3,4,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0]
]
] ]
random.seed(time.time())
for i in range(0, 16):
newmap = []
for i in range(0, 10):
newrow = []
for i in range(0, 16):
newrow.append(random.randint(1, 4))
newmap.append(newrow)
maps.append(newmap)
class Game: class Game:
# Debug flags, disable these before production
DEBUG_MODE = True
# -----
MARBLE_WIDTH = 40 MARBLE_WIDTH = 40
MARBLE_HEIGHT = 40 MARBLE_HEIGHT = 40
COLOR_MAGICPINK = (255, 0, 255, 0) COLOR_MAGICPINK = (255, 0, 255, 0)
@@ -40,8 +32,9 @@ class Game:
STATE_NONE = 0 STATE_NONE = 0
STATE_FALLING = 1 STATE_FALLING = 1
STATE_SELECTED = 2 STATE_SELECTED = 1 << 1
STATE_DEAD = 3 STATE_DEAD = 1 << 2
STATE_PLAYERTOUCHED = 1 << 3
M_IDX_MOVES = 0 M_IDX_MOVES = 0
M_IDX_TYPE = 1 M_IDX_TYPE = 1
@@ -64,6 +57,7 @@ class Game:
self.__moves__ = 0 self.__moves__ = 0
self.__maxMarbleMoves__ = 4 self.__maxMarbleMoves__ = 4
self.__selectedMarble__ = [-1, -1]
self.__setSelectedMarble__([-1, -1]) self.__setSelectedMarble__([-1, -1])
self.__selectionRect__ = None self.__selectionRect__ = None
self.__selectionSurface__ = pygame.Surface( self.__selectionSurface__ = pygame.Surface(
@@ -72,9 +66,10 @@ class Game:
self.__selectionSurface__.fill((255,255,255, 128)) self.__selectionSurface__.fill((255,255,255, 128))
self.__gameFont__ = pygame.font.SysFont(pygame.font.get_default_font(), 18) self.__gameFont__ = pygame.font.SysFont(pygame.font.get_default_font(), 18)
self.__debugFont__ = pygame.font.SysFont(pygame.font.get_default_font(), 12)
self.__mapIndex__ = 0 self.__mapIndex__ = 0
self.__setMap__(maps[self.__mapIndex__]) self.__setMap__(maps[self.__mapIndex__])
#self.__setGroupState__(zap=True)
def __load_marbles__(self): def __load_marbles__(self):
self.__marbles__.append(None) self.__marbles__.append(None)
@@ -87,7 +82,7 @@ class Game:
self.__curMap__ = [] self.__curMap__ = []
self.__curMapRect__ = pygame.Rect( self.__curMapRect__ = pygame.Rect(
((Game.SCREEN_WIDTH - (Game.MARBLE_WIDTH * len(maparray[0])))/2), ((Game.SCREEN_WIDTH - (Game.MARBLE_WIDTH * len(maparray[0])))/2),
((Game.SCREEN_HEIGHT - (Game.MARBLE_HEIGHT * len(maparray)))/2), 0,
(Game.MARBLE_WIDTH * len(maparray[0])), (Game.MARBLE_WIDTH * len(maparray[0])),
(Game.MARBLE_HEIGHT * len(maparray)) (Game.MARBLE_HEIGHT * len(maparray))
) )
@@ -109,6 +104,37 @@ class Game:
y += Game.MARBLE_HEIGHT y += Game.MARBLE_HEIGHT
def __update__(self): def __update__(self):
for ri in range(len(self.__curMap__)-1, -1, -1):
row = self.__curMap__[ri]
ci = 0
for col in row:
if ( (col[Game.M_IDX_TYPE]) and (not self.__hasMarbleState__([ci, ri], Game.STATE_DEAD)) ):
if ( self.__curMap__[ri][ci][Game.M_IDX_TYPE] == 0 ):
self.__curMap__[ri][ci][Game.M_IDX_STATE] = Game.STATE_DEAD
elif ( self.__hasMarbleState__([ci, ri], Game.STATE_FALLING) ):
if ( col[Game.M_IDX_POS][Game.P_IDX_Y] > 800 ):
self.__curMap__[ri][ci][Game.M_IDX_STATE] = Game.STATE_DEAD
continue
col[Game.M_IDX_VEL][Game.P_IDX_Y] += 1
# OH GOD, MY EYES
nextri = (col[Game.M_IDX_POS][Game.P_IDX_Y] + (Game.MARBLE_HEIGHT)) / Game.MARBLE_HEIGHT
if ( ( (nextri) >= (len(self.__curMap__)) ) or
( self.__hasMarbleState__([ci, nextri], Game.STATE_FALLING) ) or
( self.__hasMarbleState__([ci, nextri], Game.STATE_DEAD) ) ):
col[Game.M_IDX_POS][Game.P_IDX_Y] += col[Game.M_IDX_VEL][Game.P_IDX_Y]
elif ( ( ri != (nextri-1 ) ) and
( not self.__hasMarbleState__([ci, nextri], Game.STATE_FALLING) ) and
( not self.__hasMarbleState__([ci, nextri], Game.STATE_DEAD) ) ):
col[Game.M_IDX_POS][Game.P_IDX_Y] = ((nextri-1) * Game.MARBLE_HEIGHT)
self.__delMarbleState__([ci, ri], Game.STATE_FALLING)
self.__flipMarbles__([ci, ri], [ci, nextri-1])
else:
self.__delMarbleState__([ci, ri], Game.STATE_FALLING)
# --- THE GOGGLES DO NOTHING
ci += 1
ri += 1
return return
def __draw__(self): def __draw__(self):
@@ -116,9 +142,11 @@ class Game:
self.__blitTarget__.fill(Game.COLOR_MAGICPINK) self.__blitTarget__.fill(Game.COLOR_MAGICPINK)
if not self.__curMap__: if not self.__curMap__:
return return
ri = 0
for row in self.__curMap__: for row in self.__curMap__:
ci = 0
for col in row: for col in row:
if col[Game.M_IDX_TYPE]: if ( (col[Game.M_IDX_TYPE]) and (col[Game.M_IDX_STATE] != Game.STATE_DEAD)):
x = col[Game.M_IDX_POS][Game.P_IDX_X] x = col[Game.M_IDX_POS][Game.P_IDX_X]
y = col[Game.M_IDX_POS][Game.P_IDX_Y] y = col[Game.M_IDX_POS][Game.P_IDX_Y]
self.__blitTarget__.blit(self.__marbles__[col[Game.M_IDX_TYPE]], (x, y)) self.__blitTarget__.blit(self.__marbles__[col[Game.M_IDX_TYPE]], (x, y))
@@ -126,6 +154,19 @@ class Game:
textpos = text.get_rect(right = x + (Game.MARBLE_WIDTH), textpos = text.get_rect(right = x + (Game.MARBLE_WIDTH),
top = y) top = y)
self.__blitTarget__.blit(text, textpos) self.__blitTarget__.blit(text, textpos)
if Game.DEBUG_MODE:
text = self.__gameFont__.render("{}".format(col[Game.M_IDX_STATE]), 1, Game.COLOR_WHITE)
textpos = text.get_rect(left = x,
bottom = y + Game.MARBLE_HEIGHT)
self.__blitTarget__.blit(text, textpos)
text = self.__gameFont__.render("{},{}".format(ci, ri), 1, Game.COLOR_BLACK)
textpos = text.get_rect(centerx = x + (Game.MARBLE_WIDTH/2),
centery = y + (Game.MARBLE_HEIGHT/2))
self.__blitTarget__.blit(text, textpos)
ci += 1
ri += 1
if self.__selectionRect__ : if self.__selectionRect__ :
self.__blitTarget__.blit( self.__blitTarget__.blit(
self.__selectionSurface__, self.__selectionSurface__,
@@ -134,29 +175,34 @@ class Game:
self.__display__.blit(self.__blitTarget__, (0, 0)) self.__display__.blit(self.__blitTarget__, (0, 0))
def __canSelectMarble__(self, x, y): def __canSelectMarble__(self, x, y):
if self.__curMap__[y][x][Game.M_IDX_STATE] == Game.STATE_DEAD:
return False
if self.__selectedMarble__ == [-1, -1]: if self.__selectedMarble__ == [-1, -1]:
return True return True
curx = self.__selectedMarble__[Game.P_IDX_X] curx = self.__selectedMarble__[Game.P_IDX_X]
cury = self.__selectedMarble__[Game.P_IDX_Y] cury = self.__selectedMarble__[Game.P_IDX_Y]
selectable = [ selectable = [
[curx - 1, cury - 1], # -S---
[curx, cury - 1], # --S-- [curx, cury - 1], # --S--
[curx + 1, cury - 1], # ---S-
[curx - 1, cury], # -SX-- [curx - 1, cury], # -SX--
[curx + 1, cury], # --XS- [curx + 1, cury], # --XS-
[curx, cury + 1] # --S-- [curx - 1, cury + 1], # -S---
[curx, cury + 1], # --S--
[curx + 1, cury + 1] # ---S-
] ]
if [x, y] not in selectable: if [x, y] not in selectable:
return False return False
if self.__curMap__[y][x][Game.M_IDX_STATE] != Game.STATE_NONE:
return False
return True return True
def __flipMarbles__(self, m1, m2): def __flipMarbles__(self, m1, m2, force=False):
if self.__selectedMarble__ == [-1, -1]:
return
# Skip empty (black) marbles # Skip empty (black) marbles
if ( ( self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]][Game.M_IDX_TYPE] == 0 ) or if ( ( self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]][Game.M_IDX_TYPE] == 0 ) or
( self.__curMap__[m2[Game.P_IDX_Y]][m2[Game.P_IDX_X]][Game.M_IDX_TYPE] == 0 ) ): ( self.__curMap__[m2[Game.P_IDX_Y]][m2[Game.P_IDX_X]][Game.M_IDX_TYPE] == 0 ) ):
return return
if ( ( self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]][Game.M_IDX_MOVES] <= 0 ) or
( self.__curMap__[m2[Game.P_IDX_Y]][m2[Game.P_IDX_X]][Game.M_IDX_MOVES] <= 0 ) ):
return
# Swap marbles # Swap marbles
tmp = self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]] tmp = self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]]
@@ -171,22 +217,41 @@ class Game:
# Decrement movecount remaining on both marbles # Decrement movecount remaining on both marbles
self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]][Game.M_IDX_MOVES] -= 1 self.__curMap__[m1[Game.P_IDX_Y]][m1[Game.P_IDX_X]][Game.M_IDX_MOVES] -= 1
self.__curMap__[m2[Game.P_IDX_Y]][m2[Game.P_IDX_X]][Game.M_IDX_MOVES] -= 1 self.__curMap__[m2[Game.P_IDX_Y]][m2[Game.P_IDX_X]][Game.M_IDX_MOVES] -= 1
self.__setSelectedMarble__(m2)
def __setMarbleState__(self, x, y, state): def __setMarbleState__(self, pos, state):
self.__curMap__[y][x][2] = state self.__curMap__[pos[Game.P_IDX_Y]][pos[Game.P_IDX_X]][Game.M_IDX_STATE] = state
def __addMarbleState__(self, pos, state):
cs = self.__curMap__[pos[Game.P_IDX_Y]][pos[Game.P_IDX_X]][Game.M_IDX_STATE]
cs = ( cs | state )
self.__curMap__[pos[Game.P_IDX_Y]][pos[Game.P_IDX_X]][Game.M_IDX_STATE] = cs
def __delMarbleState__(self, pos, state):
if ( not self.__hasMarbleState__(pos, state) ):
return
cs = self.__curMap__[pos[Game.P_IDX_Y]][pos[Game.P_IDX_X]][Game.M_IDX_STATE]
cs = ( cs ^ state )
self.__curMap__[pos[Game.P_IDX_Y]][pos[Game.P_IDX_X]][Game.M_IDX_STATE] = cs
def __hasMarbleState__(self, pos, state):
return ( (self.__curMap__[pos[Game.P_IDX_Y]][pos[Game.P_IDX_X]][Game.M_IDX_STATE] & state) == state)
def __setSelectedMarble__(self, pos): def __setSelectedMarble__(self, pos):
if self.__selectedMarble__ != [-1, -1]:
self.__delMarbleState__(self.__selectedMarble__, Game.STATE_SELECTED)
self.__selectedMarble__ = pos self.__selectedMarble__ = pos
if pos == [-1, -1]: if pos == [-1, -1]:
self.__selectionRect__ = None self.__selectionRect__ = None
return return
if ((self.__curMap__) and (self.__curMap__[pos[Game.P_IDX_Y]][pos[Game.P_IDX_X]][Game.M_IDX_STATE] == Game.STATE_DEAD)):
self.__setSelectedMarble__([-1, -1])
return
self.__selectionRect__ = pygame.Rect( self.__selectionRect__ = pygame.Rect(
(self.__curMapRect__.left + (pos[Game.P_IDX_X] * Game.MARBLE_WIDTH)), (self.__curMapRect__.left + (pos[Game.P_IDX_X] * Game.MARBLE_WIDTH)),
(self.__curMapRect__.top + (pos[Game.P_IDX_Y] * Game.MARBLE_HEIGHT)), (self.__curMapRect__.top + (pos[Game.P_IDX_Y] * Game.MARBLE_HEIGHT)),
Game.MARBLE_WIDTH, Game.MARBLE_WIDTH,
Game.MARBLE_HEIGHT) Game.MARBLE_HEIGHT)
self.__setMarbleState__(pos[Game.P_IDX_X], pos[Game.P_IDX_Y], Game.STATE_SELECTED) self.__addMarbleState__(pos, Game.STATE_SELECTED)
def __mouseClicked__(self, event): def __mouseClicked__(self, event):
mouse_x = event.pos[Game.P_IDX_X] mouse_x = event.pos[Game.P_IDX_X]
@@ -205,14 +270,19 @@ class Game:
return False return False
if event.button == 1: if event.button == 1:
self.__setSelectedMarble__([marble_x, marble_y]) self.__setSelectedMarble__([marble_x, marble_y])
self.__addMarbleState__([marble_x, marble_y], Game.STATE_PLAYERTOUCHED)
self.__setGroupState__()
elif event.button in [2, 3]: elif event.button in [2, 3]:
if not self.__canSelectMarble__(marble_x, marble_y): if not self.__canSelectMarble__(marble_x, marble_y):
return return
self.__delMarbleState__(self.__selectedMarble__, Game.STATE_SELECTED)
self.__flipMarbles__(self.__selectedMarble__, [marble_x, marble_y]) self.__flipMarbles__(self.__selectedMarble__, [marble_x, marble_y])
#self.__setGroupState__() self.__setSelectedMarble__([marble_x, marble_y])
self.__addMarbleState__([marble_x, marble_y], Game.STATE_PLAYERTOUCHED)
self.__setGroupState__()
return return
def __setGroupState__(self): def __setGroupState__(self, zap=False):
groups = { groups = {
0: [], 0: [],
1: [], 1: [],
@@ -224,6 +294,7 @@ class Game:
[], [],
[], [],
[], [],
[],
[] []
] ]
x = 0 x = 0
@@ -236,36 +307,58 @@ class Game:
for col in row: for col in row:
if col[Game.M_IDX_TYPE] != 0: if col[Game.M_IDX_TYPE] != 0:
candidates = [ candidates = [
[x, y - 1], # --C-- # --X--
[x - 1, y], # -CX--
[x + 1, y], # --XC-
[x, y + 1] # --C-- [x, y + 1] # --C--
] ]
for c in candidates: for c in candidates:
if self.__curMap__[c[Game.P_IDX_Y]][c[Game.P_IDX_X]][Game.M_IDX_TYPE] == col[Game.M_IDX_TYPE]: cx = c[Game.P_IDX_X]
if ( (prevy != y and curMatchMarble != col[Game.M_IDX_TYPE]) or cy = c[Game.P_IDX_Y]
(prevy != y) ): if ( (cy >= len(self.__curMap__)) or
curMatchMarble = col[Game.M_IDX_TYPE] (cy < 0 ) or
(cx >= len(self.__curMap__[cy])) or
(cx < 0 ) ):
continue
if ( self.__curMap__[cy][cx][Game.M_IDX_TYPE] == col[Game.M_IDX_TYPE] ):
curMatchMarble = col[Game.M_IDX_TYPE]
group = None
for group in groups[curMatchMarble]:
if ( ( [cx, cy] in group ) or
( [x, y] in group ) ):
break
group = None group = None
for group in groups[curMatchMarble]: if not group:
if ( ( [c[Game.P_IDX_Y], c[Game.P_IDX_X]] in group ) or group = [[x, y]]
( self.__curMap__[c[Game.P_IDX_Y]][c[Game.P_IDX_X]] in group ) ): groups[curMatchMarble].append(group)
break if [cx, cy] in group:
if not group: group.append([x, y])
group = [[c[Game.P_IDX_Y], c[Game.P_IDX_X]]] else:
groups[curMatchMarble].append(group) group.append([cx, cy])
group.append([self.__curMap__[c[Game.P_IDX_Y]][c[Game.P_IDX_X]]])
x += 1 x += 1
prevy = y
y += 1 y += 1
# Go through all the matches, and make sets of all the marbles in groups > 3
for marble, group in groups.iteritems(): for marble, group in groups.iteritems():
for grp in group: for grp in group:
if len(grp) > 2: if len(grp) < 3:
groups_of_3[marble] += grp continue
for group in groups_of_3: # At least one marble in the set has to have been touched by the player
for pair in set(group): for tpair in grp:
self.__curMap__[pair[Game.P_IDX_Y]][pair[Game.P_IDX_X]][2] = Game.STATE_FALLING if self.__hasMarbleState__([tpair[Game.P_IDX_X], tpair[Game.P_IDX_Y]],
Game.STATE_PLAYERTOUCHED):
break
tpair = None
if not tpair:
continue
print "Marking group as falling: {}".format(grp)
for pair in grp:
if self.__hasMarbleState__([tpair[Game.P_IDX_X], tpair[Game.P_IDX_Y]],
Game.STATE_SELECTED):
self.__setSelectedMarble__([-1, -1])
if zap:
self.__curMap__[pair[Game.P_IDX_Y]][pair[Game.P_IDX_X]][Game.M_IDX_STATE] = Game.STATE_DEAD
else:
self.__addMarbleState__(pair, Game.STATE_FALLING)
def run(self): def run(self):
while True: while True:
@@ -282,11 +375,13 @@ class Game:
(self.__mapIndex__ > 0) ): (self.__mapIndex__ > 0) ):
self.__mapIndex__ -= 1 self.__mapIndex__ -= 1
self.__setMap__(maps[self.__mapIndex__]) self.__setMap__(maps[self.__mapIndex__])
self.__setSelectedMarble__([-1, -1])
elif ( (pygame.key.get_pressed()[pygame.K_LCTRL]) and elif ( (pygame.key.get_pressed()[pygame.K_LCTRL]) and
(event.key == pygame.K_RIGHT) and (event.key == pygame.K_RIGHT) and
(self.__mapIndex__ < (len(maps)-1))): (self.__mapIndex__ < (len(maps)-1))):
self.__mapIndex__ += 1 self.__mapIndex__ += 1
self.__setMap__(maps[self.__mapIndex__]) self.__setMap__(maps[self.__mapIndex__])
self.__setSelectedMarble__([-1, -1])
elif event.type == pygame.MOUSEBUTTONUP: elif event.type == pygame.MOUSEBUTTONUP: