Swift 如何创建圆形物体进入并与厚物质分离的效果
基于下面的图像(我使用不同的颜色来表示圆形和平面,这样可以看到它们,但最终颜色将是相同的),使用Swift和Spritekit,我尝试创建圆形物体进入厚物质(不一定是粘性的)并与厚物质分离的效果。基本上,当圆形物体分离时,当它形成一个圆时,它会从平面上拉开。 我想使用图像动画帧,但由于对象是带有物理体的SKSpriteNodes,这将使对象与动画的碰撞计时变得非常困难。另一种方法是使用CAAnimation,但我不知道如何将其与物理体的SKSpriteNodes结合起来。我如何使用上述任何一种方法或其他方法创建这种分离效果 更新 下图显示了圆形物体进入厚物质直至被淹没时,厚物质表面的变化Swift 如何创建圆形物体进入并与厚物质分离的效果,swift,sprite-kit,cadisplaylink,Swift,Sprite Kit,Cadisplaylink,基于下面的图像(我使用不同的颜色来表示圆形和平面,这样可以看到它们,但最终颜色将是相同的),使用Swift和Spritekit,我尝试创建圆形物体进入厚物质(不一定是粘性的)并与厚物质分离的效果。基本上,当圆形物体分离时,当它形成一个圆时,它会从平面上拉开。 我想使用图像动画帧,但由于对象是带有物理体的SKSpriteNodes,这将使对象与动画的碰撞计时变得非常困难。另一种方法是使用CAAnimation,但我不知道如何将其与物理体的SKSpriteNodes结合起来。我如何使用上述任何一种方
从较高的理解水平来看,有两种方法可以做到这一点
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, 0, 0);
CGPathAddQuadCurveToPoint(path, NULL, 50, 100, 100, 0);
CGPathAddLineToPoint(path, NULL, 50, -100);
CGPathCloseSubpath(path);
SKShapeNode *shape = [[SKShapeNode alloc]init];
shape.path = path;
Ball Vector (Vb)
^
|
(V) O---> Closest Fluid Surface Vector (Vs)
V = Vb x Vs
然后看V的Z分量,称为Vz。
如果(Vz<0),则钢球位于流体外部:
创建一个变量t:
t = distOfBall/radiusOfBall
然后对流体形状中的每个有序点执行以下操作:
newFluidPointX = F1pointX*(t-1) + F2pointX*t
newFluidPointY = F1pointY*(t-1) + F2pointY*t
如果Vz>0),则球位于流体内部:
t = -(((distOfBall/radiusOfBall) + 0.5)^2) *4 + 1
newFluidPointX = F2pointX*(t-1) + F3pointX*t
newFluidPointY = F2pointY*(t-1) + F3pointY*t
这是因为可以使用插值将任意两个形状混合在一起。
参数“t”用作两个形状之间混合的百分比
只要点数相同,实际上可以在任意两个形状之间创建无缝混合。这就是好莱坞电影中一个男人如何变成狼,或者一个男人如何变成一个液体水坑。这些效果的唯一原理是插值。插值是一个非常强大的工具。其定义如下:
L = A*(t-1) + B*t
where t is in between 0.0 and 1.0
and A and B is what you are morphing from and to.
有关插值的详细信息,请参见:
供进一步研究。如果你正在考虑动画任何动态形状,我会考虑理解贝塞尔曲线。Pomax有一篇关于这个主题的精彩文章。尽管许多框架中都有曲线,但对它们的工作原理有一个大致的了解将允许您对它们进行扩展性操作,或者在缺少框架的地方滚动您自己的特性。她的文章是Pomax的:
祝您进步顺利:)您正在寻找流体模拟器
这在现代硬件中确实是可能的。
让我们看看我们将在这里建造什么
组件
为了实现这一目标,我们需要
- 创建几个具有物理体和模糊图像的分子
- 使用着色器将公共颜色应用于alpha>0的每个像素
import SpriteKit
class Molecule: SKSpriteNode {
init() {
let texture = SKTexture(imageNamed: "molecule")
super.init(texture: texture, color: .clear, size: texture.size())
let physicsBody = SKPhysicsBody(circleOfRadius: 8)
physicsBody.restitution = 0.2
physicsBody.affectedByGravity = true
physicsBody.friction = 0
physicsBody.linearDamping = 0.01
physicsBody.angularDamping = 0.01
physicsBody.density = 0.13
self.physicsBody = physicsBody
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
着色器
接下来我们需要一个片段着色器,让我们创建一个名为Water.fsh
void main() {
vec4 current_color = texture2D(u_texture, v_tex_coord);
if (current_color.a > 0) {
current_color.r = 0.0;
current_color.g = 0.57;
current_color.b = 0.95;
current_color.a = 1.0;
} else {
current_color.a = 0.0;
}
gl_FragColor = current_color;
}
场景
最后我们可以定义场景
import SpriteKit
class GameScene: SKScene {
lazy var label: SKLabelNode = {
return childNode(withName: "label") as! SKLabelNode
}()
let effectNode = SKEffectNode()
override func didMove(to view: SKView) {
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
effectNode.shouldEnableEffects = true
effectNode.shader = SKShader(fileNamed: "Water")
addChild(effectNode)
}
var touchLocation: CGPoint?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let touchLocation = touch.location(in: self)
if label.contains(touchLocation) {
addRedCircle(location: touchLocation)
} else {
self.touchLocation = touchLocation
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touchLocation = nil
}
override func update(_ currentTime: TimeInterval) {
if let touchLocation = touchLocation {
let randomizeX = CGFloat(arc4random_uniform(20)) - 10
let randomizedLocation = CGPoint(x: touchLocation.x + randomizeX, y: touchLocation.y)
addMolecule(location: randomizedLocation)
}
}
private func addMolecule(location: CGPoint) {
let molecule = Molecule()
molecule.position = location
effectNode.addChild(molecule)
}
private func addRedCircle(location: CGPoint) {
let texture = SKTexture(imageNamed: "circle")
let sprite = SKSpriteNode(texture: texture)
let physicsBody = SKPhysicsBody(circleOfRadius: texture.size().width / 2)
physicsBody.restitution = 0.2
physicsBody.affectedByGravity = true
physicsBody.friction = 0.1
physicsBody.linearDamping = 0.1
physicsBody.angularDamping = 0.1
physicsBody.density = 1
sprite.physicsBody = physicsBody
sprite.position = location
addChild(sprite)
}
}
导入SpriteKit
类游戏场景:SKScene{
惰性变量标签:SKLabelNode={
将子节点(名称为“label”)返回为!SKLabelNode
}()
让effectNode=SKEffectNode()
覆盖func didMove(到视图:SKView){
physicsBody=SKPhysicsBody(edgeLoopFrom:frame)
effectNode.shouldEnableEffects=true
effectNode.shader=SKShader(文件名为:“水”)
addChild(效应节点)
}
var接触位置:CGPoint?
覆盖func TouchesBegind(Touchs:Set,带有事件:UIEvent?){
guard let touch=touch.first else{return}
让touchLocation=touch.location(in:self)
if label.contains(触摸位置){
addRedCircle(位置:touchLocation)
}否则{
self.touchLocation=touchLocation
}
}
覆盖函数touchesend(touchs:Set,带有事件:UIEvent?){
触摸位置=零
}
覆盖函数更新(uCurrentTime:TimeInterval){
如果让touchLocation=touchLocation{
设randomizeX=CGFloat(arc4random_均匀(20))-10
设randomizedLocation=CGPoint(x:touchLocation.x+randomizeX,y:touchLocation.y)
添加分子(位置:随机化位置)
}
}
专用func addMolecule(位置:CGPoint){
让分子=分子()
位置=位置
effectNode.addChild(分子)
}
专用func addRedCircle(位置:CGPoint){
let texture=SKTexture(图像名为:“圆”)
设sprite=SKSpriteNode(纹理:纹理)
让physicsBody=SKPhysicsBody