游戏中的各种力

  1. 力对物体产生作用有个前期条件那就是物体必须有物理身体(SCNPhysicsBody)
  2. 一个物体可能受到很多力的作用
  3. 如果力加到静态身体和运动身体上会产生什么影响?你应该自己去尝试。
  4. 力都能对那些类型的物体产生影响呢?怎么模拟龙卷风呢?
  5. 如何让所有物体失重呢?

你在学习一个东西的时候,应该想出很多问题,这样我们才能带着疑问探索,你会觉得很好玩。我们现在就去玩玩.

SCNPhysicsField

提示:这个类几乎包含了物理世界存在的各种力,我们要掌握它的属性的含义

控制力的强度(默认为1.0)

@property(nonatomic) CGFloat strength;

决定力的衰减指数(默认为0)

//  如果值不为0,力的计算公式是 (1 / distance ^ falloffExponent)
@property(nonatomic) CGFloat falloffExponent;

设置距离力中心点的最小不衰减距离,在这个范围内力不衰减(默认值为1e-6)

@property(nonatomic) CGFloat minimumDistance;

设置力的激活状态(默认为YES)

@property(nonatomic, getter=isActive) BOOL active;

阻止任何在它作用范围内的力(默认为NO)

@property(nonatomic, getter=isExclusive) BOOL exclusive;

决定力作用的范围

@property(nonatomic) SCNVector3 halfExtent;

决定作用的范围是个四方体还是一个球体(默认NO)

@property(nonatomic) BOOL usesEllipsoidalExtent;

决定力作用的范围是在指定的范围内,还是范围外

@property(nonatomic) SCNPhysicsFieldScope scope;

力的中心到影响范围的偏移

@property(nonatomic) SCNVector3 offset;

力的方向(默认为(0,-1,0))

// 注意它只对线性力有影响,比如重力
@property(nonatomic) SCNVector3 direction;

决定哪些节点可以被影响(高级用法,暂时不讲,当学习了碰撞检测之后,在悄悄告诉你)

@property(nonatomic) NSUInteger categoryBitMask NS_AVAILABLE(10_10, 8_0);

先提几个问题: 静态身体,动态身体,运动什么?那些可以添加速度?怎么添加速度? 拖拽力,能不能让静态的物体运动呢?

只有动态身体可以添加速度,静态身体和运动身体添加速度没有效果

// 创建拖拽力   
+ (SCNPhysicsField *)dragField;

我们给动态身体添加一个(0,0,-1000)的速度,然后给它添加一个30的拖拽力。

SCNNode *drayFieldNode = [SCNNode node];
drayFieldNode.physicsField = [SCNPhysicsField dragField];
drayFieldNode.physicsField.strength = 30;
drayFieldNode.physicsField.direction = SCNVector3Make(0, -1, 0);
[boxNode addChildNode:drayFieldNode];

拖拽力没有方向,只有大小,主要是阻碍物体的运动,如果真要说方向朝向哪里,就是和物体运动方向相反,如果物体没有速度,拖拽力不会对物体产生影响。

创建一个围绕轴旋转的力

+ (SCNPhysicsField *)vortexField;
- (void)addVortexField{
    SCNNode *vortexFieldNode = [SCNNode node];
    vortexFieldNode.physicsField = [SCNPhysicsField vortexField];
    vortexFieldNode.physicsField.strength = 1;
    vortexFieldNode.physicsField.direction = SCNVector3Make(-1, 0, 0);
    [self.scnView.scene.rootNode addChildNode:vortexFieldNode];
}

旋转力类似右手螺旋定则,设置的轴线方向为大拇指的指向的方向,手指环绕的方向才是力的方向。

创建朝向一个点的力

+ (SCNPhysicsField *)radialGravityField;
-(void)addRadialGravity{
    SCNNode *radialGravityNode = [SCNNode node];
    radialGravityNode.physicsField = [SCNPhysicsField radialGravityField];
    radialGravityNode.physicsField.strength = -1000;
    radialGravityNode.position = SCNVector3Make(0, 0, 0);
    [self.scnView.scene.rootNode   addChildNode:radialGravityNode];
}

可以设置位置,力朝向设置的位置。如果设置负值,力是朝向外边的。

线性力

+ (SCNPhysicsField *)linearGravityField;
-(void)addLineGravity{
    SCNNode *lineGravityNode = [SCNNode node];
    lineGravityNode.physicsField = [SCNPhysicsField linearGravityField];
    lineGravityNode.physicsField.strength = 1;
    lineGravityNode.physicsField.direction = SCNVector3Make(0, 0, -1);
    [self.scnView.scene.rootNode   addChildNode:lineGravityNode];
}

创建随机的力

//   smoothness 噪点的平滑性 animationSpeed运动的速度
+ (SCNPhysicsField *)noiseFieldWithSmoothness:(CGFloat)smoothness animationSpeed:(CGFloat)speed;
-(void)addNoiseField{
    SCNNode *noiseFieldNode = [SCNNode node];
    noiseFieldNode.physicsField = [SCNPhysicsField noiseFieldWithSmoothness:0 animationSpeed:1];
    noiseFieldNode.physicsField.strength = 5;
    [self.scnView.scene.rootNode addChildNode:noiseFieldNode];
}

你知道用在什么地方吗?比如你想营造下雪的效果 或者 萤火虫效果,可以使用这个力

一种和速度成正比的随机力

+ (SCNPhysicsField *)turbulenceFieldWithSmoothness:(CGFloat)smoothness animationSpeed:(CGFloat)speed;
-(void)addTurbulenceField{
    SCNNode *turbulenceFieldNode = [SCNNode node];
    turbulenceFieldNode.physicsField  = [SCNPhysicsField turbulenceFieldWithSmoothness:0 animationSpeed:1];
    turbulenceFieldNode.physicsField.strength = 5;
    [self.scnView.scene.rootNode addChildNode:turbulenceFieldNode];
}

弹性力(胡克定律)

+ (SCNPhysicsField *)springField;
SCNNode *springField = [SCNNode node];
springField.physicsField = [SCNPhysicsField springField];
springField.physicsField.strength = 0.01;
springField.position = SCNVector3Make(0, 30, 0);
[self.scnView.scene.rootNode addChildNode:springField];

创建这个力,需要设置力的位置和力的大小

创建电场

+ (SCNPhysicsField *)electricField;

提示:这种力的大小,取决于物体带的电荷的多少和距离磁场的距离 放向取决于电荷的正负。

-(void)addElectricField{
    SCNNode *electricFieldNode = [SCNNode node];
    electricFieldNode.physicsField = [SCNPhysicsField electricField];
    electricFieldNode.physicsField.strength = 10;
    [self.scnView.scene.rootNode addChildNode:electricFieldNode];
}

提示:

电场默认的属性是正的

如何创建带电荷的节点对象呢?给段代码自己看看,后面会专门讲解

SCNNode *boxNode = [SCNNode node];
boxNode.geometry = [SCNBox boxWithWidth:4 height:4 length:4 chamferRadius:0];
boxNode.geometry.firstMaterial.diffuse.contents = [UIColor redColor];
boxNode.physicsBody = [SCNPhysicsBody dynamicBody];
boxNode.position = SCNVector3Make(0, 30, 0);
boxNode.physicsBody.velocity = SCNVector3Make(0, 0, 0);
[self.scnView.scene.rootNode addChildNode:boxNode];
boxNode.physicsBody.charge = -10; // 创建电荷正负和大小

创建磁场

+ (SCNPhysicsField *)magneticField;
- (void)addMagneticField{
    SCNNode *magneticFielddNode = [SCNNode node];
    magneticFielddNode.physicsField = [SCNPhysicsField magneticField];
    magneticFielddNode.physicsField.strength = -0.5;
    [self.scnView.scene.rootNode addChildNode:magneticFielddNode];
}

吸引或者排斥物体,取决于电荷的大小,正负,速度,距离等因素

自定义力

typedef SCNVector3 (^SCNFieldForceEvaluator)(SCNVector3 position, SCNVector3 velocity, float mass, float charge, NSTimeInterval time);
import UIKit
import SceneKit

class Test17VC: UIViewController {

    var scnView:SCNView!
    var floorNode:SCNNode!

    override func viewDidLoad() {
        super.viewDidLoad()

        scnView = SCNView(frame: self.view.bounds)
        scnView.backgroundColor = UIColor.black
        scnView.scene = SCNScene()
        self.view.addSubview(scnView)

        let cameraNode = SCNNode()
        cameraNode.name = "cameraNode"
        cameraNode.camera = SCNCamera()
        cameraNode.position = SCNVector3Make(0, 30, 30)
        cameraNode.rotation = SCNVector4Make(1, 0, 0, Float(-Double.pi/6))
        scnView.scene?.rootNode.addChildNode(cameraNode)

        floorNode = SCNNode()
        floorNode.name = "floorNode"
        floorNode.geometry = SCNFloor()
        floorNode.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/1.jpg"
        floorNode.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(geometry: SCNFloor(), options: nil))
        scnView.scene?.rootNode.addChildNode(floorNode)

        let segment = UISegmentedControl(items: ["拖拽","围绕轴旋转","朝一个点的力","线性力","随机力","漂落","弹力","电场"])
        segment.frame = CGRect(x: 10, y: view.bounds.height - 44, width: view.bounds.width - 20, height: 34)
        segment.addTarget(self, action: #selector(displayChange), for: .valueChanged)
        segment.selectedSegmentIndex = 0
        view.addSubview(segment)
    }

    @objc func displayChange(sender:UISegmentedControl) {
        for node in (scnView.scene?.rootNode.childNodes)! {
            if node.name != "cameraNode" && node.name != "floorNode" {
                node.removeFromParentNode()
            }
        }
        navigationController?.title = sender.titleForSegment(at: sender.selectedSegmentIndex)
        switch sender.selectedSegmentIndex {
        case 0:
            addDragField()
        case 1:
            addVortexField()
        case 2:
            addRadialGravity()
        case 3:
            addLineBox()
        case 4:
            addNoiseField()
        case 5:
            addTurbulenceField()
        case 6:
            addSpringField()
        case 7:
            addElectricField()
        default:
            break
        }
    }

    //拖拽
    func addDragField() {
        let boxNode = createBox()

        scnView.scene?.rootNode.addChildNode(boxNode)

        let drayFieldNode = SCNNode()
        drayFieldNode.physicsField = SCNPhysicsField.drag()
        drayFieldNode.physicsField?.strength = 30
        drayFieldNode.physicsField?.direction = SCNVector3Make(0, -1000, 0)
        boxNode.addChildNode(drayFieldNode)
    }

    //围绕轴旋转
    func addVortexField() {
        let boxNode = createBox()

        scnView.scene?.rootNode.addChildNode(boxNode)

        let vortexFieldNode = SCNNode()
        vortexFieldNode.physicsField = SCNPhysicsField.vortex()
        vortexFieldNode.physicsField?.strength = 1
        vortexFieldNode.physicsField?.direction = SCNVector3Make(-1, 0, 0)
        scnView.scene?.rootNode.addChildNode(vortexFieldNode)
    }

    //朝一个点的力
    func addRadialGravity() {
        let boxNode = createBox()

        scnView.scene?.rootNode.addChildNode(boxNode)

        let radialGravityNode = SCNNode()
        radialGravityNode.physicsField = SCNPhysicsField.radialGravity()
        radialGravityNode.physicsField?.strength = 1000
        radialGravityNode.position = SCNVector3Make(0, 0, 0)
        scnView.scene?.rootNode.addChildNode(radialGravityNode)
    }

    //线性力
    func addLineBox() {
        let boxNode = createBox()

        scnView.scene?.rootNode.addChildNode(boxNode)

        let lineGravityNode = SCNNode()
        lineGravityNode.physicsField = SCNPhysicsField.linearGravity()
        lineGravityNode.physicsField?.strength = 100
        lineGravityNode.physicsField?.direction = SCNVector3Make(0, 0, -1)
        scnView.scene?.rootNode.addChildNode(lineGravityNode)
    }

    //随机力
    func addNoiseField() {
        let boxNode = createBox()

        scnView.scene?.rootNode.addChildNode(boxNode)

        let noiseFieldNode = SCNNode()
        noiseFieldNode.physicsField = SCNPhysicsField.noiseField(smoothness: 0, animationSpeed: 100)
        noiseFieldNode.physicsField?.strength = 100
        scnView.scene?.rootNode.addChildNode(noiseFieldNode)
    }

    //漂落
    func addTurbulenceField() {
        for _ in 0..<10 {
            let boxNode = SCNNode(geometry: SCNSphere(radius: 1))
            boxNode.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/earth/sun.jpg"
            boxNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(geometry: SCNBox(width: 5, height: 5, length: 5, chamferRadius: 0), options: nil))
            boxNode.position = SCNVector3Make(Float(arc4random_uniform(10)), Float(arc4random_uniform(20) + 20), 1)
            scnView.scene?.rootNode.addChildNode(boxNode)
        }

        let turbulenceFieldNode = SCNNode()
        turbulenceFieldNode.physicsField = SCNPhysicsField.turbulenceField(smoothness: 0, animationSpeed: 1)
        turbulenceFieldNode.physicsField?.strength = 5
        scnView.scene?.rootNode.addChildNode(turbulenceFieldNode)
    }

    //弹力
    func addSpringField() {
        let boxNode = createBox()

        scnView.scene?.rootNode.addChildNode(boxNode)

        let springField = SCNNode()
        springField.physicsField = SCNPhysicsField.spring()
        springField.physicsField?.strength = 5
        springField.position = SCNVector3Make(0, 30, 0)
        scnView.scene?.rootNode.addChildNode(springField)
    }

    //电场
    func addElectricField() {
        let tube = SCNTube(innerRadius: 1, outerRadius: 1.2, height: 4)
        tube.firstMaterial?.diffuse.contents = "art.scnassets/earth/moon.jpg"
        let tubeNode = SCNNode(geometry: tube)
        tubeNode.physicsBody = SCNPhysicsBody(type: .kinematic, shape: SCNPhysicsShape(geometry: SCNTube(innerRadius: 1, outerRadius: 1.2, height: 4), options: nil))
        tubeNode.position = SCNVector3Make(-5, 2, 0)
        scnView.scene?.rootNode.addChildNode(tubeNode)

        let tubeNode1 = SCNNode(geometry: SCNTube(innerRadius: 4.5, outerRadius: 5, height: 2))
        tubeNode1.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/earth/moon.jpg"
        tubeNode1.position = SCNVector3Make(6, 1, 0)
        scnView.scene?.rootNode.addChildNode(tubeNode1)

        let particleSystem = SCNParticleSystem(named: "art.scnassets/particle/fireParticle.scnp", inDirectory: nil)
        particleSystem?.colliderNodes = [tubeNode1,floorNode]
        particleSystem?.isAffectedByPhysicsFields = true
        particleSystem?.particleCharge = 10

        let particleNode = SCNNode()
        particleNode.position = SCNVector3Make(0, 0, 0)
        particleNode.addParticleSystem(particleSystem!)
        particleNode.physicsBody = SCNPhysicsBody()
        particleNode.physicsBody?.type = .dynamic
        tubeNode.addChildNode(particleNode)

        let electricFieldNode = SCNNode()
        electricFieldNode.physicsField = SCNPhysicsField.electric()
        electricFieldNode.physicsField?.strength = -10
        tubeNode1.addChildNode(electricFieldNode)
    }

    func createBox() -> SCNNode {
        let boxNode = SCNNode(geometry: SCNBox(width: 5, height: 5, length: 5, chamferRadius: 0))
        boxNode.geometry?.firstMaterial?.diffuse.contents = "art.scnassets/2.jpg"
        boxNode.position = SCNVector3Make(0, 2.5, 8)
        boxNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(geometry: SCNBox(width: 5, height: 5, length: 5, chamferRadius: 0), options: nil))
        return boxNode
    }

}

results matching ""

    No results matching ""