简体   繁体   中英

Pygame Moving a Ball with The Mouse

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM