I am doing a maze game so far I have the following code, which reads the positions of a text file the obstacles that must be placed, however I do not have extensive knowledge about pygame to display them on the screen.
def set_walls(self, walls):
walls_length = len(walls)
for i in range(walls_length):
# First case is row...
if "row" in walls[i]:
row_index = int(re.sub("[^0-9]", "", walls[i]))
print(row_index)
column_indexes = walls[i+1].split()
print(column_indexes)
for index in column_indexes:
self.wall_vertical[row_index - 1][int(index) - 1] = 1
# Second case is column...
elif "column" in walls[i]:
column_index = int(re.sub("[^0-9]", "", walls[i]))
row_indexes = walls[i + 1].split()
for index in row_indexes:
self.walls_horizontal[int(index) - 1][column_index - 1] = 1
If you have the indexes for each wall, you can multiply them by the wall width and height, this should place all the walls in the right places. I can't help much more seeing as how you did not provide a text file sample.
x = x_index * wall_width
y = y_index * wall_height
Related
So I'm making a basic 2D platformer game with the pygame module in python. Recently I've been trying to implement infinite world generation, but have been having some problems. The generation works fine, however, at the player's spawn, a bunch of random tiles spawn, obstructing the whole spawn area. I can't seem to find what's causing this.
Here's everything you need to replicate my situation:
map generation:
def generate_chunk(x,y):
chunk_data = []
for y_pos in range(CHUNK_SIZE):
for x_pos in range(CHUNK_SIZE):
target_x = x * CHUNK_SIZE + x_pos
target_y = y * CHUNK_SIZE + y_pos
tile_type = 0 # nothing
if target_y > 10:
tile_type = 2 # dirt
elif target_y == 10:
tile_type = 1 # grass
elif target_y < 10:
tile_type = 0
if tile_type != 0:
chunk_data.append([[target_x,target_y],tile_type])
return chunk_data
...
while True:
...
tile_rects = []
for y in range(3):
for x in range(4):
target_x = x - 1 + int(round(scroll[0]/(CHUNK_SIZE*16)))
target_y = y - 1 + int(round(scroll[1]/(CHUNK_SIZE*16)))
target_chunk = str(target_x) + ';' + str(target_y)
if target_chunk not in game_map:
game_map[target_chunk] = generate_chunk(target_x,target_y)
for tile in game_map[target_chunk]:
display.blit(tile_index[tile[1]],(tile[0][0]*16-scroll[0],tile[0][1]*16-scroll[1]))
if tile[1] in [1,2]:
tile_rects.append(pygame.Rect(tile[0][0]*16,tile[0][1]*16,16,16))
full code:
https://github.com/nice-404/Platformer
I can't seem to figure out what is causing the random tile spawning.
(I have been following DaFluffyPotato's platformer tutorial series because I am new to pygame)
After 2 weeks of debugging and further looking into the chunk generating code, I couldn't find out anything. However, I did figure out that the issue only happened in a small area, at the 0 x value. So what I did was I made the player spawn very far away from this, and made a boundary so that it couldn't walk far enough to see the issue. Not really fixing the issue, but at least it works now.
So I've been programming a snake game using python mode for processing, but I have been having an issue with the list I have set up for keeping track of the body of the snake itself.
My current implementation uses a list of vectors to keep track of the location of each segment of the snake. I then loop through this list to display the squares for each segment. At the beginning of the game, the list only has 1 entry (the head), but upon eating a piece of food, I insert a new vector to the front of the list with the same value as the current head. I then update the list but looping through it and finally, I update the head by using a velocity vector.
scl = 10
dim = 20
def setup():
global s
global f
size(dim * scl, dim * scl)
s = Snake()
f = Food()
def draw():
background(201)
global s
global f
if s.eat(f):
f.location()
s.update()
s.display()
f.display()
delay(50)
class Snake:
def __init__(self):
self.body = [PVector(0, 0)]
self.v = PVector(1, 0)
self.total = 1
def update(self):
for i in range(self.total - 1):
self.body[self.total - 1 - i] = self.body[self.total - 2 - i]
print("Position")
print(self.body)
self.body[0].x += self.v.x * scl
print(self.body)
self.body[0].y += self.v.y * scl
print(self.body)
def display(self):
fill(101)
for i in range(self.total):
rect(self.body[i].x + 1, self.body[i].y + 1, scl - 2, scl - 2)
def eat(self, p):
tmp = self.body[:]
dis = dist(self.body[0].x, self.body[0].y, p.pos.x, p.pos.y)
if dis < 1:
self.total += 1
self.body.insert(0, tmp[0])
return True
else:
return False
I expect the output to be a list of differing vectors, each that draw a square next to the previous and next entries. Instead, after eating food, all the vectors are the same within the body list. Does anyone know how I can fix this?
You seem to misunderstood, how python's list handles it's values.
tmp = self.body[:]
makes shallow copy, not deep copy. And:
self.body[...] = self.body[...]
doesn't copy the value. It just passes the value from one place, to another. So when you move your values in self.body by one offset, the first and the second element will end pointing to the same value.
Try something like this:
def update(self):
for i in range(self.total - 1):
self.body[self.total - 1 - i] = self.body[self.total - 2 - i]
print("Position")
print(self.body)
self.body[0] = PVector(self.body[0].x + self.v.x * scl, self.body[0].y + self.v.y * scl)
print(self.body)
and in eat function:
self.body.insert(0, PVector(tmp[0].x, tmp[0].y))
I'm working on a 2-player board game (e.g. connect 4), with parametric board size h, w. I want to check for winning condition using hw-sized bitboards.
In game like chess, where board size is fixed, bitboards are usually represented with some sort of 64-bit integer. When h and w are not constant and maybe very big (let's suppose 30*30) are bitboards a good idea? If so, are the any data types in C/C++ to deal with big bitboards keeping their performances?
Since I'm currently working on python a solution in this language is appreciated too! :)
Thanks in advance
I wrote this code while ago just to play around with the game concept. There is no intelligence behaviour involve. just random moves to demonstrate the game. I guess this is not important for you since you are only looking for a fast check of winning conditions. This implementation is fast since I did my best to avoid for loops and use only built-in python/numpy functions (with some tricks).
import numpy as np
row_size = 6
col_size = 7
symbols = {1:'A', -1:'B', 0:' '}
def was_winning_move(S, P, current_row_idx,current_col_idx):
#****** Column Win ******
current_col = S[:,current_col_idx]
P_idx= np.where(current_col== P)[0]
#if the difference between indexes are one, that means they are consecutive.
#we need at least 4 consecutive index. So 3 Ture value
is_idx_consecutive = sum(np.diff(P_idx)==1)>=3
if is_idx_consecutive:
return True
#****** Column Win ******
current_row = S[current_row_idx,:]
P_idx= np.where(current_row== P)[0]
is_idx_consecutive = sum(np.diff(P_idx)==1)>=3
if is_idx_consecutive:
return True
#****** Diag Win ******
offeset_from_diag = current_col_idx - current_row_idx
current_diag = S.diagonal(offeset_from_diag)
P_idx= np.where(current_diag== P)[0]
is_idx_consecutive = sum(np.diff(P_idx)==1)>=3
if is_idx_consecutive:
return True
#****** off-Diag Win ******
#here 1) reverse rows, 2)find new index, 3)find offest and proceed as diag
reversed_rows = S[::-1,:] #1
new_row_idx = row_size - 1 - current_row_idx #2
offeset_from_diag = current_col_idx - new_row_idx #3
current_off_diag = reversed_rows.diagonal(offeset_from_diag)
P_idx= np.where(current_off_diag== P)[0]
is_idx_consecutive = sum(np.diff(P_idx)==1)>=3
if is_idx_consecutive:
return True
return False
def move_at_random(S,P):
selected_col_idx = np.random.permutation(range(col_size))[0]
#print selected_col_idx
#we should fill in matrix from bottom to top. So find the last filled row in col and fill the upper row
last_filled_row = np.where(S[:,selected_col_idx] != 0)[0]
#it is possible that there is no filled array. like the begining of the game
#in this case we start with last row e.g row : -1
if last_filled_row.size != 0:
current_row_idx = last_filled_row[0] - 1
else:
current_row_idx = -1
#print 'col[{0}], row[{1}]'.format(selected_col,current_row)
S[current_row_idx, selected_col_idx] = P
return (S,current_row_idx,selected_col_idx)
def move_still_possible(S):
return not (S[S==0].size == 0)
def print_game_state(S):
B = np.copy(S).astype(object)
for n in [-1, 0, 1]:
B[B==n] = symbols[n]
print B
def play_game():
#initiate game state
game_state = np.zeros((6,7),dtype=int)
player = 1
mvcntr = 1
no_winner_yet = True
while no_winner_yet and move_still_possible(game_state):
#get player symbol
name = symbols[player]
game_state, current_row, current_col = move_at_random(game_state, player)
#print '******',player,(current_row, current_col)
#print current game state
print_game_state(game_state)
#check if the move was a winning move
if was_winning_move(game_state,player,current_row, current_col):
print 'player %s wins after %d moves' % (name, mvcntr)
no_winner_yet = False
# switch player and increase move counter
player *= -1
mvcntr += 1
if no_winner_yet:
print 'game ended in a draw'
player = 0
return game_state,player,mvcntr
if __name__ == '__main__':
S, P, mvcntr = play_game()
let me know if you have any question
UPDATE: Explanation:
At each move, look at column, row, diagonal and secondary diagonal that goes through the current cell and find consecutive cells with the current symbol. avoid scanning the whole board.
extracting cells in each direction:
column:
current_col = S[:,current_col_idx]
row:
current_row = S[current_row_idx,:]
Diagonal:
Find the offset of the desired diagonal from the
main diagonal:
diag_offset = current_col_idx - current_row_idx
current_diag = S.diagonal(offset)
off-diagonal:
Reverse the rows of matrix:
S_reversed_rows = S[::-1,:]
Find the row index in the new matrix
new_row_idx = row_size - 1 - current_row_idx
current_offdiag = S.diagonal(offset)
I am trying to make a GUI for an othello game that i made in Python. The for loops below only display pieces in the first row. Once it iterates through the nested for loop a second time, no more pieces are displayed on any of the next rows. What is preventing these other pieces from being drawn?
def _draw_pieces(self) -> None:
self._canvas.delete(tkinter.ALL)
rows = int(self._width/RADIUS)
columns = int(self._height/RADIUS)
x_frac = 0
y_frac = 0
for row in self._board:
for column in row:
if column == NONE:
self._draw_neutral_piece((x_frac/rows),(y_frac/columns))
x_frac += 1
elif column == BLACK:
self._draw_black_piece((x_frac/rows),(y_frac/columns))
x_frac += 1
elif column == WHITE:
self._draw_white_piece((x_frac/rows),(y_frac/columns))
x_frac += 1
else:
x_frac = 0
y_frac+= 1
The functions _draw_black_piece, _draw_white_piece, etc. are all basically written the same. They take a fractional coordinate and draw a piece of that color. The coordinates are determined by the size of the board after it is resized. The default size of the board is the number of pieces in each column and row times the RADIUS constant, which is set to 100.
def _draw_black_piece(self, x_frac: float, y_frac: float) -> None:
x_radius = self._canvas.winfo_width()/len(self._board[0])
y_radius = self._canvas.winfo_height()/len(self._board)
x1 = self._canvas.winfo_width() * x_frac
x2 = self._canvas.winfo_width() * x_frac + x_radius
y1 = self._canvas.winfo_height() * y_frac
y2 = self._canvas.winfo_height() * y_frac + y_radius
self._canvas.create_oval(x1, y1, x2, y2, fill = 'black')
Here is the the board as well:
self._board = [[NONE,BLACK,NONE,WHITE],[NONE,BLACK,WHITE,NONE],[NONE,WHITE,BLACK,NONE] [NONE,NONE,NONE,NONE]]
I've been struggling conceptually with how to implement simple square collision detection within a game I am writing while avoiding Pygame; I want to learn how to do it without cheating. The structure of the program as intended looks is this:
The game loads a text file containing a level. Each level consists of 25 rows of 25 digits (for a total of 625 digits). It is extracted into a 2D array to emulate a cartesian grid which will correspond with the screen. From there the program draws a 32x32 block at the proper place on the screen. For example, if the digit at location [2][5] is a 1, it will draw a white square at pixel coordinate (96,192) (the counting of the squares starts at zero since it is an array). It also generates a collision array consisting of True or False for each location corresponding to the original array.
I have a player object that moves freely along the grid, not confined to the 32x32 squares. My question is this: how would I implement square collision detection? I've tried a number of methods but I'm not quite sure where I'm getting stuck. I'll post my latest incarnation and the relevant code below.
Collision code:
def checkPlayerEnvCollision(self,player):
p = player
c = self.cLayer #this is the collision grid generated when loading the level
for row in range(25):
for col in range (25):
print("checkEnvCollision")
if c[row][col] != False:
tileleftx = row*32
tilerightx = tileleftx + 32
tilelefty = col*32
tilerighty = tilelefty+32
if (abs(tileleftx - p.x) * 2 < (tilerightx + (p.x + 32))) and (abs(tilelefty - p.y) * 2 < (tilerighty + (p.y + 32))):
print("OH NO, COLLISION")
The code that loads the tiles from the text file into the array:
def loadLevel(self, level):
print("Loading Level")
levelFile = open(level)
count=0
for line in levelFile:
tempArray = []
if line.startswith("|"):
dirs = line.split('|')
self.north = dirs[1]
self.south = dirs[2]
self.east = dirs[3]
self.west = dirs[4]
continue
for item in line:
if item in self.tileValues:
tempArray.append(int(item))
self.tileLayer[count] = tempArray
count+=1
for items in self.tileLayer:
if len(items) > 25:
print("Error: Loaded Level Too Large")
count = 0
for line in self.tileLayer:
tempArray = []
for item in line:
if self.tilePassableValues[item] == False:
tempArray.append(False)
else:
tempArray.append(True)
self.collisionLayer[count] = tempArray
count += 1
Not sure if this is useful, but here is a simple demonstration of the drawing method:
def levelTiles(self, level):
row = 0
for t in level:
col = 0
for r in t:
color = "white"
if r == 0:
col+=1
continue
elif r == 1:
color = "red"
elif r == 2:
color = "white"
elif r == 3:
color = "green"
self.Canvas.create_rectangle(row*32, col*32, row*32+32, col*32+32, fill=color, width=1,tags='block')
col += 1
row += 1
Lastly, here is the text file I have been testing it with:
1111111111111111111111111
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222233332222222222222221
1222233332222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222233332222222221
1222222222333332332222221
1222222222222222332222221
1222222222222222332222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1222222222222222222222221
1111111111111111111111111
|onescreen2|onescreen2|onescreen2|onescreen2
(The last line is what will load the map to the north, south, east and west when reaching the edge of the level; you can ignore it.)
Thanks for the help. It's a lot to ask, but I'm stuck on this one!
If the player is tied to the grid, why not just test the grid positions:
if grid[player.x][player.y] == some_collidable_thing:
# there was a collision
If not,
I also provided an answer to something almost identical in This question
def check_col(self, rect):
for row in self.cLayer:
for column in row:
grid_position = (row*element_size, column*element_width)
collide_x = False
collide_y = False
# check x axis for collision
if self.rect.x + self.rect.w > grid_position[0]:
collide_x = True
elif self.rect.x < grid_position[0] + element_width:
collide_x = True
# check y axis for collision
if self.rect.y < grid_position[1] + element_height:
collide_y = True
elif self.rect.y + self.rect.h > grid_position[1]:
collide_y = True
# act on a collision on both axis
if collide_x and collide_y:
# act on the collision
return True
else:
# act on no collision
return False
An easier way to do this would be to define vectors for the player's movement, and lines for the boundaries of the objects. Then you check to see if the vector collides with any line (there should not be many lines to check) as follows (I'm assuming that the player/object can be on the boundary of the other object):
Take the determinant of the triangle formed by the movement vector and endpoint of the line you're checking for a collision, and take its area via determinant. Compare its area to the area of the triangle formed with the other endpoint. If they are both positive/negative, then there is no intersection. If their signs are different, then there MIGHT be an intersection.
If their signs are different, do the same thing as above, except using the endpoints of the movement vector instead of the endpoints of the line. (And using the whole line instead of the movement vector).
If their signs are different, then there is definitely an intersection, and if they are the same, then there is no intersection.
I hope this helps (and just comment if it does not make sense).