So I'm trying to write a little simulator thing with pygame, but im stuck
I'm trying to make particles that fall and settle but i want them to stack and stop when they hit a wall
This may sound confusing so here is an example:
http://www.coolmath-games.com/0-sugar-sugar/
I want to make particles that resemble the sugar in the game above:
I started by trying:
if pygame.sprite.spritecollideany(self, self.game.block_list):
self.rect.x += 0
self.rect.y += 0
but then the particles just stop and they don't roll down sloped surfaces
also I need to know how to check if a sprite collides with any other sprite in its group
So if anyone knows how I can duplicate this liquid like particle movement in pygame that would be awesome!
Thank You!
As I stated above, I tried to write the exactly same game with pygame too but left it uncompleted.
First of all, I preferred NOT to store these particles as different objects. Instead I used a dictionary to store their coordinates. I made it so because there are HUNDREDS of them and you have to check for collisions ~50 times per second for each of them. If you try to make them all different objects, it may go out of hand at some point.
After you detect a collision, in order to make them roll down sloped surface, let them move diagonally too. First check for the cell below, if that cell is not empty, check for the cells at bottom left and bottom right of the particle.
Btw, I found my function that moves the particles but it is not really readable.
def spawnSugar(spawnPoint) :
global sugarList,mapDict
mapDict[spawnPoint] = 1
sugarList.append(spawnPoint)
def moveAll() :
global mapDict,sugarList
sugarListTmp = sugarList
sugarList = []
for sugarX,sugarY in sugarListTmp :
# m stands for the vertical movement (1 for down, 0 for staying still)
# k stands for horizontal movement (-1 for left, +1 for right)
m = 1
if mapDict[( sugarX , (sugarY+1)%mapSizeY )]==0:
# checks whether the coordinate below this particle is empty
k = randint( -(mapDict[((sugarX-1)%mapSizeX , (sugarY+1)%mapSizeY)]==0) , mapDict[((sugarX+1)%mapSizeX , (sugarY+1)%mapSizeY)]==0 )
# If it is empty; randomly chooses 1 of the 3 coordinates below the particle (1 of them is just below and the other 2 are diagonally below)
elif mapDict[((sugarX-1)%mapSizeX,(sugarY+1)%mapSizeY)]==0 and mapDict[((sugarX-1)%mapSizeX,(sugarY)%mapSizeY)]==0 and mapDict[((sugarX+1)%mapSizeX,(sugarY+1)%mapSizeY)]==0 and mapDict[((sugarX+1)%mapSizeX,(sugarY)%mapSizeY)]==0:
# If the coordinate below the particle is not empty but other 2 diagonals are empty
k = -1 if randint(0,1) else 1 #chooses 1 of them randomly
else : # If at most 1 of these 2 diagonal coordinates are empty
k = (mapDict[((sugarX+1)%mapSizeX,(sugarY+1)%mapSizeY)]==0 and mapDict[((sugarX+1)%mapSizeX,(sugarY)%mapSizeY)]==0) or -(mapDict[((sugarX-1)%mapSizeX,(sugarY+1)%mapSizeY)]==0 and mapDict[((sugarX-1)%mapSizeX,(sugarY)%mapSizeY)]==0)
if not k: # If none of them are empty
m = 0
mapDict[(sugarX,sugarY)] = 0
mapDict[((sugarX+k)%mapSizeX,(sugarY+m)%mapSizeY)] = 1
sugarList.append(((sugarX+k)%mapSizeX,(sugarY+m)%mapSizeY))
# Values to assign before entering the main loop
mapDict = {}
sugarList = []
for x in range(mapSizeX):
for y in range(mapSizeY):
mapDict[(x,y)] = 0
Related
So I am trying to scan for every tile in a game ("scan" as stepping in a tile and saving its coordinates). If the player bumps against an object, then it must try to go to one tile down and keep walking. I can even know which face the player is facing.
I am using pydirectinput because pyautogui wasn't really working with my game.
This is my code so far:
def coordinates():
visited_coordinates = []
t_end = time.time() + 90
movements = []
while time.time() < t_end:
for message in generated_object(): # generated object returns a list with 4 elements
if [message[0], message[1]] in visited_coordinates:
if "left" in movements:
if "down" in movements:
if "right" in movements:
pydirectinput.press("up")
if message[3] != 4: # 4 means it is facing up
pydirectinput.press("up") # if it isn't facing up, it needs to be pressed twice
movements.append("up")
else:
pydirectinput.press("right")
if message[3] != 12: # 12 means it is facing right
pydirectinput.press("right") # same with facing right, and so on
movements.append("right")
else:
pydirectinput.press("down")
if message[3] != 0: # 0 means it is facing down
pydirectinput.press("down")
movements.append("down")
else:
pydirectinput.press("left")
if message[3] != 8: # 8 means it is facing left
pydirectinput.press("left")
movements.append("left")
continue
movements = []
if message[2] != 4: # this means it went beyond the border, and it must return
pydirectinput.press("right", presses=2)
visited_coordinates.append([message[0], message[1]])
return visited_coordinates
One (of the many) problems with this code is that it takes forever to perform an action (I am working with named pipes, so I have to read every received message). And in the same vein, this is classic spaghetti code, which we all despise.
How can I write this code to be more "readable" and more efficient?
And on the other hand, as soon as I go beyond that border, I can't really come back. I should make the player not to move left again, but I don't really know how since I've been resetting the movements list
Could put items in a dictionary, then loop through those entries.
directions = { 'up': 4, 'right': 12, 'down': 0, 'left':8 }
for direction, val in directions .items():
if direction in movements:
pydirectinput .press( direction )
if message[3] != val:
pydirectinput .press( direction )
movements .append( direction )
break ## you might want to break out of the loop here
I am making my first game in pygame, but when I have generated my world and try to move my character his sprite is still left in the old position. I can't blit my background every frame either as its too large and grinds pygame's performance to a halt.
I tried bliting every frame but that also slowed pygame down as well. Then I tried to make it blit around the character so it covers the old pic of my character, but I couldn't get that to work either.
def MakeTerrain():
TempY = 0
for o in range(51):
for i in range(51):
TempX = 16 * i
if TempX >= 800:
TempY = 16 * o
TempX = 0
rnd = random.randrange(10)
if rnd <= 8:
tile = Tile("Grass",[TempX,TempY])
else:
tile = Tile("Stone",[TempX,TempY])
Tiles.append(tile)
tile.BlitTile(Display)
Function for making my terrain [a.k.a world/background]
class Player():
def __init__(self,MovementSpeed=1):
self.DirectionX = 0
self.DirectionY = 0
self.PlayerPos = [0,0]
self.MovementSpeed = MovementSpeed
self.PlayerSprite = pygame.image.load("Jeffrey.png")
def BlitPlayer(self,display):
display.blit(self.PlayerSprite,(self.PlayerPos[0],self.PlayerPos[1]))
Class of my player with my blit function
class Tile():
def __init__(self,sprite,Position):
self.TilePosition = Position
self.TileSprite = pygame.image.load(sprite+".png")
def BlitTile(self,display):
display.blit(self.TileSprite,(self.TilePosition[0],self.TilePosition[1]))
Tile class
http://prntscr.com/nrtnyx
This is what happens
I think the idea of only redrawing the tiles near the player can work, but it needs to be reworked slightly.
This will require changing your position values to pygame.math.Vector2, so do that first, I would also recommend changing all instances of these values to self.pos so that the loop I will show you is easier to make.
self.pos = pygame.math.Vector2(Position)
To ascess the x and y values, they are simply self.pos.x or self.pos.y
Within the drawing code, you can first change it so it iterates through every sprite:
for sprite in my_sprites:
pass
Inside this loop, you can check the distance from the sprite to the player using these new vectors:
deltaVec = player.pos - sprite.pos # Find delta [difference] between player position and sprite position
len = deltaVec.length() # Find the length between those two points through the distance formula
Then, at the end, check to see if the new distance is under a certain threshhold:
if len < 100: # 100 being the distance, change if needed
sprite.draw()
In the end, the new drawing code would look like this:
for sprite in my_sprites:
deltaVec = player.pos - sprite.pos
len = deltaVec.length()
if len < 100: # 100 being the distance, change if needed
sprite.draw()
This should only redraw the tiles nearest to the player and thats it without having to deal with managing each tile.
I have an assignment for a programming unit that asks this:
create the function enclosing(board, player, pos, direct), that represents the rules of Reversi according to the following specifications.
A board position is represented by a pair (r, c) where r and c are each integers from the range
range(8) representing a row index and a column index, respectively. For instance, the position \b3" is
represented by (2, 1). The row and column order of the \b3" style and the specication of position
is reversed. This is because it is natural to constuct lists of lists in such a way that the outer lists
correspond to rows, and the inner list positions corerspond to column positions, so we reference them
with row rst, then column. This row, column convention is quite common across maths and computer
science.
A direction is represented by a pair (dr, dc) where dr and dc are each integers from the set f-1, 0,
1g. For instance, \horizontal to the left" is described by (0, -1), \diagonal to the right and down" is
described by (1, 1), and so on).
The function enclosing(board, player, pos, dir) represents whether putting a player's stone on
a given position would enclose a straight line of opponent's stones in a given direction:
Input: A board conguration board, an integer player from the set f1, 2g, a board position pos and a direction dir.
Output: True if board contains a stone of player in direction dir from position pos and all positions
on the straight line between that stone and pos contain stones of the other player, and there is at
least one stone belonging to the other player on the straight line; False otherwise.
This is what I have:
def enclosing(board, player, pos, direct):
if player == 1:
a = direct[0]
b = direct[1]
i = 1
while i < 8:
newpos = (pos[0] + i*a , pos[1] + i*b)
if board[newpos[0]][newpos[1]] == 1:
return True
elif board[newpos[0]][newpos[1]] == 2:
i = i + 1
else:
return False
Also keep in mind this is a beginners course and I have about a months experience on python.
The code in your edit looks good, and is what I was getting at. Good luck with the rest of the project!
A couple edge cases:
board[newpos[0]][newpos[1]] will go out of bounds
Your function will return True in the case XOOOOX, which is not a capture by Othello rules (not sure if your assignment defines it differently
I strongly recommend writing a couple simple tests just to make sure your code works. They don't need to cover the full range of cases, and doesn't need to be the full board. It's usually not required, but makes it easier to evaluate: just hit "run" instead of trying to reason through your code.
Here's an example:
def test():
assert enclosing([[0, 0, 0], [0,0,0],[0,1,2]], 1, (0,2), (1,1)) == True
Is it possible to solve tower of hanoi halfway? I've done extensive research to look for codes that solves the user's configuration halfway but I've yet to find one. This is for an assignment and I require the code to take over from where the user has stopped solving and continue solving it for the user, without resetting the puzzle to square one.
I understand that there are recursion algorithms out there readily available but that is not what I'm searching for.
I'm searching for algorithms that can take over from where the user has solved until, and then continue solving from there.
Any ideas?
So far, I've come up with an algorithm that stores the optimized algorithms( which is being done by recursion) into an array, and then checks if the user's input is equal to any found in the array, and then continue solving from there. However, the problem lies when the user's configuration is not found in the optimized algorithm array.
The following are my codes so far ( I've excluded the stack.py codes):
def solveHalfway(n, start, end, middle, count):
gameInstance.stackA = [3,2]
gameInstance.stackB = []
gameInstance.stackC = [1]
loopCounter = 0 # initialise loopCounter as 0
moveCounter = 0 # initialise the move index the user is stuck at
indicator = 0 # to indicate whether the user's config equals the solution's config
while loopCounter < arrayOfStacks.size(): # while loopCounter size has not reached the end of arrayOfStacks
if loopCounter != 0 and loopCounter % 3 == 0: # if 3 stacks have been dequeued
moveCounter += 1
if gameInstance.getUserConfig() == tempStack.data: #check whether user's config is equal to the solution's config
indicator += 1
print "User is stuck at move: ", moveCounter #this will be the current move the user is at
while arrayOfStacks.size() != 0: # while not the end of arrayOfStacks
correctMovesStack.push(arrayOfStacks.dequeue()) # add the moves to correctMovesStack
if correctMovesStack.size() == 3: # if 3 stacks have been dequeued
print "Step:", moveCounter , correctMovesStack.data # display the step number plus the correct move to take
moveCounter+=1 # increase move by 1
while correctMovesStack.size() != 0: # if correct moves stack isn't empty
correctMovesStack.pop() # empty the stack
return
else:
while tempStack.size() != 0: # check if tempStack is empty
tempStack.pop() # empty tempStack so that it can be used for the next loop
tempStack.push(arrayOfStacks.dequeue()) #dequeue from arrayOfStacks for a total of 3 times and push it to tempStack
else:
tempStack.push(arrayOfStacks.dequeue()) #dequeue from arrayOfStacks for a total of 3 times and push it to tempStack
loopCounter +=1 # increase loop counter by 1
if indicator == 0:
moveWith3Towers(noOfDisks, stackA, stackC, stackB, count)
print indicator
To solve the Towers of Hanoi from an arbitrary position, you can use a recursive procedure similar to the standard solution that works from the standard start position.
It just has to be a little more general.
Write a recursive procedure moveDisks(maxSize,targetPeg) that moves all the disks with size <= maxSize to the peg targetPeg, like this:
Find the largest disk m such that m.size <= maxSize and m is not on targetPeg. If there is no such disk, then return, because all the disks with size <= maxSize are already in the right place.
Let sourcePeg be the peg where m is currently, and let otherPeg be the the peg that isn't sourcePeg or targetPeg.
Call moveDisks(m.size-1, otherPeg) recursively to get the smaller disks out of the way.
Move m from sourcePeg to targetPeg.
Call moveDisks(m.size-1, targetPeg) recursively to put the smaller disks where they belong.
In python, I would write it like this. Note that I used a different representation for the game state that works better for this algorithm and doesn't allow any illegal positions:
#
# Solve Towers of Hanoi from arbitrary position
#
# diskPostions -- the current peg for each disk (0, 1, or 2) in decreasing
# order of size. This will be modified
# largestToMove -- move this one and all smaller disks
# targetPeg -- target peg for disks to move
#
def moveDisks(diskPositions, largestToMove, targetPeg):
for badDisk in range(largestToMove, len(diskPositions)):
currentPeg = diskPositions[badDisk]
if currentPeg != targetPeg:
#found the largest disk on the wrong peg
#sum of the peg numbers is 3, so to find the other one...
otherPeg = 3 - targetPeg - currentPeg
#before we can move badDisk, we have get the smaller ones out of the way
moveDisks(diskPositions, badDisk+1, otherPeg)
print "Move ", badDisk, " from ", currentPeg, " to ", targetPeg
diskPositions[badDisk]=targetPeg
#now we can put the smaller ones in the right place
moveDisks(diskPositions, badDisk+1, targetPeg)
break;
Test:
> moveDisks([2,1,0,2], 0, 2)
Move 3 from 2 to 0
Move 1 from 1 to 2
Move 3 from 0 to 1
Move 2 from 0 to 2
Move 3 from 1 to 2
So I'm trying to get a little more proficient with Python, and decided that making a maze would be a fun thing to know how to do. I found this page that goes over a bit of how to do it.
create a CellStack (LIFO) to hold a list of cell locations
set TotalCells = number of cells in grid
choose a cell at random and call it CurrentCell
set VisitedCells = 1
while VisitedCells < TotalCells
find all neighbors of CurrentCell with all walls intact
if one or more found
choose one at random
knock down the wall between it and CurrentCell
push CurrentCell location on the CellStack
make the new cell CurrentCell
add 1 to VisitedCells
else
pop the most recent cell entry off the CellStack
make it CurrentCell
endIf
endWhile
Now, I've got the following code, although it isn't much past the obvious stuff in the pseudocode.
class Cell:
top_wall = 0
bottom_wall = 0
left_wall = 0
right_wall = 0
def knock_down(self,wall):
if wall is 'top_wall' and self.top_wall is 0:
self.top_wall = 1
if wall is 'bottom_wall' and self.bottom_wall is 0:
self.bottom_wall = 1
if wall is 'left_wall' and self.left_wall is 0:
self.left_wall = 1
if wall is 'right_wall' and self.right_wall is 0:
self.right_wall = 1
else
return 'Error: Wall Already Gone'
maze = [10][10]
CellStack = [] # LIFO stack to hold list of cell locations
TotalCells = 100 # Number of cells in grid
VisitedCells = 0 # Cells that have been visited
CurrentCell = 0 # The current cell
while VisitedCells < TotalCells:
I'm not sure that the class is the best way to do the cells, but I haven't thought of another way to do it yet. However, I've run into a bit of a problem for checking for the neighbors of a cell. The find all neighbors of CurrentCell with all walls intact is throwing me for a bit of a loop.
How can you check whether cells are neighbors?
You can give each cell a position, stored as two integers. Then, two cells are neighbors if those integers are neighbors.
def isCellNeighbor(c1, c2):
if abs(c1.x - c2.x) == 1: return True
if abs(c1.y - c2.y) == 1: return True
return False
The above considers two cells as being neighbors if at least a corner of each one touches the other. You can tweak it to suit your needs.
PS: have a look at the amazing collection of maze algorithms