我的目标是让一门大炮以线性路径发射一枚炮弹。我已经玩了一些算法很多次,但我无法获得一个流畅的动作,而是位置成块更新,我不确定如何避免这个问题。这是我的代码:
import pygame
from functools import partial
pygame.init()
display_width = 700
display_height = 500
display = pygame.display.set_mode((display_width,display_height))
cannonImg = 'C:/Users/student/Desktop/cannon.png'
skyImg = 'C:/Users/student/Desktop/sky.png'
cannonballImg = 'C:/Users/student/Desktop/cannonball.png'
cannon = pygame.image.load(cannonImg)
sky = pygame.image.load(skyImg)
cannonball = pygame.image.load(cannonballImg)
blue = (0,0,200)
light_blue = (0,0,255)
black = (0,0,0)
red = (200,0,0)
light_red = (255,0,0)
smallfont = pygame.font.SysFont("comicsansms", 25)
medfont = pygame.font.SysFont("Algerian", 50)
largefont = pygame.font.SysFont("Algerian", 85)
altSmall = pygame.font.SysFont("Algerian",20)
altMed = pygame.font.SysFont("Algerian",30)
altLarge = pygame.font.SysFont("Algerian",75)
extrasmall = pygame.font.SysFont("comicsansms",15)
def text_objects(text, color,size = "small"):
if size == "small":
textSurface = smallfont.render(text, True, color)
if size == "medium":
textSurface = medfont.render(text, True, color)
if size == "large":
textSurface = largefont.render(text, True, color)
if size == "altMed":
textSurface = altMed.render(text,True,color)
if size == "altSmall":
textSurface = altSmall.render(text,True,color)
if size == "medFont":
textSurface = medfont.render(text,True,color)
if size == "smallFont":
textSurface = smallfont.render(text,True,color)
if size == "extraSmall":
textSurface = extrasmall.render(text,True,color)
return textSurface, textSurface.get_rect()
def message_display(text):
largeText = pygame.font.Font('freesansbold.ttf',200)
TextSurf, TextRect = text_objects(text, largeText)
TextRect.center = ((display_width/2),(display_height/2))
gameDisplay.blit(TextSurf, TextRect)
pygame.display.update()
time.sleep(2)
game_loop()
class Button():
text = str()
x = int()
y = int()
width = int()
height = int()
inactive_color = None
active_color = None
action = str()
active = bool()
def __init__(self,text,x,y,width,height,inactive_color,active_color,action,text_color,text_size,active):
self.text = text
self.x = x
self.y = y
self.width = width
self.height = height
self.inactive_color = inactive_color
self.active_color = active_color
self.action = action
self.text_color = text_color
self.text_size = text_size
self.active = active
def nothing():
pass
def handle_event(self,event):
if self.is_hovered() and event.type == pygame.MOUSEBUTTONDOWN:
self.action()
def text_to_button(self,surface):
textSurf, textRect = text_objects(self.text,self.text_color,self.text_size)
textRect.center = ((self.x+(self.width/2)), self.y+(self.height/2))
surface.blit(textSurf, textRect)
def is_hovered(self):
cur = pygame.mouse.get_pos()
return self.x + self.width > cur[0] > self.x and self.y + self.height > cur[1] > self.y
def drawButton(self, surface):
if self.active:
pygame.draw.rect(surface,self.inactive_color,[self.x,self.y,self.width,self.height])
if self.is_hovered() and self.active:
pygame.draw.rect(surface, self.active_color,[self.x,self.y,self.width,self.height])
self.text_to_button(surface)
def nothing():
pass
class kinematic():
obj_x = 110
obj_y = 240
v = 0
t = 0
def __init__(self,v,t):
self.v = v
self.t = t
def addOneV(self):
self.v += 1
def addOneXI(self):
self.xi += 1
def addOneT(self):
self.t += 1
def reset(self):
self.v = 0
self.t = 0
self.obj_x = 125
self.obj_y = 240
def calculatePos(self):
n = 0
while n < self.t+1:
self.obj_x = self.t * 10
self.obj_y = self.v * n
n += 1
def programLoop():
object1 = kinematic(0,10)
reset = Button("Reset",400,25,100,75,red,light_red,object1.reset,black,"smallFont",True)
programExit = False
while not programExit:
addVelocity = Button("Velocity: %i " % object1.v + "m/s",50, 25,150,50,red,light_red,object1.addOneV,black,"extraSmall",True)
addTime = Button("Time: %i " % object1.t + "s",50, 75,150,50,red,light_red,object1.addOneT,black,"extraSmall",True)
fireCannon = Button("Fire",display_width/2 - 75,25,125,75,red,light_red,object1.calculatePos,black,"smallFont",True)
for evt in pygame.event.get():
fireCannon.handle_event(evt)
addVelocity.handle_event(evt)
addTime.handle_event(evt)
reset.handle_event(evt)
if evt.type == pygame.QUIT:
pygame.quit()
quit()
display.blit(sky,[0,0])
display.blit(cannon,[25,300])
fireCannon.drawButton(display)
addVelocity.drawButton(display)
addTime.drawButton(display)
reset.drawButton(display)
display.blit(cannonball,[object1.obj_x,object1.obj_y])
display.blit(cannonball,[object1.obj_x,object1.obj_y])
pygame.display.update()
programLoop()
谢谢!任何帮助将不胜感激。
您需要将对象的速度添加到其在每一帧中的位置才能移动它。我还将增量时间传递给update
方法,并将其与速度相乘,以使对象每秒移动self.v
像素。
import pygame
pygame.init()
display_width = 700
display_height = 500
display = pygame.display.set_mode((display_width,display_height))
CANNONBALL = pygame.Surface((30, 30))
CANNONBALL.fill((90, 90, 90))
LIGHT_BLUE = (140,220,255)
BLACK = (0,0,0)
RED = (200,0,0)
LIGHT_RED = (255,0,0)
SMALLFONT = pygame.font.SysFont("comicsansms", 25)
def text_objects(text, color, font): # You can pass the font object.
textSurface = font.render(text, True, color)
return textSurface, textSurface.get_rect()
class Button:
def __init__(self, text, x, y, width, height, inactive_color, active_color,
action, text_color, font, active):
self.text = text
# Create a rect instead of the separate x, y, w, h attributes.
self.rect = pygame.Rect(x, y, width, height)
self.inactive_color = inactive_color
self.active_color = active_color
self.action = action
self.text_color = text_color
self.font = font # The font is an attribute now.
self.active = active
def handle_event(self, event):
if self.is_hovered() and event.type == pygame.MOUSEBUTTONDOWN:
self.action()
def text_to_button(self, surface):
textSurf, textRect = text_objects(self.text, self.text_color, self.font)
textRect.center = self.rect.center
surface.blit(textSurf, textRect)
def is_hovered(self):
return self.rect.collidepoint(pygame.mouse.get_pos())
def drawButton(self, surface):
if self.active:
pygame.draw.rect(surface, self.inactive_color, self.rect)
if self.is_hovered() and self.active:
pygame.draw.rect(surface, self.active_color, self.rect)
self.text_to_button(surface)
class Kinematic:
def __init__(self, v):
self.obj_x = 110
self.obj_y = 240
self.v = v
self.started = False
def reset(self):
self.started = False
self.v = 0
self.obj_x = 125
self.obj_y = 240
def start(self):
self.started = True
def update(self, dt):
if self.started:
# Just add the velocity to the position to
# move the object.
# Multiply the velocity by the delta time
# to move `self.v` pixels per second.
self.obj_x += self.v * dt
def programLoop():
clock = pygame.time.Clock()
object1 = Kinematic(0)
# Callback functions to modify the object and update the button texts.
def add_v():
object1.v += 10
addVelocity.text = f"Velocity: {object1.v} m/s"
def reset():
object1.reset()
addVelocity.text = f"Velocity: {object1.v} m/s"
reset = Button(
"Reset", 400, 25, 100, 75, RED, LIGHT_RED,
reset, BLACK, SMALLFONT, True)
addVelocity = Button(
f"Velocity: {object1.v} m/s", 50, 25, 150, 50,
RED, LIGHT_RED, add_v, BLACK, SMALLFONT, True)
fireCannon = Button(
"Fire", display_width/2 - 75, 25, 125, 75, RED, LIGHT_RED,
object1.start, BLACK, SMALLFONT, True)
# You can put all buttons into a list and use for loops to
# draw them and pass the events.
buttons = [reset, addVelocity, fireCannon]
dt = 0
programExit = False
while not programExit:
for evt in pygame.event.get():
for button in buttons:
button.handle_event(evt)
if evt.type == pygame.QUIT:
return
# Call the `update` method once per frame.
object1.update(dt) # Pass the delta time to the object.
display.fill(LIGHT_BLUE)
for button in buttons:
button.drawButton(display)
display.blit(CANNONBALL, [object1.obj_x, object1.obj_y])
pygame.display.update()
# dt is the time that has passed since the last clock.tick call.
dt = clock.tick(60) / 1000
programLoop()
pygame.quit()
我还尝试改进和简化更多的事情。看看评论。