SceneKit_中級(jí)04_約束的使用

SceneKit_入門01_旋轉(zhuǎn)人物
SceneKit_入門02_如何創(chuàng)建工程
SceneKit_入門03_節(jié)點(diǎn)
SceneKit_入門04_燈光
SceneKit_入門05_照相機(jī)
SceneKit_入門06_行為動(dòng)畫(huà)
SceneKit_入門07_幾何體
SceneKit_入門08_材質(zhì)
SceneKit_入門09_物理身體
SceneKit_入門10_物理世界
SceneKit_入門11_粒子系統(tǒng)
SceneKit_入門12_物理行為
SceneKit_入門13_骨骼動(dòng)畫(huà)
SceneKit_中級(jí)01_模型之間的過(guò)渡動(dòng)畫(huà)
SceneKit_中級(jí)02_SCNView 詳細(xì)講解
SceneKit_中級(jí)03_切換照相機(jī)視角
SceneKit_中級(jí)04_約束的使用
SceneKit_中級(jí)05_力的使用
SceneKit_中級(jí)06_場(chǎng)景的切換
SceneKit_中級(jí)07_動(dòng)態(tài)修改屬性
SceneKit_中級(jí)08_陰影詳解
SceneKit_中級(jí)09_碰撞檢測(cè)
SceneKit_中級(jí)10_濾鏡效果制作
SceneKit_中級(jí)11_動(dòng)畫(huà)事件
SceneKit_高級(jí)01_GLSL
SceneKit_高級(jí)02_粒子系統(tǒng)深入研究
SceneKit_高級(jí)03_自定義力
SceneKit_高級(jí)04_自定義場(chǎng)景過(guò)渡效果
SceneKit_高級(jí)05 檢測(cè)手勢(shì)點(diǎn)擊到節(jié)點(diǎn)
SceneKit_高級(jí)06_加載頂點(diǎn)、紋理、法線坐標(biāo)
SceneKit_高級(jí)07_SCNProgram用法探究
SceneKit_高級(jí)08_天空盒子制作
SceneKit_高級(jí)09_霧效果
SceneKit_大神01_掉落的文字
SceneKit_大神02_彈幕來(lái)襲
SceneKit_大神03_navigationbar上的3D文字

讓學(xué)習(xí)成為一種習(xí)慣

先告訴你

我們?cè)谧鰬?yīng)用開(kāi)發(fā)的時(shí)候,也會(huì)用到約束,應(yīng)用中的約束,就是當(dāng)一個(gè)視圖變化的時(shí)候,讓和他之間有約束關(guān)系的其他視圖,按照一定的約束規(guī)則變化,那在游戲中,我們的約束是用來(lái)干什么的?
官方的解釋:

約束能夠根據(jù)你定義的規(guī)則,自動(dòng)調(diào)整這些變化(位置 旋轉(zhuǎn) 和 比例)

認(rèn)識(shí)新朋友

  • SCNConstraint

這個(gè)是游戲中的約束類,是一個(gè)抽象的類,我們不能直接使用,但是它有3個(gè)子類可以供我們使用。

我們看這個(gè)類有哪些屬性

 /* 
  * 作用: 影響因子,決定約束的強(qiáng)度
  * 工作原理: 如果設(shè)置為1 那么在游戲每一幀渲染的時(shí)候,系統(tǒng)都會(huì)調(diào)整這個(gè)約束,如果你設(shè)置為0.5 在游戲的某些幀,系統(tǒng)不會(huì)進(jìn)行約束調(diào)整 0 完全忽略約束
  * 注意 SCNTransformConstraint  對(duì)這類約束不起作用
  */
 var influenceFactor: CGFloat,默認(rèn)值為 1,這是為0 時(shí),則

接下來(lái)我們分析三個(gè)子類

  • SCNLookAtConstraint

1.作用:

讓一個(gè)節(jié)點(diǎn)的方向,總是指向另外一個(gè)一個(gè)節(jié)點(diǎn)

2.怎么用? 我舉個(gè)簡(jiǎn)單的例子,幫助大家理解它的用法

如果你想要玩第一視角的游戲,這是我們需要讓攝像機(jī)捕捉到人物移動(dòng)時(shí)的位置,這是需要給照相機(jī)節(jié)點(diǎn)添加一個(gè)SCNLookAtConstraint 類型的約束,就能實(shí)現(xiàn)這個(gè)效果。

3.原理:

其實(shí)這個(gè)約束的原理是更改節(jié)點(diǎn)的transform的屬性

4.怎么創(chuàng)建

 // target 就是指向的那個(gè)目標(biāo)節(jié)點(diǎn) 
+ (instancetype)lookAtConstraintWithTarget:(SCNNode *)target;

5.我們?nèi)绻胍障鄼C(jī)的視野保持在水平面上,也就是說(shuō)只沿在Y軸轉(zhuǎn)動(dòng)跟隨目標(biāo)節(jié)點(diǎn),我們應(yīng)該怎么做呢?

// 設(shè)置下面的屬性為YES,就能實(shí)現(xiàn)上面的效果,默認(rèn)為NO
var gimbalLockEnabled: Bool
  • SCNTransformConstraint

1.作用:

創(chuàng)建一個(gè)轉(zhuǎn)換約束(提供給節(jié)點(diǎn)一個(gè)新的轉(zhuǎn)換的計(jì)算),當(dāng)系統(tǒng)進(jìn)行下一次渲染的時(shí)候,會(huì)重新計(jì)算這個(gè)塊中的約束,然后調(diào)整節(jié)點(diǎn)的狀態(tài)

2.創(chuàng)建方法

 /*
  * world 設(shè)置為YES 使用世界坐標(biāo)系,設(shè)置為NO 使用自身坐標(biāo)系 
+ (instancetype)transformConstraintInWorldSpace:(BOOL)world  withBlock:(SCNMatrix4 (^)(SCNNode *node,  SCNMatrix4 transform))block
  • SCNIKConstraint(反向運(yùn)動(dòng)約束)

1.作用:

將一個(gè)節(jié)點(diǎn)鏈移動(dòng)到一個(gè)目標(biāo)位置

給張圖理解一下:

讓學(xué)習(xí)成為一種習(xí)慣

2.使用步驟:

1.創(chuàng)建一個(gè)節(jié)點(diǎn)鏈
2.給根節(jié)點(diǎn)添加 SCNIKConstraint 約束對(duì)象(胳膊)
3.添加約束給執(zhí)行器(手)
3.限定鏈?zhǔn)焦?jié)點(diǎn)移動(dòng)的范圍
4.設(shè)置目標(biāo)位置,這個(gè)值可以動(dòng)態(tài)的改變

3.舉個(gè)例子理解一下

比如機(jī)器人的組成身體 上臂 胳膊 和 手,身體是上臂的根節(jié)點(diǎn),上臂是胳膊的根節(jié)點(diǎn),胳膊是手的根節(jié)點(diǎn),手是身體的根節(jié)點(diǎn),如果我們要實(shí)現(xiàn)上面的約束的話,需要將約束的根節(jié)點(diǎn)設(shè)置為上臂,那我們把這個(gè)約束應(yīng)該添加到手(執(zhí)行)這個(gè)節(jié)點(diǎn)上去

4.創(chuàng)建反向運(yùn)動(dòng)約束

- (instancetype)initWithChainRootNode:(SCNNode *)chainRoot  
+ inverseKinematicsConstraintWithChainRootNode:

5.設(shè)置約束的最大旋轉(zhuǎn)角度

- (void)setMaxAllowedRotationAngle:(CGFloat)angle
                      forJoint:(SCNNode *)node

6.設(shè)置目標(biāo)位置

var targetPosition: SCNVector3

走進(jìn)代碼的世界

友情提示:

第一種約束和第二種約束都很簡(jiǎn)單,在這里就不寫(xiě)代碼了,我們重點(diǎn)研究一下,第三種約束的實(shí)現(xiàn)。

制作一個(gè)機(jī)器手模型

1.創(chuàng)建工程(略)
2.添加模型文件(略)
3.添加框架<SceneKit/SceneKit.h>
4.創(chuàng)建游戲場(chǎng)景

scnView = [[SCNView alloc]initWithFrame:self.view.bounds];
scnView.backgroundColor = [UIColor blackColor];
scnView.allowsCameraControl = true;
scnView.scene = [SCNScene scene];
scnView.scene.physicsWorld.gravity = SCNVector3Make(0, 90, 0);// 添加一個(gè)重力,我們讓其方向朝上
[self.view addSubview:scnView];

5.添加照相機(jī)

 SCNNode *cameraNode = [SCNNode node];
cameraNode.camera = [SCNCamera camera];
cameraNode.camera.automaticallyAdjustsZRange = true;
cameraNode.position = SCNVector3Make(0, 0,1000);
[scnView.scene.rootNode addChildNode:cameraNode];

6.添加機(jī)器手臂并設(shè)置約束

-(void)addArmToScene{

// 創(chuàng)建手掌
SCNNode *handNode = [SCNNode node];
handNode.geometry = [SCNBox boxWithWidth:20 height:20 length:20 chamferRadius:0];
handNode.geometry.firstMaterial.diffuse.contents = [UIColor purpleColor];
handNode.position = SCNVector3Make(0, -50, 0);

// 創(chuàng)建小手臂
SCNNode *lowerArm = [SCNNode node];
lowerArm.geometry = [SCNCylinder cylinderWithRadius:1 height:100];
lowerArm.geometry.firstMaterial.diffuse.contents = [UIColor redColor];
lowerArm.position = SCNVector3Make(0, -50, 0);
lowerArm.pivot = SCNMatrix4MakeTranslation(0, 50, 0); // 連接點(diǎn)
[lowerArm addChildNode:handNode];

// 創(chuàng)建上臂
SCNNode *upperArm = [SCNNode node];
upperArm.geometry = [SCNCylinder cylinderWithRadius:1 height:100];
upperArm.geometry.firstMaterial.diffuse.contents = [UIColor greenColor];
upperArm.pivot = SCNMatrix4MakeTranslation(0, 50, 0);
[upperArm addChildNode:lowerArm];

// 創(chuàng)建控制點(diǎn)
SCNNode *controlNode = [SCNNode node];
controlNode.geometry = [SCNSphere sphereWithRadius:10];
controlNode.geometry.firstMaterial.diffuse.contents = [UIColor blueColor];
[controlNode addChildNode:upperArm];
controlNode.position= SCNVector3Make(0, 100, 0);

// 添加到場(chǎng)景中去
[scnView.scene.rootNode addChildNode:controlNode];
scnView.delegate = self;

// 創(chuàng)建約束
 ikContrait =[SCNIKConstraint inverseKinematicsConstraintWithChainRootNode:controlNode];

// 給執(zhí)行器添加約束
handNode.constraints = @[ikContrait];
}

7.添加一個(gè)手,每次點(diǎn)擊屏幕,隨機(jī)增加一個(gè)球

// 添加手勢(shì)
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapHandle)];
[scnView addGestureRecognizer:tap];
-(void)tapHandle{
[self createNodeToScene:scnView.scene andConstraint:ikContrait];
}

-(void)createNodeToScene:(SCNScene*)scene andConstraint:(SCNIKConstraint*)ikConstrait{
SCNNode *node = [SCNNode node];
node.position = SCNVector3Make(arc4random_uniform(100), arc4random_uniform(100), arc4random_uniform(100));
[scene.rootNode addChildNode:node];
node.geometry = [SCNSphere sphereWithRadius:10];
node.geometry.firstMaterial.diffuse.contents = [UIColor colorWithRed:arc4random_uniform(255.0)/255.0 green:arc4random_uniform(255.0)/255.0 blue:arc4random_uniform(255.0)/255.0 alpha:1];
// 創(chuàng)建動(dòng)畫(huà),當(dāng)手掌接觸到小球時(shí),給小球添加一個(gè)動(dòng)態(tài)身體
[SCNTransaction begin];
[SCNTransaction setAnimationDuration:0.5];
ikConstrait.targetPosition = node.position;
[SCNTransaction commit];
node.physicsBody = [SCNPhysicsBody dynamicBody];  
}

運(yùn)行一下試試看:

讓學(xué)習(xí)成為一種習(xí)慣

總結(jié)

今天我們使用了反向運(yùn)動(dòng)約束,不知道你學(xué)會(huì)了沒(méi)有,其他兩種約束都比較簡(jiǎn)單,請(qǐng)自行進(jìn)行學(xué)習(xí),如有疑問(wèn),請(qǐng)聯(lián)系我!


代碼庫(kù),聽(tīng)說(shuō)經(jīng)常給人點(diǎn)贊都當(dāng)老板了!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容