I have my update_entities function that is constantly updating my "entities' " states. The upward and downward functions activate the prototype movement for the entities.
The reason the function is in a for loop is because in each "round" in my game there are three entities / enemies, so the loop iterates through each of the entities and takes control of their states (positions and whether they shot their weapons).
The problem I'm running into is the shooting function, the function itself works just fine but only for the 3rd of the three entities. It's quite weird behavior and definitely unexpected, I don't understand why that's been happening because when iterating through each of the entities, each of them gets an opportunity to move in an oscillating behavior, but, again, the 3rd one is the only one that shoots.
Here is the code that could relate to the problem.
entity_bullet = None
ebullet_coordinates = [(0, 0), (0, 0)]
entity_bullets = []
def get_ebullet_coordinates(self):
for child in self.entity_bullets:
x1, y1 = child.pos
self.ebullet_coordinates[0] = (x1, y1)
x2, y2 = child.pos[0] + child.width, child.pos[1] + child.height
self.ebullet_coordinates[1] = (x2, y2)
def entity_shoot(self):
for child in self.entities:
self.get_entity_coordinates()
x = self.entity_coordinates[0][0]
y = self.entity_coordinates[0][1] - 20
if child.source == "images/evil_drone.png":
self.entity_bullet = Image(source="images/evil_drone_bullet2.png",
pos=(x, y))
elif child.source == "images/angry_cloud.png":
self.entity_bullet = Image(source="images/lightning_bullet2.png",
pos=(x, y))
elif child.source == "images/skullairballoon.png":
self.entity_bullet = Image(source="images/bomb.png",
pos=(x, y))
self.add_widget(self.entity_bullet)
self.entity_bullets.append(self.entity_bullet) # Add to list for them to move
def update_entity_bullets(self):
self.get_drone_coordinates()
self.get_entity_coordinates()
drone_xmin, drone_ymin = self.drone_coordinates[0][0], self.drone_coordinates[0][1]
drone_xmax, drone_ymax = self.drone_coordinates[1][0], self.drone_coordinates[1][1]
bullet_xmin, bullet_ymin = self.entity_coordinates[0][0], self.entity_coordinates[0][1] - 20
bullet_xmax, bullet_ymax = self.entity_coordinates[1][0], self.entity_coordinates[1][1]
xdistance = bullet_xmax - drone_xmin
ydistance = bullet_ymin - drone_ymax
final_xdistance = (xdistance / 60) + 1
final_ydistance = (ydistance / 60) + 1
for self.entity_bullet in self.entity_bullets:
for child in self.entity_bullets:
if child.pos[1] <= 0:
self.remove_widget(child)
elif child.pos[1] >= self.height - 10:
self.remove_widget(child)
if child.pos[0] <= -10:
self.remove_widget(child)
elif child.pos[0] >= self.width - 10:
self.remove_widget(child)
self.entity_bullet.pos[0] -= final_xdistance
self.entity_bullet.pos[1] -= final_ydistance
pass
def check_ebullet_collision(self, dt):
if self.game_ongoing:
self.get_drone_coordinates()
self.get_ebullet_coordinates()
drone_xmin, drone_ymin = self.drone_coordinates[0][0], self.drone_coordinates[0][1]
drone_xmax, drone_ymax = self.drone_coordinates[1][0], self.drone_coordinates[1][1]
bullet_xmin, bullet_ymin = self.ebullet_coordinates[0][0], self.ebullet_coordinates[0][1]
bullet_xmax, bullet_ymax = self.ebullet_coordinates[1][0], self.ebullet_coordinates[1][1]
if ((drone_xmax - 40) >= bullet_xmin >= (drone_xmin - 50)) and ((drone_ymax - 65) >= bullet_ymin >= (drone_ymin - 50)):
print("hit")
for self.entity_bullet in self.entity_bullets:
self.remove_widget(self.entity_bullet)
for ebullet in self.entity_bullets:
self.entity_bullets.remove(ebullet)
self.remove_widget(ebullet)
def update_entities(self):
for child in self.entities:
z = random.randint(1, 3000)
a = random.randint(1, 215)
def upward():
child.pos[1] += .1
def downward():
child.pos[1] -= .1
if z >= 2800 or z % 2 == 0:
for i in range(random.randint(1, 20)):
upward()
else:
for i in range(random.randint(1, 22)):
downward()
if a == 205:
self.entity_shoot()
I'm in the process of creating a minesweeper style game using a turtle-based grid setup. I need to find the closest cell within the grid and reveal the icon located under it whether that be a bomb or a number icons. I'm not looking to make it exact, I just need the mouse click to find the nearest cell in the grid even if the click isn't directly on the board. Currently my code only reveals the icon of the last turtle created on the board and then does nothing else with further clicks.
What can I do to make it recognize the real closest click and do it multiple times until the last bomb is found?
import random
import turtle
import cell
class Game:
def __init__(self, size):
registershapes()
self.__boardsize = size
self.__boardlist = []
self.__bombnum = 0
self.__probe = 0
self.__probelist = []
offset = (size-1) * 17
for x in range(size):
for y in range(size):
t = cell.Cell(x,y)
t.up()
t.shape('question.gif')
t.goto(y*34-offset, offset-x*34)
self.__boardlist.append(t)
def hideMines(self, num):
if num > self.__boardsize ** 2:
return False
self.__bombnum = num
self.__rnums = []
i = 0
while i < self.__bombnum:
currentnum = random.randrange(0, (self.__boardsize**2) - 1)
if currentnum not in self.__rnums:
self.__rnums.append(currentnum)
i += 1
return True
def probe(self, x, y):
for t in self.__boardlist:
pos = t.position()
distx = abs(x - pos[0])
disty = abs(y - pos[1])
distfinal = (distx ** 2 + disty ** 2) ** 0.5
curdist = 0
if curdist < distfinal:
curdist = distfinal
closest = t
if closest in self.__probelist:
return (self.__probe, self.__bombnum)
elif closest in self.__rnums:
closest.shape("bomb.gif")
self.__bombnum -= 1
self.__probe += 1
self.__probelist.append(closest)
return (self.__probe, self.__bombnum)
else:
closest.shape("0.gif")
self.__probe += 1
self.__probelist.append(closest)
return (self.__probe, self.__bombnum)
def registershapes():
wn = turtle.Screen()
wn.register_shape('0.gif')
wn.register_shape('1.gif')
wn.register_shape('2.gif')
wn.register_shape('3.gif')
wn.register_shape('4.gif')
wn.register_shape('5.gif')
wn.register_shape('6.gif')
wn.register_shape('7.gif')
wn.register_shape('8.gif')
wn.register_shape('9.gif')
wn.register_shape('bomb.gif')
wn.register_shape('question.gif')
I believe you're approaching this problem the wrong way. You're activating screen.onclick() and trying to map it to a turtle. Instead, activate turtle.onclick() on the individual turtles, deactivating it when a turtle is selected. Then you don't have to search for the turtle in question, and not actively ignore turtles that have already been selected.
Below is my rework of your code from this and your previous question into an example you can run. I had to guess about the definition of the Cell class:
from turtle import Turtle, Screen
import random
class Cell(Turtle):
def __init__(self, number):
super().__init__("question.gif")
self.__number = number
self.penup()
def number(self):
return self.__number
class Game:
def __init__(self, size):
registershapes()
self.__boardsize = size
self.__boardlist = []
self.__bombnum = 0
self.__probe = 0
self.__rnums = None
offset = (size - 1) * 17
for y in range(size):
for x in range(size):
t = Cell(x + y * size)
t.goto(x * 34 - offset, offset - y * 34)
t.onclick(lambda x, y, self=t: closure(self))
self.__boardlist.append(t)
def hideMines(self, num):
if num > self.__boardsize ** 2:
return False
self.__bombnum = num
self.__rnums = []
i = 0
while i < self.__bombnum:
currentnum = random.randrange(0, self.__boardsize ** 2 - 1)
if currentnum not in self.__rnums:
self.__rnums.append(currentnum)
i += 1
return True
def probe(self, closest):
closest.onclick(None)
if closest.number() in self.__rnums:
closest.shape("bomb.gif")
self.__bombnum -= 1
else:
closest.shape("0.gif")
self.__probe += 1
return (self.__probe, self.__bombnum)
def registershapes():
screen.register_shape('0.gif')
# ...
screen.register_shape('bomb.gif')
screen.register_shape('question.gif')
def closure(closest):
_, rem = mine.probe(closest)
if rem == 0:
over = screen.textinput("Text Input", "Would you like to play again? (Y)es or (N)o")
if over.upper() == 'Y':
main()
else:
screen.bye()
def main():
global mine
board = screen.numinput("Numeric Input", "Enter desired board size: ")
mine = Game(int(board))
nummine = screen.numinput("Numeric Input", "Enter desired number of mines: ")
mine.hideMines(int(nummine))
screen = Screen()
mine = None
main()
screen.mainloop()
I'm making a sudoku board using turtle in python. Right now I'm having a little trouble trying to figure out how to let the program easily check which box I am looking at. I have 5 grids in different positions. The game will automatically pick one to play. Since each grid is in a different position, I have to be careful where I have my turtle positioned. I have 16 functions that calculate where I want my turtle cursor to be to draw the number.
#Below is a guide to where each box is relative to its position on the grid.
#To find center of the box, add 75 to x and 20 to y.
#Box(1,1) = x, y Box(1,2) = x+150, y Box(1,3) = x+300, y Box(1,4) = x+450, y
#Box(2,1) = x, y-150 Box(2,2) = x+150, y-150 Box(2,3) = x+300, y-150 Box(2,4) = x+450, y-150
#Box(3,1) = x, y-300 Box(3,2) = x+150, y-300 Box(3,3) = x+300, y-300 Box(3,4) = x+450, y-300
#Box(4,1) = x, y-450 Box(4,2) = x+150, y-450 Box(4,3) = x+300, y-450 Box(4,4) = x+450, y-450
def box1_1(x, y):
return(x+75, y+20)
def box1_2(x, y):
return(x+225, y+20)
def box1_3(x, y):
return(x+375, y+20)
def box1_4(x, y):
return(x+525, y+20)
def box2_1(x, y):
return(x+75, y-130)
def box2_2(x, y):
return(x+225, y-130)
def box2_3(x, y):
return(x+375, y-130)
def box2_4(x, y):
return(x+525, y-130)
def box3_1(x, y):
return(x+75, y-280)
def box3_2(x, y):
return(x+225, y-280)
def box3_3(x, y):
return(x+375, y-280)
def box3_4(x, y):
return(x+525, y-280)
def box4_1(x, y):
return(x+75, y-430)
def box4_2(x, y):
return(x+225, y-430)
def box4_3(x, y):
return(x+375, y-430)
def box4_4(x, y):
return((x+525, y-430))
I can get the boards to be drawn how I want and the given numbers are also drawn correctly. I want the user to have the option to play with real time correction or play traditionally where they can enter all the values and the game will check if their solution is correct. The problem I am running into is during the part where the user enters in their desired number into a box. Right now I have:
def playSudoku():
playboard = []
board1 = [[0,0,0,3],[0,1,0,4],[4,2,0,1],[0,3,4,0]]
board2 = [[4,3,0,0],[1,0,3,0],[0,0,2,0],[2,1,0,0]]
board3 = [[0,4,0,1],[3,0,3,0],[1,0,0,4],[0,2,1,0]]
board4 = [[1,0,3,0],[0,4,2,1],[0,0,0,2],[0,0,4,0]]
board5 = [[0,4,3,2],[3,0,0,0],[4,0,0,0],[0,0,4,1]]
boardchoice = random.randint(1,5)
if boardchoice == 1:
drawBoard1()
playboard = board1
posx = -900
posy = 850
elif boardchoice == 2:
drawBoard2()
playboard = board2
posx = -200
posy = 850
elif boardchoice == 3:
drawBoard3()
playboard = board3
posx = 500
posy = 850
elif boardchoice == 4:
drawBoard4()
playboard = board4
posx = -500
posy = 100
else:
drawBoard5()
playboard = board5
posx = 200
posy = 100
rtc = turtle.textinput("Sudoku", "Do you want to play with real time correction?")
if rtc == 'y':
for i in range (0,3):
for j in range (0,3):
if playboard[i][j] != 0:
pass
num = turtle.numinput('Sudoku', 'Enter a number for box[' + str(i) + ',' + str(j) + ']?: ', minval=1, maxval=4)
turtle.goto(box[i]_[j](posx,posy))
turtle.write(str(num), move=True, align="center", font=("Times New Roman", 24))
I want to bring attention specifically to this line
turtle.goto(box[i]_[j](posx,posy))
The reason why each board has a different posx and posy is because they sit in different spots on the turtle grid. So as you saw above, I have functions with names "boxA _ B" where A and B are the position numbers for the box. I know that what I wrote doesn't work (I tried it too, just in case), but I was wondering if there was a python function out there that would let me do what I'm trying to achieve.
In my loop, whatever i and j are, I would like my my program to use box[i]_[j].
I apologize if this is poorly worded. If more clarification is needed, I will eagerly tell you. I was just hoping someone out there knows what I'm looking for.
You should probably define the box function like this.
def box(i, j, x, y):
return (x + 150*j - 75, y - 150*i + 170)
Then just call box(i, j, posx, posy) instead.
Although in this particular case writing a generic box() function as shown in the other answer would be the best approach since the function's result can be determined via a relatively simply formula from the i and j arguments. However in more general circumstances where that's not true, you'd want to use something like a dictionary to map the different possible combinations to the desired function. Below is how that could have been to solve your problem.
First add a dictionary to associate the different argument values with the corresponding function:
box_map = {
(1, 1): box1_1,
(1, 2): box1_2,
(1, 3): box1_3,
(1, 4): box1_4,
(2, 1): box2_1,
(2, 2): box2_2,
(2, 3): box2_3,
(2, 4): box2_4,
(3, 1): box3_1,
(3, 2): box3_2,
(3, 3): box3_3,
(3, 4): box3_4,
(4, 1): box4_1,
(4, 2): box4_2,
(4, 3): box4_3,
(4, 4): box4_4,
}
Next would be to modify the playSudoku() function to use it to lookup the function to call:
...
rtc = turtle.textinput("Sudoku", "Do you want to play with real time correction?")
if rtc == 'y':
for i in range (0,3):
for j in range (0,3):
if playboard[i][j] != 0:
pass
num = turtle.numinput('Sudoku', 'Enter a number for box[' + str(i) + ',' + str(j) + ']?: ', minval=1, maxval=4)
# turtle.goto(box[i]_[j](posx, posy))
turtle.goto(box_map[i, j](posx, posy))
turtle.write(str(num), move=True, align="center", font=("Times New Roman", 24))
I am programming an Othello game in a GUI. I have begun working on the animations that flip certain tiles, which is here. My computer(s) will start choking when the when the amount of tiles on the board becomes larger. I do not know what to do to simplify this code or use less memory. (I can use an automove key I have enabled to finish the game at light speed, without the animations. That works fine.) Here is the definition I am using to flip the tiles.
def animateFlips(self, i):
self._canvas.delete(tkinter.ALL)
column_width = self._canvas.winfo_width()/Othello.COLUMNS
row_height = (self._canvas.winfo_height()-self._scoreBoard)/Othello.ROWS
newBoard = self._game.board
animatedTileCoords = []
color = ''
oppcolor = ''
if self._game.turn == 2:
color = 'black'
oppcolor = 'white'
elif self._game.turn == 1:
color = 'white'
oppcolor = 'black'
for x in range(Othello.COLUMNS):
for y in range(Othello.ROWS):
x1 = x * column_width
y1 = y * row_height
x2 = x1 + column_width
y2 = y1 + row_height
self._canvas.create_rectangle(x1,y1,x2,y2)
if self._game.board[x][y] == 1:
self._canvas.create_oval(x1,y1,x2,y2,fill='black')
elif self._game.board[x][y] == 2:
self._canvas.create_oval(x1,y1,x2,y2,fill='white')
elif self._game.board[x][y] == 3 or self._game.board[x][y] == 4:
animatedTileCoords.append([x,y])
for x, y in animatedTileCoords:
x1 = x * column_width
y1 = y * row_height
x2 = x1 + column_width
y2 = y1 + row_height
if i == 1:
self._canvas.create_oval(x1,y1,x2,y2,fill=oppcolor)
self._canvas.after(50, lambda: self.animateFlips(2))
elif i == 2:
self._canvas.create_oval(x1 + (column_width/4),y1,x1 + (3*column_width/4),y2,fill=oppcolor)
self._canvas.after(50, lambda: self.animateFlips(3))
elif i == 3:
self._canvas.create_oval(x1 + (column_width/2),y1,x1 + (column_width/2),y2,fill=oppcolor)
self._canvas.after(50, lambda: self.animateFlips(4))
elif i == 4:
self._canvas.create_oval(x1 + (column_width/4),y1,x1 + (3*column_width/4),y2,fill=color)
self._canvas.after(50, lambda: self.animateFlips(5))
elif i == 5:
self._canvas.create_oval(x1,y1,x2,y2,fill=color)
newBoard[x][y] = Othello.nextTurn(self._game.turn)
self._game = GameState(board = newBoard, turn = self._game.turn, skipped = 0)
self.displayMoves()
self.displayButtons()
self.displayInfo()
self.displayWinner(self.getWinner())
self._canvas.bind('<Configure>',self.draw_handler)
The simplest solution is to not delete and recreate the game pieces on each iteration. Draw them once, and then use the itemconfig method to alter the appearance of the game pieces.
Even better would be to create a GamePiece class so that each piece is represented by this class. Then, move the animation function inside the class. This will make your main logic much easier to understand.
I'm just starting out with python and I'm trying to make a little archery game. However, it creates an error at this point: d = math.sqrt(x*x + y*y) (i.e. the distance between the new point and the original center of the cirlce) Any ideas on why this doesn't work?
def archery():
win = GraphWin("Archery Game", 500,500)
win.setCoords(-50, -50, 50, 50)
circle1 = Circle(Point(0,0), 40)
circle1.setFill("white")
circle1.draw(win)
circle2 = Circle(Point(0,0), 35)
circle2.setFill("black")
circle2.draw(win)
circle3 = Circle(Point(0,0), 30)
circle3.setFill("blue")
circle3.draw(win)
circle4 = Circle(Point(0,0), 25)
circle4.setFill("red")
circle4.draw(win)
circle5 = Circle(Point(0,0), 20)
circle5.setFill("yellow")
circle5.draw(win)
score = 0
for i in range(5):
p = win.getMouse()
p.draw(win)
x = p.getX
y = p.getY
d = math.sqrt(x*x + y*y)
if 40 >= d > 35:
score = score + 1
elif 35 >= d > 30:
score = score + 3
elif 30 >= d > 25:
score = score + 5
elif 25 >= d > 20:
score = score + 7
elif 20 >= d >= 0:
score = score + 9
else:
score = score + 0
print("Your current score is:", score)
win.getMouse()
win.close()
x = p.getX
y = p.getY
will return the function getX and getY instead of executing it. As Mike Steder said, try getX(), that should return a value.
First, you probably need to do:
x = p.getX()
y = p.getY()
i.e. call the functions and use the return value, instead of using the functions themselves.
Second, you can change the math.sqrt(x*x + y*y) call to:
d = math.hypot(x, y)