1.File->New ->Project...
2.选择Game模板工程,然后点击Next;
3.设置工程名,GameTechnology选择Scenekit,此为三维模板基类;SpriteKit为二维游戏的基础模板;语言选择的是ObejectC,当然了,好多人是选择swift的,这个好开发嘛;点击Next,选择工程保存位置;OK,工程建好了。
4.然后运行查看效果,是一个支持手势操作的旋转的飞机。下方有一个统计面板。方便开发时候查看性能,发布的时候可以代码关闭。
5.接下来说一些技术:
5.1 加载obj文件方法
NSString* resPath = [[NSBundle mainBundle] resourcePath];
NSString * str2 = @"/art.scnassets/car/yjjcar.obj";
NSString *string = [resPath stringByAppendingString:str2];
NSURL* nsurl = [NSURL fileURLWithPath:string];
MDLAsset *asset = [[MDLAsset alloc] initWithURL:nsurl];
carnode = [SCNNode nodeWithMDLObject:[asset objectAtIndex:0]];
carnode.scale = SCNVector3Make(0.01, 0.01, 0.01);
[self.scene.rootNode addChildNode:carnode];
5.2 模型旋转
floorNode.transform = SCNMatrix4Rotate(floorNode.transform, M_PI/2, 1, 0, 0);
[self.scene.rootNode addChildNode:floorNode];
5.3 计时器
[NSTimer scheduledTimerWithTimeInterval:0.15 target:self selector:@selector(actionTimer:) userInfo:nil repeats:YES];
- (void)actionTimer:(NSTimer *)timer
{
}
5.4 添加手势操作
初始化的时候
[self addGesture];
addGesture定义
- (void)addGesture
{
//一指拖拽手势
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handlePan:)];
pan.minimumNumberOfTouches = 1;
pan.maximumNumberOfTouches = 1;
pan.delegate = self;
[self.view addGestureRecognizer:pan];
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc]
initWithTarget:self action:@selector(scale:)];
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotatePiece:)];
[pinchRecognizer setDelegate:self];
[self.view addGestureRecognizer:pinchRecognizer];
[self.view addGestureRecognizer:rotationGesture];
}
- (void)handlePan:(UITapGestureRecognizer *)gestureRecognizer
{
static float previousX,previousY;
CGPoint p = [gestureRecognizer locationInView:self.sceneView];
if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
}else if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
}else if (gestureRecognizer.state == UIGestureRecognizerStateChanged) {
float dx = p.x - previousX;
float dy = p.y - previousY;
[self transCamera:dx dy:dy];
}
previousX = p.x;previousY = p.y;
}
-(void)scale:(UIPinchGestureRecognizer*)sender {
//当手指离开屏幕时,将lastscale设置为1.0
if([sender state] == UIGestureRecognizerStateEnded) {
lastScale = 1.0;
return;
}
CGFloat scale = 1.0 - (lastScale - [(UIPinchGestureRecognizer*)sender scale]);
[self ScaleCamera:scale];
lastScale = [sender scale];
}
5.5 直接根据顶点数据绘制线条
-(void) drawArea
{
// //三角形网格场地
SCNGeometrySource *vertexSource = [SCNGeometrySource geometrySourceWithVertices:&g_Vertices[0]
count:g_Vertices.size()];
NSData *indexData = [NSData dataWithBytes:&g_Indices[0]
length:g_Indices.size()*4];
SCNGeometryElement *element = [SCNGeometryElement geometryElementWithData:indexData
primitiveType:SCNGeometryPrimitiveTypeTriangles
primitiveCount:g_Indices.size()/3
bytesPerIndex:sizeof(int)];
SCNGeometry *triangles = [SCNGeometry geometryWithSources:@[vertexSource]
elements:@[element]];
SCNMaterial* myMaterial = [SCNMaterial new];
[myMaterial setDoubleSided:true];
myMaterial.diffuse.contents =[UIColor colorWithRed:0.336 green:0.336 blue:0.336 alpha:1];
triangles.firstMaterial = myMaterial;
SCNNode *trianglesNode = [SCNNode nodeWithGeometry:triangles];
// [self.scene.rootNode addChildNode:trianglesNode];
//白色场地边线绘制
SCNGeometrySource *vertexSource2 = [SCNGeometrySource geometrySourceWithVertices:&m_whiteLineVertices[0]
count:m_whiteLineVertices.size()];
NSData *indexData2 = [NSData dataWithBytes:&m_whiteLineIndices[0]
length:m_whiteLineIndices.size()*4];
SCNGeometryElement *element2 = [SCNGeometryElement geometryElementWithData:indexData2
primitiveType:SCNGeometryPrimitiveTypeLine
primitiveCount:m_whiteLineIndices.size()/2
bytesPerIndex:sizeof(int)];
SCNGeometry *line = [SCNGeometry geometryWithSources:@[vertexSource2]
elements:@[element2]];
SCNNode *lineNode = [SCNNode nodeWithGeometry:line];
[self.scene.rootNode addChildNode:lineNode];
//黄色场地边线绘制
SCNGeometrySource *vertexSourceYellow = [SCNGeometrySource geometrySourceWithVertices:&m_yellowLineVertices[0]
count:m_yellowLineVertices.size()];
NSData *indexDataYellow = [NSData dataWithBytes:&m_yellowLineIndices[0]
length:m_yellowLineIndices.size()*4];
SCNGeometryElement *elementYellow = [SCNGeometryElement geometryElementWithData:indexDataYellow
primitiveType:SCNGeometryPrimitiveTypeLine
primitiveCount:m_yellowLineIndices.size()/2
bytesPerIndex:sizeof(int)];
SCNGeometry *lineYellow = [SCNGeometry geometryWithSources:@[vertexSourceYellow]
elements:@[elementYellow]];
SCNMaterial* MaterialYellow = [SCNMaterial new];
[MaterialYellow setDoubleSided:true];
MaterialYellow.diffuse.contents =[UIColor colorWithRed:1 green:1 blue:0 alpha:1];
lineYellow.firstMaterial = MaterialYellow;
SCNNode *lineYellowNode = [SCNNode nodeWithGeometry:lineYellow];
[self.scene.rootNode addChildNode:lineYellowNode];
}
这里需要注意:点顺序要一致,绘制线条要尽量少用图元,图元多了性能会下降很明显。
5.6 添加相机节点并控制
//添加摄像机节点
nodeCarema = [SCNNode node];
SCNCamera* ccCamera = [SCNCamera camera];
ccCamera.xFov = 3;
ccCamera.yFov = 6;
nodeCarema.camera = ccCamera;
SCNVector3 defaultPos = [dataPool getCenterOfArea];
nodeCarema.position = SCNVector3Make(defaultPos.x, defaultPos.y, first_height);
[mEyeBaseNode addChildNode:nodeCarema];
控制:
-(void) transCamera:(float)dx dy:(float)dy
{
SCNVector3 vvv = mEyeBaseNode.position;
if (isEntered) {
switch (mOperaMode) {
case HEIGHT_ZOOM:
nodeCarema.transform = SCNMatrix4Translate(nodeCarema.transform, -dx/800, dy/800, 0);
break;
case ROTATE_VIEW:
break;
case FREE_VIEW:
if(dy>0&&xRotate<=M_PI_4)
{
xRotate+=0.01;
mEyeBaseNode.transform = SCNMatrix4Mult(eyeBaseTransMatrix, SCNMatrix4MakeRotation(xRotate, 1, 0, 0));
}
else if(dy<0 && xRotate>=0){
xRotate-=0.01;
mEyeBaseNode.transform = SCNMatrix4Mult(eyeBaseTransMatrix, SCNMatrix4MakeRotation(xRotate, 1, 0, 0));
}
if(dx>0)
eyeRoot.transform = SCNMatrix4Mult(eyeRoot.transform, SCNMatrix4MakeRotation(-0.04, 0, 0, 1));
else
eyeRoot.transform = SCNMatrix4Mult(eyeRoot.transform, SCNMatrix4MakeRotation(0.04, 0, 0, 1));
break;
default:
break;
}
}
}
-(void) ScaleCamera:(float)dz
{
SCNVector3 vvv = nodeCarema.position;
if (isEntered) {
switch (mOperaMode) {
case HEIGHT_ZOOM:
if(dz>1.0 && vvv.z>3)
nodeCarema.position = SCNVector3Make(vvv.x, vvv.y, vvv.z-0.3);
else if(dz<1.0 && vvv.z<7)
nodeCarema.position = SCNVector3Make(vvv.x, vvv.y, vvv.z+0.3);
break;
case ROTATE_VIEW:
if(dz>1.0 && vvv.z>3)
nodeCarema.position = SCNVector3Make(vvv.x, vvv.y, vvv.z-0.3);
else if(dz<3.0 && vvv.z<7)
nodeCarema.position = SCNVector3Make(vvv.x, vvv.y, vvv.z+0.3);
break;
case FREE_VIEW:
if(dz>1.0 && vvv.z>3)
nodeCarema.position = SCNVector3Make(vvv.x, vvv.y, vvv.z-0.3);
else if(dz<1.0 && vvv.z<7)
nodeCarema.position = SCNVector3Make(vvv.x, vvv.y, vvv.z+0.3);
break;
default:
break;
}
}
}
5.7 关闭自带的控制面板
self.sceneView.showsStatistics = NO;
6 Spritekit开发
1>导入SpriteKit.Framework
点击工程名,选择General,点击Linked Frameworks and Library,点击下面的+号,选择SpriteKit.Framework,添加到当前工程中去。
2>新建一个SpriteKit类
#import <SpriteKit/SpriteKit.h>
@interface AAPLOverlayScene : SKScene
{
SKShapeNode* lhPanel; //离合节点
SKShapeNode* ymPanel; //油门节点
SKShapeNode* scPanel; //刹车节点
SKNode *fangxiangpan; //方向盘节点
SKNode *fxpCenter; //方向盘旋转中心节点
SKLabelNode* qsLabel; //圈数
}
@property (readonly) SKNode *speedNeedle;
-(void)setPanelValueWithAngle:(float)angle YM:(float)ym LH:(float)lh SC:(float)sc;
@end
#import "AAPLOverlayScene.h"
@implementation AAPLOverlayScene
{
float commonScale;
}
-(id)initWithSize:(CGSize)size {
commonScale = 0.4;
if (self = [super initWithSize:size]) {
//setup the overlay scene
self.anchorPoint = CGPointMake(0.5, 0.5);
//automatically resize to fill the viewport
self.scaleMode = SKSceneScaleModeResizeFill;
//make UI larger on iPads
BOOL iPad = ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad);
float scale = iPad ? 1.5 : 1;
//add the speed gauge
SKSpriteNode *myImage = [SKSpriteNode spriteNodeWithImageNamed:@"panel3x.png"];
myImage.anchorPoint = CGPointMake(0, 0);
CGSize imgSize = myImage.size;
myImage.position = CGPointMake(-imgSize.width*0.5*commonScale, -size.height*0.5);
myImage.xScale = commonScale * scale;
myImage.yScale = commonScale * scale;
[self addChild:myImage];
SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
myLabel.text = @"Blood, Error!";
myLabel.fontSize = 45;
myLabel.position = CGPointMake(CGRectGetMidX(self.frame),
CGRectGetMidY(self.frame));
myLabel.fontColor = [UIColor colorWithRed:1.0 green:0 blue:0 alpha:1];
// [self addChild:myLabel];
//add the needed
fangxiangpan = [SKNode node];
SKSpriteNode *needle = [SKSpriteNode spriteNodeWithImageNamed:@"fangxiangpan3x.png"];
needle.anchorPoint = CGPointMake(0.5, 0.5);
needle.zRotation = 0;
fangxiangpan.position = CGPointMake(140,26*4);
[fangxiangpan addChild:needle];
[myImage addChild:fangxiangpan];
qsLabel = [SKLabelNode labelNodeWithFontNamed:@"quanshu"];
qsLabel.name = @"quanshu";
qsLabel.text = @"aaaaaa";
qsLabel.fontSize = 22;
qsLabel.fontColor = [SKColor whiteColor];
qsLabel.position = CGPointMake(280,100);
[myImage addChild:qsLabel];
UIBezierPath* bkBezierPath = [[UIBezierPath alloc] init];
[bkBezierPath moveToPoint:CGPointMake(0.0, 0.0)];
[bkBezierPath addLineToPoint:CGPointMake(0.0, 114.0)];
[bkBezierPath addLineToPoint:CGPointMake(15, 114.0)];
[bkBezierPath addLineToPoint:CGPointMake(15.0, 0.0)];
UIBezierPath* BezierPath = [[UIBezierPath alloc] init];
[BezierPath moveToPoint:CGPointMake(0.0, 0.0)];
[BezierPath addLineToPoint:CGPointMake(0.0, 114)];
[BezierPath addLineToPoint:CGPointMake(9.0, 114)];
[BezierPath addLineToPoint:CGPointMake(9.0, 0.0)];
SKShapeNode* ymPanel_bk = [SKShapeNode node];
ymPanel_bk.path = bkBezierPath.CGPath;
ymPanel_bk.lineWidth = 1.0;
ymPanel_bk.fillColor = [UIColor grayColor];
ymPanel_bk.antialiased = NO;
ymPanel_bk.position = CGPointMake(383, 50);
[myImage addChild:ymPanel_bk];
ymPanel = [SKShapeNode node];
ymPanel.position =CGPointMake(3, 0);
ymPanel.path = BezierPath.CGPath;
ymPanel.lineWidth = 1.0;
ymPanel.fillColor = [UIColor blueColor];
ymPanel.antialiased = NO;
ymPanel.yScale = 1;
[ymPanel_bk addChild:ymPanel];
SKLabelNode* ymLabel = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
ymLabel.name = @"myCounterLabel";
ymLabel.text = @"油门";
ymLabel.fontSize = 20;
ymLabel.fontColor = [SKColor whiteColor];
ymLabel.position = CGPointMake(ymPanel_bk.position.x+7.5,18);
[myImage addChild:ymLabel];
SKShapeNode* scPanel_bk = [SKShapeNode node];
scPanel_bk.position =CGPointMake(448, 50);
scPanel_bk.path = bkBezierPath.CGPath;
scPanel_bk.lineWidth = 1.0;
scPanel_bk.fillColor = [UIColor grayColor];
scPanel_bk.antialiased = NO;
[myImage addChild:scPanel_bk];
scPanel = [SKShapeNode node];
scPanel.position =CGPointMake(3, 0);
scPanel.path = BezierPath.CGPath;
scPanel.lineWidth = 1.0;
scPanel.fillColor = [UIColor redColor];
scPanel.antialiased = NO;
scPanel.yScale = 0.5;
[scPanel_bk addChild:scPanel];
SKLabelNode* scLabel = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
scLabel.name = @"myCounterLabel";
scLabel.text = @"刹车";
scLabel.fontSize = 20;
scLabel.fontColor = [SKColor whiteColor];
scLabel.position = CGPointMake(scPanel_bk.position.x+7.5,18);
[myImage addChild:scLabel];
SKShapeNode* lhPanel_bk = [SKShapeNode node];
lhPanel_bk.position =CGPointMake(514, 50);
lhPanel_bk.path = bkBezierPath.CGPath;
lhPanel_bk.lineWidth = 1.0;
lhPanel_bk.fillColor = [UIColor grayColor];
lhPanel_bk.antialiased = NO;
[myImage addChild:lhPanel_bk];
lhPanel = [SKShapeNode node];
lhPanel.position =CGPointMake(3, 0);
lhPanel.path = BezierPath.CGPath;
lhPanel.lineWidth = 1.0;
lhPanel.fillColor = [UIColor greenColor];
lhPanel.antialiased = NO;
lhPanel.yScale = 0.5;
[lhPanel_bk addChild:lhPanel];
SKLabelNode* lhLabel = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
lhLabel.name = @"Cluster";
lhLabel.text = @"离合";
lhLabel.fontSize = 20;
lhLabel.fontColor = [SKColor whiteColor];
lhLabel.position = CGPointMake(lhPanel_bk.position.x+7.5,18);
[myImage addChild:lhLabel];
}
return self;
}
-(void)setPanelValueWithAngle:(float)angle YM:(float)ym LH:(float)lh SC:(float)sc
{
lhPanel.yScale = lh/100;
scPanel.yScale = sc/100;
ymPanel.yScale = ym/99;
fangxiangpan.zRotation = angle/180*M_PI;
NSString* strRoll;
int s = (int)angle>>31;
if(s == 0)
{
strRoll = @"左";
}else{
strRoll = @"右";
}
const int n = abs(angle);
qsLabel.text = strRoll;
// NSLog(@"%@@",strRoll);
}
@end
3>将建好的二维面板导入到Scenekit中去,算是合并场景吧
@property (nonatomic,strong) AAPLOverlayScene *panelView;
_panelView = [[AAPLOverlayScene alloc] initWithSize:self.view.bounds.size];
self.sceneView.overlaySKScene = _panelView;
self.sceneView.showsStatistics = NO;
[self.view addSubview:self.sceneView];
ok! 三维中有了二维面板了。
模糊效果图如下: