I was unsure whether to post the full code or not, but here's what I have:
from tkinter import *
from random import randint
HEIGHT = 500
WIDTH = 800
MID_X = WIDTH/2
MID_Y = HEIGHT/2
SHIP_R = 15
SHIP_SPD = 10
bub_id = list()
bub_r = list()
bub_speed = list()
MIN_BUB_R = 10
MAX_BUB_R = 30
MAX_BUB_SPD = 6
GAP = 100
window = Tk()
window.title('Bubble Blaster')
c = Canvas(window, width=WIDTH, height=HEIGHT, bg='darkblue')
c.pack()
ship_id = c.create_polygon(5, 5, 5, 25, 30, 15, fill='red')
ship_id2 = c.create_oval(0, 0, 30, 30, outline='red')
c.move(ship_id, MID_X, MID_Y)
c.move(ship_id2, MID_X, MID_Y)
def move_ship(event):
fixed = True
while fixed == True:
ship_x, ship_y = event.x, event.y
c.move(ship_id, ship_x, ship_y)
c.move(ship_id2, ship_x, ship_y)
sleep(0.01)
def create_bubble():
x = WIDTH + GAP
y = randint(0, HEIGHT)
r = randint(MIN_BUB_R, MAX_BUB_R)
id1 = c.create_oval(x-r, y-r, x+r, y+r, outline='white')
bub_id.append(id1)
bub_r.append(r)
bub_speed.append(randint(1, MAX_BUB_SPD))
def move_bubbles():
for i in range(len(bub_id)):
c.move(bub_id[i], -bub_speed[i], 0)
def get_coords(id_num):
pos = c.coords(id_num)
x = (pos[0] + pos[2])/2
y = (pos[1] + pos[3])/2
return x, y
def del_bubble(i):
del bub_r[i]
del bub_speed[i]
c.delete(bub_id[i])
del bub_id[i]
def clean_up_bubs():
for i in range(len(bub_id)-1, -1, -1):
x, y = get_coords(bub_id[i])
if x < -GAP:
del_bubble(i)
from math import sqrt
def distance(id1, id2):
x1, y1 = get_coords(id1)
x2, y2 = get_coords(id2)
return sqrt((x2-x1)**2 + (y2-y1)**2)
def collision():
points = 0
for bub in range(len(bub_id)-1, -1, -1):
if distance(ship_id2, bub_id[bub]) < (SHIP_R+bub_r[bub]):
points += (bub_r[bub] + bub_speed[bub])
del_bubble(bub)
return points
c.create_text(50, 30, text='TIME', fill='white')
c.create_text(150, 30, text='SCORE', fill='white')
time_text = c.create_text(50, 50, fill='white')
score_text = c.create_text (150, 50, fill='white')
def show_score(score):
c.itemconfig(score_text, text=str(score))
def show_time(time_left):
c.itemconfig(time_text, text=str(time_left))
from time import sleep, time
BUB_CHANCE = 20
TIME_LIMIT = 30
BONUS_SCORE = 1000
# MAIN GAME LOOP
c.bind("<B1_Motion>", move_ship)
score = 0
bonus = 0
end = time() + TIME_LIMIT
while time() < end:
if randint(1, BUB_CHANCE) == 1:
create_bubble()
move_bubbles()
move_ship("<B1_Motion>")
clean_up_bubs()
score += collision()
if (int(score / BONUS_SCORE)) > bonus:
bonus += 1
end += TIME_LIMIT
show_score(score)
show_time(int(end-time()))
window.update()
sleep(0.01)
c.create_text(MID_X, MID_Y, \
text='PARTY TIME, EXCELLENT', fil='white', font=('Helvetica', 30))
c.create_text(MID_X, MID_Y + 30, \
text='Score: ' + str(score), fill='white')
c.create_text(MID_X, MID_Y + 45, \
text='BONU TIME: ' + str(bonus*TIME_LIMIT), fill='white')
I'm a complete beginner when it comes to python, and have been given an assignment to only use tkinter and the standard libraries to give mouse movement to this "game". I just can't seem to get the right grasp of it. Any suggestions would be appreciated!
The first step is to remove your while loop, and put most of your functionality into a function. Put everything you want to do in a single frame of animation into this function.
Next, call this function on a regular interval using the after command. This allows the event loop to run continuously, which is important for your UI to be responsive. You can do your time() < end calculation inside this function, and use the result to break the cycle once time is up.
It looks something like this:
def draw_one_frame():
if randint(1, BUB_CHANCE) == 1:
create_bubble()
move_bubbles()
# move_ship("<B1_Motion>")
clean_up_bubs()
score += collision()
if (int(score / BONUS_SCORE)) > bonus:
bonus += 1
end += TIME_LIMIT
show_score(score)
show_time(int(end-time()))
if time() < end:
after(10, draw_one_frame)
You can use the first parameter to after to control how many frames per second you wish your program to run at.
Next, you need to handle mouse movement. You do this by creating a binding to the movement of the mouse. You do this outside of the draw_one_frame method. It looks something like this:
c.bind("<B1-Motion>", move_ship)
You also need to remove the infinite loop from move_ship, and also remove the sleep. You simply need to do all the calculations for the current mouse position. The function will be already be looping -- being called once each time the mouse moves.
Finally, you need to call window.mainloop() after all your other code, so that the program can process events. This should be the very last line of your program. It will run until the window is destroyed.
Related
I can't find a source on how to add play again for my python code. I am currently using a snake game that i found on YouTube but I honestly am having trouble figuring this out.
github.com/Amfuhr/Snake-game.git
def game_over():
canvas.delete(ALL)
canvas.create_text(canvas.winfo_width()/2, canvas.winfo_height()/2,
font=('consolas',70), text="GAME OVER", fill="red", tag="gameover")
The full script:
#The tkinter package (“Tk interface”) is the standard Python interface to the Tcl/Tk GUI toolkit.
#Tkinter are available on most Unix platforms, including macOS, as well as on Windows systems.
from tkinter import *
import random
#box size, game speed, and color schemes
#classes for the game settings
GAME_WIDTH = 700
GAME_HEIGHT = 700
SPEED = 400
#Snake and food size
SPACE_SIZE = 50
BODY_PARTS = 3
#class for snake and food
#RGB for the color of the backgrund, snake, and food
SNAKE_COLOR = "white"
FOOD_COLOR = "blue"
BACKGROUND_COLOR = "#000000"
class Snake:
#set the body size of the snake, a list of square graphics
def __init__(self):
self.body_size = BODY_PARTS
self.coordinates = []
self.squares = []
#list of coordinates
for i in range(0, BODY_PARTS):
self.coordinates.append([0, 0])
for x, y in self.coordinates:
square = canvas.create_rectangle(x, y, x + SPACE_SIZE, y + SPACE_SIZE, fill=SNAKE_COLOR, tag="snake")
self.squares.append(square)
class Food:
def __init__(self):
#food is set into random location using the random module
#based on orientation. We use fill to set the food color
x = random.randint(0, (GAME_WIDTH / SPACE_SIZE)-1) * SPACE_SIZE
y = random.randint(0, (GAME_HEIGHT / SPACE_SIZE) - 1) * SPACE_SIZE
self.coordinates = [x, y]
canvas.create_oval(x, y, x + SPACE_SIZE, y + SPACE_SIZE, fill=FOOD_COLOR, tag="food")
def next_turn(snake, food):
#head of the snake and the direction of the snake movements
x, y = snake.coordinates[0]
if direction == "up":
y -= SPACE_SIZE
elif direction == "down":
y += SPACE_SIZE
elif direction == "left":
x -= SPACE_SIZE
elif direction == "right":
x += SPACE_SIZE
snake.coordinates.insert(0, (x, y))
square = canvas.create_rectangle(x, y, x + SPACE_SIZE, y + SPACE_SIZE, fill=SNAKE_COLOR)
snake.squares.insert(0, square)
if x == food.coordinates[0] and y == food.coordinates[1]:
global score
score += 1
label.config(text="Score:{}".format(score))
canvas.delete("food")
food = Food()
else:
del snake.coordinates[-1]
canvas.delete(snake.squares[-1])
del snake.squares[-1]
if check_collisions(snake):
game_over()
else:
window.after(SPEED, next_turn, snake, food)
def change_direction(new_direction):
global direction
if new_direction == 'left':
if direction != 'right':
direction = new_direction
elif new_direction == 'right':
if direction != 'left':
direction = new_direction
elif new_direction == 'up':
if direction != 'down':
direction = new_direction
elif new_direction == 'down':
if direction != 'up':
direction = new_direction
def check_collisions(snake):
x, y = snake.coordinates[0]
if x < 0 or x >= GAME_WIDTH:
return True
elif y < 0 or y >= GAME_HEIGHT:
return True
for body_part in snake.coordinates[1:]:
if x == body_part[0] and y == body_part[1]:
return True
return False
def game_over():
canvas.delete(ALL)
canvas.create_text(canvas.winfo_width()/2, canvas.winfo_height()/2,
font=('consolas',70), text="GAME OVER", fill="red", tag="gameover")
#Window sizing so it does not game
window = Tk()
window.title("Snake game")
window.resizable(False, False)
score = 0
direction = 'down'
#this is to show the score in a specific font size
label = Label(window, text="Score:{}".format(score), font=('consolas', 40))
label.pack()
#canvas sets the background and opens the window
canvas = Canvas(window, bg=BACKGROUND_COLOR, height=GAME_HEIGHT, width=GAME_WIDTH)
canvas.pack()
window.update()
window_width = window.winfo_width()
window_height = window.winfo_height()
screen_width = window.winfo_screenwidth()
screen_height = window.winfo_screenheight()
x = int((screen_width/2) - (window_width/2))
y = int((screen_height/2) - (window_height/2))
# Geometry method is used to set the dimensions of the
# Tkinter window and is used to set the position of the main
# window on the user’s desktop.
window.geometry(f"{window_width}x{window_height}+{x}+{y}")
window.bind('<Left>', lambda event: change_direction('left'))
window.bind('<Right>', lambda event: change_direction('right'))
window.bind('<Up>', lambda event: change_direction('up'))
window.bind('<Down>', lambda event: change_direction('down'))
snake = Snake()
food = Food()
next_turn(snake, food)
window.mainloop()
Think about it this way. Your app works upon running the first time around, and you just want to repeat, that behavior, (aka run that portion of the code again), once the initial game is over without having to restart the app.
This is precisely what functions are for.
The portion of your code that executes the game is just the last three lines of your script.
snake = Snake()
food = Food()
next_turn(snake, food)
So what you can do is stick those 3 lines into a function, and put the function call just before the mainloop call where the lines used to be.
def start_game(*arg):
canvas.delete(ALL)
snake = Snake()
food = Food()
next_turn()
start_game()
window.mainloop()
So now in order to restart the game, all you need to do is call the start_game function. Adding the canvas.delete(ALL) ensures that the "GAME OVER" message is removed before the new game starts.
Now all you need is a trigger. For this you can add a double-click signal on the canvas so that when it says "GAME OVER" all you need to do is double-click on the window and the new game starts. You can even add an instruction for the user.
To do this just add a window.bind call for the double-click action gesture:
window.bind('<Double-Button-1>', start_game)
Then to add the note to your "Game Over" message in your game_over function:
def game_over():
canvas.delete(ALL)
canvas.create_text(canvas.winfo_width()/2, canvas.winfo_height()/2,
font=('consolas',70), text="GAME OVER",
fill="red", tag="gameover")
canvas.create_text(canvas.winfo_width()/2, canvas.winfo_height()/1.8,
font=('consolas',20), text="double click for new game",
fill='green', tag='newgame')
And that should do it. This solution does create a new issue though, since there are no conditions on the new event binder, double clicking the screen will start a new game even if the current game is still ongoing.
I will leave this for you to try to solve. Or if you prefer you can use a different trigger.
Working on this Game of Life version in pygame.
In the end I want to have two options to run the game: one where you can start the game and it runs automatically with a random grid and a game where the user starts with an empty grid and can activate/deactivate cells.
Currently I only have the random grid mode and Im struggling with the activation/deactivation of cells.
In handle_events() there is a function that allows the user to click on cells to activate them in the random grid if the game is paused, but for some reason it doesn't allow the user to deactivate those cells again. Also, it is overwritten in the next iteration.
Does anyone know how i can fix this? And what would be the best way to create two different game modes ("random game" and "user selects cell mode").
Thanks in advance
I have posted the code below.
import pygame
import random
import sys
grid_size = width, height = 400, 400
cell_size = 10
color_dead = 0, 0, 0 # Background
color_alive = 255, 255, 255 # alive cell, can be any color. #orange = 255, 100, 0 #yellow = 255,255,0, # red=255,0,0 #Green 0,200,0
fps_max = 10
class GameOfLife:
def __init__(self):
#The screen
pygame.init()
pygame.display.set_caption("Game of Life - Created by ")
self.FPSCLOCK = pygame.time.Clock()
self.screen = pygame.display.set_mode(grid_size)
self.clear_screen() # you clear the screen before it starts running
pygame.display.flip() #Update the full display Surface to the screen
self.last_update_completed = 0
#self.desired_milliseconds_between_updates = (1.0 / fps_max) * 1000
self.active_grid = 0
self.num_cols = int(width / cell_size)
self.num_rows = int(height / cell_size)
self.grids = []
self.init_grids()
self.set_grid()
self.paused = False
self.game_over = False
def is_in_range(self, x, y):
if x in range(self.x, self.x + self.size + 1) and y in range(self.y, self.y + self.size + 1):
return True
else:
return False
def init_grids(self):
def create_grid():
rows = []
for row_num in range(self.num_rows):
list_of_columns = [0] * self.num_cols
rows.append(list_of_columns)
return rows
self.grids.append(create_grid())
self.grids.append(create_grid())
self.active_grid = 0
#print(self.grids[0])
#print(rows)
#print(type(rows))
#set_grid(0) = all dead
#set_grid(1) = all alive
#set_grid() = random
#set_grid(None) = random
def set_grid(self, value=None, grid =0):
for r in range(self.num_rows):
for c in range(self.num_cols):
if value is None:
cell_value = random.choice([0,1])
else:
cell_value = value
self.grids[grid][r][c] = cell_value
def draw_grid(self):
self.clear_screen() # you clear the screen before it starts running
for c in range(self.num_cols):
for r in range(self.num_rows):
if self.grids[self.active_grid][r][c] == 1:
color = color_alive
else:
color = color_dead
#pygame.draw.rect(self.screen, color, ((c * cell_size + (cell_size / 2)),(r * cell_size + (cell_size / 2)), cell_size, cell_size) )
posn = (int(c * cell_size + cell_size / 2),
int(r * cell_size + cell_size / 2))
pygame.draw.circle(self.screen, color, posn, int(cell_size / 2), 0)
pygame.display.flip()
def clear_screen(self):
self.screen.fill(color_dead)
def get_cell(self, r, c):
try:
cell_value = self.grids[self.active_grid][r][c]
except:
#print("Couldn't get cell value: row: %d, col %d" % (r, c))
cell_value = 0
return cell_value
def check_cell_neighbors(self, row_index, col_index):
# Get the number of alive cells surrounding the current cell
# self.grids[self.active_grid][r][c] #is the current cell
num_alive_neighbors = 0
num_alive_neighbors += self.get_cell(row_index - 1, col_index - 1)
num_alive_neighbors += self.get_cell(row_index - 1, col_index)
num_alive_neighbors += self.get_cell(row_index - 1, col_index + 1)
num_alive_neighbors += self.get_cell(row_index, col_index - 1)
num_alive_neighbors += self.get_cell(row_index, col_index + 1)
num_alive_neighbors += self.get_cell(row_index + 1, col_index - 1)
num_alive_neighbors += self.get_cell(row_index + 1, col_index)
num_alive_neighbors += self.get_cell(row_index + 1, col_index + 1)
#print(num_alive_neighbors)
#print("alive neighbors: %d")
# Rules
#1 Any live cell with fewer than two live neighbours dies, as if by underpopulation.
#2 Any live cell with two or three live neighbours lives on to the next generation.
#3 Any live cell with more than three live neighbours dies, as if by overpopulation.
#4 Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
if self.grids[self.active_grid][row_index][col_index] == 1: #Alive
if num_alive_neighbors > 3:
return 0 # it dies of overpopulation # More than three live neighbors, rule number 3.
if num_alive_neighbors < 2:
return 0 # it dies of underpopulation = Rule number 1 = fewer than two live neighbors
if num_alive_neighbors == 2 or num_alive_neighbors == 3: # If there are 3 or 4 neighbors, and the cell is alive, it stays alive.
return 1 # Rule number 2. Two or three live neighbours, it continuous to live.
elif self.grids[self.active_grid][row_index][col_index] == 0: #Dead
if num_alive_neighbors ==3:
return 1 #It comes to life.
return self.grids[self.active_grid][row_index][col_index]
def update_generation(self):
"""
Inspect current generation state, prepare next generation
:return:
"""
self.set_grid(0, self.inactive_grid())
for r in range(self.num_rows - 1):
for c in range(self.num_cols - 1):
next_gen_state = self.check_cell_neighbors(r, c)
# Set inactive grid future cell state
self.grids[self.inactive_grid()][r][c] = next_gen_state # if it is zero, than is is 1. if it is 1, it is gonna be 0. Picks the offgrid.
self.active_grid = self.inactive_grid()
#inspect the current active generation
# update the inactive grid to store next generation
#swap out the active grid
#self.set_grid(None) #This means that you randomize the grid
def inactive_grid(self):
return (self.active_grid + 1) % 2
def handle_events(self):
for event in pygame.event.get():
if self.paused:
if event.type == pygame.MOUSEBUTTONDOWN:
if(event.button==1):
mousepos_x, mousepos_y = event.pos
r, c = ((mousepos_x - cell_size / 2) // cell_size,
(mousepos_y - cell_size / 2) // cell_size)
print(event.pos, '->', (r, c)) # Show result.
mousepos_x, mousepos_y = event.pos# Index Y rows down, X columns to the right
for col in range(self.num_cols):
for row in range(self.num_rows):
if self.grids[self.active_grid][col][row] == 1:
color = color_dead
elif self.grids[self.active_grid][col][row] == 0:
color = 255,0,255#color_alive
posn = (int(r * cell_size + cell_size / 2),
int(c * cell_size + cell_size / 2))
print(posn)
pygame.draw.circle(self.screen, color, posn, int(cell_size / 2), 0)
pygame.display.flip()
if event.type == pygame.KEYDOWN:
if event.unicode == 's':
if self.paused:
self.paused = False
print("unpaused")
else:
self.paused = True
print("paused")
#Randomizin the grid
elif event.unicode == 'r':
print("randomizing the grid")
self.active_grid = 0
self.set_grid(None, self.active_grid) #randomizing
self.set_grid(0,self.inactive_grid()) #set to 0.
self.draw_grid() #Even if it is paused.
# Quitfunction
elif event.unicode == 'q': #If I press q, game_over becomes TRUE, which returns/ends in the def run().
print("Quitting the grid")
self.game_over = True
# print(event.unicode)
# print("Key pressed")
# print(event.unicode)
# if event is keypress of "s" then pause the loop/game.
#if event is keypress "r" then randomize grid
# if event is keypress of "q"then quit
if event.type == pygame.QUIT:
sys.exit()
def run(self):
while True:
if self.game_over:
return #So if it is game_over by pressing Q, you leave the loop.
self.handle_events() # when you run, you want to handle the events
if self.paused:
continue
self.update_generation() # Upgrade the generation
self.draw_grid() # and draw the grid
self.FPSCLOCK.tick(fps_max)
if __name__ == "__main__":
game = GameOfLife()
game.run()
It looks like you're simply changing the color of the cells instead of directly changing the values themselves. So add the specific indexing and set the value to their opposite and that should fix both problems.
mousepos_x, mousepos_y = event.pos# Index Y rows down, X columns to the right
if self.grids[self.active_grid][int(mousepos_x / 10)][int(mousepos_y / 10)] == 1:
color = color_dead
self.grids[self.active_grid][int(mousepos_x / 10)][int(mousepos_y / 10)] = 0
elif self.grids[self.active_grid][int(mousepos_x / 10)][int(mousepos_y / 10)] == 0:
color = 255,0,255#color_alive
self.grids[self.active_grid][int(mousepos_x / 10)][int(mousepos_y / 10)] = 1
This should fix both problems.
I'm not sure what you're trying to do in the handle_events() function for handling mouse button clicks. Here's a version that will allow cells to be activated and deactived when clicked, and the changes are overwritten in the next generation (unless they all happened to die due to application of the generation update rules).
I don't think you need to have the different modes (e.g. "random" vs "user selects") because that can be accomplished via the various single-key commands you've already implemented, although you woujld need to add one more that allowed manual clearing of the grid.
def handle_events(self):
for event in pygame.event.get():
if self.paused:
if event.type == pygame.MOUSEBUTTONDOWN:
if(event.button==1):
mousepos_x, mousepos_y = event.pos
c, r = (int((mousepos_x - cell_size / 2) // cell_size),
int((mousepos_y - cell_size / 2) // cell_size))
#print(event.pos, '->', (r, c)) # Show result.
if r in range(self.num_rows) and c in range(self.num_cols):
# Toggle state of cell: active <--> inactive
if self.grids[self.active_grid][r][c] == 1:
self.grids[self.active_grid][r][c] = 0
color = color_dead
else:
self.grids[self.active_grid][r][c] = 1
color = color_alive
# Redraw cell in its new color.
posn = (int(c * cell_size + cell_size / 2),
int(r * cell_size + cell_size / 2))
#print(' posn:', posn)
pygame.draw.circle(self.screen, color, posn, int(cell_size / 2), 0)
pygame.display.flip()
if event.type == pygame.KEYDOWN:
if event.unicode == 's':
.
.
.
I'm making a snake game in pygame and i've run into a problem. Whenever the snake eats food, the player gains a point. From that point on a tail is created behind the snake whenever it moves. Only the tails the number of player points away from the snake head will be drawn while the rest are deleted. The problem arises when i'm creating the tails. Whenever i create an instance of the tail, i have to get the position of the snake head and subtract away a value equal to the snake size in the opposite direction. That's where the tail will be drawn. However the position of all the tails are set to the same value for some reason and i cant't figure out why that is. I'm using my own library so i cant post it in here but iv'e determined it's not the cause.
import pygame as pg
from random import randrange
import widget
# disp -> display properties
disp = widget.get_json("config", ["display"])
food = widget.Surface(image="../images/food.png", pos=[0, 0])
def set_food_pos(snake):
while True:
pos = [randrange(0, disp["size"][_], disp["cell"]) for _ in range(2)]
safe = 0
for tail in snake.tails:
if tail.pos != pos: safe += 1
if safe == len(snake.tails):
food.pos = pos
food.rect.topleft = food.pos
break
class Snake(widget.Sprite):
""" Snake: main playable sprite """
SIZE = [disp["cell"]] * 2
KEYS = [[276, 275], [273, 274]]
def __init__(self):
self.image = pg.image.load("../images/snake_head.png")
self.pos = widget.VEC(0, 0)
super().__init__(pg.sprite.GroupSingle)
self.axis, self.orient, self.do_move = 0, 1, False
self.past, self.delay = pg.time.get_ticks(), 150
self.speed, self.vel = disp["cell"], [-1, 1]
self.alive, self.points = True, 0
self.tails = [self]
def control(self, key):
axis = [0 if key in Snake.KEYS[0] else 1][0]
if axis != self.axis:
if self.do_move:
self.axis = axis
self.orient = Snake.KEYS[axis].index(key)
self.do_move = False
def time_base_movement(self):
now = pg.time.get_ticks()
if now - self.past >= self.delay:
self.do_move = True
self.pos[self.axis] += self.vel[self.orient] * self.speed
self.past = pg.time.get_ticks()
def eat_food(self):
if food.rect.contains(self.rect):
set_food_pos(self)
self.points += 1
def create_tail(self):
if self.points:
if self.do_move:
pos = [_ for _ in self.rect.topleft]
pos[self.axis] += self.vel[::-1][self.orient] * 20
tail = widget.Sprite(image="../images/snake_head.png", pos=pos)
self.tails.insert(0, tail)
def render_tails(self, surface):
if self.points > 0:
tails = self.tails[:-1]
for tail in tails[0:self.points]: tail.group.draw(surface)
[self.tails.remove(tail) for tail in tails[self.points:]]
def check_boundary_collision(self):
for _ in range(2):
if self.pos[_] > disp["size"][_] - Snake.SIZE[_]:self.alive = False
elif self.pos[_] < 0: self.alive = False
for tail in self.tails[:-1]:
if tail.rect.contains(self.rect): self.alive = False
def reset_properties(self):
if self.alive == False:
print([tail.pos for tail in self.tails[:-1]])
self.tails = [self]
self.do_move = False
self.pos = widget.VEC([0, 0])
self.rect.topleft = self.pos
self.axis, self.orient = 0, 1
self.points, self.alive = 0, True
set_food_pos(self)
def update(self):
if self.alive:
self.time_base_movement()
self.check_boundary_collision()
self.reset_properties()
self.rect.topleft = self.pos
I figured it out, it seems python doesn't create a new copy of an attribute each time it is assigned to a different attribue. Instead the new attribute points to the assigned attribute. The fix for this is the "deepcopy" method in the built in module "copy".
Exe: new_value = copy.deepcopy(old_value)
So I'm making a game in python and when I shoot my fly object it explodes, but then after it explodes no more objects come down. I need to know how to fix this so that objects will keep coming down for me to shoot and destroy. Here's my code:
SPEED = 3
#set initial location of image
image_x = random.randrange(0, 480)
image_y = -50
image_y = image_y + SPEED
if image_y > 640:
image_x = random.randrange(0, 480)
image_y = -25
def __init__(self, x = 40, y = 40, speed = 2, odds_change = 200):
""" Initialize the Fly object. """
super(Fly, self).__init__( image = Fly.image,
y = y, x = random.randrange(0, 480),
dy = speed,
dx = speed)
self.bottom = 0
self.odds_change = odds_change
self.time_til_drop = 500
def update(self):
""" Determine if direction needs to be reversed."""
if self.left < 0 or self.right > games.screen.width:
self.dx = -self.dx
elif random.randrange(self.odds_change) == 0:
self.dx = -self.dx
self.check_drop()
def check_drop(self):
""" Decrease countdown or drop fly and reset countdown. """
if self.time_til_drop > 0:
self.time_til_drop -= 1
else:
self.time_til_drop = 500
new_fly = Fly(x = self.x)
games.screen.add(new_fly)
#set buffer to approx 30% of fly height regardless of fly speed
self.time_til_drop = int(new_fly.height * 1000 / Fly.SPEED) + 1000
def die(self):
"""Destroy Fly."""
#If fly is destroyed, then continue playing
self.destroy()
You're not actually using a class, you're just writing functions.
So, I know about the sleep function, but it doesn't work how I expected it to work.
If I do something like this:
from time import sleep
print('Something')
sleep (10)
print('Something')
It works how (I think) it should (it prints one thing, waits and then prints the other one).
But in my code it doesn't work like that.
This is the whole code:
from tkinter import *
from time import sleep
# Fenster
window = Tk()
window.title('Test')
c = Canvas(window, height=450, width=800)
c.pack()
# Bildelemente
Hintergrund = PhotoImage(file='Hintergrund.gif')
Background = Label(image=Hintergrund)
Background.image = Hintergrund
Background.place(x=0, y=0)
Boden = PhotoImage(file='Boden.gif')
Ground = Label(image=Boden)
Ground.image = Boden
Ground.place(x=0, y=300)
Char = PhotoImage(file='Char.gif')
Character = Label(image=Char)
Character.image = Char
Character.pack()
# Koordinaten ermitteln
def coordinatesX(id_num):
pos = c.coords(id_num)
x = (pos[0] + pos[2])/2
return x
def coordinatesY(id_num):
pos = c.coords(id_num)
y = (pos[1] + pos[3])/2
return y
# Charakter bewegen
def Char_move(event):
if event.keysym == 'Right' and coordinatesX(Char_) < 800 - 50:
c.move(Char_, 10, 0)
Character.place(x=(coordinatesX(Char_)), y=(coordinatesY(Char_)))
if event.keysym == 'Left' and coordinatesX(Char_) > 0:
c.move(Char_, -10, 0)
Character.place(x=(coordinatesX(Char_)), y=(coordinatesY(Char_)))
if event.keysym == 'Up' and coordinatesY(Char_) < 300 and coordinatesY(Char_) > 0:
jump()
sleep(5)
print('NA')
c.bind_all('<Key>', Char_move)
def jump():
c.move(Char_, 0, -50)
Character.place(x=(coordinatesX(Char_)), y=(coordinatesY(Char_)))
# Objekt zur Postitionsbestimmung vom Charakter
Char_ = c.create_oval(0, 0, 50, 50, fill='red')
c.move(Char_, 100, 223)
Character.place(x=(coordinatesX(Char_)), y=(coordinatesY(Char_)))
In this part I want it to wait and then do something (in this "example" print):
jump()
sleep(5)
print('NA')
But when I run the program and hit 'Up', it waits and then the object goes up and the program prints "NA" at the same time.
How do I have to do this so that the object goes up, it waits and then prints something?
Do not use sleep. Use the tkinter after method instead.
jump()
window.after(5000, lambda x: print('NA'))
Sleep freezes your gui. Jump is executed but sleep prevents the gui from being redrawn, therefore you do not see any change. After is a method from Tk and allows you to schedule operations.