Reputation: 21
I have this assignment where when I click the mouse a ball will be launched and eventually destroy a box. I am having trouble moving the ball with the mouse click. The variables that are defined after the "print initial value line" are required to be those values. I'm not too familiar with pygame and don't know where I should be drawing and if I should remove the ball before I draw a new one.
import pygame, sys
from Drawable import *
from Ball import *
from Block import *
from Text import *
from pygame.locals import *
pygame.init()
surface = pygame.display.set_mode((500,500))
surface.fill((255,255,255))
class Line(Drawable):
def __init__(self,x=0, y=0,color=(0,255,0)):
super().__init__(x, y, color)
self.position = x , y
self.visible = False
def draw(self):
if self.visible == True:
pygame.draw.line(surface,(0,0,0),(0,400),(500,400))
def get_rect(self):
pass
ground = Line()
ground.visible = True
ground.draw()
ball = Ball()
ball.visible = True
ball.draw(surface)
block = Block()
block.visible = True
block.draw(surface)
text = Text()
text.visible = True
text.draw(surface)
print("Initial Ball Location:", ball.position)
dt = 0.1
g = 6.67
R = 0.7
eta = 0.5
mouespos1 = 0
mousepos2 = 0
xv = 1
yv = 1
def mousedown():
global mousepos1
mousepos1 = pygame.mouse.get_pos()
def mouseup():
global xv
global yv
mousepos2 = pygame.mouse.get_pos()
xv = mousepos2[0] - mousepos1[0]
print("XV in mouseup:", xv)
yv = -1 * (mousepos2[1] - mousepos1[1])
print("YV in mouesup:", yv)
def updateballpos():
global xv, yv
print("Ran Update")
moveX = ball.x + (dt * xv)
ball.moveX(moveX)
moveY = ball.y - (dt * yv)
ball.moveY(moveY)
print("new x", ball.x)
print("new y", ball.y)
if ball.y > 400:
yv = -R * yv
xv = eta * xv
else:
yv = yv - g * dt
ball.draw(surface)
pygame.display.update()
while(True):
for event in pygame.event.get():
if (event.type == pygame.QUIT) or \
(event.type == pygame.KEYDOWN and event.__dict__['key'] == pygame.K_q):
pygame.quit()
exit()
if event.type == pygame.MOUSEBUTTONDOWN:
mousedown()
if event.type == pygame.MOUSEBUTTONUP:
mouseup()
print("xv in while", xv)
print("yv in while", yv)
if yv > 0 and xv > 0:
updateballpos()
pygame.display.update()
And this is the Ball Class and Drawable Class
import pygame
import abc
import random
class Drawable(metaclass = abc.ABCMeta):
def __init__(self,x,y,color):
self.x = x
self.y = y
self.color = color
self.position = (self.x,self.y)
self.visible = False
def getLoc(self):
return (self.x, self.y)
def setLoc(self,p):
self.x = p[0]
self.y = p[1]
def getColor(self):
return self.__color
def getX(self):
return self.__x
def getY(self):
return self.__y
@abc.abstractmethod
def draw(self,surface):
pass
@abc.abstractmethod
def get_rect(self):
pass
from Drawable import *
import pygame, sys
from pygame.locals import *
class Ball(Drawable):
def __init__(self, x=20, y=400,color=(0, 0,0)):
super().__init__(x, y,color)
self.x = x
self.y = y
self.position = (self.x,self.y)
self.visible = False
def draw(self,s):
if self.visible == True:
pygame.draw.circle(s,(255,0,0),(int(self.x), int(self.y)),8)
def get_rect(self):
pass
def getLoc(self):
return (self.x, self.y)
def setLoc(self, x, y):
self.x = x
self.y = y
def moveX(self, inc):
self.x = self.x + inc
def moveY(self, inc):
self.y = self.y + inc
Upvotes: 2
Views: 1220
Reputation: 20478
I recommend adding the updateballpos
as a method of the Ball
, because it only updates the ball attributes. The xv
and yv
variables should also be attributes of the balls, then you can give every ball a different velocity.
To spawn new balls, you can just create Ball
instances and append them to a list, and then use for
loops to update and draw the balls in this list. You can clear the screen with the fill
method (or blit a background surface) before you draw the balls.
For the slingshot effect you could store the rel
attribute (relative movement of the mouse in pixels) of the pygame.MOUSEMOTION
events, pass it to the balls when you instantiate them and just assign it to the xv
, yv
attributes.
Here's a minimal, complete example:
import sys
import pygame
pygame.init()
screen = pygame.display.set_mode((500,500))
class Ball:
# Pass the xv, yv as arguments as well.
def __init__(self, x=20, y=400, xv=0, yv=0, color=(0, 0,0)):
self.x = x
self.y = y
# Give the objects xv and yv attributes.
self.xv = xv
self.yv = yv
self.position = (self.x,self.y)
self.visible = False
def draw(self,s):
if self.visible == True:
pygame.draw.circle(s,(255,0,0),(int(self.x), int(self.y)),8)
def get_rect(self):
pass
def getLoc(self):
return (self.x, self.y)
def setLoc(self, x, y):
self.x = x
self.y = y
def moveX(self, dt):
self.x += dt * self.xv
def moveY(self, dt):
self.y += dt * self.yv
# Add a method to update the position and other attributes.
# Call it every frame.
def update(self, dt):
self.moveX(dt)
self.moveY(dt)
if self.y > 400:
self.yv = -R * self.yv
self.xv = eta * self.xv
else:
self.yv = self.yv - g * dt
dt = 0.1
g = 6.67
R = 0.7
eta = 0.5
balls = []
clock = pygame.time.Clock()
rel_x = 0
rel_y = 0
while True:
for event in pygame.event.get():
if (event.type == pygame.QUIT or
event.type == pygame.KEYDOWN and event.key == pygame.K_q):
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONUP:
# Create a new ball instance and append it to the list.
# Pass the rel (the relative mouse movement) as well.
ball = Ball(xv=rel_x*10, yv=rel_y*10) # * 10 to make the balls faster.
ball.visible = True
balls.append(ball)
if event.type == pygame.MOUSEMOTION:
# event.rel is the relative movement of the mouse.
rel_x = event.rel[0]
rel_y = event.rel[1]
# Call the update methods of all balls.
for ball in balls:
ball.update(dt)
# Clear the screen with fill (or blit a background surface).
screen.fill((255,255,255))
# Draw the balls.
for ball in balls:
ball.draw(screen)
pygame.display.update()
dt = clock.tick(30) / 1000
Upvotes: 1