So, as a personal project, I'm trying to build a PONG game. I have set up the window, all the code, the paddles move fine... It's just the ball. The ball moves once, and then never again. I have no clue whether this is an issue with the definition of the ball's movement or if it's just me not understanding how to use mainloop() correctly, but if I knew how to get the ball to keep moving FOREVER, that would be wonderful. If you want me to explain what I intend for the ball to do, look below the code
#Setting up the window
from tkinter import *
from time import *
HEIGHT=800
WIDTH=1280
window=Tk()
window.title('PONG!')
c=Canvas(window,width=WIDTH,height=HEIGHT,bg='black')
c.pack()
MID_X=WIDTH/2
MID_Y=HEIGHT/2
def pongstick():
return c.create_polygon(0,0, 10,0, 10,70, 0,70, fill='white')
def ball():
return c.create_oval(MID_X-10,MID_Y-10, MID_X+10,MID_Y+10, fill='white')
pong1=pongstick()
pong2=pongstick()
ballplay=ball()
MID_Y=MID_Y-35
c.move(pong1, 40, MID_Y)
c.move(pong2, WIDTH-40, MID_Y)
#Scores
player1p=0
player2p=0
ballspeed=10
#Movement of the paddles
stickspeed=10
def move_stick(event):
if event.keysym == 'w':
c.move(pong1, 0, -stickspeed)
elif event.keysym == 's':
c.move(pong1, 0, stickspeed)
if event.keysym == 'Up':
c.move(pong2, 0, -stickspeed)
elif event.keysym == 'Down':
c.move(pong2, 0, stickspeed)
#Ball movement logic
ballspeed=10
ballY=ballspeed
ballX=ballspeed
ballXadd=WIDTH/2
ballYadd=HEIGHT/2
def move_ball(ballX,ballY,ballXadd,ballYadd,player1p,player2p):
#Movement + edge hit detector
c.move(ballplay, ballX, ballY)
ballXadd=ballXadd+ballX
ballYadd=ballYadd+ballY
if ballXadd > WIDTH:
player2p=player2p+1
c.move(ball,MID_X-10,MID_Y-10)
ballXadd=0
ballYadd=0
elif ballXadd < WIDTH:
player1p=player1p+1
c.move(ball,MID_X-10,MID_Y-10)
ballXadd=0
ballYadd=0
elif ballYadd > HEIGHT:
if ballX == ballspeed:
ballY = -ballspeed
elif ballX == -ballspeed:
ballY = ballspeed
elif ballYadd < HEIGHT:
if ballX == ballspeed:
ballY = ballspeed
elif ballX == -ballspeed:
ballY = -ballspeed
#GAME!
c.bind_all('<Key>',move_stick)
while 5<7:
move_ball(ballX,ballY,ballXadd,ballYadd,player1p,player2p)
mainloop()
So, ballX is moving along the x axis, and ballY... Obvious
ballX/Yadd are the variables that set hit detection against the edge of the window. If ballYadd is more or less than the height, then the trajectory will change. If ballXadd is more or less than the width, the ball is returned to the middle, and a point (player1p or player2p, depending on which side it hit) and the trajectory resets.
Related
I am making a one man pong game and I got everything except for moving the paddle up and down and I don't really understand how to do it can someone help. Is it something to do with the "pos" or is it something to do it with the syntax of the lines. The part where it controls the movements of the paddles is def move paddle
import tkinter
# steps
# ball diagonal
# paddle draw
# paddle animation with keyboard (right/left) -> challenge up/down
# collisions (if time)
# graphic parameters
canvas_width = 400
canvas_height = 500
ball_size = 30
timer_refresh = 20
paddle_width = 100
paddle_height = 20
# ball movement
y_move = 2
x_move = 2
# paddle movement
paddle_speed = 6
# game_state
game_running = True
def end_game():
global game_running
game_running = False
canvas.create_text(canvas_width/2, canvas_height/2, text="you lost!")
# move paddle when key is pressed
def move_paddle(event):
key_symbol = event.keysym
print(key_symbol)
pos = canvas.coords(paddle)
left = pos[0]
right = pos[2]
up = pos[1]
down = pos[3]
if key_symbol == "Left" and left > 0:
canvas.move(paddle, -paddle_speed, 0)
elif key_symbol == "Right" and right <= canvas_width:
canvas.move(paddle, paddle_speed, 0)
# move paddle up
elif key_symbol == "Up" and up >= 0:
canvas.move(paddle, paddle_speed, 0)
# move paddle down
elif key_symbol == "Down" and down <= canvas_width:
canvas.move(paddle, paddle_speed, 0)*
def collision(ball_pos):
overlap_result = canvas.find_overlapping(ball_pos[0],ball_pos[1],ball_pos[2],ball_pos[3])
if paddle in overlap_result:
return True;
else:
return False;
# draw/move ball
def draw():
global y_move, x_move
canvas.move(ball1, x_move, y_move)
pos = canvas.coords(ball1)
top_y = pos[1]
bottom_y = pos[3]
left = pos[0]
right = pos[2]
if top_y <= 0:
y_move = -y_move
elif bottom_y >= canvas_height-5:
y_move = -y_move
end_game()
# did I hit left or right wall?
elif left <= 0 or right >= canvas_width-5:
x_move = -x_move
# did I collide with the paddle? if so bounce vertically
if collision(pos):
y_move = -y_move
# animation timer
def master_timer():
# draw/move ball
draw()
# tkinter processing
tk.update_idletasks()
tk.update()
if game_running:
tk.after(timer_refresh, master_timer)
tk = tkinter.Tk()
tk.title("Simplified Pong")
# block resizing window
tk.resizable(0,0)
# drawing the canvasd
canvas = tkinter.Canvas(tk, width=canvas_width, height=canvas_height, bd=0, highlightthickness=0)
canvas.pack()
ball1 = canvas.create_oval(0, 0, ball_size, ball_size, fill="red")
canvas.move(ball1, canvas_width/2, canvas_height/2)
paddle = canvas.create_rectangle(0,0,paddle_width, paddle_height, fill="black")
canvas.move(paddle, canvas_width/2, canvas_height/1.2)
canvas.bind_all("<KeyPress-Right>", move_paddle)
canvas.bind_all("<KeyPress-Left>", move_paddle)
canvas.bind_all("<KeyPress-Up>", move_paddle)
canvas.bind_all("<KeyPress-Down>", move_paddle)
master_timer()
tk.mainloop()
The problem is quite simple if you refer to the docs of move method, for tkinter, or have an understanding of how to use it. From the docs:
.move(tagOrId, xAmount, yAmount)
Moves the items specified by tagOrId by adding xAmount to their x coordinates and yAmount to their y coordinates.
So if you notice, it takes the x coords first and then the y coords. So when you want to translate(move) upon the y axis(up and down), you want to alter the y axis argument, but instead you are doing it for the x axis. So you have to pass the variable onto the correct parameter only.
elif key_symbol == "Up" and up >= 0:
canvas.move(paddle, 0, -paddle_speed)
# move paddle down
elif key_symbol == "Down" and down <= canvas_width:
canvas.move(paddle, 0, paddle_speed)
Also note that you can get rid of all the key binds and just keep a single general bind, because inside your function, you are already getting the key that is pressed dynamically, so it doesn't make much sense to bind to all possible keys:
canvas.bind_all("<KeyPress>", move_paddle) # Instead of Up, Down, Left and Right
Also another tip is, you can take advantage of * to pass the contents of the iterable as the argument to the function:
canvas.find_overlapping(*ball_pos) # Instead of ball_pos[0] and so on
I am new to programming and started with pygame zero. I am making a little game where you shoot a rocket to an alien. But my rocket keeps stuck to the border when fired, I made a reload function but I want it to go automatically ( when it hits the border or alien to go back to its normal position). Can anyone help me with that?
alien = Actor('alien', (100,100))
ship =Actor('ship', (500,400))
rocket_fire = Actor('rocket_fire', (500,400))
WIDTH = 1000
HEIGHT =500
def draw():
screen.clear()
screen.blit('space_back', (0,0))
rocket_fire.draw()
ship.draw()
alien.draw()
def move_ship(ship):
if keyboard.left:
ship.x -= 3
rocket_fire.x -= 3
elif keyboard.right:
ship.x += 3
rocket_fire.x += 3
elif keyboard.space:
animate(rocket_fire, pos = (ship.x,0))
elif keyboard.r:
rocket_fire.pos = (ship.x,ship.y)
def move_alien(alien):
alien.right +=2
if alien.left > WIDTH:
alien.right = 0
collide = rocket_fire.colliderect(alien)
if collide == 0:
alien.image = 'alien'
elif collide == 1:
alien.image = 'nuclear_explosion'
def update():
rocket_fire.draw()
ship.draw()
alien.draw()
move_ship(ship)
move_alien(alien)
You can try to assign the initial values to 'rocket_fire' after 'collide == 1'.
elif collide == 1:
alien.image = 'nuclear_explosion'
// rocket_fire = (500,400) -> this is just a representation to assign position; not accurate as per the code
Im sorta new to python and pygame, and I need help with something relating to acceleration. I followed a tutorial on youtube on how to make a base for a platforming game, and I've been using it to create a game that plays like a Kirby game. One of the tiny little details i notice in a Kirby game is how he skids when you move in a direction and then quickly move turn to the other direction, and for the past few days I was figuring out how to get it to work. The solution I came up with was to make it so instead of the character just moving whenever a key is pressed, the character will accelerate and then stop accelerating once it's reached its max speed, and then quickly slow down and accelerate again once you press another direction key. Problem is, I dont know how to program acceleration. Can anyone help me with this?
Here is the code i wrote for the game (first bit is for collision, second bit is for actually moving the player):
def move(rect, movement, tiles):
collide_types = {'top': False, 'bottom': False, 'right': False, 'left': False}
rect.x += movement[0]
hit_list = collide_test(rect, tiles)
for tile in hit_list:
if movement[0] > 0:
rect.right = tile.left
collide_types['right'] = True
if movement[0] < 0:
rect.left = tile.right
collide_types['left'] = True
rect.y += movement[1]
hit_list = collide_test(rect, tiles)
for tile in hit_list:
if movement[1] > 0:
rect.bottom = tile.top
collide_types['bottom'] = True
if movement[1] < 0:
rect.top = tile.bottom
collide_types['top'] = True
return rect, collide_types
Second bit:
player_move = [0, 0]
if move_right:
player_move[0] += 2.5
elif run:
player_move[0] += -3
if move_left:
player_move[0] -= 2
elif run:
player_move[0] -= -3
player_move[1] += verticle_momentum
verticle_momentum += 0.4
if verticle_momentum > 12:
verticle_momentum = 12
elif slow_fall == True:
verticle_momentum = 1
if fly:
verticle_momentum = -2
slow_fall = True
if verticle_momentum != 0:
if ground_snd_timer == 0:
ground_snd_timer = 20
Instead of directly changing the position of the character on button press, you should change the velocity.
So for example, taking movement on the X axis only:
acc = 0.02 # the rate of change for velocity
if move_right:
xVel += acc
if move_left:
xVel -= acc
# And now change your character position based on the current velocity
character.pose.x += xVel
Other things you can add: make it so when you don't press any keys you lose momentum so you can come at a stop. You can do this by substracting from velocity or adding to it a certain decay factor (which is smaller than your acceleration constant, but you will have to tune it as you experiment with your game).
I'm making a simple game in Tkinter, and I'm working on the basic movement. It works well except for the fact that the player can move off the screen.
How would I add collision detection to the sides of the window?
I'm moving the player with a move function bound to the arrow keys, like this:
def move(event):
if event.keysym == 'Up':
self.canvas.move(self.id, 0, -5)
elif event.keysym == 'Down':
self.canvas.move(self.id, 0, 5)
elif event.keysym == 'Left':
self.canvas.move(self.id, -5, 0)
else:
self.canvas.move(self.id, 5, 0)
You can get the size of your canvas like this:
size, _ = self.canvas.winfo_geometry().split('+', maxsplit=1)
w, h = (int(_) for _ in size.split('x'))
And the position of your Squarey like this:
x, y, _, __ = self.canvas.coords(self.id)
(There may be better ways to do this, of course)
Then just adapt your movement function like this:
if event.keysym == 'Up':
if y > 0:
self.canvas.move(self.id, 0, -5)
elif event.keysym == 'Down':
if y+50 < h:
self.canvas.move(self.id, 0, 5)
elif event.keysym == 'Left':
if x > 0:
self.canvas.move(self.id, -5, 0)
else:
if x+50 < w:
self.canvas.move(self.id, 5, 0)
That should work for you (at least it does for me). But you shouldn't stop here, there are some improvements that you can make.
The first one that I would do is something like this:
def __init__(self, canvas, color, width=50, height=50):
self.canvas = canvas
self.width = width
self.height = height
self.id = canvas.create_rectangle(10, 10, width, height, fill=color)
Then you could change your move:
left_edge = x
right_edge = left_edge + self.width
top_edge = y
bottom_edge = top_edge + self.height
if event.keysym == 'Up' and top_edge > 0:
...
elif event.keysym == 'Down' and bottom_edge < h:
...
elif event.keysym == 'Left' and left_edge > 0:
...
elif event.keysym == 'Right' and right_edge < w:
...
I assume you want to detect the collision of a rectangle with the edges of the screen. I am stranger to tkinter, however I have experience with pygame, let me explain as well as I can.
In pygame, a rectange position are given as left_top corner, a(one side), b(another side). Such as,
(x, y) b
...............
. .
. .
a. .
. .
...............
if you want to detect collision, you have to check all sides, using these values.
Let's say screen is (width, height)
# Top side collision
if y < 0:
print "Touched top"
# Right side collision
if x + b > width:
print "Touched right"
# Bottom side collision
if y + a > height:
print "Touched bottom"
# Left side collision
if x < 0:
print "Touched left"
I am pretty sure quite similar logic is needed in tkinter as well.
I am just starting out learning pygame and livewires, and I'm trying to make a single-player pong game, where you just hit the ball, and it bounces around until it passes your paddle (located on the left side of the screen and controlled by the mouse), which makes you lose. I have the basic code, but the ball doesn't stay on the screen, it just flickers and doesn't remain constant. Also, the paddle does not move with the mouse. I'm sure I'm missing something simple, but I just can't figure it out. Help please! Here's what I have:
from livewires import games
import random
games.init(screen_width=640, screen_height=480, fps=50)
class Paddle(games.Sprite):
image=games.load_image("paddle.bmp")
def __init__(self, x=10):
super(Paddle, self).__init__(image=Paddle.image,
y=games.mouse.y,
left=10)
self.score=games.Text(value=0, size=25, top=5, right=games.screen.width - 10)
games.screen.add(self.score)
def update(self):
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_collide()
def check_collide(self):
for ball in self.overlapping_sprites:
self.score.value+=1
ball.handle_collide()
class Ball(games.Sprite):
image=games.load_image("ball.bmp")
speed=5
def __init__(self, x=90, y=90):
super(Ball, self).__init__(image=Ball.image,
x=x, y=y,
dx=Ball.speed, dy=Ball.speed)
def update(self):
if self.right>games.screen.width:
self.dx=-self.dx
if self.bottom>games.screen.height or self.top<0:
self.dy=-self.dy
if self.left<0:
self.end_game()
self.destroy()
def handle_collide(self):
self.dx=-self.dx
def end_game(self):
end_message=games.Message(value="Game Over",
size=90,
x=games.screen.width/2,
y=games.screen.height/2,
lifetime=250,
after_death=games.screen.quit)
games.screen.add(end_message)
def main():
background_image=games.load_image("background.bmp", transparent=False)
games.screen.background=background_image
paddle_image=games.load_image("paddle.bmp")
the_paddle=games.Sprite(image=paddle_image,
x=10,
y=games.mouse.y)
games.screen.add(the_paddle)
ball_image=games.load_image("ball.bmp")
the_ball=games.Sprite(image=ball_image,
x=630,
y=200,
dx=2,
dy=2)
games.screen.add(the_ball)
games.mouse.is_visible=False
games.screen.event_grab=True
games.screen.mainloop()
main()
I can't help you because you did not post the complete code here. At least, I do not see where you're updating the positions of the sprites (self.x += self.dx somewhere?) and updating the draw to screen. You're also not utilising your classes in the main() function.
That said, I'm seeing
def __init__(self, x=10):
and inside the constructor you never used the x variable. That worries me, too.
Consider using the Paddle and Ball class as a Sprite, like the following:
if __name__ == '__main__':
background_image = games.load_image("background.bmp", transparent=False)
games.screen.background = background_image
the_paddle = Puddle()
games.screen.add(the_paddle)
the_ball = Ball()
games.screen.add(the_ball)
games.mouse.is_visible = False
games.screen.event_grab = True
games.screen.mainloop()
Note I've taken the liberty to make your code read more Pythonic. I have never used livewires, however, so my code may not function. But it should point you to the right direction. Good luck!
Why are you using livewires? You can use only pygame for a pong game.
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480)) # window size
pygame.display.set_caption("Simple pong") # window title
# this is a rect that contains the ball
# at the beginning it is set in the center of the screen
ball_rect = pygame.Rect((312, 232), (16, 16))
# speed of the ball (x, y)
ball_speed = [4, 4]
# this contains your paddle
# vertically centered on the left side
paddle_rect = pygame.Rect((8, 200), (8, 80))
# 1 point if you hit the ball
# -5 point if you miss the ball
score = 0
# load the font for displaying the score
font = pygame.font.Font(None, 30)
# mainloop
while True:
# event handler
for event in pygame.event.get():
# quit event => close the game
if event.type == pygame.QUIT:
exit(0)
# control the paddle with the mouse
elif event.type == pygame.MOUSEMOTION:
paddle_rect.centery = event.pos[1]
# correct paddle position if it's going out of window
if paddle_rect.top < 0:
paddle_rect.top = 0
elif paddle_rect.bottom >= 480:
paddle_rect.bottom = 480
# this test if up or down keys are pressed
# if yes move the paddle
if pygame.key.get_pressed()[pygame.K_UP] and paddle_rect.top > 0:
paddle_rect.top -= 5
elif pygame.key.get_pressed()[pygame.K_DOWN] and paddle_rect.bottom < 480:
paddle_rect.top += 5
# update ball position
# this move the ball
ball_rect.left += ball_speed[0]
ball_rect.top += ball_speed[1]
# these two if block control if the ball is going out on the screen
# if it's going it reverse speed to simulate a bounce
if ball_rect.top <= 0 or ball_rect.bottom >= 480:
ball_speed[1] = -ball_speed[1]
if ball_rect.right >= 640:
ball_speed[0] = -ball_speed[0]
# this control if the ball touched the left side
elif ball_rect.left <= 0:
score -= 5
# reset the ball to the center
ball_rect = pygame.Rect((312, 232), (16, 16))
# test if the ball is hit by the paddle
# if yes reverse speed and add a point
if paddle_rect.colliderect(ball_rect):
ball_speed[0] = -ball_speed[0]
score += 1
# clear screen
screen.fill((255, 255, 255))
# draw the ball, the paddle and the score
pygame.draw.rect(screen, (0, 0, 0), paddle_rect) # paddle
pygame.draw.circle(screen, (0, 0, 0), ball_rect.center, ball_rect.width/2) # ball
score_text = font.render(str(score), True, (0, 0, 0))
screen.blit(score_text, (320-font.size(str(score))[0]/2, 5)) # score
# update screen and wait 20 milliseconds
pygame.display.flip()
pygame.time.delay(20)