I am beginner in Python and want just to make a red square that will move by pressed keys on keyboard. But after I had run this, only green canvas showed up, no red square. Here is the code:
Imports:
try:
import Tkinter
except:
import tkinter as Tkinter
import time
Here just some constants
__author__ = "Brano"
print(__author__)
GAME_WIDTH = 800
GAME_HEIGHT = 600
GAME_BG = 'green'
MOVE_SPEED = 10
Main class with initialization:
class Game(Tkinter.Tk):
def __init__(self, *args, **kwargs):
Tkinter.Tk.__init__(self, *args, **kwargs)
# Trigger Of Other Functions
self.x = GAME_WIDTH/2
self.y = GAME_HEIGHT/2
self.create_board()
self.create_men()
self.bind('<Any-KeyPress>',self.move)
Creating board:
def create_board(self):
self.board = Tkinter.Canvas(width=GAME_WIDTH, height=GAME_HEIGHT,
bg=GAME_BG)
self.board.pack(padx=10, pady=10)
return
Creating red square:
def create_men(self):
self.men = self.board.create_rectangle(300, 300, 310, 310, fill='red')
return
Move square after pressing keys:
def move(self, event=None):
key = event.keysym
if key=='Left':
self.x = MOVE_SPEED
elif key=='Right':
self.x = -MOVE_SPEED
elif key=='Up':
self.y = MOVE_SPEED
elif key=='Down':
self.y = -MOVE_SPEED
else:
pass
return
Just tkinter updates:
def TkUpdate(self):
self.update()
self.update_idletasks()
return
My main move update:
def GameUpdate(self):
self.board.move(self.men, self.x, self.y)
return
Checking if it is imported:
if __name__ == '__main__':
root=Game(className=" Snake Game ")
while True:
root.TkUpdate()
root.GameUpdate()
time.sleep(0.09)
else :
print("U cannot import me !")
Here is the canvas I have
Here is the whole class:
class Game(Tkinter.Tk):
def __init__(self, *args, **kwargs):
Tkinter.Tk.__init__(self, *args, **kwargs)
# Trigger Of Other Functions
self.x = GAME_WIDTH/2
self.y = GAME_HEIGHT/2
self.create_board()
self.create_men()
self.bind('<Any-KeyPress>',self.move)
def create_board(self):
self.board = Tkinter.Canvas(width=GAME_WIDTH, height=GAME_HEIGHT, bg=GAME_BG)
self.board.pack(padx=10, pady=10)
return
def create_men(self):
self.men = self.board.create_rectangle(300, 300, 310, 310, fill='red')
return
def move(self, event=None):
key = event.keysym
if key=='Left':
self.x = MOVE_SPEED
elif key=='Right':
self.x = -MOVE_SPEED
elif key=='Up':
self.y = MOVE_SPEED
elif key=='Down':
self.y = -MOVE_SPEED
else:
pass
return
def TkUpdate(self):
self.update()
self.update_idletasks()
return
def GameUpdate(self):
self.board.move(self.men, self.x, self.y)
return
Avoid calling update and sleep. Instead use after and mainloop. Your code should schedule your gameloop using after and enter the mainloop after setting up everything. Then keep scheduling the gameloop with after calls.
Your actual problem is you have confused using self.x and self.y as a position in the setup but then use these as a relative move in the game loop. So when you first call GameUpdate you move the rectangle by half the canvas size and it immediately moves out of view. Below is a version that uses these as the 'man' position and asserts the position using coords each time around the game loop.
import tkinter as tk
GAME_WIDTH = 800
GAME_HEIGHT = 600
GAME_BG = 'green'
MOVE_SPEED = 10
MAN_SIZE = 20
class Game(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# Trigger Of Other Functions
self.x = GAME_WIDTH/2
self.y = GAME_HEIGHT/2
self.create_board()
self.create_men()
self.bind('<Any-KeyPress>',self.move)
def create_board(self):
self.board = tk.Canvas(width=GAME_WIDTH, height=GAME_HEIGHT, bg=GAME_BG)
self.board.pack(padx=10, pady=10)
def create_men(self):
self.men = self.board.create_rectangle((self.x, self.y, self.x + MAN_SIZE, self.y + MAN_SIZE), fill='red', outline='black')
def move(self, event=None):
key = event.keysym
print(key)
if key=='Left':
self.x = self.x - MOVE_SPEED
elif key=='Right':
self.x = self.x + MOVE_SPEED
elif key=='Up':
self.y = self.y - MOVE_SPEED
elif key=='Down':
self.y = self.y + MOVE_SPEED
else:
pass
return
def game_loop(self):
self.board.coords(self.men, (self.x, self.y, self.x + MAN_SIZE, self.y + MAN_SIZE))
self.after(10, self.game_loop)
def main():
game = Game(className="Snake")
game.after(10, game.game_loop)
game.mainloop()
if __name__ == '__main__':
main()
Related
I'm working on a simulation in which some cubes of the same class are moving randomly. My aim is to give them another moving pattern, when they fulfill some characteristics (for example their object number).
My Problem:
If they fulfill the characteristics, how can I "switch off" the first moving pattern and activate the next?
Here a strongly simplified example of the simulation, and how it doesn't work:
from tkinter import *
from random import *
class Cubes:
def __init__(self, master, canvas, number, x1, y1, color):
self.master = master
self.canvas = canvas
self.number = number
self.x1 = x1
self.y1 = y1
self.x2 = x1 + 15
self.y2 = y1 + 15
self.color = color
self.rectangle = canvas.create_rectangle(x1, y1, self.x2, self.y2, fill=color)
def movement(self):
self.x = randint(-10, 10)
self.y = randint(-10, 10)
canvas.move(self.rectangle, self.x, self.y)
if self.number == 2:
def movementII(self):
canvas.move(self.rectangle, 0, 0)
self.canvas.after(100, self.movementII)
self.canvas.after(100, self.movement)
if __name__ == "__main__":
master = Tk()
canvas = Canvas(master, width=900, height=600)
canvas.pack()
master.title("Simulation")
cube = Cubes(master, canvas, 2, randint(50, 800), randint(25, 500), "black")
cube.movement()
mainloop()
how can I "switch off" the first moving pattern and activate the next?
When you call after, it returns a unique identifier. You can save that identifier and then later pass it to after_cancel to cancel the job if it hasn't already run.
I'm not entirely clear what you want, but if you want to turn off the old movement when you switch to the new, it would look something like this:
class Cubes:
def __init__(self, master, canvas, number, x1, y1, color):
...
self.after_id = None
...
def cancel(self):
if self.after_id is not None:
self.after_cancel(self.after_id)
self.after_id = None
def movement(self):
self.x = randint(-10, 10)
self.y = randint(-10, 10)
canvas.move(self.rectangle, self.x, self.y)
if self.number == 2:
def movementII(self):
canvas.move(self.rectangle, 0, 0)
self.cancel()
self.after_id = self.canvas.after(100, self.movementII)
self.after_id = self.canvas.after(100, self.movement)
A better way might be to have a single method that you call with after, and it simply calls the appropriate method.
For example, something like this:
def move(self):
if self.number == 1:
self.movement_1()
elif self.number == 2:
self.movement_2()
self.canvas.after(100, self.move)
def movement_1(self):
self.x = randint(-10, 10)
self.y = randint(-10, 10)
canvas.move(self.rectangle, self.x, self.y)
def movement_2(self):
canvas.move(self.rectangle, 0, 0)
Then, to switch the movement method, just change self.number and it will automatically be called at the appropriate time.
I'm just starting to learn how to code, and I'm facing an issue. This is the first time I'm dealing with classes, and I have a simple program to make, but even though it is simple I'm have trouble making it work.
It is not finished, nor cleaned up so It'll look messy, but I need someone's help to move ahead.
In my code, I'm try to run a loop to creates instances of an object, and the number of instances is defined by the user in my Sousfenetre() class.
Inside that class, I have methods, including one which sets the variable 'nbrboules'
I'm trying to access its values at the end of my code, but can't seem to figure out how to.
(And if someone could explain why "nbr" Stringvar() isn't showing in "saisie" Entry widget, and why self.nbr.get() returns the wrong value, that would be nice as well :)
from tkinter import *
import random
fenetre = Tk()
fenetre.title("Boules")
fenetre.geometry("600x600")
Tx,Ty = 600,600
canvas = Canvas(fenetre,height=600,width=600,bg="yellow")
canvas.pack()
class Sousfenetre(Tk):
def __init__(self):
global label
Tk.__init__(self)
self.nbr = StringVar()
self.nbr.set("Entrez un nombre entier")
self.saisie = Entry(self, textvariable=self.nbr, width=200)
self.saisie.grid(row=0)
self.bouton = Button(self, text="VALIDER", font=(None, 30), command=self.valider)
self.bouton.grid(row=1)
self.label = Label(self, text="")
self.label.grid(row=2)
def valider(self):
global nbrboules,label
try:
nbrboules = int(self.saisie.get())
# POURQUOI SELF.NBR.GET() RENVOIE LA MAUVAISE VALEUR PUTAIN
self.destroy()
except ValueError:
self.label.config(text="Entrez un nombre entier !")
def access(self):
return self.nbrboules
class Boule():
def __init__(self):
self.x=random.randint(10,590)
self.y = random.randint(10, 590)
self.dx = random.randint(20,40)
self.dy = random.randint(20, 40)
self.r = random.randint(2,10)
def inversedx(self):
self.dx = -self.dx
def inversedy(self):
self.dy = -self.dy
def deplacementx(self):
self.x += self.dx
def deplacementy(self):
self.y += self.y
def setdx(self,param):
self.x = param
def setdy(self,param):
self.y = param
def collisionBords(self,Tx,Ty):
if self.x + self.dx > Tx - self.r or self.x + self.dx < 0 + self.r :
return self.x
if self.y + self.dy > Ty - self.r or self.y + self.dy < 0 + self.r :
return self.y
# def collisionBoule(self,boule):
# if abs(self.x - boule.x) and abs(self.y - boule.y) < self.r + boule.r:
Sousfenetre()
listeboule = []
Cercles = []
couleur = ["blue","red","green"]
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
listeboule.append(Boule())
#I know this isn't efficient, it was for testing purposes
f = Sousfenetre()
for i in range(0,f.access()):
Cercles.append(canvas.create_oval(listeboule[i].x-listeboule[i].r,listeboule[i].y-listeboule[i].r,listeboule[i].x+listeboule[i].r,listeboule[i].y+listeboule[i].r,fill=random.choice(couleur)))
print(listeboule)
def test():
print(nbrboules)
fenetre.mainloop()
This code works for me.
It uses Toplevel to creates Sousfenetre so Entry displays text from self.nbr.
Because mainloop starts program so everything before mainloop is executed before you press button. I sends listeboule, cercles to Sousfenetre as parameters and it can use them in valider when you press button.
I also used fenetre.after(100, f.lift) to move Sousfenetre to the front 100ms after creating main window so it is not hidden behind main window.
import tkinter as tk # `import *` is not preferred
import random
# --- classes ---
class Sousfenetre(tk.Toplevel):
def __init__(self, listeboule, cercles):
super().__init__() # in Python 3 you can use `super()` instead of class name
# remeber as class variable to have access in other methods
self.listeboule = listeboule
self.cercles = cercles
self.nbr = tk.StringVar()
self.nbr.set("Entrez un nombre entier")
self.saisie = tk.Entry(self, textvariable=self.nbr)
self.saisie.grid(row=0)
self.bouton = tk.Button(self, text="VALIDER", command=self.valider)
self.bouton.grid(row=1)
self.label = tk.Label(self, text="")
self.label.grid(row=2)
def valider(self):
try:
nbrboules = int(self.saisie.get())
# uses
for i in range(nbrboules):
b = self.listeboule[i]
c = random.choice(couleur)
self.cercles.append(canvas.create_oval(b.x-b.r, b.y-b.r, b.x+b.r, b.y+b.r, fill=c))
self.destroy()
except ValueError:
self.label.config(text="Entrez un nombre entier !")
class Boule():
def __init__(self):
self.x = random.randint(10,590)
self.y = random.randint(10, 590)
self.dx = random.randint(20,40)
self.dy = random.randint(20, 40)
self.r = random.randint(2,10)
def inversedx(self):
self.dx = -self.dx
def inversedy(self):
self.dy = -self.dy
def deplacementx(self):
self.x += self.dx
def deplacementy(self):
self.y += self.y
def setdx(self,param):
self.x = param
def setdy(self,param):
self.y = param
def collisionBords(self,Tx,Ty):
if self.x + self.dx > Tx - self.r or self.x + self.dx < 0 + self.r :
return self.x
if self.y + self.dy > Ty - self.r or self.y + self.dy < 0 + self.r :
return self.y
# --- functions ---
# empty
# --- main ---
#listeboule = []
#for _ in range(12):
# listeboule.append(Boule())
listeboule = [Boule() for _ in range(12)] # create 12 circles
cercles = []
couleur = ["blue", "red", "green"]
Tx = 600
Ty = 600
# ---
fenetre = tk.Tk()
fenetre.title("Boules")
fenetre.geometry("600x600")
canvas = tk.Canvas(fenetre, height=600, width=600, bg="yellow")
canvas.pack()
# send `listeboule`, `cercles` to class
f = Sousfenetre(listeboule, cercles)
# Move `Sousfenetre` to the front 100ms after creating main window.
# This way Sousfenetre is not hidden behind main window.
fenetre.after(100, f.lift)
# start program
fenetre.mainloop()
As a novice when it comes to Python, I've tried programming my own game to start, with the advice of a guidebook. However, for this game, I'm trying to detect when a key is held down consistently instead of just pressed. The current code I'm using doesn't make the character move, and without the halt(self, evt) code being implemented, causes the ship to speed up uncontrollably after the button is held down for long enough.
from tkinter import *
import random
import time
class Game:
def __init__(self):
self.tk = Tk()
self.tk.title("Shooter")
self.tk.resizable(0, 0)
self.tk.wm_attributes("-topmost", 1)
self.canvas = Canvas(self.tk, width=500, height=1000, highlightthickness=0)
self.canvas.pack()
self.tk.update()
self.canvas_height = 1000
self.canvas_width = 500
self.bg = PhotoImage(file="background.gif")
w = self.bg.width()
h = self.bg.height()
for x in range(0, 5):
for y in range(0, 10):
self.canvas.create_image(x * w, y * h, \
image=self.bg, anchor='nw')
self.sprites = []
self.running = True
def mainloop(self):
while 1:
if self.running == True:
for sprite in self.sprites:
sprite.move()
self.tk.update_idletasks()
self.tk.update()
time.sleep(0.01)
class Coords:
def __init__(self, x1=0, y1=0, x2=0, y2=0):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
class Sprite:
def __init__(self, game):
self.game = game
self.endgame = False
self.coordinates = None
def move(self):
pass
def coords(self):
return self.coordinates
class PlayerSprite(Sprite):
def __init__(self, game):
Sprite.__init__(self, game)
self.renderimage = [
PhotoImage(file="player_1.gif"),
PhotoImage(file="player_2.gif"),
PhotoImage(file="player_3.gif"),
PhotoImage(file="player_4.gif"),
]
self.image = game.canvas.create_image(225, 900, \
image=self.renderimage[0], anchor='nw')
self.x = 0
self.y = 0
self.velx = 0
self.current_image = 0
self.current_image_add = 1
self.shoot_timer = 0
self.last_time = time.time()
self.coordinates = Coords()
x_move = None
y_move = None
game.canvas.bind_all('<KeyPress-Left>', self.move_left)
game.canvas.bind_all('<KeyPress-Right>', self.move_right)
game.canvas.bind_all('<KeyPress-Up>', self.move_up)
game.canvas.bind_all('<KeyPress-Down>', self.move_down)
game.canvas.bind_all('<KeyPress-Left>', self.halt)
game.canvas.bind_all('<KeyPress-Right>', self.halt)
game.canvas.bind_all('<KeyPress-Up>', self.halt)
game.canvas.bind_all('<KeyPress-Down>', self.halt)
game.canvas.bind_all('<space>', self.shoot)
def move_left(self, evt):
x_move = self.x - 1.5
self.x = x_move
def move_right(self, evt):
x_move = self.x + 1.5
self.x = x_move
def move_up(self, evt):
y_move = self.y - 1.5
self.y = y_move
def move_down(self, evt):
y_move = self.y + 1.5
self.y = y_move
def halt(self, evt):
time.sleep(0.01)
if x_move < 0:
x_move = -1.5
elif x_move > 0:
x_move = 1.5
elif y_move < 0:
y_move = -1.5
elif y_move > 0:
y_move = 1.5
def shoot(self, evt):
print("Placeholder")
def move(self):
self.game.canvas.move(self.image, self.x, self.y)
def coords(self):
xy = self.game.canvas.coords(self.image)
self.coordinates.x1 = xy[0]
self.coordinates.y1 = xy[1]
self.coordinates.x2 = xy[0] + 24
self.coordinates.y2 = xy[1] + 32
return self.coordinates
g = Game()
sp = PlayerSprite(g)
g.sprites.append(sp)
g.mainloop()
My goal is to have my character move at a constant rate (as opposed to uncontrollably fast after a while) when the respective key is pressed.
The most straightforward solution to your question would be to avoid adding a value at every keypress, but rather set a constant value.
def move_left(self, evt):
x_move = -5
self.x = x_move
The movement would however lose its dynamic, but it will be constant. Otherwise, you could create a max value. Something like this:
def move_left(self, evt):
int max_val_left = -10
if( self.x < max_val_left):
x_move = self.x - 1.5
self.x = x_move
Thereby forcing self.x to remain capped and constant if it has reached the max_val.
Holding down a key is essentially the same as pressing that key repeatedly. What you're doing by adding to/subtracting from the self.x/self.y attributes in your move_* functions is you're increasing the amount that the canvas will move your player sprite in each function call (e.g. from 1.5 to 3 to 4.5 to 6, etc. as you hold down a direcitonal key).
Since the canvas will be moving your player by (self.x, self.y) units every time "move" is called under the "PlayerSprite" class, we want self.x and self.y to be either 0 or whatever speed you desire (1.5 in the following code). So instead of adding to self.x and self.y, we should assign it to a constant value:
def move_left(self, evt):
self.x = -1.5
def move_right(self, evt):
self.x = 1.5
def move_up(self, evt):
self.y = -1.5
def move_down(self, evt):
self.y = -1.5
Also, instead of using "halt", what you could do is include 'KeyRelease-*' bindings to stop your player once you've stopped holding down a directional key:
game.canvas.bind_all('KeyRelease-Left'>, self.stop_horz_move)
game.canvas.bind_all('KeyRelease-Right'>, self.stop_horz_move)
game.canvas.bind_all('KeyRelease-Up'>, self.stop_vert_move)
game.canvas.bind_all('KeyRelease-Down'>, self.stop_vert_move)
(I've generalized the left and right directions to horz as well as up and down to vert to save on the number of function definitions.)
Then you can create functions that assign your self.x value or self.y value to 0, so that your player doesn't move once "move" is called.
def stop_move_horz(self, evt):
self.x = 0
def stop_move_vert(self, evt):
self.y = 0
I'm new to python and am working on a final project for my intro to python class. I have the majority of a paddle ball game done, but can't figure out how to make the ball object bounce off of my paddle object.
I've looked on Stackoverflow for a while and have spent a few hours trying to figure it out on my own without any success. If anyone has any ideas I could really use the help.
If there's anything I need to explain better in order for you to get a better understanding please just comment.
GUI FILE:
Import tkinter, random, particle, and helpers
from tkinter import *
from ball import *
from paddle import *
from time import *
class PaddleBall:
def __init__(self, window):
''' Construct the paddle ball GUI '''
self.window = window
self.window.protocol('WM_DELETE_WINDOW', self.safe_exit)
self.width = 700
self.height = 900
self.canvas = Canvas(self.window, bg='black', width=self.width, height=self.height, highlightthickness=0)
self.canvas.bind_all("<KeyPress-Left>", self.move_left)
self.canvas.bind_all("<KeyPress-Right>", self.move_right)
self.canvas.pack()
# Create a label to indicate instructions
instructions = Label(window, text="Controls: Left & Right Arrow Keys")
instructions.pack(side=BOTTOM, expand=YES)
# Create a button to clear Ball
restart_button = Button(window, text="Play", command=self.reset)
restart_button.pack(side=BOTTOM, expand=YES)
self.ball = Ball(350, 350)
self.paddle = Paddle(300, 850, 400, 860, 0, 0)
self.terminated = False
self.render()
def ballobject(self):
self.ball = Ball(350, 350)
self.paddle = Paddle(300, 850, 400, 860, 0, 0)
self.render()
def reset(self):
self.terminated = True
def safe_exit(self):
''' Turn off the event loop before closing the GUI '''
self.terminated = True
self.window.destroy()
# Render everything
def render(self):
# While program is not terminated
if not self.terminated:
# Erase Canvas
self.canvas.delete(ALL)
# Move ball
self.ball.move(self.canvas, self.paddle)
# Render ball
self.ball.render(self.canvas)
# Render paddle
self.paddle.render(self.canvas)
# use distance() to detect collision between ball and paddle.
'''Ball.bounce(self)'''
# Animate the particles movement
self.canvas.after(10, self.render)
else:
# Erase Canvas
self.canvas.delete(ALL)
self.terminated = False
self.canvas.after(50, self.ballobject)
def move_left(self, event):
self.paddle.move_left(event)
def move_right(self, event):
self.paddle.move_right(event)
if __name__ == '__main__':
root = Tk()
root.option_add('*font', ('Verdana', 12, 'bold italic')) # Found at http://effbot.org/tkinterbook/tkinter-widget-styling.htm
root.resizable(0,0) # Found at https://mail.python.org/pipermail/tutor/2001-September/008504.html
root.title('Paddle Ball')
root.wm_attributes("-topmost", -1)
app = PaddleBall(root)
root.mainloop()
BALL CLASS FILE:
class Ball:
'''
Ball models a single ball that may be rendered to a canvas
'''
def __init__(self, x, y, radius = 15,):
'''
Constructor
'''
self._x = x
self._y = y
self._velX = randint(-10,10)
self._velY = randint(-10,-5)
self._radius = radius
self._color = 'white'
self._tx = 350
self._ty = 400
self._t = ""
self._tfill = "red"
self._tfont = ("Arial", 35, "bold italic")
# This method renders the ball
def render(self, canvas):
canvas.create_oval(self._x - self._radius, self._y - self._radius, self._x + self._radius, self._y + self._radius, fill = self._color)
canvas.create_text(self._tx, self._ty, text = self._t, fill = self._tfill, font = self._tfont)
# This method moves the ball
def move(self, canvas, Paddle):
# Update Position
self._x += self._velX
self._y += self._velY
# If the ball hits any of the wall negate the velocity
if (self._x + self._radius > canvas.winfo_reqwidth() and self._velX > 0) or (self._x - self._radius < 0 and self._velX < 0):
self._velX = -self._velX
if (self._y + self._radius < 0 and self._velY < 0):
self._velY = -self._velY
if (self._y + self._radius > canvas.winfo_reqheight() and self._velY > 0):
self._velY = 0
self._velX = 0
self._t = " GAME OVER! \n Click the play button to play again."
#*****THIS IS WHAT I'M HAVING TROUBLE WITH******
# Determine if the ball hits the paddle
if ((self._x + self._radius > Paddle._x(self) and self._velX > 0) or (self._x + self._radius < Paddle._x2(self))) and (self._y < Paddle._y(self)):
self._velX = -self._velX
PADDLE CLASS FILE:
# Import math and helpers
from tkinter import *
import math
from gui import *
class Paddle:
def __init__(self, x, y, x2, y2, velX, velY):
'''
Constructor
'''
self._x = x
self._y = y
self._x2 = x2
self._y2 = y2
self._velX = velX
self._velY = velY
self._color = 'white'
def getpadx(self):
return self._x
def getpady(self):
return self._y
def getpadx1(self):
return self._x2
def getpady2(self):
return self._y2
# This method renders the paddle
def render(self, canvas):
canvas.create_rectangle(self._x, self._y, self._x2, self._y2, fill = self._color)
# This method moves the paddle
def move(self, canvas):
# Update Position
# If the paddle hits any of the wall negate the velocity
if (self._x + self._radius > canvas.winfo_reqwidth() and self._velX > 0) or (self._x - self._radius < 0 and self._velX < 0):
self._velX = -self._velX
def move_left(self, event):
self._x -= 35
self._x2 -= 35
def move_right(self, event):
self._x += 35
self._x2 += 35
I figured it out with the help of a friend. All I had to do was change this code:
From this:
if ((self._x + self._radius > Paddle._x(self) and self._velX > 0) or (self._x + self._radius < Paddle._x2(self))) and (self._y < Paddle._y(self)):
self._velX = -self._velX
To this:
`if (self._x > Paddle._x) and (self._x < Paddle._x2):
if (self._y + self._radius > Paddle._y):
self._velY = -self._velY
self._velX = self._velX + randint(-2,2)`
Below is a little Kivy app I'm working on. At the moment I'm trying to implement a basic reset feature. Essentially, if an enemy collides with the player, I want the game to reset. The games ends by unscheduling clock schedules upon collision with an enemy. I thought after that I could just call main() afterwards, but this simply causes massive bugs where the game spews out errors left and right. I also tried added reschedule rules after the unshedule, but that just overrides the unshedule and keeps the game going.
Note: The game is handled mostly from the game class towards the bottom of the code. It's also where you'll see clock schedule rules.
import kivy
kivy.require('1.1.1')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty, ListProperty, NumericProperty, BooleanProperty
from kivy.core.audio import SoundLoader
import math
from kivy.clock import Clock
import time
import random
sound = SoundLoader.load('gamemusic.mp3')
PLAYER_SPEED = 10
ENEMY_SPEED = 4
ENEMY_SPAWN = 5
UPDATE_SPEED = .01
MIN_INITIAL_PLAYER_MINION_DISTANCE = 200
UPDATE_SCORE = 1
MAX_DECOYS = 3
if sound:
sound.loop = True
sound.play()
class Movable(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
target = ListProperty([])
def move(self):
dx = self.target[0] - self.center[0]
dy = self.target[1] - self.center[1]
total = math.sqrt(dx**2 + dy**2)
if total >0:
self.velocity_x = (dx / total) * self.speed
self.velocity_y = (dy / total) * self.speed
new_x = self.pos[0] + self.velocity_x
new_y = self.pos[1] + self.velocity_y
self.pos = (new_x,new_y)
elif total <=0:
self.velocity_x = self.speed
self.velocity_y = self.speed
class Player(Movable):
target = ListProperty([])
def __init__(self, **kwargs):
Widget.__init__(self)
self.target = [399.0, 399.0]
self.speed = PLAYER_SPEED
def update_target(self, new_target):
self.target = new_target
if distance_pos(self.center, self.target) <= self.speed*2:
self.target = self.center
class Enemy(Movable):
randomColor = random.randint(0,1)
alert = BooleanProperty(False)
def __init__(self, **kwargs):
Widget.__init__(self)
self.world_width = kwargs.get("width",0)
self.world_height = kwargs.get("height",0)
self.speed = ENEMY_SPEED
x_target = float(random.randint(0, self.world_width))
y_target = float(random.randint(0, self.world_height))
self.target = [x_target, y_target]
self.center = kwargs.get('start_pos',[0,0])
def update_target(self, player, enemies, decoys):
alert_list = self.alerted(enemies)
if len(decoys) > 0:
self.target = decoys[0].center
self.alert = False
elif distance(player, self) < 150:
self.alert = True
self.target = player.center
elif len(alert_list) > 0:
self.target = alert_list[0].center
self.alert = False
else:
if distance_pos(self.center, self.target) <= self.speed*2:
x_new_target = float(random.randint(0, self.world_width))
y_new_target = float(random.randint(0, self.world_height))
self.target = [x_new_target, y_new_target]
def alerted(self, enemies):
alert_list = []
for item in enemies:
if item.alert == True and distance(self, item) < 150:
alert_list.append(item)
return alert_list
class Decoy(Widget):
def __init__(self, **kwargs):
Widget.__init__(self)
self.center = kwargs.get('start_pos',[0,0])
pass
def distance(widget1, widget2):
return distance_pos(widget1.center, widget2.center)
def distance_pos(pos1, pos2):
dist = math.sqrt((pos1[0]-pos2[0])**2 + (pos1[1]-pos2[1])**2)
return dist
class Game(Widget):
player1 = ObjectProperty(None)
enemies = ListProperty([])
decoys = ListProperty([])
score = NumericProperty()
def setup(self):
self.enemies = []
self.decoys = []
self.player1.center = self.center
self.setup_schedules()
#Don't forget about good code organization!
def setup_schedules(self):
Clock.schedule_interval(self.update, UPDATE_SPEED)
Clock.schedule_interval(self.spawn_enemy, ENEMY_SPAWN)
Clock.schedule_interval(self.increase_score, UPDATE_SCORE)
def update(self,dt):
self.player1.move()
for item in self.enemies:
item.update_target(self.player1,self.enemies,self.decoys)
item.move()
if self.player1.collide_widget(item):
Clock.unschedule(self.spawn_enemy)
Clock.unschedule(self.update)
Clock.unschedule(self.increase_score)
"""
def death_restart(self, player):
if self.collide_widget(player):
print("error")
#main()
"""
def spawn_enemy(self, dt):
if len(self.enemies) <= 8:
x = float(random.randint(0, self.width))
y = float(random.randint(0, self.height))
enemy = Enemy(start_pos = (x,y),width = self.width,height = self.height)
while distance(enemy, self.player1)< MIN_INITIAL_PLAYER_MINION_DISTANCE:
x = float(random.randint(0, self.width))
y = float(random.randint(0, self.height))
enemy.pos = (x,y)
self.enemies.append(enemy)
self.add_widget(enemy)
def spawn_decoy(self, location):
x = location[0]
y = location[1]
decoy = Decoy(start_pos = (x,y))
self.decoys.append(decoy)
self.add_widget(decoy)
def increase_score(self, dt):
self.score += 1
#on_touch_move vs on_touch_down
def on_touch_move(self, touch):
self.player1.update_target([touch.x, touch.y])
def on_touch_down(self, touch):
if touch.is_double_tap and len(self.decoys) < MAX_DECOYS:
self.spawn_decoy([touch.x, touch.y])
#Entry Point into app
class GameApp(App):
def build(self):
game = Game()
game.setup()
return game
def main():
GameApp().run()
main()