Why my ball Sprite doesnt always bounce on my Sprite bar?! - python

I have some problems and I cant figure out how to fix them...
It is really simple game. A bar moved by the mouse and one ball is (or some balls) bouncing.
The user just need to keep the ball bouncing.
The user can choose how many balls he wants (1,2,3), the size of the bar (small, medium,large) and the speed of the balls (slow, normal, fast).
Problems:
- sometimes everything works fine, and sometimes the ball (or balls) just goes through the bar. Like if the collision function does not work. Is there any other way I can do?
everytime there is a collision, the score should add 10 points for the total displayed on top of the screen, but this score is been overwriting all the time.
For this game be run, I just have to call the function (startGame) from other file (settings), where it also sends the value of number of balls, size of bar and speed of balls.
If anyone can help I appreciate.
Thanks
from livewires import games, color
from tkinter import*
import random
games.init(screen_width = 735, screen_height = 350, fps = 60)
class Bounce(games.Sprite):
global total_score
total_score = 0
def update(self):
global total_score
if self.bottom == 315 and self.overlapping_sprites:
self.dy = -self.dy
total_score += 10
the_score = games.Text(value = 0, size = 25,
color = color.gray,x = 700, y = 20)
games.screen.add(the_score)
if self.right > games.screen.width or self.left < 0:
self.dx = -self.dx
if self.top < 0:
self.dy = -self.dy
if self.bottom == 400:
lose_message = games.Message(value = " - GAME OVER -",
size = 50,
color = color.gray,
x = games.screen.width/2,
y = games.screen.height/2,
lifetime = 300,
after_death = games.screen.quit)
games.screen.add(lose_message)
class Bar_moving(games.Sprite):
def update(self):
self.x = games.mouse.x
self.y = 315
if self.left < 0:
self.left = 0
if self.right > games.screen.width:
self.right = games.screen.width
class have_settings():
def __init__(self):
global the_ball_speed
global the_ball_number
global the_bar_size
if "the_ball_speed" not in globals():
the_ball_speed = "normal"
if "the_bar_size" not in globals():
the_bar_size = "medium"
if "the_ball_number" not in globals():
the_ball_number = 1
def set_all(self, number, size, speed):
global the_ball_speed
global the_bar_size
global the_ball_number
if speed in ("slow","normal","fast"):
the_ball_speed = speed
if size in ("small","medium","large"):
the_bar_size = size
if number in (1,2,3):
the_ball_number = number
def startGame():
call = have_settings()
background = games.load_image("BG.jpg", transparent = False)
games.screen.background = background
#-------------------------------------SPEED
sp_is = 0
if the_ball_speed == "slow":
sp_is = 2
elif the_ball_speed == "normal":
sp_is = 3
elif the_ball_speed == "fast":
sp_is = 4
#-------------------------------------BALL NUMBER
if the_ball_number in (1,2,3):
for n in range(the_ball_number):
position_x_list =(50,150,250,350,400,450,500,550)
position_x = random.choice(position_x_list)
position_y_list =(50,100,150,200,225,250)
position_y = random.choice(position_y_list)
vert_speed_list = (-2,2)
vert_speed = random.choice(vert_speed_list)
ball_img = games.load_image("ball.bmp")
ball = Bounce(image = ball_img,
x = position_x,
y = position_y,
dx = vert_speed,
dy = - sp_is)
games.screen.add(ball)
#-------------------------------------BAR SIZE
if the_bar_size in ("small","medium","large"):
if the_bar_size == "small":
bar_pic = "bar_small.jpg"
elif the_bar_size == "medium":
bar_pic = "bar_medium.jpg"
elif the_bar_size == "large":
bar_pic = "bar_large.jpg"
bar = games.load_image(bar_pic, transparent = False)
the_bar = Bar_moving(image = bar, x = games.mouse.x)
games.screen.add(the_bar)
games.mouse.is_visible = False
games.screen.event_grab = True
games.screen.mainloop()

You should do a greater than check rather than an equals check as follows:
if self.bottom >= 315 and self.overlapping_sprites:
^^
instead of
if self.bottom == 315 and self.overlapping_sprites:
This is because rarely will the ball's y position ever perfectly line up with the bottom. In some cases it may go from y==314 to y==316. In such cases, your method above wouldn't work. Therefore, you should be a greater than test rather than an equality test.
You can apply similar changes everywhere else and it should work.

Related

Python Snake Game - Why does the food only gets eaten occasionally?

I'm currently taking a python course where we had to built a snake game. I did not follow the tutors instuctions and I tried to do it on my own. I could make it work for the most part, but I can't figure out why the purple food elements sometimes are not eaten by the snake, even though the snake directly strikes over the food. I would appreciate it, if someone with more experience than me could look over my code to find the bug, I certainly don't know where the mistake is. Here is the code:
from turtle import Turtle, Screen
import random
import time
class Snake():
def __init__(self):
screen.onkeypress(self.look_left, 'a')
screen.onkeypress(self.look_right, 'd')
screen.listen()
self.snake_squares = {
1: Turtle(),
2: Turtle(),
3: Turtle(),
}
for square in self.snake_squares:
self.design_square(self.snake_squares[square])
self.snake_head = self.snake_squares[1]
self.look_left()
def design_square(self, current_square):
current_square.penup()
current_square.shape('square')
current_square.color('white')
current_square.shapesize(1.00)
current_square.pensize(1)
def add_square(self, new_score):
square_amount = new_score + 3
self.snake_squares[square_amount] = Turtle()
self.design_square(self.snake_squares[square_amount])
self.snake_squares[square_amount].setposition(self.old_position)
def look_left(self):
self.snake_head.left(90)
def look_right(self):
self.snake_head.right(90)
def move(self):
self.old_position = self.snake_head.position()
self.snake_head.forward(10.00)
all_square_positions = []
for square in self.snake_squares:
if square != 1:
next_square = self.snake_squares[square]
new_position = self.old_position
self.old_position = next_square.position()
next_square.setposition(new_position)
all_square_positions.append(new_position)
return self.snake_head.position(), all_square_positions
def check_self_hit(self, head_position, tail_positions):
if head_position in tail_positions:
return False
else:
return True
class Board():
def __init__(self, height):
self.score_board = Turtle()
self.score_board.hideturtle()
self.score_board.setposition(0, height + 10)
self.score_board.color('white')
self.score = 0
def add_to_score(self, old_score):
self.score_board.color('black')
self.score_board.write(arg=f"Score: {self.score}", font=('Arial', 25, "normal"), align='center')
self.score = old_score + 1
self.score_board.color('white')
self.score_board.write(arg=f"Score: {self.score}", font=('Arial', 25, "normal"), align='center')
return self.score
class Border():
def __init__(self, width, height):
self.width = width
self.height = height
self.positive_borders = [self.width, self.height]
self.negative_borders = [- self.width, - self.height]
def check_borders(self, snake_position):
no_hit = True
for border in self.positive_borders:
if snake_position[0] >= border:
no_hit = False
elif snake_position[1] >= border:
no_hit = False
else:
pass
for border in self.negative_borders:
if snake_position[0] <= border:
no_hit = False
elif snake_position[1] <= border:
no_hit = False
else:
pass
return no_hit
def print_border(self, width, height):
line = Turtle()
line.hideturtle()
line.setposition(-float(width), -float(height))
line.shape("circle")
line.speed('fastest')
line.color('white')
for wall in range(4):
line.forward(800)
line.left(90)
class Food():
def __init__(self, width, height):
self.width = width
self.height = height
self.food = Turtle()
self.food.hideturtle()
self.food.speed('fastest')
self.food.penup()
self.food.pensize(3)
self.food.shape('circle')
self.food.color('purple')
def create_food(self):
self.food.showturtle()
self.food.clear()
return self.random_position()
def random_position(self):
x_min = -self.width + 10 #-390
x_max = self.width - 10 #390
y_min = -self.height + 10 #-390
y_max = self.height - 10 #390
x = 11
y = 11
while x % 10.00 != 0.00:
x = float(random.randint(x_min, x_max))
while y % 10.00 != 0.00:
y = float(random.randint(y_min, y_max))
self.food.setposition((x, y))
x += 10.00
y += 10.00
all_possible_hits = []
for hits in range(3):
all_possible_hits.append((x, y -10.00))
x -= 10.00
for hits in range(3):
all_possible_hits.append((x + 10.00, y))
y -= 10.00
return all_possible_hits
def erase_food(self):
self.food.hideturtle()
screen = Screen()
screen.tracer(0)
canvas_width = 400
canvas_height = 400
screen.bgcolor("black")
border = Border(canvas_width, canvas_height)
border.print_border(canvas_width, canvas_height)
snake = Snake()
food = Food(canvas_width, canvas_height)
board = Board(canvas_height)
current_score = board.add_to_score(-1)
current_food_positions = food.create_food()
snake_alive = True
screen.update()
snake_path = []
while snake_alive:
time.sleep(0.03)
screen.update()
snake_current_position, all_positions = snake.move()
snake_path.append(snake_current_position)
if snake.check_self_hit(snake_current_position, all_positions):
if border.check_borders(snake_current_position):
if snake_current_position in current_food_positions:
current_score = board.add_to_score(current_score)
snake.add_square(current_score)
food.erase_food()
current_food_positions = food.create_food()
screen.update()
else:
snake_alive = False
else:
snake_alive = False
screen.exitonclick()
I don't really know why that happens, especially because it only happens sometimes and at different score amounts.
A few things here:
As the first comment pointed out, generally, you would not come to stackoverflow for debugging advice like this, at least without trying to debug on your own and posting the results with your question
Something you will need to keep in mind always is that directly comparing floating point values for equality is a big no-no in any programming (that is only one of the hundreds of articles explaining why, for a much more in depth and possibly over your head look, check out this). I believe that is directly where your problem lies in this case as well. By using snake_current_position in current_food_positions, you are likely asking for that comparison to be made between a bunch of floats as your have it written, and therefor failing the equality check when it looks like it should be true.
To find this out and debug your next program on your own, think about how debugging could be done. There are many tools but the simplest is sometimes just to print things. When taking a look myself, the first thing I did was add
print("snake:")
print(snake_pos_int)
print("food")
print(current_food_positions)
as well as turned the game speed down (sleep time up) so I could watch the output. This allowed me to get an idea if the values were sane, and also notice that the values were printing as floating point numbers with different amounts of rounding (10.0 vs 10.00) which is another indicator you definitely should not be directly comparing them.
This brings me to the "solution"
from turtle import Turtle, Screen
import random
import time
class Snake():
def __init__(self):
screen.onkeypress(self.look_left, 'a')
screen.onkeypress(self.look_right, 'd')
screen.listen()
self.snake_squares = {
1: Turtle(),
2: Turtle(),
3: Turtle(),
}
for square in self.snake_squares:
self.design_square(self.snake_squares[square])
self.snake_head = self.snake_squares[1]
self.look_left()
def design_square(self, current_square):
current_square.penup()
current_square.shape('square')
current_square.color('white')
current_square.shapesize(1)
current_square.pensize(1)
def add_square(self, new_score):
square_amount = new_score + 3
self.snake_squares[square_amount] = Turtle()
self.design_square(self.snake_squares[square_amount])
self.snake_squares[square_amount].setposition(self.old_position)
def look_left(self):
self.snake_head.left(90)
def look_right(self):
self.snake_head.right(90)
def move(self):
self.old_position = self.snake_head.position()
self.snake_head.forward(10)
all_square_positions = []
for square in self.snake_squares:
if square != 1:
next_square = self.snake_squares[square]
new_position = self.old_position
self.old_position = next_square.position()
next_square.setposition(new_position)
all_square_positions.append(new_position)
return self.snake_head.position(), all_square_positions
def check_self_hit(self, head_position, tail_positions):
if head_position in tail_positions:
return False
else:
return True
class Board():
def __init__(self, height):
self.score_board = Turtle()
self.score_board.hideturtle()
self.score_board.setposition(0, height + 10)
self.score_board.color('white')
self.score = 0
def add_to_score(self, old_score):
self.score_board.color('black')
self.score_board.write(arg=f"Score: {self.score}", font=('Arial', 25, "normal"), align='center')
self.score = old_score + 1
self.score_board.color('white')
self.score_board.write(arg=f"Score: {self.score}", font=('Arial', 25, "normal"), align='center')
return self.score
class Border():
def __init__(self, width, height):
self.width = width
self.height = height
self.positive_borders = [self.width, self.height]
self.negative_borders = [- self.width, - self.height]
def check_borders(self, snake_position):
no_hit = True
for border in self.positive_borders:
if snake_position[0] >= border:
no_hit = False
elif snake_position[1] >= border:
no_hit = False
else:
pass
for border in self.negative_borders:
if snake_position[0] <= border:
no_hit = False
elif snake_position[1] <= border:
no_hit = False
else:
pass
return no_hit
def print_border(self, width, height):
line = Turtle()
line.hideturtle()
line.setposition(-float(width), -float(height))
line.shape("circle")
line.speed('fastest')
line.color('white')
for wall in range(4):
line.forward(800)
line.left(90)
class Food():
def __init__(self, width, height):
self.width = width
self.height = height
self.food = Turtle()
self.food.hideturtle()
self.food.speed('fastest')
self.food.penup()
self.food.pensize(3)
self.food.shape('circle')
self.food.color('purple')
def create_food(self):
self.food.showturtle()
self.food.clear()
return self.random_position()
def random_position(self):
x_min = -self.width + 10 #-390
x_max = self.width - 10 #390
y_min = -self.height + 10 #-390
y_max = self.height - 10 #390
x = 11
y = 11
while x % 10 != 0:
x = random.randint(x_min, x_max)
while y % 10 != 0:
y = random.randint(y_min, y_max)
self.food.setposition((x, y))
x += 10
y += 10
all_possible_hits = []
for hits in range(3):
all_possible_hits.append((x, y -10))
x -= 10
for hits in range(3):
all_possible_hits.append((x+10, y))
y -= 10
return all_possible_hits
def erase_food(self):
self.food.hideturtle()
screen = Screen()
screen.tracer(0)
canvas_width = 400
canvas_height = 400
screen.bgcolor("black")
border = Border(canvas_width, canvas_height)
border.print_border(canvas_width, canvas_height)
snake = Snake()
food = Food(canvas_width, canvas_height)
board = Board(canvas_height)
current_score = board.add_to_score(-1)
current_food_positions = food.create_food()
snake_alive = True
screen.update()
snake_path = []
while snake_alive:
time.sleep(0.1)
screen.update()
snake_current_position, all_positions = snake.move()
snake_path.append(snake_current_position)
if snake.check_self_hit(snake_current_position, all_positions):
if border.check_borders(snake_current_position):
snake_pos_int = (round(int(snake_current_position[0])/10)*10, round(int(snake_current_position[1])/10)*10)
if snake_pos_int in current_food_positions:
current_score = board.add_to_score(current_score)
snake.add_square(current_score)
food.erase_food()
current_food_positions = food.create_food()
screen.update()
else:
snake_alive = False
else:
snake_alive = False
screen.exitonclick()
You can note the main change: The previously floating point values are integers (I notice that you even cast the random ints for food to floats, do not do this if you do not need to, in your case this only hurt) and the snake head values are somewhat hacked to be integers (simply casting them to integers was not enough, as in another demonstration of why not to use floats here, at one point one got rounded down to 9, breaking the game, so I apply a rounding to the nearest 10 as well). THIS IS NOT AN IDEAL SOLUTION. It is meant to demonstrate that the problem is the use of floats and that you should be using integers for this all the way through.
With this hacky solution, I was able to run multiple games out to and past 25 score, so I believe that mostly fixes your main problem. I will leave it to you to fix the secondary but related issue that if your snake grows long enough to run into itself, the collision detection may not work consistently because of the same issue with comparing floats for equality as you do with if head_position in tail_positions:.

Hi, I need to build a platform game using only tkinter, cant use pygame, and Im having trouble moving two objects at the same time

cant move the character at the same time the obstacle is moving, pirincipal is the name of the image that works as the player
def move():
def left(event):
x = -5
y = 0
canvasGame.update()
edgeReached()
canvasGame.move(principal,x, y)
collision()
def right(event):
x = 5
y = 0
canvasGame.update()
edgeReached()
canvasGame.move(principal,x, y)
collision()
canvasGame.bind_all("<Left>", left)
canvasGame.bind_all("<Right>", right
move()
class Barrel:
def __init__(self, canvas):
self.canvas = canvas
self.obs = canvasGame.create_image(125, 500, image=nuevoObs, anchor=tk.NW)
self.x = 16
self.y = 0
def movement(self):
while True:
coords = canvasGame.coords(self.obs)
if (coords[0] >= 1000):
self.x = -10
self.y = 0
elif (coords[0] < 0):
self.x = 10
self.y = 0
self.canvas.move(self.obs, self.x,self.y)
canvasGame.update()
time.sleep(0.05)
def createBarrel():
barrel = Barrel(canvasGame)
circle_thread = Thread(target=barrel.movement())
circle_thread.daemon = True
circle_thread.start()
createBarrel()
def plzmove():
moveplz = Thread(target=move())
moveplz.daemon = True
moveplz.start()
plzmove()
I tried creating threads but the problem continues, if there is a barrel moving, the player cant move (if there is nothing else moving, the player can move with freedom), also, the player movement is just an image being moved, any tip is appreciated, much love.

Can't get attack animation to work for arcade library with python

I'm using a tutorial from arcade.academy and the game runs fine so far (a guy walking around collecting coins and scoring points) but I want to have an attack animation occur when the user presses Q so I can turn some of the coins into enemies and make a little RPG and increase my knowledge.
This is what I've got so far but for some reason the self.is_attacking boolean either doesn't trigger or isn't linked up properly.
Here's what I've got so far.
import arcade
import random
import os
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SCREEN_TITLE = "Move with a Sprite Animation Example"
COIN_SCALE = 0.5
COIN_COUNT = 50
CHARACTER_SCALING = 1
MOVEMENT_SPEED = 5
UPDATES_PER_FRAME = 7
# Constants used to track if the player is facing left or right
RIGHT_FACING = 0
LEFT_FACING = 1
def load_texture_pair(filename):
"""
Load a texture pair, with the second being a mirror image.
"""
return [
arcade.load_texture(filename, scale=CHARACTER_SCALING),
arcade.load_texture(filename, scale=CHARACTER_SCALING, mirrored=True)
]
class PlayerCharacter(arcade.Sprite):
def __init__(self):
# Set up parent class
super().__init__()
# Default to face-right
self.character_face_direction = RIGHT_FACING
# Used for flipping between image sequences
self.cur_texture = 0
self.attack_texture = 0
# Track our state
self.jumping = False
self.climbing = False
self.is_on_ladder = False
self.is_attacking = False
# Adjust the collision box. Default includes too much empty space
# side-to-side. Box is centered at sprite center, (0, 0)
self.points = [[-22, -64], [22, -64], [22, 28], [-22, 28]]
# --- Load Textures ---
# Images from Kenney.nl's Asset Pack 3
main_path = "images/Sprites/rogue like character/rogue like"
# main_path = "platform_tutorial/images/Female person/PNG/Poses/character_femalePerson"
# main_path = "platform_tutorial/images/Male person/PNG/Poses/character_malePerson"
# main_path = "platform_tutorial/images/Male adventurer/PNG/Poses/character_maleAdventurer"
# main_path = "platform_tutorial/images/Zombie/PNG/Poses/character_zombie"
# main_path = "platform_tutorial/images/Robot/PNG/Poses/character_robot"
# Load textures for idle standing
self.idle_texture_pair = load_texture_pair(f"{main_path} idle_Animation 1_0.png")
# Load textures for walking
self.walk_textures = []
for i in range(6):
texture = load_texture_pair(f"{main_path} run_Animation 1_{i}.png")
self.walk_textures.append(texture)
# Load textures for attacking
self.attack_textures = []
for i in range(10):
texture = load_texture_pair(f"{main_path} attack_Animation 1_{i}.png")
self.attack_textures.append(texture)
def update_animation(self, delta_time: float = 1/60):
# Figure out if we need to flip face left or right
if self.change_x < 0 and self.character_face_direction == RIGHT_FACING:
self.character_face_direction = LEFT_FACING
elif self.change_x > 0 and self.character_face_direction == LEFT_FACING:
self.character_face_direction = RIGHT_FACING
# Idle animation
if self.change_x == 0 and self.change_y == 0:
self.texture = self.idle_texture_pair[self.character_face_direction]
return
# Walking animation
self.cur_texture += 1
if self.cur_texture > 5 * UPDATES_PER_FRAME:
self.cur_texture = 0
self.texture = self.walk_textures[self.cur_texture // UPDATES_PER_FRAME][self.character_face_direction]
# Attacking animation
if self.is_attacking:
self.cur_texture += 1
if self.cur_texture > 9 * UPDATES_PER_FRAME:
self.cur_texture = 0
self.is_attacking = False
self.texture = self.attack_textures[self.cur_texture // UPDATES_PER_FRAME][self.character_face_direction]
class MyGame(arcade.Window):
# Main application class.
def __init__(self, width, height, title):
# Initializer
super().__init__(width, height, title)
# Set the working directory (where we expect to find files) to the same
# directory this .py file is in. You can leave this out of your own
# code, but it is needed to easily run the examples using "python -m"
# as mentioned at the top of this program.
file_path = os.path.dirname(os.path.abspath(__file__))
os.chdir(file_path)
# Set up the game and initialize the variables.
# Sprite lists
self.player_list = None
self.coin_list = None
# Set up the player
self.score = 0
self.player = None
self.is_attacking = False
def setup(self):
self.player_list = arcade.SpriteList()
self.coin_list = arcade.SpriteList()
# Set up the player
self.score = 0
self.player = PlayerCharacter()
self.player.center_x = SCREEN_WIDTH // 2
self.player.center_y = SCREEN_HEIGHT // 2
self.player.scale = 0.8
self.player_list.append(self.player)
for i in range(COIN_COUNT):
coin = arcade.AnimatedTimeSprite(scale=0.5)
coin.center_x = random.randrange(SCREEN_WIDTH)
coin.center_y = random.randrange(SCREEN_HEIGHT)
coin.textures = []
coin.textures.append(arcade.load_texture("images/items/Coingold.png", scale=COIN_SCALE))
coin.textures.append(arcade.load_texture("images/items/Coingold.png", scale=COIN_SCALE))
coin.textures.append(arcade.load_texture("images/items/Coingold.png", scale=COIN_SCALE))
coin.textures.append(arcade.load_texture("images/items/Coingold.png", scale=COIN_SCALE))
coin.textures.append(arcade.load_texture("images/items/Coingold.png", scale=COIN_SCALE))
coin.textures.append(arcade.load_texture("images/items/Coingold.png", scale=COIN_SCALE))
coin.cur_texture_index = random.randrange(len(coin.textures))
self.coin_list.append(coin)
# Set the background color
arcade.set_background_color(arcade.color.AMAZON)
def on_draw(self):
# Render the screen.
# This command has to happen before we start drawing
arcade.start_render()
# Draw all the sprites.
self.coin_list.draw()
self.player_list.draw()
# Put the text on the screen.
output = f"Score: {self.score}"
arcade.draw_text(output, 10, 20, arcade.color.WHITE, 14)
def on_key_press(self, key, modifiers):
# Called whenever a key is pressed.
if key == arcade.key.UP:
self.player.change_y = MOVEMENT_SPEED
elif key == arcade.key.DOWN:
self.player.change_y = -MOVEMENT_SPEED
elif key == arcade.key.LEFT:
self.player.change_x = -MOVEMENT_SPEED
elif key == arcade.key.RIGHT:
self.player.change_x = MOVEMENT_SPEED
elif key == arcade.key.Q:
self.is_attacking = True
def on_key_release(self, key, modifiers):
# Called when the user releases a key.
if key == arcade.key.UP or key == arcade.key.DOWN:
self.player.change_y = 0
elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
self.player.change_x = 0
elif key == arcade.key.Q:
self.is_attacking = False
def on_update(self, delta_time):
# Movement and game logic
self.coin_list.update()
self.coin_list.update_animation()
self.player_list.update()
self.player_list.update_animation()
# Generate a list of all sprites that collided with the player.
hit_list = arcade.check_for_collision_with_list(self.player, self.coin_list)
# Loop through each colliding sprite, remove it, and add to the score.
for coin in hit_list:
coin.remove_from_sprite_lists()
self.score += 1
def main():
# Main method
window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
window.setup()
arcade.run()
if __name__ == "__main__":
main()
You can try setting
self.player.is_attacking=True

I'm making a Pong game using Pygame through livewires and I can't get the collision detection to work propery

Working on a pong game while I am reading the Python Programming for the beginner book and I am lost as to what I am missing in this game's code. Everything in the game works except for whenever the ball overlaps the board sprite it doesn't detect it and it goes right to the edge of the window, ending the game.
# single player pong
# the player must rebound the ball to avoid it going off screen.
from livewires import games, color
games.init(screen_width = 1152, screen_height = 768, fps = 60)
class board(games.Sprite):
"""The object used to bounce the ball."""
image = games.load_image("paddle.png")
def __init__(self):
"""initialize the board"""
super(board, self).__init__(image = board.image,
y = games.mouse.y,
right = games.screen.width)
def update(self):
"""
:return:move mouse to y position
"""
self.y = games.mouse.y
if self.top < 0:
self.top = 0
if self.bottom > games.screen.height:
self.bottom = games.screen.height
self.check_rebound()
def check_rebound(self):
"""Check for ball rebound"""
for ball in self.overlapping_sprites:
ball.rebound()
class ball(games.Sprite):
""" A bouncing pizza."""
image = games.load_image("ball.png")
def __init__(self):
"""initialize the ball"""
super(ball, self).__init__(image = ball.image,
x = games.screen.width/2,
y = games.screen.height/2,
dx = 1,
dy = 1)
def end_game(self):
""" End the game. """
end_message = games.Message(value = "Game Over",
size = 90,
color = color.red,
x = games.screen.width/2,
y = games.screen.height/2,
lifetime = 5 * games.screen.fps,
after_death = games.screen.quit)
games.screen.add(end_message)
def update(self):
""" Reverse a velocity component if edge of screen is reached and end game if the right wall is reached."""
if self.left < 0:
self.dx = -self.dx
if self.bottom > games.screen.height or self.top < 0:
self.dy = -self.dy
if self.right > games.screen.width:
self.end_game()
self.destroy()
def rebound(self):
"Ball rebounds from board."
self.dx = -self.dx
self.dy = -self.dy
def main():
""" Play the game. """
the_board = board()
games.screen.add(the_board)
the_ball = ball()
games.screen.add(the_ball)
games.screen.add(the_ball)
games.mouse.is_visible = False
games.screen.event_grab = True
games.screen.mainloop()
# start it up!
main()
Apologies if the code is sorted a bit wonky, I had to quadruple space it to work on the site.
Remove dy = -dy in the rebound method.

Need help timing the iterations for a for loop

any help you can give me would be great. I am working on a simple game in python. I would like to have a countdown timer running on the screen. Based on other questions answered on this site, I think I have the code mostly correct, the problem I am having is that I am running the timer code using a "for" loop. I am not really sure why it is not working for me at the moment, when I run the game, I do not get any errors, the countdown displays but it has only counted down one second and it sticks on this time (01:29). Any suggestions would be really appreciated. The code that I am struggling with is towards the end of the program in a section called """Timer Countdown""" in the main loop for the game (line 354). Many thanks.
# Ice Hockey Game
from livewires import games, color
from tkinter import*
import pygame
import math, random
import os
import sys
import time
pygame.init()
games.init(screen_width = 1016, screen_height = 511, fps = 50)
################################################################################
"""timer variables"""
################################################################################
clock = pygame.time.Clock()
font = pygame.font.Font(None, 25)
red = ( 255, 0, 0)
frame_count = 0
frame_rate = 50
start_time = 90
done= False
output_string = ""
################################################################################
"""Score display variables"""
################################################################################
right_score = games.Text(value = 0, size = 25, color = color.black,
top = 30, right = games.screen.width - 250,
is_collideable = False)
games.screen.add(right_score)
left_score = games.Text(value = 0, size = 25, color = color.black,
top = 30, right = 250,
is_collideable = False)
games.screen.add(left_score)
player1_message = games.Message(value = "Player 1 Score",
size = 35,
color = color.black,
x = 250,
y = 15,
lifetime = 100000000,
is_collideable = False)
games.screen.add(player1_message)
player2_message = games.Message(value = "Player 2 Score",
size = 35,
color = color.black,
x = 750,
y = 15,
lifetime = 100000000,
is_collideable = False)
games.screen.add(player2_message)
###############################################################################
"""Player 1 and Player 2 WIN messages"""
###############################################################################
p1_won_message = games.Message(value = "Player 1 Wins!!!",
size = 100,
color = color.blue,
x = games.screen.width/2,
y = games.screen.height/2,
lifetime = 500,
after_death = games.screen.quit,
is_collideable = False)
p2_won_message = games.Message(value = "Player 2 Wins!!!",
size = 100,
color = color.blue,
x = games.screen.width/2,
y = games.screen.height/2,
lifetime = 500,
after_death = games.screen.quit,
is_collideable = False)
##############################################################################
"""Goal animation images and functions"""
################################################################################
"""Animation images"""
goal_anim_files = ["Goal_Anim_001.bmp", "Goal_Anim_002.bmp", "Goal_Anim_003.bmp",
"Goal_Anim_004.bmp","Goal_Anim_005.bmp","Goal_Anim_006.bmp",
"Goal_Anim_007.bmp","Goal_Anim_008.bmp","Goal_Anim_009.bmp","Goal_Anim_010.bmp", "Goal_Anim_011.bmp", "Goal_Anim_012.bmp", "Goal_Anim_013.bmp",
"Goal_Anim_014.bmp","Goal_Anim_015.bmp","Goal_Anim_016.bmp",
"Goal_Anim_017.bmp","Goal_Anim_018.bmp","Goal_Anim_019.bmp","Goal_Anim_020.bmp", "Goal_Anim_021.bmp","Goal_Anim_022.bmp", "Goal_Anim_023.bmp",
"Goal_Anim_024.bmp","Goal_Anim_025.bmp"]
def goal_msg_left(self):
global goal_anim_left
goal_anim_left = games.Animation(images = goal_anim_files, x = 250,
y= games.screen.height/2, n_repeats = 1,
repeat_interval = 1, is_collideable = False)
#print("inside goal_msg_left")
def goal_msg_right(self):
global goal_anim_right
goal_anim_right = games.Animation(images = goal_anim_files, x = 750,
y= games.screen.height/2, n_repeats = 1,
repeat_interval = 1, is_collideable = False)
#print("inside goal_msg_right")
class Leftgoalanim(games.Animation):
"""goal animation"""
def update(self):
self.check_collide()
def check_collide(self):
for player1 in self.overlapping_sprites:
player1.handle_player_collide()
for player2 in self.overlapping_sprites:
player2.handle_player_collide()
class Leftgoal(games.Sprite):
def update(self):
self.check_collide()
self.check_goal()
def check_collide(self):
""" Check for collision with puck. """
for puck in self.overlapping_sprites:
puck.handle_collide()
def handle_collide(self):
""" Move to a random screen location. """
self.dx = -self.dx
self.dy = 0
self.x = games.screen.width/2
self.y = games.screen.height/2
def check_goal(self):
""" Check if left goal. """
global goal_anim_left
for puck in self.overlapping_sprites:
#puck.handle_collide()
goal_msg_left(self)
games.screen.add(goal_anim_left)
right_score.value += 1
if right_score.value >= 10:
games.screen.add(p2_won_message)
class Rightgoal(games.Sprite):
def update(self):
self.check_collide()
self.check_goal()
def check_collide(self):
""" Check for collision with puck. """
for puck in self.overlapping_sprites:
puck.handle_collide()
def handle_collide(self):
""" Move to a random screen location. """
self.dx = -self.dx
self.dy = 0
self.x = games.screen.width/2
self.y = games.screen.height/2
def check_goal(self):
""" Check if left goal. """
for puck in self.overlapping_sprites:
#puck.handle_collide()
goal_msg_right(self)
games.screen.add(goal_anim_right)
left_score.value += 1
if left_score.value >= 10:
games.screen.add(p1_won_message)
################################################################################
"""Classes for Players sprites"""
################################################################################
class Player1(games.Sprite):
"""move the player 1"""
VELOCITY_STEP = .03
VELOCITY_MAX = 3
def update(self):
if games.keyboard.is_pressed(games.K_w):
self.y -= 3
if games.keyboard.is_pressed(games.K_s):
self.y += 3
if games.keyboard.is_pressed(games.K_a):
self.x -= 3
if games.keyboard.is_pressed(games.K_d):
self.x += 3
if self.right > 940:
self.x = 913
if self.left < 85:
self.x = 108
if self.bottom > games.screen.height:
self.y = 475
if self.top < 0:
self.y = 50
self.check_collide()
def check_collide(self):
""" Check for collision with puck. """
for puck in self.overlapping_sprites:
puck.handle_collide()
def handle_player_collide(self):
self.dx = -self.dx
self.dy = 0
def handle_collide(self):
""" Move to a random screen location. """
self.dx = -self.dx
self.dy = 0
class Player2(games.Sprite):
"""move the player 2"""
VELOCITY_STEP = .03
VELOCITY_MAX = 3
def update(self):
if games.keyboard.is_pressed(games.K_UP):
self.y -= 3
if games.keyboard.is_pressed(games.K_DOWN):
self.y += 3
if games.keyboard.is_pressed(games.K_LEFT):
self.x -= 3
if games.keyboard.is_pressed(games.K_RIGHT):
self.x += 3
if self.right > 940:
self.x = 913
if self.left < 85:
self.x = 108
if self.bottom > games.screen.height:
self.y = 475
if self.top < 0:
self.y = 50
self.check_collide()
def check_collide(self):
""" Check for collision with puck. """
for puck in self.overlapping_sprites:
puck.handle_collide()
def handle_collide(self):
""" Move to a random screen location. """
self.dx = -self.dx
self.dy = 0
def handle_player_collide(self):
self.dx = -self.dx
self.dy = 0
################################################################################
"""Class for Puck"""
################################################################################
class Puck(games.Sprite):
""" A bouncing puck. """
def update(self):
""" Reverse a velocity component if edge of screen reached. """
if self.right > games.screen.width or self.left < 0:
self.dx = -self.dx
if self.bottom > games.screen.height or self.top < 0:
self.dy = -self.dy
def handle_collide(self):
""" reverses x direction when collides. """
self.dx = -self.dx
self.dy = self.dy
def handle_goal(self):
"""what happens to the puck when goal"""
self.dx = -self.dx
self.dy = self.dy
################################################################################
"""Main Loop For Game"""
################################################################################
def main():
wall_image = games.load_image("Table_002_1016H_511W.jpg", transparent = False)
games.screen.background = wall_image
#########image left and right goal images and add them to game##########
left_goal_image = games.load_image("Goal_left_cropped.bmp")
the_left_goal = Leftgoal(image = left_goal_image,
x = 40,
y = games.screen.height/2,
)
right_goal_image = games.load_image("Goal_right_cropped.bmp")
the_right_goal = Rightgoal(image = right_goal_image,
x = 976,
y = games.screen.height/2,
)
#########player 1 import image and add to game##########################
player1_image = games.load_image("Player_red_half_50_75_Fixed.bmp")
the_player1 = Player1(image = player1_image,
x = games.screen.width/4,
y = games.screen.height/2)
games.screen.add(the_player1)
#########player 2 import image and add to game##########################
player2_image = games.load_image("Player_green_half_50_75_flipped_fixed.bmp")
the_player2 = Player2(image = player2_image,
x = 750,
y = games.screen.height/2)
games.screen.add(the_player2)
################Import image for the Puck and Add to the game###########
puck_image = games.load_image("puck_small.png", transparent = True)
the_puck = Puck(image = puck_image,
x = games.screen.width/2,
y = games.screen.height/2,
dx = -3,
dy = 3)
counter = 0
###########################################################################
"""TIMER COUNTDOWN"""
###########################################################################
clock = pygame.time.Clock()
font = pygame.font.Font(None, 25)
red = ( 255, 0, 0)
frame_count = 0
frame_rate = 50
start_time = 90
done= False
output_string = ""
for n in reversed(range(0, start_time)):
total_seconds = frame_count // frame_rate
minutes = total_seconds // 60
seconds = total_seconds % 60
output_string = "Time: {0:02}:{1:02}".format(minutes, seconds)
# Blit to the screen
text = font.render(output_string, True, red)
#screen.blit(text, [250, 250])
# --- Timer going down ---
# --- Timer going up ---
# Calculate total seconds
total_seconds = start_time - (frame_count // frame_rate)
if total_seconds < 0:
total_seconds = 0
# Divide by 60 to get total minutes
minutes = total_seconds // 60
# Use modulus (remainder) to get seconds
seconds = total_seconds % 60
# Use python string formatting to format in leading zeros
output_string = "Time left: {0:02}:{1:02}".format(minutes, seconds)
# Blit to the screen
text = font.render(output_string, True, red)
#screen.blit(text, [250, 280])
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
frame_count += 1
# Limit to 20 frames per second
clock.tick_busy_loop(50)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
###Timer Display###
timer_text = games.Message(value = "TIME",
size = 45,
color = color.red,
top = 30, right = games.screen.width/2,
lifetime = 100000000,
is_collideable = False)
timer_countdown = games.Text(value = output_string, size = 25, color = color.red,
top = 60, right = 600,
is_collideable = False)
games.screen.add(timer_countdown)
games.screen.add(timer_text)
games.screen.add(the_left_goal)
games.screen.add(the_right_goal)
games.screen.add(the_puck)
games.screen.event_grab = True
games.mouse.is_visible = False
games.screen.mainloop()
# start the game
main()
Using pygame.time.get_ticks() to store a start time,
calling this again every frame will give a time greater than your stored start time, simply subtract your start time from this to get the interval in milliseconds since the timer started
As #jonrsharpe said however, it should be a code "sample", not the whole sodding thing, As such I might not have actually answered your question, I can't tell because I'm not going to read and understand the whole code.

Categories

Resources