【问题标题】:How create a simulation (pendulum, projectile motion) in pygame如何在 pygame 中创建模拟(钟摆、抛射运动)
【发布时间】:2019-12-02 21:46:09
【问题描述】:

我创建了一个程序,它可以生成摆的位置、长度、球的位置、速度、角度和轨迹。该程序的任务是找到一个解决方案,让球可以安全地穿过“洞穴”。摆锤位于 85.75 x 66.75 区域内,长度

我想在 pygame 中创建一个模拟实验,它将运行我的第一个程序以生成所有参数,然后显示解决方案和球将遵循的路径。过去几天我一直在学习 pygame,但不知道如何“转移”我的第一个程序。我查看了其他钟摆模拟器,并试图将其更改为适合我的实验,但我迷路了,决定来 StackOverflow 寻求建议。如果有人能告诉我我在进行模拟时出错的地方,将不胜感激。

第一个程序

import math as m
import numpy as np

# Variables
c = 28.5
Wx = 20
Wy = 30
d = 85.75
f = 66.75
g = 385.826772
ay = -g

# Calculations
for theta in np.arange(1, 90, .01):
    l = Wx + (m.tan(m.radians(theta)) * (f - Wy))
    if Wx <= l <= d:
        phi = 90 - theta
        v = (d - l) / m.sin(m.radians(phi))
        vc = v - 1.25
        if (f - Wy) <= v <= 65:
            h = f - (m.cos(m.radians(phi)) * v)
            a = v * m.sin(m.radians(theta))
            b = v * m.cos(m.radians(theta))
            by = f - b
            bx = l - a
            if h <= f and by <= c:
                vel = m.sqrt((2 * g) * (h - by)) * .95
                velx = vel * m.cos(m.radians(theta))
                vely = vel * m.sin(m.radians(theta))
                y = (-vely**2) / (2 * ay)
                Ymax = y + by
                if m.isclose(Ymax, c, abs_tol= .01):
                    t1 = -vely / ay
                    t2 = m.sqrt((2 * Ymax) / -ay)
                    T = t1 + t2
                    x = velx * T
                    print(' l: {0} v: {1}  vc: {2} h: {3}\n bx: {4} by: {5}\n vel: {6} velx: {7} vely: {8}\n y: {9} Ymax: {10} x: {11} T: {12}\n theta: {13} phi: {14}\n'
                          .format(l, v, vc, h, bx, by, vel, velx, vely, y, Ymax, x, T, theta, phi))

模拟器

import pygame
import numpy as np
import math as m
from math import pi

# Tarzan Variables
c = 28.5
Wy = 30
Wx = 20
d = 85.75
f = 66.75

# Colors
black = (0, 0, 0)
red = (255, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)

# Pygame Variables
theta = 0
v = 0
vel = 0
acc = 0

# Start Pygame
width, height = 900, 700
pygame.init()
background = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()


# Tarzan
class Pendulum(object):
    def __init__(self, XY, l, radius):
        self.x = XY[0]
        self.y = XY[1]
        self.l = l
        self.radius = radius

    def draw(self, bg):
        pygame.draw.line(bg, white, (self.l, 0), (self.x, self.y), 4)
        pygame.draw.circle(bg, red, (self.x, self.y), self.radius)
        pygame.draw.line(bg, green, (Wx, height), (Wx, (height - Wy)), 4)
        # pygame.draw.circle(bg, white, (self.l, 0), int(v)) --- to see if pendulum is following an arc


def theta_v():
    v = m.sqrt(m.pow(pendulum.x - (width / 2), 2) + m.pow(pendulum.y, 2))
    theta = m.asin(((pendulum.x - (width / 2)) / v))
    return theta, v


def get_path(theta, v):
    pendulum.x = round(pendulum.l + (v * m.sin(theta)))
    pendulum.y = round(v * m.cos(theta))
    pendulum.l = pendulum.x - (v * m.sin(m.radians(theta)))


def redraw():
    background.fill(black)
    pendulum.draw(background)
    pygame.display.update()


pendulum = Pendulum((75, 67), 500, 15)
# Close Pygame
stop = False
acceleration = False
while not stop:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            stop = True
        if event.type == pygame.MOUSEBUTTONDOWN:
            pendulum = Pendulum(pygame.mouse.get_pos(), 500, 15)
            theta, v = theta_v()
            acceleration = True

    if acceleration:
        acc = -.005 * m.sin(theta)
        vel += acc
        vel *= .995
        theta += vel
        get_path(theta, v)
        print(pendulum.x, pendulum.y, (theta * (180 / pi)), v, vel, pendulum.l)
    redraw()
pygame.quit()
quit()

【问题讨论】:

  • 请定义您所说的“转移”是什么意思?转成什么形式?您的意思是将“第一个程序”代码合并到“模拟器”代码中吗?
  • Kinglsey,你是对的,当我说“转移”时,我的意思是在模拟器代码中实现“第一个程序”。我想使用结果来创建实验模拟。

标签: python pygame physics simulator


【解决方案1】:

我想你想让这个程序创建一个悬挂的钟摆正确摆动。您的代码有一些问题:

  1. 为了计算 pendulum.l 值,您首先将 theta 转换为弧度。由于您的 theta 值已经是弧度,这绝对不是必要的,并且使您的 pendulum.l 值几乎没有变化。
  2. 现在执行代码时,您可能会看到钟摆的附着点正在发生变化。这是因为您正在更改 pendulum.l,并同时使用它来绘制钟摆。这可以通过保存您的第一个 pendulum.l 值来轻松解决,并使用该值来绘制钟摆。
  3. 您的程序不断尝试永远移动钟摆,有时会产生意想不到的结果。您应该添加一些方法来确定钟摆是否仍在移动(可能是通过确定其中一个变量是否没有足够的变化 - 我没有足够的时间来弄清楚)
  4. 如果最后舍入错误,则舍入 x 和 y 值会导致累积,从而使钟摆在仍然稍微倾斜的同时停止。您可以在绘制钟摆时进行四舍五入来解决此问题。
整个代码应如下所示:

import time
import pygame
import numpy as np
import math as m
from math import pi

# Tarzan Variables
c = 28.5
Wy = 30
Wx = 20
d = 85.75
f = 66.75

# Colors
black = (0, 0, 0)
red = (255, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)

# Pygame Variables
theta = 0
v = 0
vel = 0
acc = 0

# Start Pygame
width, height = 900, 700
pygame.init()
background = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()


# Tarzan
class Pendulum(object):
    def __init__(self, XY, l, radius):
        self.x = XY[0]
        self.y = XY[1]
        self.l = l
        self.lfixed = l
        self.radius = radius

    def draw(self, bg):
        pygame.draw.line(bg, white, (self.lfixed, 0), (self.x, self.y), 4)
        pygame.draw.circle(bg, red, (round(self.x), round(self.y)), self.radius)
        pygame.draw.line(bg, green, (Wx, height), (Wx, (height - Wy)), 4)
        # pygame.draw.circle(bg, white, (self.l, 0), int(v)) --- to see if pendulum is following an arc


def theta_v():
    v = m.sqrt(m.pow(pendulum.x - (width / 2), 2) + m.pow(pendulum.y, 2))
    theta = m.asin(((pendulum.x - (width / 2)) / v))
    return theta, v


def get_path(theta, v):
    pendulum.x = pendulum.l + (v * m.sin(theta))
    pendulum.y = v * m.cos(theta)
    pendulum.l = pendulum.x - (v * m.sin((theta)))


def redraw():
    background.fill(black)
    pendulum.draw(background)
    pygame.display.update()


pendulum = Pendulum((75, 67), 500, 15)
# Close Pygame
stop = False
acceleration = False
while not stop:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            stop = True
        if event.type == pygame.MOUSEBUTTONDOWN:
            pendulum = Pendulum(pygame.mouse.get_pos(), 500, 15)
            theta, v = theta_v()
            acceleration = True

    if acceleration:
        acc = -.005 * m.sin(theta)
        vel += acc
        vel *= .995
        theta += vel
        get_path(theta, v)
        print(pendulum.x, pendulum.y, (theta * (180 / pi)), v, vel, pendulum.l)
    redraw()
    time.sleep(0.1)
pygame.quit()
quit()

【讨论】:

    猜你喜欢
    • 2015-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多