PyGame 矢量单独重力功能不起作用。

huangapple go评论68阅读模式
英文:

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)

PyGame 矢量单独重力功能不起作用。
PyGame 矢量单独重力功能不起作用。

答案1

得分: 0

我建议简化代码并使用pygame.math.Vector2来进行计算。非常方便的是scale_to_length方法,它可以将向量缩放到特定长度。当然,你也可以自行进行数学计算,但我强烈建议引入帮助函数,比如normalizescale_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()

huangapple
  • 本文由 发表于 2023年2月7日 03:01:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75365514.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定