I am working to create a version of asteroids using Python and Tkinter. When the left or right arrow key is pressed the ship needs to rotate. The ship is a triangle on the Tkinter canvas. I am having trouble coming up with formula to adjust the coordinates for the triangle. I believe it has something to do with sin and cos, though I am not exactly sure. So far I have two classes one for the ship and the other for the game. In the ship class I have callback methods for the key presses. Any help would be greatly appreciated. Thanks.
Ship Class
import math
class Ship:
def __init__(self,canvas,x,y,width,height):
self.canvas = canvas
self.x = x - width/2
self.y = y + height/2
self.width = width
self.height = height
self.x0 = self.x
self.y0 = self.y
self.x1 = self.x0 + self.width/2
self.y1 = self.y0-self.height
self.x2 = self.x0 + self.width
self.y2 = self.y0
self.ship = self.canvas.create_polygon((self.x0, self.y0, self.x1, self.y1, self.x2, self.y2), outline="white", width=3)
def changeCoords(self):
self.canvas.coords(self.ship,self.x0, self.y0, self.x1, self.y1, self.x2, self.y2)
def rotateLeft(self, event=None):
# Should rotate one degree left.
pass
def rotateRight(self, event=None):
# Should rotate one degree right.
self.x0 = self.x0 -1
self.y0 = self.y0 - 1
self.x1 = self.x1 + 1
self.y1 = self.y1 + 1
self.x2 = self.x2 - 1
self.y2 = self.y2 + 1
self.changeCoords()
Game Class
from Tkinter import *
from ship import *
class Game:
def __init__(self, gameWidth, gameHeight):
self.root = Tk()
self.gameWidth = gameWidth
self.gameHeight = gameHeight
self.gameWindow()
self.ship = Ship(self.canvas, x=self.gameWidth/2,y=self.gameHeight/2, width=50, height=50)
self.root.bind('<Left>', self.ship.rotateLeft)
self.root.bind('<Right>', self.ship.rotateRight)
self.root.mainloop()
def gameWindow(self):
self.frame = Frame(self.root)
self.frame.pack(fill=BOTH, expand=YES)
self.canvas = Canvas(self.frame,width=self.gameWidth, height=self.gameHeight, bg="black", takefocus=1)
self.canvas.pack(fill=BOTH, expand=YES)
asteroids = Game(600,600)
First of all, you need to rotate around a center of the triangle. The centroid would probably work best for that. To find that, you can use the formula C = (1/3*(x0 + x1 + x2), 1/3*(y0 + y1 + y2)), as it's the average of all points in the triangle. Then you have to apply the rotation with that point as the center. So it'd be something like this...
import math
class Ship:
def centroid(self):
return 1 / 3 * (self.x0 + self.x1 + self.x2), 1 / 3 * (self.y0 + self.y1 + self.y2)
def __init__(self, canvas, x, y, width, height, turnspeed, acceleration=1):
self._d = {'Up':1, 'Down':-1, 'Left':1, 'Right':-1}
self.canvas = canvas
self.width = width
self.height = height
self.speed = 0
self.turnspeed = turnspeed
self.acceleration = acceleration
self.x0, self.y0 = x, y
self.bearing = -math.pi / 2
self.x1 = self.x0 + self.width / 2
self.y1 = self.y0 - self.height
self.x2 = self.x0 + self.width
self.y2 = self.y0
self.x, self.y = self.centroid()
self.ship = self.canvas.create_polygon((self.x0, self.y0, self.x1, self.y1, self.x2, self.y2), outline="white", width=3)
def changeCoords(self):
self.canvas.coords(self.ship,self.x0, self.y0, self.x1, self.y1, self.x2, self.y2)
def rotate(self, event=None):
t = self._d[event.keysym] * self.turnspeed * math.pi / 180 # the trig functions generally take radians as their arguments rather than degrees; pi/180 radians is equal to 1 degree
self.bearing -= t
def _rot(x, y):
#note: the rotation is done in the opposite fashion from for a right-handed coordinate system due to the left-handedness of computer coordinates
x -= self.x
y -= self.y
_x = x * math.cos(t) + y * math.sin(t)
_y = -x * math.sin(t) + y * math.cos(t)
return _x + self.x, _y + self.y
self.x0, self.y0 = _rot(self.x0, self.y0)
self.x1, self.y1 = _rot(self.x1, self.y1)
self.x2, self.y2 = _rot(self.x2, self.y2)
self.x, self.y = self.centroid()
self.changeCoords()
def accel(self, event=None):
mh = int(self.canvas['height'])
mw = int(self.canvas['width'])
self.speed += self.acceleration * self._d[event.keysym]
self.x0 += self.speed * math.cos(self.bearing)
self.x1 += self.speed * math.cos(self.bearing)
self.x2 += self.speed * math.cos(self.bearing)
self.y0 += self.speed * math.sin(self.bearing)
self.y1 += self.speed * math.sin(self.bearing)
self.y2 += self.speed * math.sin(self.bearing)
self.x, self.y = self.centroid()
if self.y < - self.height / 2:
self.y0 += mh
self.y1 += mh
self.y2 += mh
elif self.y > mh + self.height / 2:
self.y0 += mh
self.y1 += mh
self.y2 += mh
if self.x < -self.width / 2:
self.x0 += mw
self.x1 += mw
self.x2 += mw
elif self.x > mw + self.width / 2:
self.x0 -= mw
self.x1 -= mw
self.x2 -= mw
self.x, self.y = self.centroid()
self.changeCoords()
I made some changes to the controls that make the game a bit more like Asteroids, by the way. (Didn't implement firing, though. I may have gotten more into this than I expected, but I'm not going to do everything. Also, there's a bit of a problem when you try to use multiple movement keys at once, but that's due to the way Tk does event handling. It wasn't designed for gaming, so you'd have to fiddle around a fair bit to get that working properly with Tk/Tkinter.)
from tkinter import *
from ship import *
class Game:
def __init__(self, gameWidth, gameHeight):
self.root = Tk()
self.gameWidth = gameWidth
self.gameHeight = gameHeight
self.gameWindow()
self.ship = Ship(self.canvas, x=self.gameWidth / 2,y=self.gameHeight / 2, width=50, height=50, turnspeed=10, acceleration=5)
self.root.bind('<Left>', self.ship.rotate)
self.root.bind('<Right>', self.ship.rotate)
self.root.bind('<Up>', self.ship.accel)
self.root.bind('<Down>', self.ship.accel)
self.root.mainloop()
def gameWindow(self):
self.frame = Frame(self.root)
self.frame.pack(fill=BOTH, expand=YES)
self.canvas = Canvas(self.frame,width=self.gameWidth, height=self.gameHeight, bg="black", takefocus=1)
self.canvas.pack(fill=BOTH, expand=YES)
asteroids = Game(600,600)
As an aside, you might want to use properties to allow for easier handling of the points and such.
Related
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.
New to programming. Working on a simple pong clone. Started the ball but want to make sure all sides of the window (500x500) will have the ball bounce off of it. How could I do this? Thanks!
P.S. This is my current code if needed.
import threading
import random
import time
import string
import os.path
from random import randint
from tkinter import *
class Pong:
Title = 'Pong'
Size = '500x500'
class Ball:
def __init__(self,canvas,x1,y1,x2,y2):
self.x1 =x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
self.canvas = canvas
self.ball = canvas.create_oval(self.x1, self.y1, self.x2, self.y2, fill="black")
def move_ball(self):
deltax = randint(0,5)
deltay = randint(0,5)
self.canvas.move(self.ball,deltax,deltay)
self.canvas.after(50,self.move_ball)
def PongGame():
print("Moved to PongGame.")
ball1 = Ball(canvas,10,10,30,30)
ball1.move_ball()
def titleButtonClicked(event):
print("Title screen button clicked.")
btn.pack_forget()
btn.place(x=600,y=600)
msg.pack_forget()
PongGame()
root = Tk()
root.geometry(Pong.Size)
root.title(Pong.Title)
root.resizable(False,False)
msg = Label(root, text = Pong.Title, font = ("", 50))
msg.pack()
canvas = Canvas(root, width = 500, height = 500)
canvas.pack()
btn=Button(root, text = "Start")
btn.bind('<Button-1>', titleButtonClicked)
btn.place(x=220,y=300)
root.mainloop()
Collisions are not trivial; the simplest is to reverse the x or the y velocity after checking which edge of the bounding box of the ball intersects with the boundaries of the canvas.
Maybe something like this:
import random
import tkinter as tk
WIDTH, HEIGHT = 500, 500
class Ball:
radius = 10
spawn_center = (250, 100)
def __init__(self, canvas):
self.canvas = canvas
self.id = None
self.create_ball()
self.velocity = None
self.assign_random_velocity()
self.keep_moving = True
self.move()
def create_ball(self):
xc, yc = self.spawn_center
x0, y0, = xc - self.radius, yc + self.radius
x1, y1, = xc + self.radius, yc - self.radius
self.id = self.canvas.create_oval(x0, y0, x1, y1)
def assign_random_velocity(self):
dx = random.randrange(1, 5) * random.choice((1, -1))
dy = random.randrange(1, 5) * random.choice((1, -1))
self.velocity = (dx, dy)
def move(self):
if self.keep_moving is None:
return
self.check_collision()
self.canvas.move(self.id, *self.velocity)
self.keep_moving = self.canvas.after(10, self.move)
def cancel_move(self):
if self.keep_moving is not None:
self.canvas.after_cancel(self.keep_moving)
self.keep_moving = None
def check_collision(self):
x0, y0, x1, y1 = self.canvas.coords(self.id)
dx, dy = self.velocity
if x0 < 0:
x0 = 0
dx = -dx
elif x1 > WIDTH:
x1 = WIDTH
dx = -dx
if y0 < 0:
y0 = 0
dy = -dy
elif y1 > HEIGHT:
y1 = HEIGHT
dy = -dy
self.velocity = dx, dy
class PongBoard(tk.Canvas):
def __init__(self, master):
self.master = master
super().__init__(self.master)
self.ball = None
self.spawn_new_ball()
def spawn_new_ball(self):
if self.ball is not None:
self.ball.cancel_move()
self.delete(self.ball.id)
self.ball = Ball(self)
root = Tk()
root.geometry(f'{WIDTH}x{HEIGHT+20}')
board = PongBoard(root)
new_ball_btn = tk.Button(root, text='spawn new ball', command=board.spawn_new_ball)
board.pack(expand=True, fill=tk.BOTH)
new_ball_btn.pack()
root.mainloop()
This will get you started, but you will have to implement the paddles, the paddles movement, the collision checking of the ball with the paddles, and keep the score by yourself.
I have a Point class and Rectangle class set up, here is the code for that:
import math
class Point:
"""A point in two-dimensional space."""
def __init__(self, x: float = 0.0, y: float = 0.0)->None:
self.x = x
self.y = y
def moveIt(self, dx: float, dy: float)-> None:
self.x = self.x + dx
self.y = self.y + dy
def distance(self, otherPoint: float):
if isinstance(otherPoint, Point):
x1 = self.x
y1 = self.y
x2 = otherPoint.x
y2 = otherPoint.y
return ( (x1 - x2)**2 + (y1 - y2)**2 )**0.5
class Rectangle:
def __init__(self, topLeft = Point(0,0), bottomRight = Point(1,1)):
self.topLeft = topLeft
self.bottomRight = bottomRight
The two points are the top left and the bottom right for the rectangle. How could I find the area and perimeter of this rectangle from two points? Would appreciate any and all help!
We can access the x and y values of each point and calculate the height and width, from there we can create methods that calculate area and perimeter
class Rectangle():
def __init__(self, topLeft = Point(0,0), bottomRight = Point(1,1)):
self.topLeft = topLeft
self.bottomRight = bottomRight
self.height = topLeft.y - bottomRight.y
self.width = bottomRight.x - topLeft.x
self.perimeter = (self.height + self.width) * 2
self.area = self.height * self.width
rect = Rectangle(Point(3,10),Point(4,8))
print(rect.height)
print(rect.width)
print(rect.perimeter)
print(rect.area)
chrx#chrx:~/python/stackoverflow/9.24$ python3.7 rect.py
2
1
6
2
Or using methods
class Rectangle():
def __init__(self, topLeft = Point(0,0), bottomRight = Point(1,1)):
self.topLeft = topLeft
self.bottomRight = bottomRight
self.height = topLeft.y - bottomRight.y
self.width = bottomRight.x - topLeft.x
def make_perimeter(self):
self.perimeter = (self.height + self.width) * 2
return self.perimeter
def make_area(self):
self.area = self.height * self.width
return self.area
rect = Rectangle(Point(3,10),Point(4,8))
print(rect.height)
print(rect.width)
print(rect.make_perimeter())
print(rect.make_area())
I think i've worked out the calculations for the collision i just need to know how to send the positional co-ords of my sprites to the class where the collision is being checked. I also need to know how to check all of the sprites so it knows which one is being collided with.
class Enemy(object):
'''single enemy'''
def __init__(self, canvas):
# access to canvas
self.canvas = canvas
self.radius = 12.5 # random
self.color = random.choice( ('blue', 'red', 'green') )
self.x = random.uniform(self.radius, RES_X-self.radius)
self.y = random.uniform(self.radius, RES_Y-self.radius)
self.x1 = self.x-self.radius
self.y1 = self.y-self.radius
self.x2 = self.x+self.radius
self.y2 = self.y+self.radius
self.oval = self.canvas.create_oval(self.x1, self.y1, self.x2, self.y2, fill=self.color, outline=self.color)
self.moving = True
self.start()
def start(self):
'''start moving'''
self.moving = True
# move this enemy after random time
random_time = random.randint(150, 3000)
root.after(random_time, self.move)
def move(self):
global enposx, enposy
if self.moving: # to stop root.after
direction = random.randint(1,4)
if direction == 1: # up
self.y -= self.radius
self.y1 -= self.radius
self.y2 -= self.radius
elif direction == 2: # down
self.y += self.radius
self.y1 += self.radius
self.y2 += self.radius
elif direction == 3: # left
self.x -= self.radius
self.x1 -= self.radius
self.x2 -= self.radius
elif direction == 4: # right
self.x += self.radius
self.x1 += self.radius
self.x2 += self.radius
self.enposx = int(self.x1-self.radius)
self.enposy = int(self.y1-self.radius)
self.canvas.coords(self.oval, self.x1, self.y1, self.x2, self.y2)
The code above is the one i need to transfer self.enposx and self.enposy (the centre point of the circle) from
class Projectile(object):
'''single projectile'''
def __init__(self, parent, canvas):
# access to canvas
self.parent = parent
self.repcount = 0
self.canvas = canvas
self.radius = 6 # random
self.color = random.choice( ('blue', 'red', 'green', 'yellow', 'orange') )
self.x1 = x + self.radius
self.y1 = y + self.radius
self.x2 = x - self.radius
self.y2 = y - self.radius
self.oval = self.canvas.create_oval(self.x1, self.y1, self.x2, self.y2, fill=self.color, outline=self.color)
self.moving = True
self.direction = shootdir
self.start()
def start(self):
global direction
'''start moving'''
self.moving = True
# move this enemy after random time
root.after(20, self.move)
def move(self):
if self.repcount < 20:
if self.moving: # to stop root.after
if self.direction == 1: # up
self.y1 -= self.radius
self.y2 -= self.radius
elif self.direction == 2: # down
self.y1 += self.radius
self.y2 += self.radius
elif self.direction == 3: # left
self.x1 -= self.radius
self.x2 -= self.radius
elif self.direction == 4: # right
self.x1 += self.radius
self.x2 += self.radius
self.canvas.coords(self.oval, self.x1, self.y1, self.x2, self.y2)
self.proposx, self.proposy = int(self.x1-self.radius), int(self.y1-self.radius)
self.repcount += 1
xlist, ylist = [self.proposx, self.enposx], [self.proposy, self.enposy]
xmax, xmin = max(xlist), min(xlist)
ymax, ymin = max(ylist), min(ylist)
xval, yval = int(xmax - xmin), int(ymax - ymin)
if xval < 12.5 and yval < 12.5:
print("hit")
self.parent.remove(self)
else:
root.after(20, self.move)
else:
print('done')
self.parent.remove(self)
The code above is where i need it sent too but im not sure how to send it without it giving out an error
thanks
From what I understand, you are creating some sort of space invaders-like game, and you are not certain how to compare enemies' (x,y) coordinates with (player's) projectiles' coordinates.
Before going any further, please take note that I have never programmed that kind of game, so what follows may (will) require optimisation.
I would suggest building a 3rd class built specifically to detect collisions between "enemies" and "projectiles":
class CollisionManager:
def __init__(self, enemies, projectiles):
self.enemies = enemies
self.projectiles = projectiles
self.pending_collisions = []
def detect_collisions(self):
# Your collision detection magic here
pass
You might need to add a get_propertiesmethod / property to bundle all information you need to do your math (see this post for clarification).
The pending_collisionsattribute is merely a suggestion to help you iterate in a clean way over enemies and projectiles, then perform whatever operation you may need.
The reason behind this suggestion is that I don't think handling collision belongs inside a "projectile" class. If you are to destroy (remove all references to) enemy objects, you are probably going to end up doing stuff like all_enemies.remove(destroyed_enemy) and doing that from your projectile class will make your code very messy in no time.
I'm learning Python. At the moment, I can do what I want to do by composition, but when I try to do the same thing using inheritance, I get an error. Here's my code. I'm basically trying to make a class for a colored square.
from graphics import *
class Block(Rectangle):
def __init__(self, corner, colour):
self.corner = corner
self.colour = colour
self.x1 = self.corner.getX() * 30
self.y1 = self.corner.getY() * 30
self.x2 = self.x1 + 30
self.y2 = self.y1 + 30
self.point1 = Point(self.x1, self.y1)
self.point2 = Point(self.x2, self. y2)
Rectangle.__init__(self, self.point1, self.point2)
def draw(self, window):
self.window = window
self.Rectangle.draw(self.window)
new_win = GraphWin("thingy", 700, 500)
corner = Point(1, 1)
square1 = Block(corner, 'red')
square1.draw(new_win)
new_win.mainloop()
The error I get is
File "F:\Python\4\4_3.py", line 24, in draw
self.draw(self.window)
The error is repeated indefinitely.
Here is the code that does what I want when I do it with composition:
from graphics import *
class Block():
def __init__(self, corner, colour):
self.corner = corner
self.colour = colour
self.x1 = self.corner.getX() * 30
self.y1 = self.corner.getY() * 30
self.x2 = self.x1 + 30
self.y2 = self.y1 + 30
self.point1 = Point(self.x1, self.y1)
self.point2 = Point(self.x2, self. y2)
self.Rectangle = Rectangle(self.point1, self.point2)
def draw(self, window):
self.window = window
self.Rectangle.draw(self.window)
self.Rectangle.setFill(self.colour)
new_win = GraphWin("thingy", 150, 150)
corner = Point(1, 1)
square1 = Block(corner, 'red')
square1.draw(new_win)
new_win.mainloop()
from graphics import *
class Block(Rectangle):
def __init__(self, corner, colour):
self.corner = corner
self.colour = colour
self.x1 = self.corner.getX() * 30
self.y1 = self.corner.getY() * 30
self.x2 = self.x1 + 30
self.y2 = self.y1 + 30
self.point1 = Point(self.x1, self.y1)
self.point2 = Point(self.x2, self. y2)
Rectangle.__init__(self, self.point1, self.point2)
def draw(self, window):
self.window = window
Rectangle.draw(self, self.window)
# instead of self.Rectangle.draw(self.window)
In the case of inheritance, there is no self.Rectangle
The simple code for python 2.7 is:
BaseClassName.__init__(self, args)