My code as of now is as below:
width = 200
class G:
My code as of now is as below:
width = 200
class G:
Welcome @millionish!
I’ll address the collision detection first –
This is kinda hacky, but it’ll work. I’m using the get()
function to detect if the adjacent cells are background-coloured (therefore, empty). I’ve drawn some points (after the checks) to indicate the coordinates I’m sampling.
...
if get(x+10, y+30) == -2960686:
print('cell below is empty')
if get(x+10, y+30) == -2960686:
print('cell to the right is empty')
if get(x+10, y+30) == -2960686:
print('cell to the left is empty')
stroke(5)
point(x+10, y+30)
point(x+30, y+10)
point(x-10, y+10)
moveDown(1)
-2960686
is the color code for background(210)
. You can find this out by sampling any background pixel using get()
.
To be honest, I’d approach this task differently – instead, use a 2D-list to store the block locations, to check for collisions, etc. You can render the tiles using this list. Conceptually, something like:
cells = [
[ 0, 0, 0, 0 ],
[ 0, 0, 0, 0 ],
[ 0, 0, 0, 0 ],
[ G, 0, R, 0 ],
[ 0, B, R, 0 ],
]
So, for example, I can determine whether G (cells[3,0]
) can move another row down by checking if cells[4,0]
is a zero.
If you prefer your current approach, that’s cool. In that case, it’s probably a good to start with a class for each falling box:
class Box:
def __init__(self):
self.fill = (225, 0, 0)
self.x = 0
self.y = 0
...
You can use this to spawn new Box instances, in random positions, using random fills, and so on.
If I may, @millionish can also make use of Processing built-in functions like:
constrain()
to keep the x
and y
coordinates within the boundaries of the canvascreateShape()
to display the grid permanently and avoid computing it at each frameframeCount
to manage the descent rate of the moving rectangleI would also second @tabreturn’s suggestion regarding the collision detection part. In this case, looking for the state of the cell below the currently visited cell is probably the best way to go.
Example with 1D list:
W, H = 200, 400 # dimensions of canvas
nC, nR = 10, 20 # number of cols and rows
S = W/nC # step / size of unit cell
x, y = 80, -S # coordinates of starting cell
disabled = False # keyboard is NOT disabled
filled = [i for i in xrange(163,180) if random(1)>.6] + range(173, 200) # randomly fill the bottom of the grid
def setup():
size(W, H)
fill(225,0,0)
updateGrid() # function that creates a grid showing both 'filled' and 'empty' cells
def draw():
global y, disabled
shape(grid) # display the grid
rect(x,y,S,S) # draw the moving rectangle (red)
t = frameCount%20 == 0 # time/tempo of descent
id = (x//S)+(y//S)*nC # convert coordinates to 1D index of currently visited cell (red)
if id+nC not in filled: # if no blue cell below: (note: 'id+nC' = index of cell below)
if t and y < H-S: # if time to move down and empty cell below is within canvas:
y+=S # -> increment 'y' position
else: # else:
disabled = True # -> disable keyboard
if t: # when time to move:
filled.append(id) # -> put id of current cell (red) in 'filled' array list
updateGrid() # -> update the grid accordingly
y = -S # -> reset 'y' position
disabled = False # -> re-enable keyboard
def keyPressed():
global x, y
if not disabled:
k = keyCode
if k == 39: x+=S # move RIGHT
elif k == 37: x-=S # move LEFT
elif k == 40: y+=S # move DOWN
x = constrain(x, 0, W-S) # make sure that x and y coordinates stay within the boundaries of canvas
y = constrain(y, 0, H-S)
def updateGrid():
global grid
grid = createShape(GROUP)
for i in xrange(nC*nR):
cell = createShape(RECT, (i%nC)*S, (i//nC)*S, S, S)
cell.setFill(color(0, 180, 255) if i in filled else 255)
grid.addChild(cell)
Hey Thank you so much for your help and efforts!!!
Also, I wish to remove those random blue filled cells at bottom and start doing that when first square falls down. It should basically retain its colours and not turn blue. How do I do that?
All the code I posted is carefully annotated. If you look at line 7 I have written # randomly fill the bottom of the grid
. If you don’t want anything at start (an unfilled grid), just delete the content of the filled
list.
You could pick a random color at each start and save it in a list when the square is being stopped. This way, the updateGrid()
function knows what color to assign to each grid cell for the next run.
To change the stroke width and color of the grid cells just add:
cell.setStrokeWeight( a float )
cell.setStroke( an int )
inside the updateGrid()
function
Full sketch (annotated)
W, H = 200, 400 # dimensions of canvas
nC, nR = 10, 20 # number of cols and rows
S = W/nC # step / size of unit cell
x, y = 80, -S # coordinates of starting cell
disabled = False # keyboard is NOT disabled
filled = [] # list storing the cells that have been stopped
colors = [255] * nC*nR # list storing the colors of each grid cell
curcol = color(random(80,255),random(80,255),random(80,255)) # current color (picked randomly)
def setup():
size(W, H)
updateGrid() # function that creates a grid showing both 'filled' and 'empty' cells
def draw():
global y, curcol, disabled
shape(grid) # display the grid
fill(curcol)
rect(x,y,S,S) # draw the moving rectangle (red)
t = frameCount%20 == 0 # time/tempo of descent
id = (x//S)+(y//S)*nC # convert coordinates to 1D index of currently visited cell (red)
if id+nC not in filled and id+nC<nC*nR: # if no blue cell below: (note: 'id+nC' = index of cell below)
if t and y < H-S: # if time to move down and empty cell below is within canvas:
y+=S # -> increment 'y' position
else: # else:
disabled = True # -> disable keyboard
if t: # when time to move:
filled.append(id) # -> put id of current cell (red) in 'filled' array list
colors[id] = curcol # -> store current color to 'colors' list
curcol = color(random(80,255),random(80,255),random(80,255)) # -> pick a new color at random
updateGrid() # -> update the grid accordingly
y = -S # -> reset 'y' position
disabled = False # -> re-enable keyboard
def keyPressed():
global x, y
if not disabled:
k = keyCode
if k == 39: x+=S # move RIGHT
elif k == 37: x-=S # move LEFT
elif k == 40: y+=S # move DOWN
x = constrain(x, 0, W-S) # make sure that x and y coordinates stay within the boundaries of canvas
y = constrain(y, 0, H-S)
def updateGrid():
global grid
grid = createShape(GROUP)
for i in xrange(nC*nR):
cell = createShape(RECT, (i%nC)*S, (i//nC)*S, S, S)
cell.setFill(colors[i]) # fill with corresponding color
cell.setStrokeWeight(1) # stroke width
cell.setStroke(0) # stroke color
grid.addChild(cell)
Thanks so much!!! So suppose I want to restart the game after I click the mouse anywhere inside the window, how do I use mousePressed() function?
I’ve looked at many different topics in the forum and tried to get the code to work, but it won’t restart.
The mousePressed() works similarly to keyPressed()
. There’s no conditional statement required to detect where you’re clicking (like on a button, or something) because you’re happy using the entire display window –
...
def keyPressed():
...
def mousePressed():
global colors, filled, grid, x, y
# code to reset the game variables
# ...
...
thanks I actually figured it out myself was pretty simple
Can you post your attempts (the code) for the 2 problems you’re mentioning:
This way we can better help you understand what is not functioning or missing in your script.
Now that you have asked your question here, please try not to open another thread for it. There are just a handful of people looking at the “Python” tag so do not expect to have an answer within the hour.
If you really are in a hurry, feel free to look at the OpenProcessing website where plenty of examples for tetris game are available for inspiration.
Back to your question. Every time the moving square “collides” with another colored square below, you could:
Annotated example:
W, H = 200, 400 # dimensions of canvas
nC, nR = 10, 20 # number of cols and rows
S = W/nC # step / size of unit cell
x, y = 80, -S # coordinates of starting cell
disabled = False # keyboard is NOT disabled
filled = set() # set storing the id of cells that have been stopped
colors = [235] * nC*nR # list storing the colors of each grid cell (all white-ish at start)
palette = (color(40,38,31), # color palette
color(95,181,179),
color(251,177,44),
color(252,169,191))
curcol = palette[int(random(4))] # current color picked randomly
patterns = (set(range(1,4)), set(range(nC, nC*4, nC))) # a pattern = a set of distances from cell 0 (ex: horizontal block -> 0 to 1, to 2 and to 3, vertical block -> 0 to 10, to 20 and to 30)
dir = (-1, 1, -nC, nC)
def setup():
size(W, H)
stroke(255)
updateGrid() # function that creates a grid showing both 'filled' and 'empty' cells
def draw():
global y, curcol, filled, disabled
shape(grid) # display the grid
fill(curcol) # draw the moving rectangle (red)
rect(x,y,S,S) #
t = frameCount%20 == 0 # time/tempo of descent
id = (x//S)+(y//S)*nC # convert coordinates of currently visited cell to 1D index
if id+nC not in filled and id+nC<nC*nR: # if NO occupied cell below: (note: 'id+nC' = index of cell below)
if t and y < H-S: # if time to move down and empty cell below is within canvas:
y+=S # -> increment 'y' position
else: # else (there IS an occupied cell below!):
disabled = True # -> disable keyboard
if t: # when time to move:
s = stack(id,[]) # look for cells with similar colors around (a 'stack')
to_remove = set()
if len(s)>1: # if stack of similar cells (same color) is found:
for n, i1 in enumerate(s): # -> check if patterns can be found in it
d = set(abs(i2-i1) for i2 in s[n:] if i1!=i2)
for p in patterns:
if p.issubset(d): # if so:
to_remove.update([i1] + map(lambda x: x+i1, p)) # -> store id of their cells in 'to_remove'
if to_remove: # if patterns have been found:
filled -= to_remove # -> remove the corresponding cells from 'filled'
for i in to_remove: colors[i] = 235 # -> make them appear white again
to_shift = set() # check if there are cells above the removed cells
for i in filled:
if i<min(to_remove) and i%nC in [k%nC for k in to_remove]:
to_shift.add(i)
if to_shift: # if so, shift them down*
shifted = [i+nC for i in to_shift]
filled -= to_shift # -> *(remove their ids form 'filled')
filled.update(shifted) # -> *(replace with new shifted/incremented ids)
temp = [colors[i] for i in to_shift] # let's not forget to shift the corresponding 'colors' as well
for i, n in enumerate(shifted):
colors[n] = temp[i] # cells below inherit the color from the cell above
for i in to_shift.difference(shifted):
colors[i] = 235 # cell on top becomes white
else: # if NO pattern to remove:
filled.add(id) # -> put id of current cell in 'filled' array list
colors[id] = curcol # -> store current color to 'colors' list
# IN ANY CASE, at the end DO NOT FORGET TO
curcol = palette[int(random(4))] # -pick a new color at random
updateGrid() # -update the grid
y = -S # -reset 'y' position
disabled = False # -re-enable keyboard
def keyPressed():
global x, y
if not disabled:
k = keyCode
if k == 39: x+=S # move RIGHT
elif k == 37: x-=S # move LEFT
elif k == 40: y+=S # move DOWN
x = constrain(x, 0, W-S) # make sure that x and y coordinates stay within the boundaries of canvas
y = constrain(y, 0, H-S)
def updateGrid():
global grid
grid = createShape(GROUP)
for i in xrange(nC*nR):
cell = createShape(RECT, (i%nC)*S, (i//nC)*S, S, S)
cell.setFill(colors[i]) # fill with corresponding color
cell.setStrokeWeight(1) # stroke width
cell.setStroke(255) # stroke color
grid.addChild(cell)
def stack(id, v):
v.append(id)
for d in dir:
nid = id+d
if 0<=nid<nC*nR and nid not in v:
if colors[nid] == curcol:
stack(nid, v)
return sorted(v)