我正在尝试使用 Apple 的 SpriteKit 游戏引擎创建游戏。
在游戏中实现一些基于物理的计算时,我注意到计算结果与实际发生在对象上的结果不同。
示例:通过射弹运动的方程计算身体的轨迹会导致身体实际上比计算的更快/更快地下降。
在计算与重力相关的东西时,如何使物理引擎与现实世界的物理定律相匹配?
我正在尝试使用 Apple 的 SpriteKit 游戏引擎创建游戏。
在游戏中实现一些基于物理的计算时,我注意到计算结果与实际发生在对象上的结果不同。
示例:通过射弹运动的方程计算身体的轨迹会导致身体实际上比计算的更快/更快地下降。
在计算与重力相关的东西时,如何使物理引擎与现实世界的物理定律相匹配?
I think I know what's going on with the sample code you have supplied on GitHub, which I'll reproduce here as questions on SO should contain the code:
//
// GameScene.swift
// SpriteKitGravitySample
//
// Created by Emilio Schepis on 17/01/2020.
// Copyright © 2020 Emilio Schepis. All rights reserved.
//
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private var subject: SKNode!
override func didMove(to view: SKView) {
super.didMove(to: view)
// World setup (no friction, default gravity)
// Note that this would work with any gravity set to the scene.
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
physicsBody?.friction = 0
subject = SKShapeNode(circleOfRadius: 10)
subject.position = CGPoint(x: frame.midX, y: 30)
subject.physicsBody = SKPhysicsBody(circleOfRadius: 10)
subject.physicsBody?.allowsRotation = false
// Free falling body (no damping)
subject.physicsBody?.linearDamping = 0
subject.physicsBody?.angularDamping = 0
addChild(subject)
// Set an arbitrary velocity to the body
subject.physicsBody?.velocity = CGVector(dx: 30, dy: 700)
// Inaccurate prediction of position over time
for time in stride(from: CGFloat(0), to: 1, by: 0.01) {
let inaccuratePosition = SKShapeNode(circleOfRadius: 2)
inaccuratePosition.strokeColor = .red
// These lines use the projectile motion equations as-is.
// https://en.wikipedia.org/wiki/Projectile_motion#Displacement
let v = subject.physicsBody?.velocity ?? .zero
let x = v.dx * time
let y = v.dy * time + 0.5 * physicsWorld.gravity.dy * pow(time, 2)
inaccuratePosition.position = CGPoint(x: x + subject.position.x,
y: y + subject.position.y)
addChild(inaccuratePosition)
}
// Actual prediction of position over time
for time in stride(from: CGFloat(0), to: 1, by: 0.01) {
let accuratePosition = SKShapeNode(circleOfRadius: 2)
accuratePosition.strokeColor = .green
// These lines use the projectile motion equations
// as if the gravity was 150 times stronger.
// The subject follows this curve perfectly.
let v = subject.physicsBody?.velocity ?? .zero
let x = v.dx * time
let y = v.dy * time + 0.5 * physicsWorld.gravity.dy * 150 * pow(time, 2)
accuratePosition.position = CGPoint(x: x + subject.position.x,
y: y + subject.position.y)
addChild(accuratePosition)
}
}
}
What you've done is to:
subject
with a physicsBody and placed it
on screen with a initial velocity.inaccuratePosition
node, using Newton's laws of
motion (v = ut + 1/2at²)accuratePosition
node, using Newton's laws of
motionAll this is is didMoveTo
. When the simulation runs, the path of the node subject
follows the accuratePosition
path accurately.
I think what's happening is that you are calculating the predicted position using subject's physicsBody's velocity
, which is in m/s, but the position is in points, so what you should do is convert m/s into point/s first.
So what's the scale factor? Well from Apple's documentation here; it's.... 150 which is too much of a coincidence , so I think that's the problem.
Bear in mind that you set the vertical velocity of your object to 700m/s - that's 1500mph or 105000 SK point/s. You'd expect it to simply disappear out through the top of the screen at high speed, as predicted by your red path. The screen is somewhere between 1,000 and 2,000 points.
编辑- 我创建了一个示例项目来演示使用和不使用乘数的计算路径。
https://github.com/emilioschepis/spritekit-gravity-sample
TL;DR - 在 SpriteKit 中计算与重力相关的东西时,将场景的重力乘以151以获得准确的结果。
在尝试解决这个问题时,我首先开始阅读与重力相关的 SpriteKit 文档:
https://developer.apple.com/documentation/spritekit/skphysicsworld/1449623-gravity
文档说:
此属性的组成部分以米/秒为单位。默认值为(0.0,-9.8),代表地球的重力。
然而,重力是在 中计算的,m/s^2
而不是在 中计算的m/s
。
认为这是在 SpriteKit 中实现重力的错误,我开始认为基于现实世界的物理定律可能无法应用于场景中。
然而,我确实遇到了另一个关于线性重力场的文档页面,该页面正确地报告了m/s^2
在 SpriteKit 中测量重力。
https://developer.apple.com/documentation/spritekit/skfieldnode/1520145-lineargravityfield
然后我设置了一个简单的自由落体场景,将初始速度应用于物理物体,然后计算预期轨迹,同时将其与实际轨迹进行比较。
x 轴的计算从一开始就是准确的,这表明唯一的问题是重力值。
然后我尝试手动修改场景中的重力,直到实际轨迹与预测的轨迹相匹配。
我发现在游戏中使用物理世界的重力属性时,必须考虑到~151的“魔法”值。
例如,修改轨迹的 y 轴计算
let dy = velocity.dy * time + 0.5 * gravity * pow(time, 2)
至
let dy = velocity.dy * time + 0.5 * 151 * gravity * pow(time, 2)
导致了准确的计算。
我希望这对将来可能遇到同样问题的人有用。