I am following a tutorial. I wrote this :
import pygame
import time
import os
import random
import neat
WIN_WIDTH = 600
WIN_HEIGHT = 800
Bird_imgs = [pygame.transform.scale2x(pygame.image.load(os.path.join("imgs", "bird1.png"))), pygame.transform.scale2x(pygame.image.load(os.path.join("imgs", "bird2.png"))), pygame.transform.scale2x(pygame.image.load(os.path.join("imgs", "bird3.png")))]
Base_img = pygame.transform.scale2x(pygame.image.load(os.path.join("imgs,", "base.png")))
Pipe_img = pygame.transform.scale2x(pygame.image.load(os.path.join("imgs,", "pipe.png")))
Bg_img = pygame.transform.scale2x(pygame.image.load(os.path.join("imgs,", "bg.png")))
class Bird:
imgs = Bird_imgs
Max_Rotation = 25
Rot_Vel = 20
Animation_Time = 5
#Init
def __init__(self, x, y):
self.x = x
self.y = y
self.tilt = 0
self.tick_count = 0
self.vel = 0
self.height = self.y
self.img_count = 0
self.img = self.imgs[0] #It's the image from Bird_imgs (bird1)
def jump(self):
self.vel = -10.5
self.tick_count = 0
self.height = self.y
def move(self):
self.tick_count += 1
d = self.vel*self.tick_count + 1.5*self.tick_count**2
if d >= 16:
d = 16
if d < 0:
d -= 2
self.y += d
if d < 0 or self.y < self.height + 50:
if self.tilt < self.Max_Rotation:
self.tilt = self.Max_Rotation
else:
if self.tilt > -90:
self.tilt -= self.Rot_Vel
def draw(self, win):
self.img_count += 1
if self.img_count < self.Animation_Time:
self.img = self.imgs[0]
elif self.img_count < self.Animation_Time*2:
self.img = self.imgs[1]
elif self.img_count < self.Animation_Time*3:
self.img = self.imgs[2]
elif self.img_count < self.Animation_Time*4:
self.img = self.imgs[1]
elif self.img_count == self.Animation_Time*4 +1:
self.img = self.imgs[0]
self.img_count = 0
if self.tilt <= 80:
self.img = self.imgs[1]
self.img_count = self.Animation_Time*2
rotated_image = pygame.transform.rotate(self.img, self.tilt)
new_rectangle = rotated_image.get_rect(center=self.img.get_rect(topleft = (self.x, self.y)).center)
I understood almost everything. First, we import modules. We define the resolution.
Then we load images and we scale them. We create a few variables in our class. We initialize...
But,
This line :
d = self.vel*self.tick_count + 0.5*(3)*(self.tick_count)**2
comes from a physic formula. But why 3 ?
Can you tell me what does :
if d < 0 or self.y < self.height + 50:
if self.tilt < self.Max_Rotation:
self.tilt = self.Max_Rotation
else:
if self.tilt > -90:
self.tilt -= self.Rot_Vel do ? And why these values ?
Can you explain to me these 2 lines :
rotated_image = pygame.transform.rotate(self.img, self.tilt)
new_rectangle = rotated_image.get_rect(center=self.img.get_rect(topleft = (self.x, self.y)).center)
? Especially the last one.
Thank you.
Your first question is why the "3" in the kinematic equation in place of "a". Well, my guess is whoever wrote your simulation felt like a value of 3 for the acceleration constant worked the best visually.
It seems to me that "d" is the distance your bird falls from its height at the time of a previous jump. After every time you jump, you have to reset your height and "time" (tick_marks) and return to normal, kinematic, constant acceleration physics, and from there you can continually measure a height deviation from that point ("d"). If the "d" value is negative (ie you are still jumping upwards) or after the bird has fallen 50 pixels from the max_height setpoint, you set your tilt (angle) to a certain rotation amount. If it hasn't dropped that far yet, you are slowly tilting the bird every frame.
First line rotates the image object. The 2nd line is to determine WHERE the image should be bilted. Namely, you are creating a new surface with rectangular dimensions of the same area as the previous image and the same center (ie rotating the location).
I'll let you figure out which parts of the syntax refer to the actions above and why, but feel free to ask questions in the comments.
Related
I am doing flappyBird game with neat from Tech with Tim tutorial and I created self.type inside Bird Class which means that bird is controllable by keyboard input or neat class, but I am getting this error after finish last generation:
C:/Users/papadi166/Documents/MEGAsync/AppDev/FlappyBird/main.py:185: DeprecationWarning: an integer is required (got type float). Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
new_rect = rotated_image.get_rect(center = image.get_rect(topleft = topleft).center)
Traceback (most recent call last):
File "C:/Users/papadi166/Documents/MEGAsync/AppDev/FlappyBird/main.py", line 393, in <module>
run(config_path, genome_path="dict.pickle")
File "C:/Users/papadi166/Documents/MEGAsync/AppDev/FlappyBird/main.py", line 364, in run
winner = p.run(main, 2)
File "C:\Users\papadi166\PycharmProjects\FlappyBird\venv\lib\site-packages\neat\population.py", line 99, in run
if best is None or g.fitness > best.fitness:
TypeError: '>' not supported between instances of 'NoneType' and 'float'
Process finished with exit code 1
before i added this code to population.py:
self.population = fitness_function(list(iteritems(self.population)), self.config)
self.species.species[1].members = self.population
I got this error after finish one generation:
if best is None or g.fitness > best.fitness:
TypeError: '>' not supported between instances of 'NoneType' and 'float'
I understand that there is something wrong with loaded winner object, but I dont' know how to fix that in my code..
class Bird:
IMGS = BIRD_IMGS
P_IMGS = PLAYER_BIRD_IMGS
MAX_ROTATION = 25
ROT_VEL = 20
ANIMATION_TIME = 5
def __init__(self, x, y, t):
self.x = x
self.y = y
self.tilt = 0
self.tick_count = 0
self.vel = 0
self.height = self.y
self.img_count = 0
self.p_img = self.P_IMGS[0]
self.img = self.IMGS[0]
self.type = t
def jump(self):
self.vel = -10.5
self.tick_count = 0
self.height = self.y
def move(self):
self.tick_count +=1
d = self.vel * (self.tick_count) + 0.5 * (3) * (self.tick_count)**2
if d >= 16:
d = (d/abs(d)) * 16
if d < 0:
d -= 2
self.y = self.y + d
if d < 0 or self.y < self.height + 50:
if self.tilt < self.MAX_ROTATION:
self.tilt = self.MAX_ROTATION
else:
if self.tilt > -90:
self.tilt -= self.ROT_VEL
def draw(self, win):
self.img_count += 1
if self.type == 0:
if self.img_count < self.ANIMATION_TIME:
self.img = self.IMGS[0]
elif self.img_count < self.ANIMATION_TIME*2:
self.img = self.IMGS[1]
elif self.img_count < self.ANIMATION_TIME*3:
self.img = self.IMGS[2]
elif self.img_count < self.ANIMATION_TIME*4:
self.img = self.IMGS[1]
elif self.img_count < self.ANIMATION_TIME*4 + 1:
self.img = self.IMGS[0]
self.img_count = 0
if self.tilt <= -80:
self.img = self.IMGS[1]
self.img_count = self.ANIMATION_TIME*2
blitRotateCenter(win, self.img, (self.x, self.y), self.tilt)
if self.type == 1:
if self.img_count < self.ANIMATION_TIME:
self.img = self.P_IMGS[0]
elif self.img_count < self.ANIMATION_TIME * 2:
self.img = self.P_IMGS[1]
elif self.img_count < self.ANIMATION_TIME * 3:
self.img = self.P_IMGS[2]
elif self.img_count < self.ANIMATION_TIME * 4:
self.img = self.P_IMGS[1]
elif self.img_count < self.ANIMATION_TIME * 4 + 1:
self.img = self.P_IMGS[0]
self.img_count = 0
if self.tilt <= -80:
self.img = self.P_IMGS[1]
self.img_count = self.ANIMATION_TIME * 2
blitRotateCenter(win, self.p_img, (self.x, self.y), self.tilt)
def get_mask(self):
if self.type == 0:
return pygame.mask.from_surface(self.img)
elif self.type == 1:
return pygame.mask.from_surface(self.p_img)
def main(genomes, config):
"""
We need to keep track of neural network that controls each bird, because these genomes when they come in
are really just a bunch of neural networks that are gonna control each of our birds, I need to keep track of the bird
that that neural networks controlling so where that position is in the screen and I need to keep track of our genomes so
that I actually change their fitness based on you know for they move or if they hit a pipe or if they do all this stuff
so i do three lists to do this maybe not the most efficient way but should work fine
"""
global GEN
GEN += 1
nets = []
birds = []
ge = []
# Change bird = Bird(230, 350) to
x = 0
for _, g in genomes:
if (x < len(genomes) -1) :
net = neat.nn.FeedForwardNetwork.create(g, config)
nets.append(net)
birds.append(Bird(230, 350, 0))
g.fitness = 0
ge.append(g)
x += 1
if (x == len(genomes) -1):
net = neat.nn.FeedForwardNetwork.create(g, config)
nets.append(net)
birds.append(Bird(230, 350, 1))
g.fitness = 0
ge.append(g)
x += 1
base = Base(730)
pipes = [Pipe(600)]
win = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT))
run = True
clock = pygame.time.Clock()
score = 0
while run:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
for bird in birds:
if bird.type == 1:
bird.jump()
pipe_ind = 0
if len(birds) > 0:
if len(pipes) > 1 and birds[0].x > pipes[0].x + pipes[0].PIPE_TOP.get_width():
pipe_ind = 1
else:
run = False
break
for x, bird in enumerate(birds):
bird.move()
ge[x].fitness += 0.1
output = nets[x].activate((bird.y, abs(bird.y - pipes[pipe_ind].height), abs(bird.y - pipes[pipe_ind].bottom)))
if output[0] > 0.5:
if bird.type != 1:
bird.jump()
#bird.move()
add_pipe = False
rem = []
for pipe in pipes:
for x, bird in enumerate(birds):
# indent only this collision if becouse the rest of code don't have to be running at this for loop.
if pipe.collide(bird):
ge[x].fitness -= 1 # Every time a bird hits a pipe is gonna have one removed from its fitness score
birds.pop(x)
nets.pop(x)
ge.pop(x)
#Change bird.x to birds[0]... OR NOT.. better put that function into this for loop, because mian will runs 50 times so caling birds[0] 50 times isn't.. IDK. Efficient?
if not pipe.passed and pipe.x < bird.x:
pipe.passed = True
add_pipe = True
if pipe.x + pipe.PIPE_TOP.get_width() < 0:
rem.append(pipe)
pipe.move()
if add_pipe:
score += 1
for g in ge:
g.fitness += 5
pipes.append(Pipe(700))
for r in rem:
pipes.remove(r)
for x, bird in enumerate(birds):
if bird.y + bird.img.get_height() >= 730 or bird.y < 0:
birds.pop(x)
nets.pop(x)
ge.pop(x)
base.move()
draw_window(win, birds, pipes, base, score, GEN)
if score >= 50:
for x, bird in enumerate(birds):
# indent only this collision if becouse the rest of code don't have to be running at this for loop.
ge[x].fitness -= 1 # Every time a bird hits a pipe is gonna have one removed from its fitness score
birds.pop(x)
nets.pop(x)
ge.pop(x)
def run(config_path, genome_path="dict.pickle"):
import pickle
genomes = []
# Load the configuration
config = neat.config.Config(neat.DefaultGenome, neat.DefaultReproduction,
neat.DefaultSpeciesSet, neat.DefaultStagnation, config_path)
# Setup population
p = neat.Population(config)
#Set the output that we gonna see
p.add_reporter(neat.StdOutReporter(True))
stats = neat.StatisticsReporter()
p.add_reporter(stats)
# Set the fitness funnction ( This func. runs main func. 50 times and pass it all of the genoms so like that population current generation populations )
winner = p.run(main, 2)
with open("dict.pickle", "wb") as infile:
pickle.dump(winner, infile)
infile.close()
# Unpickle saved winner
with open(genome_path, "rb") as infile:
genome = pickle.load(infile)
# Convert loaded genome into required data structure
genomes = [(1, genome)]
type = "test"
# Call game with only the loaded genome
main(genomes, config)
print("LOL")
if __name__ == '__main__':
local_dir = os.path.dirname(__file__)
config_path = os.path.join(local_dir, "config-feedforward.txt")
run(config_path, genome_path="dict.pickle")
For me, Declaring ge[x].fitness in a for loop before worked.
# put this above the other for loops
for x, bird in enumerate(birds):
ge[x].fitness = 0
I'm trying to code a pong game on Python with Pygame. Weirdly, the game works good, the ball bounces off on edges, respawns using space, the paddles move (up/down arrow and i/k keys) without leaving the screen. Most of the time the ball collides with paddles but some other times the ball acts weirdly or teleports.
I thought the problem might with the collision logic. So that's what I'm sharing, if you want more there's the link below.
P1 and P2 represent the paddles. Basically I check if x is near the paddle and then check if y is in the paddle range (from topPaddleY to bottomPaddleY)
For more code, I'm sharing it with codeskulptor3. https://py3.codeskulptor.org/#user305_Voqctw5Vzh_0.py
class Ball:
def __init__(self, radius, center, color):
self.radius = radius
self.initial_attributes = center
self.center = list(center)
self.color = color
self.vel = [random.choice(VELOCITIES), random.choice(VELOCITIES)]
def draw(self):
pygame.draw.circle(screen, self.color, tuple(self.center), self.radius )
def update(self, p1, p2):
x = self.center[0]
y = self.center[1]
y_adjusted = (y+self.radius, y-self.radius)
if y_adjusted[0] >= HEIGHT or y_adjusted[1] <= 0:
self.vel[1] = -self.vel[1]
if x <= 28 or x >= WIDTH - 28:
p1_range = [p1.pos[1], p1.pos[1] + 100]
if p1_range[0] <= y <= p1_range[1]:
self.vel[0] = (-self.vel[0])
p2_range = [p2.pos[1], p2.pos[1] + 100]
if p2_range[0] <= y <= p2_range[1]:
self.vel[0] = (-self.vel[0])
def move(self, p1, p2):
self.center[0] = self.center[0] + self.vel[0]
self.center[1] = self.center[1] + self.vel[1]
self.update(p1, p2)
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
self.spawn()
def spawn(self):
self.center = list(self.initial_attributes)
self.vel = [random.choice(VELOCITIES), random.choice(VELOCITIES)]
Edit : I was able to fix it by using as suggested the y_adjusted + adding a print statement to check the position of the ball during the collision. It appeared that velocity changed more than once during the collision So i added a flag for reflection. It seems to be rolling good now. Thanks SO.
def update(self, p1, p2):
x = self.center[0]
y = self.center[1]
y_adjusted = (y+self.radius, y-self.radius)
reflected = False
if y_adjusted[0] >= HEIGHT or y_adjusted[1] <= 0:
self.vel[1] = -self.vel[1]
if x <= 28 or x >= WIDTH - 28:
p1_range = [p1.pos[1], p1.pos[1] + 100]
if ((p1_range[0] <= y_adjusted[0] <= p1_range[1]) or (p1_range[0] <= y_adjusted[1] <= p1_range[1])) and (not(reflected)):
self.vel[0] = (-self.vel[0])
reflected = True
p2_range = [p2.pos[1], p2.pos[1] + 100]
if ((p2_range[0] <= y_adjusted[0] <= p2_range[1]) or (p2_range[0] <= y_adjusted[1] <= p2_range[1])) and (not(reflected)):
self.vel[0] = (-self.vel[0])
reflected = True
else :
reflected = False
I was able to fix it by using as suggested the y_adjusted + adding a print statement to check the position of the ball during the collision. It appeared that velocity changed more than once during the collision So i added a flag for reflection. It seems to be rolling good now.
def update(self, p1, p2):
x = self.center[0]
y = self.center[1]
y_adjusted = (y+self.radius, y-self.radius)
reflected = False
if y_adjusted[0] >= HEIGHT or y_adjusted[1] <= 0:
self.vel[1] = -self.vel[1]
if x <= 28 or x >= WIDTH - 28:
p1_range = [p1.pos[1], p1.pos[1] + 100]
if ((p1_range[0] <= y_adjusted[0] <= p1_range[1]) or (p1_range[0] <= y_adjusted[1] <= p1_range[1])) and (not(reflected)):
self.vel[0] = (-self.vel[0])
reflected = True
p2_range = [p2.pos[1], p2.pos[1] + 100]
if ((p2_range[0] <= y_adjusted[0] <= p2_range[1]) or (p2_range[0] <= y_adjusted[1] <= p2_range[1])) and (not(reflected)):
self.vel[0] = (-self.vel[0])
reflected = True
else :
reflected = False
I'm trying to code a little Jump´n´Run game in tkinter with canvas and so far its working pretty well, but I have a problem that I cant´t wrap my head around.
Look at these three pictures: on the first the collision works fine - I can jump from one paddle to the other.
On the second picture, you can see that whenever I get under the paddle it doesn't fall down and jumping up is also not possible, probably because i have self.y = 0 in the self.brick collision detection. How could I get this working such that even when its under the paddle it bounces off, because that's important, for example when I start to add the second line of paddles.
My Collision code:
def brick_hit(self, pos):
for brick_line in self.bricks:
for brick in brick_line:
brick_pos = self.gamerootCanvas.coords(brick.id)
try:
if pos[3] > brick_pos[1]:
if pos[2] > brick_pos[0] and pos[0] < brick_pos[2]:
return True
except:
continue
return False
My Full code:
def jump_and_run():
gameroot = Toplevel()
gameroot.title("Game Root")
gameroot.resizable(0, 0)
gameroot.wm_attributes("-topmost", 1)
gamerootCanvas = Canvas(gameroot, width=1800, height=800, bd=0, highlightthickness=0)
gameroot_Background = PhotoImage(file="jumpnrunbackground.png")
gamerootCanvas.create_image(500, 250, image=gameroot_Background)
gamerootCanvas.pack()
gamerootCanvas.update()
class Player:
def __init__(self, gamerootCanvas, bricks, color):
self.gamerootCanvas = gamerootCanvas
self.id = gamerootCanvas.create_rectangle(25,25,0,0, fill=color)
self.gamerootCanvas.move(self.id, 5, 650)
self.bricks = bricks
self.x = 0
self.y = 0
self.gravity = 0.1
self.gamerootCanvas_height = gamerootCanvas.winfo_height()
self.gamerootCanvas_width = gamerootCanvas.winfo_width()
self.gamerootCanvas.bind_all("<KeyPress-Right>", self.move_right)
self.gamerootCanvas.bind_all("<KeyRelease-Right>", self.move_right_stop)
self.gamerootCanvas.bind_all("<KeyPress-Left>", self.move_left)
self.gamerootCanvas.bind_all("<KeyRelease-Left>", self.move_left_stop)
self.gamerootCanvas.bind_all("<KeyPress-Up>", self.jump_)
self.gamerootCanvas.bind_all("<KeyRelease-Up>", self.jump_stop)
self.jump_counter = 0
self.move_counter = 0
def move_player(self):
self.gamerootCanvas.move(self.id, self.x, self.y)
pos = self.gamerootCanvas.coords(self.id)
self.y += self.gravity
if pos[0] <= 0:
self.x = 1
elif pos[2] >= self.gamerootCanvas_width:
self.x = -1
elif pos[1] <= 0:
self.y = 1
elif pos[3] >= self.gamerootCanvas_height:
self.y = 0
elif self.brick_hit(pos) == True:
self.y = 0
def move_right(self, evt):
self.x = 2
def move_right_stop(self, evt):
self.x = 0
def move_left(self, evt):
self.x = -2
def move_left_stop(self, evt):
self.x = 0
def jump_(self, evt):
if self.jump_counter < 2:
self.y = -6
self.jump_counter += 2
def jump_stop(self, evt):
self.y = 0
self.jump_counter = 0
def brick_hit(self, pos):
for brick_line in self.bricks:
for brick in brick_line:
brick_pos = self.gamerootCanvas.coords(brick.id)
try:
if pos[3] > brick_pos[1]:
if pos[2] > brick_pos[0] and pos[0] < brick_pos[2]:
return True
except:
continue
return False
class Bricks1:
def __init__(self, gamerootCanvas, color):
self.gamerootCanvas = gamerootCanvas
self.id = gamerootCanvas.create_rectangle(50, 15, 0, 0, fill=color, width=2)
self.gamerootCanvas.move(self.id, 5, 700)
def generate_bricks():
global bricks
bricks = []
for i in range(0, 1):
b = []
for j in range(0, 14):
Bricks_1 = Bricks1(gamerootCanvas, "Blue")
b.append(Bricks_1)
bricks.append(b)
for i in range(0, 1):
for j in range(0, 14):
gamerootCanvas.move(bricks[i][j].id, 158.2 * j, 40 * i)
generate_bricks()
player1 = Player(gamerootCanvas, bricks, "Red")
while True:
gameroot.update_idletasks()
player1.move_player()
gameroot.update()
gameroot.after(5)
play_gameloop_sound()
gameUI.mainloop()
You should offset yourself from the brick to prevent becoming stuck. When resting on a brick, you should also have an altered state to prevent jittering.
I'm trying to make a game like snake, where when you catch/eat the apple and the apple moves to a different spot in tkinter.
But I want to place the "apple", or in this case, a blue triangle, to a random place on the canvas,but the only command I can find is canvas.move(), which moves the widget a certain number of pixels in any direction. This can't fulfill what I need(I think, maybe there is a way around it?). Is there a way to place the blue triangle randomly on the canvas?
from Tkinter import *
import random
import time
class Ball:
def __init__(self, canvas,square):
self.square = square
self.canvas = canvas
self.id = canvas.create_oval(10,10,25,25,fill='red')
self.canvas.move(self.id,245,100)
self.text = self.canvas.create_text(10, 10, text='GAME OVER', font=('Courier', 80))
self.canvas.move(self.text, -7000, -7000)
starts = [-3,-2,-1,1,2,3]
self.x = random.choice(starts)
self.y = -30
def draw(self):
self.canvas.move(self.id,self.x,self.y)
pos = self.canvas.coords(self.id)
if pos[1] <= 0:
self.y = 4
if pos[3] >= self.canvas.winfo_height():
self.y = -4
if self.hit_square(pos) == True:
self.canvas.move(self.text,245,100)
time.sleep(2)
tk.destroy()
if pos[0] <= 0:
self.x = 4
if pos[2] >= self.canvas.winfo_width():
self.x = -4
def hit_square(self, pos):
square_pos = self.canvas.coords(self.square.id)
if pos[2] >= square_pos[0] and pos[0] <= square_pos[2]:
if pos[3] >= square_pos[1] and pos[3] <= square_pos[3]:
return True
return False
def stay(self):
self.x = 0
self.y = 0
class Square:
def __init__(self,canvas):
self.canvas = canvas
self.id = canvas.create_rectangle(15, 15, 30, 30,fill='green')
self.x = 0
self.y = 0
self.canvas.move(self.id, 200, 250)
self.canvas.bind_all('<KeyPress-Left>',self.left)
self.canvas.bind_all('<KeyPress-Right>', self.right)
self.canvas.bind_all('<KeyPress-Up>', self.up)
self.canvas.bind_all('<KeyPress-Down>', self.down)
def draw(self):
self.canvas.move(self.id,self.x,self.y)
pos = self.canvas.coords(self.id)
if pos[0] <= 0:
self.x = 0
elif pos[2] >= self.canvas.winfo_width():
self.x = 0
if pos[1] <= 0:
self.y = 0
elif pos[3] >= self.canvas.winfo_height():
self.y = 0
def left(self, evt):
self.x = -2
self.y = 0
def right(self, evt):
self.x = 2
self.y = 0
def up(self, evt):
self.y = -2
self.x = 0
def down(self, evt):
self.y = 2
self.x = 0
class Triangle:
def __init__(self,canvas,square):
self.canvas = canvas
self.square = square
self.id = self.canvas.create_polygon(26.5,10,20,25,35,25,fill='blue')
self.canvas.move(self.id,random.randint(10,450),random.randint(10,380))
self.score = 0
def draw_score(self):
self.score_show = self.canvas.create_text(450, 20, text='score:' + str(self.score), font=('Arial', 20))
def hit_square(self):
pos = self.canvas.coords(self.id)
square_pos = self.canvas.coords(self.square.id)
if pos[2] >= square_pos[0] and pos[0] <= square_pos[2]:
if pos[3] >= square_pos[1] and pos[3] <= square_pos[3]:
self.teleport(pos)
def teleport(self, pos):
x = self.canvas.winfo_width()-pos[0]-10
y = self.canvas.winfo_height() - pos[1]-10
self.score += 1
self.canvas.move(self.id,)
tk = Tk()
tk.title("Run from the ball!")
tk.resizable(0,0)
tk.wm_attributes('-topmost',1)
canvas = Canvas(tk, width=500,height=400,bd=0,highlightthickness=0)
canvas.pack()
tk.update()
square = Square(canvas)
ball = Ball(canvas, square)
ball1 = Ball(canvas, square)
ball2 = Ball(canvas, square)
ball3 = Ball(canvas, square)
ball4 = Ball(canvas, square)
triangle = Triangle(canvas, square)
x = 0
while x < float('inf'):
ball.draw()
triangle.draw_score()
triangle.hit_square()
if x >= 10:
ball1.draw()
if x >= 20:
ball2.draw()
if x >= 30:
ball3.draw()
if x >= 40:
ball4.draw()
square.draw()
tk.update_idletasks()
tk.update()
time.sleep(0.01)
x += 0.01
Yes, I know that the score function is messed up, and that the one overlaps the zero. Could you guys help me with that too?
Is there a way to place the blue triangle randomly on the canvas?
Yes. the coords method can get you the current coordinates, but it also lets you change the coordinates to whatever you want.
self.canvas.coords(self.id, 36.5, 20, 30, 35, 45, 35)
Trying to code the classic arcade game 'Pong', I've gotten stuck trying to reset the 'ball' into it's original position after the computer scores.
class Pong:
def __init__(self, width, height, x,y, color, screenw, screenh):
self.width = width
self.height = height
self.x = x
self.y = y
self.point = (self.x,self.y)
self.color = color
self.speed = random.randint(3,5)
self.screenw = screenw
self.screenh = screenh
self.dx = random.choice([-2,-1,1,2])
self.dy = random.choice([1,-1])
self.compscore = 0
self.playerscore = 0
self.score = False
def game_logic(self):
x,y = self.point
x += self.speed*self.dx
y += self.speed*self.dy
if x + self.width >= self.screenw:
self.dx = -1
self.color = GREEN
self.playerpoint()
print(str(self.playerscore)+" : "+str(self.compscore))
if x <= 100:
self.dx = 1
self.color = WHITE
self.comppoint()
print(str(self.playerscore)+" : "+str(self.compscore))
if y + self.height >= self.screenh:
self.dy = -1
self.color = ORANGE
if y <= 0:
self.dy = 1
self.color = SALMON
self.point = (x,y)
return
def resetpong(self):
self.point = (200,200)
self.dx = random.choice([-2,-1,1,2])
self.dy = random.choice([1,-1])
return self.point
def comppoint(self):
self.compscore += 1
print("The computer has scored a point.")
self.resetpong()
return self.compscore
def playerpoint(self):
self.playerscore += 1
print("Nice! You've scored a point.")
self.resetpong()
return self.playerscore
I've created the reset method and no matter where I've put it, whether in an if statement in the game_logic method in my pygame starter, or inside the game_logic in the Pong class. It does work though if I set it to a keybinding?
Am I an idiot?
The function resetpong changes the value of self.point. This function gets called by playerpoint or comppoint. The call to playerpoint or comppoint occurs in the function game_logic. This line at the end of game_logic:
self.point = (x,y)
therefore clobbers the new value of self.point. A similar problem affects the variable self.dx which gets set in game_logic and then clobbered by a call to playerpoint or comppoint.
Change the function game_logic as follows to fix both of these:
def game_logic(self):
x,y = self.point
x += self.speed*self.dx
y += self.speed*self.dy
self.point = x, y # parenthesis not needed here
if x + self.width >= self.screenw:
self.color = GREEN
self.playerpoint()
print(str(self.playerscore)+" : "+str(self.compscore))
elif x <= 100: # elif here: only test this if previous if is false
self.color = WHITE
self.comppoint()
print(str(self.playerscore)+" : "+str(self.compscore))
if y + self.height >= self.screenh:
self.dy = -1
self.color = ORANGE
elif y <= 0: # elif here: only test this if previous if is false
self.dy = 1
self.color = SALMON
# return not needed here
I also recommend removing the variables self.x and self.yfrom the Pong constructor since they are never used. The variable self.point contains those numbers and it's a violation of a basic principle to keep the same information in two different places.