tkinter jump and run game canvas object collision - python

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.

Related

tkinter breakout game beginner problems

I am trying to build a Breakout game for python tkinter with different levels. I don't quite understand the self and __init__ functions in this code.
Is there a way to create the game without those functions or replacing them with simpler functions if it's possible? Also, I don't quite understand the + self.radius parts in the code as well.
import tkinter as tk
def new_window():
root1 = tk.Tk()
root1.title('Jeu')
game = Game(root1)
class GameObject(object):
def __init__(self, canvas, item):
self.canvas = canvas
self.item = item
def get_position(self):
return self.canvas.coords(self.item)
def move(self, x, y):
self.canvas.move(self.item, x, y)
def delete(self):
self.canvas.delete(self.item)
class Ball(GameObject):
def __init__(self, canvas, x, y):
self.radius = 10
self.direction = [1, -1]
# increase the below value to increase the speed of ball
self.speed = 5
item = canvas.create_oval(x - self.radius, y - self.radius,
x + self.radius, y + self.radius,
fill='white')
super(Ball, self).__init__(canvas, item)
def update(self):
coords = self.get_position()
width = self.canvas.winfo_width()
if coords[0] <= 0 or coords[2] >= width:
self.direction[0] *= -1
if coords[1] <= 0:
self.direction[1] *= -1
x = self.direction[0] * self.speed
y = self.direction[1] * self.speed
self.move(x, y)
def collide(self, game_objects):
coords = self.get_position()
x = (coords[0] + coords[2]) * 0.5
if len(game_objects) > 1:
self.direction[1] *= -1
elif len(game_objects) == 1:
game_object = game_objects[0]
coords = game_object.get_position()
if x > coords[2]:
self.direction[0] = 1
elif x < coords[0]:
self.direction[0] = -1
else:
self.direction[1] *= -1
for game_object in game_objects:
if isinstance(game_object, Brick):
game_object.hit()
class Paddle(GameObject):
def __init__(self, canvas, x, y):
self.width = 80
self.height = 10
self.ball = None
item = canvas.create_rectangle(x - self.width / 2,
y - self.height / 2,
x + self.width / 2,
y + self.height / 2,
fill='#FFB643')
super(Paddle, self).__init__(canvas, item)
def set_ball(self, ball):
self.ball = ball
def move(self, offset):
coords = self.get_position()
width = self.canvas.winfo_width()
if coords[0] + offset >= 0 and coords[2] + offset <= width:
super(Paddle, self).move(offset, 0)
if self.ball is not None:
self.ball.move(offset, 0)
class Brick(GameObject):
COLORS = {1: '#4535AA', 2: '#ED639E', 3: '#8FE1A2'}
def __init__(self, canvas, x, y, hits):
self.width = 75
self.height = 20
self.hits = hits
color = Brick.COLORS[hits]
item = canvas.create_rectangle(x - self.width / 2,
y - self.height / 2,
x + self.width / 2,
y + self.height / 2,
fill=color, tags='brick')
super(Brick, self).__init__(canvas, item)
def hit(self):
self.hits -= 1
if self.hits == 0:
self.delete()
else:
self.canvas.itemconfig(self.item,
fill=Brick.COLORS[self.hits])
class Game(tk.Frame):
def __init__(self, master):
super(Game, self).__init__(master)
self.lives = 3
self.width = 610
self.height = 400
self.canvas = tk.Canvas(self, bg='#D6D1F5',
width=self.width,
height=self.height, )
self.canvas.pack()
self.pack()
self.items = {}
self.ball = None
self.paddle = Paddle(self.canvas, self.width / 2, 326)
self.items[self.paddle.item] = self.paddle
# adding brick with different hit capacities - 3,2 and 1
for x in range(5, self.width - 5, 75):
self.add_brick(x + 37.5, 50, 3)
self.add_brick(x + 37.5, 70, 2)
self.add_brick(x + 37.5, 90, 1)
self.hud = None
self.setup_game()
self.canvas.focus_set()
self.canvas.bind('<Left>',
lambda _: self.paddle.move(-10))
self.canvas.bind('<Right>',
lambda _: self.paddle.move(10))
def setup_game(self):
self.add_ball()
self.update_lives_text()
self.text = self.draw_text(300, 200,
'Press Space to start')
self.canvas.bind('<space>', lambda _: self.start_game())
def add_ball(self):
if self.ball is not None:
self.ball.delete()
paddle_coords = self.paddle.get_position()
x = (paddle_coords[0] + paddle_coords[2]) * 0.5
self.ball = Ball(self.canvas, x, 310)
self.paddle.set_ball(self.ball)
def add_brick(self, x, y, hits):
brick = Brick(self.canvas, x, y, hits)
self.items[brick.item] = brick
def draw_text(self, x, y, text, size='40'):
font = ('Forte', size)
return self.canvas.create_text(x, y, text=text,
font=font)
def update_lives_text(self):
text = 'Lives: %s' % self.lives
if self.hud is None:
self.hud = self.draw_text(50, 20, text, 15)
else:
self.canvas.itemconfig(self.hud, text=text)
def start_game(self):
self.canvas.unbind('<space>')
self.canvas.delete(self.text)
self.paddle.ball = None
self.game_loop()
def game_loop(self):
self.check_collisions()
num_bricks = len(self.canvas.find_withtag('brick'))
if num_bricks == 0:
self.ball.speed = None
self.draw_text(300, 200, 'You win! You the Breaker of Bricks.')
elif self.ball.get_position()[3] >= self.height:
self.ball.speed = None
self.lives -= 1
if self.lives < 0:
self.draw_text(300, 200, 'You Lose! Game Over!')
else:
self.after(1000, self.setup_game)
else:
self.ball.update()
self.after(50, self.game_loop)
def check_collisions(self):
ball_coords = self.ball.get_position()
items = self.canvas.find_overlapping(*ball_coords)
objects = [self.items[x] for x in items if x in self.items]
self.ball.collide(objects)
game.mainloop()
root = tk.Tk()
root.title('Jeu')
game = Game(root)
btn1= tk.Button(root, text='Click me', bd= '5',command=new_window)
Is there a way to create the game without those functions or replacing them with simpler functions if it's possible?
As a proof of concept below a much simpler code of the game for beginners rewritten to get rid of classes as an example that it is possible to write the game without them. You can compare the rewritten code with the original code (link is given in a comment at the beginning of code) to see how it can be done and then rewrite yourself a more complex code:
# https://codingshiksha.com/python/python-3-tkinter-2d-brick-breaker-breakout-game-in-gui-desktop-app-full-project-for-beginners/
from tkinter import Tk, Canvas
import random
import time
tk = Tk()
tk.title("Game")
tk.resizable(0, 0)
tk.wm_attributes("-topmost", 1)
canvas_height = 400
canvas_width = 500
canvas = Canvas(tk, width=canvas_width, height=canvas_height, bd=0, highlightthickness=0)
canvas.pack()
tk.update()
ball_id = canvas.create_oval(10, 10, 25, 25, fill='red')
canvas.move(ball_id, 245, 100)
starts = [-3, -2, -1, 1, 2, 3]
random.shuffle(starts)
ball_x = starts[0]
ball_y = -3
paddle_id = canvas.create_rectangle(0, 0, 100, 10, fill='blue')
canvas.move(paddle_id, 200, 300)
paddle_x = 0
def draw_ball():
global ball_x, ball_y
canvas.move(ball_id, ball_x, ball_y)
pos = canvas.coords(ball_id)
if pos[1] <= 0:
ball_y = 3
if pos[3] >= canvas_height:
ball_y = -3
if hit_paddle(pos) == True:
ball_y = -3
if pos[0] <= 0:
ball_x = 3
if pos[2] >= canvas_width:
ball_x = -3
def hit_paddle(pos):
paddle_pos = canvas.coords(paddle_id)
if pos[2] >= paddle_pos[0] and pos[0] <= paddle_pos[2]:
if pos[3] >= paddle_pos[1] and pos[3] <= paddle_pos[3]:
return True
return False
def turn_left(evt):
global paddle_x
paddle_x = -2
def turn_right(evt):
global paddle_x
paddle_x = 2
def draw_paddle():
global paddle_x
canvas.move(paddle_id, paddle_x, 0)
pos = canvas.coords(paddle_id)
if pos[0] <= 0:
paddle_x = 0
elif pos[2] >= canvas_width:
paddle_x = 0
canvas.bind_all('<KeyPress-Left>' , turn_left)
canvas.bind_all('<KeyPress-Right>', turn_right)
while True:
draw_ball()
draw_paddle()
tk.update_idletasks()
tk.update()
time.sleep(0.01)
By the way: not always usage of classes makes sense if there is a simpler and sometimes even more intuitive way of achieving the same result.
The init function is a part of a class that is run every time you create an instance of that class. Self makes the variable an attribute to the class, or that it can be accessed in other parts of your code by, for example ball = Ball() print(ball.radius). There is more information here at the documentation: https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces . If you are using object-oriented programming, there aren't any alternatives to self and init. The only way not to use them would be to not use classes in your code.
The self.radius part of the code is creating a variable representing the size of the ball. This link describes how the different points you set creates the shape of the oval: https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/create_oval.html. The short answer is that self.radius creates the size by spacing out the two points of the oval.

Python - Genetic Algorithm mutation function is not working

I created an AI in python/pygame but even after spending hours of debugging, I could not find why the individuals(dots) are not getting mutated. After few generations, all the individuals just overlap each other and follow the same exact path. But after mutation they should move a little bit differently.
Here is what a population size of 10 looks like after every 2-3 generations..
Image 1 Image 2 Image 3
As you can see, just after few generations they just overlap and all the individuals in the population move together, following exact same path! We need mutations!!!
I would be really grateful to you if you could find any mistake. Thank!
I saw the code from: https://www.youtube.com/watch?v=BOZfhUcNiqk&t
and tried to make it in python. Here's my code
import pygame, random
import numpy as np
pygame.init()
width = 800
height = 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("The Dots")
FPS = 30
clock = pygame.time.Clock()
gameExit = False
grey = [30, 30, 30]
white = [255, 255, 255]
black = [0, 0, 0]
red = [255, 0, 0]
goal = [400, 10]
class Dot():
def __init__(self):
self.x = int(width/2)
self.y = int(height - 150)
self.r = 3
self.c = black
self.xVel = self.yVel = 0
self.xAcc = 0
self.yAcc = 0
self.dead = False
self.steps = 0
self.reached = False
self.brain = Brain(200)
def show(self):
pygame.draw.circle(screen, self.c, [int(self.x), int(self.y)], self.r)
def update(self):
if (self.x >= width or self.x <= 0 or self.y >= height or self.y <= 0):
self.dead = True
elif (np.sqrt((self.x-goal[0])**2 + (self.y-goal[1])**2) < 5):
self.reached = True
if not self.dead and not self.reached:
if len(self.brain.directions) > self.steps:
self.xAcc = self.brain.directions[self.steps][0]
self.yAcc = self.brain.directions[self.steps][1]
self.steps += 1
self.xVel += self.xAcc
self.yVel += self.yAcc
if self.xVel > 5:
self.xVel = 5
if self.yVel > 5:
self.yVel = 5
self.x += self.xVel
self.y += self.yVel
else: self.dead = True
def calculateFitness(self):
distToGoal = np.sqrt((self.x-goal[0])**2 + (self.y-goal[1])**2)
self.fitness = 1/(distToGoal**2)
return self.fitness
def getChild(self):
child = Dot()
child.brain = self.brain
return child
class Brain():
def __init__(self, size):
self.size = size
self.directions = []
self.randomize()
def randomize(self):
self.directions.append((np.random.normal(size=(self.size, 2))).tolist())
self.directions = self.directions[0]
def mutate(self):
for i in self.directions:
rand = random.random()
if rand < 1:
i = np.random.normal(size=(1, 2)).tolist()[0]
class Population():
def __init__(self, size):
self.size = size
self.dots = []
self.fitnessSum = 0
for i in range(self.size):
self.dots.append(Dot())
def show(self):
for i in self.dots:
i.show()
def update(self):
for i in self.dots:
i.update()
def calculateFitness(self):
for i in self.dots:
i.calculateFitness()
def allDead(self):
for i in self.dots:
if not i.dead and not i.reached:
return False
return True
def calculateFitnessSum(self):
self.fitnessSum = 0
for i in self.dots:
self.fitnessSum += i.fitness
def SelectParent(self):
rand = random.uniform(0, self.fitnessSum)
runningSum = 0
for i in self.dots:
runningSum += i.fitness
if runningSum > rand:
return i
def naturalSelection(self):
newDots = []
self.calculateFitnessSum()
for i in self.dots:
parent = self.SelectParent()
newDots.append(parent.getChild())
self.dots = newDots
def mutate(self):
for i in self.dots:
i.brain.mutate()
test = Population(100)
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
screen.fill(white)
if test.allDead():
#Genetic Algorithm
test.calculateFitness()
test.naturalSelection()
test.mutate()
else:
test.update()
test.show()
pygame.draw.circle(screen, red, goal, 4)
clock.tick(FPS)
pygame.display.update()
pygame.quit()
Thanks for any help!
I didn't go through the whole code, but over here
def mutate(self):
for i in self.directions:
rand = random.random()
if rand < 1:
i = np.random.normal(size=(1, 2)).tolist()[0]
you are trying to assign a new value to i (which is an iterater), so it won't change anything, which explains why you'r having trouble with the mutations.
You should have something like this:
def mutate(self):
for i in range(len(self.directions)):
rand = random.random()
if rand < 1:
self.directions[i] = np.random.normal(size=(1, 2)).tolist()[0]
or you can use list comprehensions
https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions

Moving a Tkinter widget to a specific coordinates and changing the text of a text widget

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)

reset object position in pygame

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.

Python Game problems

I'm working on a 2D python game project for my CS class, and I've hit a bump, I don't know what the problem is:
The project is a large part of my grade, and up until now I've had an A+
This project is incredibly frustrating
NEW
ok so i've got everything working so far, except for some reason My protaganist() is stuck at the top left corner of the game screen !
Also, i need ideas on how to create a jump action
If anyone could help I would be incredibly grateful!
I am importing a game engine my teacher made available from his book website, but i it is too long for me to add but i will try to add some of it at the bottom
Here is all my code:
import gameEngine
import pygame
import math
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.mixer.init()
sndAtk = pygame.mixer.Sound("OOT_AdultLink_Attack1.wav")
#goal is to create a game
#must have menu to start game
#menu should have a start and quit button.. start runs gaming operations and quit exits program
#sprites for character and enemies and bullets maybe, use one large image and simply move visibiliy
#this saves memory as 1 image is loaded instead of many
"""
class game(gameEngine.scene):
def __init__(self, scene):
self.background()
self.sprites["spawn.gif", "badguys.gif"]
"""
"""
protaganist is our hero sprite
should run left and right, jump left and right
and attack left and right...
I might add in the bow and jump attack
"""
class scrollinggrass(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.setImage("gamebackground.jpg")
self.rect.centerx = 20
self.rect.centery = 500
self.rect = self.image.get_rect()
self.dx = 10
self.dy = 0
self.checkKeys()
def checkKeys(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
print("working")
self.forward(3)
run.play()
if keys[pygame.K_LEFT]:
self.forward(-3)
class hearts(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.setImage("heart.png")
self.setTransparentColor = self.imageMaster.get_at((1,1))
self.imageMaster.set_colorkey(self.setTransparentColor)
self.setPosition((550 , 30))
class badguy(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.setImage("badguy1.png")
self.rect = self.imageMaster.get_rect()
self.health = 2
self.DEAD = 1
self.state = 0
class protaganist(gameEngine.SuperSprite):
def __init__(self, scene):
gameEngine.SuperSprite.__init__(self, scene)
self.imageList = []
self.rect = self.imageMaster.get_rect()
self.STANDING = 0
self.RUNNING = 1
self.ATTACKING = 2
self.JUMPING = 3
self.DEAD = 10
self.imageFrame = 0
self.state = self.STANDING
self.hearts = 1
self.heartPts = self.hearts * 3
self.stats()
self.loadImages()
# self.image = self.imageList[0]
self.checkKeys()
def stats(self):
#sets it up so each heart is essentially 3 hit points
if self.heartPts >= 3:
self.hearts = 1
elif self.heartPts >= 6:
self.hearts = 2
elif self.heartPts == 9:
self.hearts = 3
elif self.heartPts > 9:
self.heartPts = 9
# changes state to dead if hp == 0
if self.heartPts == 0:
self.state = DEAD
def loadImages(self):
self.setPosition((320 , 380))
self.setImage("heroSTANDING.gif")
self.setTransparentColor = self.imageMaster.get_at((1,1))
self.imageMaster.set_colorkey(self.setTransparentColor)
def checkKeys(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
self.state = runRight
self.frame += 1
if self.frame >= len(self.imageList):
self.frame = 1
self.image = self.imageList[self.frame]
# self.image = self.image.get_rect()
# self.rect.center = (320, 240)
if keys[pygame.K_LEFT]:
self.state = 1
while keys[pygame.K_g]:
self.state = Attacking
sndAtk.play()
if self.state == self.DEAD:
self.image = self.deadImgList[0]
self.frame += 1
self.image = self.deadImgList[self.frame]
#self.image = self.image.get_rect()
#self.rect.center = (320, 240)
class game(gameEngine.Scene):
def __init__ (self):
gameEngine.Scene.__init__(self)
pygame.display.set_caption("Link's Mediocre Adventure")
background = pygame.Surface(screen.get_size())
background.fill((0, 0, 0))
screen.blit(background, (0, 0))
pro = protaganist(self)
baddy = badguy(self)
baddy1 = badguy(self)
heart = hearts(self)
grass = scrollinggrass(self)
goodlySprites = self.makeSpriteGroup((grass, pro, heart))
baddySprites = self.makeSpriteGroup((baddy, baddy1))
# self.addSpriteGroup(goodlySprites)
self.addGroup((baddySprites))
clock = pygame.time.Clock()
keepGoing = True
while keepGoing:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
if pro.state == pro.ATTACKING:
if pro.collidesGroup(baddySprites):
baddy.health -= 1
baddy1.health -= 1
if baddy.health == 0:
baddy.reset()
elif baddy1.health == 0:
baddy.reset()
elif pro.state != pro.ATTACKING:
if pro.collideGroup(baddySprites):
pro.heartPts -= 1
goodlySprites.update()
baddySprites.update()
goodlySprites.draw(screen)
baddySprites.draw(screen)
pygame.display.flip()
def main():
game.start()
if __name__ == "__main__":
game()
game engine
class SuperSprite(pygame.sprite.Sprite):
""" An enhanced Sprite class
expects a gameEngine.Scene class as its one parameter
Use methods to change image, direction, speed
Will automatically travel in direction and speed indicated
Automatically rotates to point in indicated direction
Five kinds of boundary collision
"""
def __init__(self, scene):
pygame.sprite.Sprite.__init__(self)
self.scene = scene
self.screen = scene.screen
#create constants
self.WRAP = 0
self.BOUNCE = 1
self.STOP = 2
self.HIDE = 3
self.CONTINUE = 4
#create a default text image as a placeholder
#This will usually be changed by a setImage call
self.font = pygame.font.Font("freesansbold.ttf", 30)
self.imageMaster = self.font.render(">sprite>", True, (0, 0,0), (0xFF, 0xFF, 0xFF))
self.image = self.imageMaster
self.rect = self.image.get_rect()
#create properties
#most will be changed through method calls
self.x = 200
self.y = 200
self.dx = 0
self.dy = 0
self.dir = 0
self.rotation = 0
self.speed = 0
self.maxSpeed = 10
self.minSpeed = -3
self.boundAction = self.WRAP
self.pressed = False
self.oldCenter = (100, 100)
self.states = {}
self.currentState = "default"
def update(self):
self.oldCenter = self.rect.center
self.checkEvents()
self.__rotate()
self.__calcVector()
self.__calcPosition()
self.checkBounds()
self.rect.center = (self.x, self.y)
def checkEvents(self):
""" overwrite this method to add your own event code """
pass
def __rotate(self):
""" PRIVATE METHOD
change visual orientation based on
rotation property.
automatically called in update.
change rotation property directly or with
rotateBy(), setAngle() methods
"""
oldCenter = self.rect.center
self.oldCenter = oldCenter
self.image = pygame.transform.rotate(self.imageMaster, self.rotation)
self.rect = self.image.get_rect()
self.rect.center = oldCenter
def __calcVector(self):
""" calculates dx and dy based on speed, dir
automatically called in update
"""
theta = self.dir / 180.0 * math.pi
self.dx = math.cos(theta) * self.speed
self.dy = math.sin(theta) * self.speed
self.dy *= -1
def __calcPosition(self):
""" calculates the sprites position adding
dx and dy to x and y.
automatically called in update
"""
self.x += self.dx
self.y += self.dy
def checkBounds(self):
""" checks boundary and acts based on
self.BoundAction.
WRAP: wrap around screen (default)
BOUNCE: bounce off screen
STOP: stop at edge of screen
HIDE: move off stage and wait
CONTINUE: keep going at present course and speed
automatically called by update
"""
scrWidth = self.screen.get_width()
scrHeight = self.screen.get_height()
#create variables to simplify checking
offRight = offLeft = offTop = offBottom = offScreen = False
if self.x > scrWidth:
offRight = True
if self.x < 0:
offLeft = True
if self.y > scrHeight:
offBottom = True
if self.y < 0:
offTop = True
if offRight or offLeft or offTop or offBottom:
offScreen = True
if self.boundAction == self.WRAP:
if offRight:
self.x = 0
if offLeft:
self.x = scrWidth
if offBottom:
self.y = 0
if offTop:
self.y = scrHeight
elif self.boundAction == self.BOUNCE:
if offLeft or offRight:
self.dx *= -1
if offTop or offBottom:
self.dy *= -1
self.updateVector()
self.rotation = self.dir
elif self.boundAction == self.STOP:
if offScreen:
self.speed = 0
elif self.boundAction == self.HIDE:
if offScreen:
self.speed = 0
self.setPosition((-1000, -1000))
elif self.boundAction == self.CONTINUE:
pass
else:
# assume it's continue - keep going forever
pass
def setSpeed(self, speed):
""" immediately sets the objects speed to the
given value.
"""
self.speed = speed
def speedUp(self, amount):
""" changes speed by the given amount
Use a negative value to slow down
"""
self.speed += amount
if self.speed < self.minSpeed:
self.speed = self.minSpeed
if self.speed > self.maxSpeed:
self.speed = self.maxSpeed
def setAngle(self, dir):
""" sets both the direction of motion
and visual rotation to the given angle
If you want to set one or the other,
set them directly. Angle measured in degrees
"""
self.dir = dir
self.rotation = dir
def turnBy (self, amt):
""" turn by given number of degrees. Changes
both motion and visual rotation. Positive is
counter-clockwise, negative is clockwise
"""
self.dir += amt
if self.dir > 360:
self.dir = amt
if self.dir < 0:
self.dir = 360 - amt
self.rotation = self.dir
def rotateBy(self, amt):
""" change visual orientation by given
number of degrees. Does not change direction
of travel.
"""
self.rotation += amt
if self.rotation > 360:
self.rotation = amt
if self.rotation < 0:
self.rotation = 360 - amt
def setImage (self, image):
""" loads the given file name as the master image
default setting should be facing east. Image
will be rotated automatically """
self.imageMaster = pygame.image.load(image)
self.imageMaster = self.imageMaster.convert()
def setDX(self, dx):
""" changes dx value and updates vector """
self.dx = dx
self.updateVector()
def addDX(self, amt):
""" adds amt to dx, updates vector """
self.dx += amt
self.updateVector()
def setDY(self, dy):
""" changes dy value and updates vector """
self.dy = dy
self.updateVector()
def addDY(self, amt):
""" adds amt to dy and updates vector """
self.dy += amt
self.updateVector()
def setComponents(self, components):
""" expects (dx, dy) for components
change speed and angle according to dx, dy values """
(self.dx, self.dy) = components
self.updateVector()
def setBoundAction (self, action):
""" sets action for boundary. Values are
self.WRAP (wrap around edge - default)
self.BOUNCE (bounce off screen changing direction)
self.STOP (stop at edge of screen)
self.HIDE (move off-stage and stop)
self.CONTINUE (move on forever)
Any other value allows the sprite to move on forever
"""
self.boundAction = action
def setPosition (self, position):
""" place the sprite directly at the given position
expects an (x, y) tuple
"""
(self.x, self.y) = position
def moveBy (self, vector):
""" move the sprite by the (dx, dy) values in vector
automatically calls checkBounds. Doesn't change
speed or angle settings.
"""
(dx, dy) = vector
self.x += dx
self.y += dy
self.checkBounds()
def forward(self, amt):
""" move amt pixels in the current direction
of travel
"""
#calculate dx dy based on current direction
radians = self.dir * math.pi / 180
dx = amt * math.cos(radians)
dy = amt * math.sin(radians) * -1
self.x += dx
self.y += dy
def addForce(self, amt, angle):
""" apply amt of thrust in angle.
change speed and dir accordingly
add a force straight down to simulate gravity
in rotation direction to simulate spacecraft thrust
in dir direction to accelerate forward
at an angle for retro-rockets, etc.
"""
#calculate dx dy based on angle
radians = angle * math.pi / 180
dx = amt * math.cos(radians)
dy = amt * math.sin(radians) * -1
self.dx += dx
self.dy += dy
self.updateVector()
def updateVector(self):
#calculate new speed and angle based on dx, dy
#call this any time you change dx or dy
self.speed = math.sqrt((self.dx * self.dx) + (self.dy * self.dy))
dy = self.dy * -1
dx = self.dx
radians = math.atan2(dy, dx)
self.dir = radians / math.pi * 180
def setSpeedLimits(self, max, min):
""" determines maximum and minimum
speeds you will allow through
speedUp() method. You can still
directly set any speed you want
with setSpeed() Default values:
max: 10
min: -3
"""
self.maxSpeed = max
self.minSpeed = min
def dataTrace(self):
""" utility method for debugging
print major properties
extend to add your own properties
"""
print "x: %d, y: %d, speed: %.2f, dir: %.f, dx: %.2f, dy: %.2f" % \
(self.x, self.y, self.speed, self.dir, self.dx, self.dy)
def mouseDown(self):
""" boolean function. Returns True if the mouse is
clicked over the sprite, False otherwise
"""
self.pressed = False
if pygame.mouse.get_pressed() == (1, 0, 0):
if self.rect.collidepoint(pygame.mouse.get_pos()):
self.pressed = True
return self.pressed
def clicked(self):
""" Boolean function. Returns True only if mouse
is pressed and released over sprite
"""
released = False
if self.pressed:
if pygame.mouse.get_pressed() == (0, 0, 0):
if self.rect.collidepoint(pygame.mouse.get_pos()):
released = True
return released
def collidesWith(self, target):
""" boolean function. Returns True if the sprite
is currently colliding with the target sprite,
False otherwise
"""
collision = False
if self.rect.colliderect(target.rect):
collision = True
return collision
def collidesGroup(self, target):
""" wrapper for pygame.sprite.collideany
simplifies checking sprite - group collisions
returns result of collision check (sprite from group
that was hit or None)
"""
collision = pygame.sprite.spritecollideany(self, target)
return collision
def distanceTo(self, point):
""" returns distance to any point in pixels
can be used in circular collision detection
"""
(pointx, pointy) = point
dx = self.x - pointx
dy = self.y - pointy
dist = math.sqrt((dx * dx) + (dy * dy))
return dist
def dirTo(self, point):
""" returns direction (in degrees) to
a point """
(pointx, pointy) = point
dx = self.x - pointx
dy = self.y - pointy
dy *= -1
radians = math.atan2(dy, dx)
dir = radians * 180 / math.pi
dir += 180
return dir
def drawTrace(self, color=(0x00, 0x00, 0x00)):
""" traces a line between previous position
and current position of object
"""
pygame.draw.line(self.scene.background, color, self.oldCenter,
self.rect.center, 3)
self.screen.blit(self.scene.background, (0, 0))
def addState(self, stateName, stateImageFile):
""" Creates a new sprite state with the associated name
and image. Useful to build multi-state sprites.
"""
#load the image
tempImage = pygame.image.load(stateImageFile)
tempImage.convert()
self.states[stateName] = tempImage
def setState(self, stateName):
""" attempts to set the sprite to the indicated state
(image)
"""
self.imageMaster = self.states[stateName]
self.rect = self.imageMaster.get_rect()
self.currentState = stateName
def getState(self):
""" returns the current state name
(default if no states have been explicitly set)
"""
return self.currentState
if pro.state == pro.ATTACKING:
if pro.collidesWith(baddySprites):
baddy.health -= 1
if baddy.health == 0:
baddy.reset()
elif pro.state != pro.ATTACKING:
if pro.collidesWith(baddySprites):
pro.heartPts -= 1
baddySprites is a sprite group, so I bet you have to use collidesGroup instead of collidesWith.
if pro.state == pro.ATTACKING:
if pro.collidesGroup(baddySprites):
baddy.health -= 1
if baddy.health == 0:
baddy.reset()
elif pro.state != pro.ATTACKING:
if pro.collidesGroup(baddySprites):
pro.heartPts -= 1
But even if you do this, it seems like you'll still have problems. Namely, this code only ever deducts health from baddy and not baddy1. I'm assuming sprite groups support iteration. If so, you should perform collision detection independently on each enemy.
for enemy in baddySprites:
if pro.state == pro.ATTACKING:
if pro.collidesWith(enemy):
enemy.health -= 1
if enemy.health == 0:
enemy.reset()
elif pro.state != pro.ATTACKING:
if pro.collidesWith(enemy):
pro.heartPts -= 1

Categories

Resources