英文:
PyGame Vector Only Gravity Function not Working
问题
在PyGame中创建仅使用向量的游戏(移动和位置使用向量),并尝试创建以行星为中心的引力时,引力的拉力是不一致的。以下是引力函数的代码:
import math
import pygame
import time
class movementObj:
def __init__(self, posX = 0.0, posY = 0.0, currentVelocity = [0,0], maxVelocity = 20.0):
self.x = posX
self.y = posY
self.vel = currentVelocity
self.maxVel = maxVelocity
def gravity(self, pos, val):
pos = self.__subVec(pos,[self.x,self.y])
currentSpeed = math.sqrt(math.pow(pos[0]-self.x,2)+math.pow(pos[1]-self.y,2))
change = val / currentSpeed
pos = self.__mulVec(pos,change)
self.accelerate(pos)
return pos
整个代码如下:
import math
import pygame
import time
# ... (其他代码未提供翻译)
def gameloop():
counter = 0
while True:
# ... (其他代码未提供翻译)
gline = obj.gravity([200,200],0.1)
# print(gline, end="\r")
# obj.resistance(0.015)
# ... (其他代码未提供翻译)
运行时,目标是在平面上的任何位置向中心具有一致的加速度,但实际上是不一致的。有什么想法是为什么会出现这种情况吗?
英文:
When creating a vector only game in PyGame (movement and location use vectors) and attempting to make a planetary style centered gravity, the gravitation pull is inconsistent. Here is the code for the gravity function:
import math
import pygame
import time
class movementObj:
def __init__(self, posX = 0.0, posY = 0.0, currentVelocity = [0,0], maxVelocity = 20.0):
self.x = posX
self.y = posY
self.vel = currentVelocity
self.maxVel = maxVelocity
def gravity(self, pos, val):
pos = self.__subVec(pos,[self.x,self.y])
currentSpeed = math.sqrt(math.pow(pos[0]-self.x,2)+math.pow(pos[1]-self.y,2))
change = val / currentSpeed
pos = self.__mulVec(pos,change)
self.accelerate(pos)
return pos
Here is the whole code:
import math
import pygame
import time
class movementObj:
def __init__(self, posX = 0.0, posY = 0.0, currentVelocity = [0,0], maxVelocity = 20.0):
self.x = posX
self.y = posY
self.vel = currentVelocity
self.maxVel = maxVelocity
def __addVec(self, vectorOne, vectorTwo):
returnVec = [(vectorOne[i] + vectorTwo[i]) for i in range(len(vectorOne))]
return returnVec
def __mulVec(self,vectorOne,mulValue):
returnVec = [(i*mulValue) for i in vectorOne]
return returnVec
def resistance(self,val):
self.vel = self.__mulVec(self.vel,1-val)
def gravity(self, pos, val):
# pos = self.__subVec(pos,[self.x,self.y])
# spd = math.sqrt(math.pow(pos[0]-self.x,2)+math.pow(pos[1]-self.y,2))
# over = spd-val
# overPercent = 1-(over/spd)
# pos = self.__mulVec(pos,overPercent)
# # print(pos,end="\r")
# self.accelerate(pos)
# return overPercent
pos = self.__subVec(pos,[self.x,self.y])
currentSpeed = math.sqrt(math.pow(pos[0]-self.x,2)+math.pow(pos[1]-self.y,2))
change = val / currentSpeed
pos = self.__mulVec(pos,change)
self.accelerate(pos)
return pos
def __getSpeed(self):
return math.sqrt(math.pow(self.vel[0],2)+math.pow(self.vel[1],2))
def __subVec(self, vectorOne, vectorTwo):
returnVec = [(vectorOne[i] - vectorTwo[i]) for i in range(len(vectorOne))]
return returnVec
def updatePos(self):
self.x += self.vel[0]
self.y += self.vel[1]
self.normalizeVelocity()
# print(str(self.vel[0]-self.x) + "," + str(self.vel[1]-self.y), end="\r")
def accelerate(self, acc):
self.vel = self.__addVec(self.vel,acc)
def normalizeVelocity(self):
currentSpeed = self.__getSpeed()
if self.x > 400:
self.x = self.x-400
self.y = 400-self.y
if self.x < 0:
self.y = 400-self.y
self.x = self.x+400
if self.y > 400:
self.x = 400-self.x
self.y = self.y-400
if self.y < 0:
self.x = 400-self.x
self.y = self.y+400
if currentSpeed < self.maxVel:
return
over = currentSpeed-self.maxVel
overPercent = 1-(over/currentSpeed)
self.vel = self.__mulVec(self.vel,overPercent)
def start(self):
print(self.__getSpeed())
size = 400
obj = movementObj()
pygame.init()
screen = pygame.display.set_mode([size, size])
def gameloop():
counter = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
keys=pygame.key.get_pressed()
if keys[pygame.K_DOWN]:
obj.accelerate([0,0.2])
if keys[pygame.K_UP]:
obj.accelerate([0,-0.2])
if keys[pygame.K_LEFT]:
obj.accelerate([-0.2,0])
if keys[pygame.K_RIGHT]:
obj.accelerate([0.2,0])
gline = obj.gravity([200,200],0.1)
# print(gline, end="\r")
# obj.resistance(0.015)
screen.fill((255, 255, 255))
pygame.draw.line(screen, (0,0,255), (obj.x,obj.y), (obj.x+(1000*gline[0]),obj.y+(1000*gline[1])), 2)
pygame.draw.line(screen, (0,255,0), (obj.x,obj.y), (obj.x+(10*obj.vel[0]),obj.y+(10*obj.vel[1])), 2)
pygame.draw.circle(screen, (0, 0, 0), (obj.x,obj.y), 1)
pygame.draw.circle(screen, (0, 0, 0), (200,200), 1)
pygame.display.flip()
obj.updatePos()
# obj.accelerate([0.08,-0.08])
time.sleep(50/1000)
counter += 1
import sys
gameloop()
sys.stdout.close()
pygame.quit()
When running it, the goal is to have consistent acceleration towards the center from any location on the plane, but instead it is inconsistent. Any ideas why?
(photos of the problem: green is the velocity, blue is acceleration)
答案1
得分: 0
我建议简化代码并使用pygame.math.Vector2
来进行计算。非常方便的是scale_to_length
方法,它可以将向量缩放到特定长度。当然,你也可以自行进行数学计算,但我强烈建议引入帮助函数,比如normalize
和scale_to_length
。
import pygame
import sys
class MovementObj:
def __init__(self, posX=0.0, posY=0.0, currentVelocity=[0, 0], maxVelocity=5.0):
self.pos = pygame.math.Vector2(posX, posY)
self.vel = pygame.math.Vector2(currentVelocity)
self.maxVel = maxVelocity
def gravity(self, target, accVal):
acc = pygame.math.Vector2(target) - self.pos
if acc.length() > 0:
acc.scale_to_length(accVal)
self.accelerate(acc)
return acc
def updatePos(self):
self.pos += self.vel
def accelerate(self, acc):
self.vel += acc
if self.vel.length() > self.maxVel:
self.vel.scale_to_length(self.maxVel)
size = 400
pygame.init()
screen = pygame.display.set_mode([size, size])
def gameloop():
obj = MovementObj()
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
keys = pygame.key.get_pressed()
ax = (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * 0.2
ay = (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * 0.2
obj.accelerate([ax, ay])
gline = obj.gravity([200, 200], 0.1)
obj.updatePos()
screen.fill((255, 255, 255))
pygame.draw.circle(screen, (0, 0, 0), obj.pos, 5)
pygame.draw.circle(screen, (0, 0, 0), (200, 200), 5)
pygame.draw.line(screen, (0, 0, 255), obj.pos, obj.pos + gline * 200, 2)
pygame.draw.line(screen, (255, 0, 0), obj.pos, obj.pos + obj.vel * 5, 2)
pygame.display.flip()
clock.tick(20)
gameloop()
sys.stdout.close()
pygame.quit()
英文:
I suggest to simplify the code and to use pygame.math.Vector2
for the calculations. Very handy is the scale_to_length
method, which scales the vector to a certain length. This function can also be used to limit the length of a vector. Of course you can do the math your own, however I strongly suggest to introduce helper functions like normalize
and scale_to_lenght
.
import pygame
import sys
class MovementObj:
def __init__(self, posX = 0.0, posY = 0.0, currentVelocity = [0,0], maxVelocity = 5.0):
self.pos = pygame.math.Vector2(posX, posY)
self.vel = pygame.math.Vector2(currentVelocity)
self.maxVel = maxVelocity
def gravity(self, target, accVal):
acc = pygame.math.Vector2(target) - self.pos
if acc.length() > 0:
acc.scale_to_length(accVal)
self.accelerate(acc)
return acc
def updatePos(self):
self.pos += self.vel
def accelerate(self, acc):
self.vel += acc
if self.vel.length() > self.maxVel:
self.vel.scale_to_length(self.maxVel)
size = 400
pygame.init()
screen = pygame.display.set_mode([size, size])
def gameloop():
obj = MovementObj()
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
keys=pygame.key.get_pressed()
ax = (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * 0.2
ay = (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * 0.2
obj.accelerate([ax, ay])
gline = obj.gravity([200,200], 0.1)
obj.updatePos()
screen.fill((255, 255, 255))
pygame.draw.circle(screen, (0, 0, 0), obj.pos, 5)
pygame.draw.circle(screen, (0, 0, 0), (200, 200), 5)
pygame.draw.line(screen, (0, 0, 255), obj.pos, obj.pos + gline * 200, 2)
pygame.draw.line(screen, (255, 0, 0), obj.pos, obj.pos + obj.vel * 5, 2)
pygame.display.flip()
clock.tick(20)
gameloop()
sys.stdout.close()
pygame.quit()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论