SpriteKit 如何用精灵制作按钮

前言

    前段时间,在知乎看到一个回答,iOS开发以及被玩的差不多了,只有SpriteKit,SceneKit这两个难兄难弟还没有被“开发”。确实,毕竟做手游,有unity,虚幻等,谁用这玩意。。
    随着ARKIT的发布,SpriteKit和SceneKit渐渐重回视野。最近研究了一下SpriteKit。用下来还是觉得很鸡肋。可以说是要啥没啥。啥轮子都没,都得自己做。没办法,毕竟也不是专门做游戏的,这样子也不错了。
    言归正传。在你兴致勃勃的,准备制作一个菜单界面的时候。你习惯性找一个按钮。UIButton扔进去?显然不可行啊。浏览一圈,居然没有可以用的Button。WTF?
    OK,没有,那咱自己做呗。造轮子什么的我最擅长了。

预览

按钮可以设置不同的点击颜色,和文字颜色,但是暂不支持图片。


button.gif

讲解

先上代码

//
//  MeCustomButton.swift
//  mng
//
//  Created by WTFKL on 2018/4/16.
//  Copyright © 2018年 WTF. All rights reserved.
//

import SpriteKit
import UIKit
class MeCustomButton: SKSpriteNode{
    /**
         在创建完成后,调用touchUpInside方法来触发点击事件
     */
    private var m_ButtonLabel : SKLabelNode?;
    private var border : SKShapeNode?;

    //边框颜色
    public var borderColor : SKColor = SKColor.yellow{
        didSet{
            border?.strokeColor = borderColor;
        }
    };
    //按钮背景颜色
    public var m_BackgroundColor : SKColor = SKColor.white{
        didSet{
            border?.fillColor = m_BackgroundColor;
        }
    };
    //按钮文字
    public var m_LabelText : String = "Label"{
        didSet{
            m_ButtonLabel?.text = m_LabelText;
        }
    };
    //按钮字体颜色
    public var m_fontColor : SKColor = .black{
        didSet{
            m_ButtonLabel?.fontColor = m_fontColor;
        }
    };
    //按钮边框宽度
    public var m_borderLineWidth:CGFloat = 1{
        didSet{
            border?.lineWidth = m_borderLineWidth;
        }
    }
    
    //按钮文字字体
    public var m_FontName : String = ""{
        didSet{
            m_ButtonLabel?.fontName = m_FontName;
        }
    }
    //按钮文字尺寸
    public var m_FontSize : CGFloat = 20 {
        didSet{
            m_ButtonLabel?.fontSize = m_FontSize;
        }
    }
    
    public var clickEvent = {};
    

    convenience init(btnName : String,btnSize:CGSize,btnCornerRadius:CGFloat) {
        self.init(color: .clear, size: btnSize);
        self.color = .clear;
        self.name = btnName;
        let location = CGRect(x: -self.frame.size.width/2, y:-self.frame.size.height/2 , width: self.frame.size.width, height: self.frame.size.height);
        border = SKShapeNode(rect: location, cornerRadius: btnCornerRadius);
        border!.fillColor = m_BackgroundColor;
        border?.lineWidth = m_borderLineWidth;
        border?.strokeColor = borderColor;
        self.addChild(border!);
        
        m_ButtonLabel = SKLabelNode(text: m_LabelText);
        m_ButtonLabel?.position = CGPoint(x: 0, y: -((m_ButtonLabel?.frame.size.height)!/2));
        m_ButtonLabel?.fontColor = m_fontColor;
        m_ButtonLabel?.fontName = m_FontName;
        m_ButtonLabel?.fontSize = m_FontSize;
        self.addChild(m_ButtonLabel!);
    }
    
    public func touchUpInside(highLightBGColor:SKColor,highLightFontColor:SKColor){
        let oldBGColor = self.m_BackgroundColor;
        let oldFontColor = self.m_fontColor;
        self.m_BackgroundColor = highLightBGColor;
        self.m_fontColor = highLightFontColor;
        let waitTime = SKAction.wait(forDuration: 0.05);
        let bgcolor = SKAction.run {
            self.m_BackgroundColor = oldBGColor;
            self.m_fontColor = oldFontColor;
        }
        self.run(SKAction.sequence([waitTime,bgcolor]));
        clickEvent();
    }
    
    
    
}

首先是属性
 private var m_ButtonLabel : SKLabelNode?;
    private var border : SKShapeNode?;

    //边框颜色
    public var borderColor : SKColor = SKColor.yellow{
        didSet{
            border?.strokeColor = borderColor;
        }
    };
    //按钮背景颜色
    public var m_BackgroundColor : SKColor = SKColor.white{
        didSet{
            border?.fillColor = m_BackgroundColor;
        }
    };
    //按钮文字
    public var m_LabelText : String = "Label"{
        didSet{
            m_ButtonLabel?.text = m_LabelText;
        }
    };
    //按钮字体颜色
    public var m_fontColor : SKColor = .black{
        didSet{
            m_ButtonLabel?.fontColor = m_fontColor;
        }
    };
    //按钮边框宽度
    public var m_borderLineWidth:CGFloat = 1{
        didSet{
            border?.lineWidth = m_borderLineWidth;
        }
    }
    
    //按钮文字字体
    public var m_FontName : String = ""{
        didSet{
            m_ButtonLabel?.fontName = m_FontName;
        }
    }
    //按钮文字尺寸
    public var m_FontSize : CGFloat = 20 {
        didSet{
            m_ButtonLabel?.fontSize = m_FontSize;
        }
    }
    public var clickEvent = {};//点击事件

一目了然,重写了set方法,因为后面要随时更改这些属性。swift重写set方法也是比较奇葩的。重点提一下

public var clickEvent = {}

这个传递了一个闭包,将点击事件传递进来,方便调用。
其他这段基本都写注释了。我就不多嘴了。

其次是便利构造方法
 convenience init(btnName : String,btnSize:CGSize,btnCornerRadius:CGFloat) {
        self.init(color: .clear, size: btnSize);
        self.color = .clear;
        self.name = btnName;
        let location = CGRect(x: -self.frame.size.width/2, y:-self.frame.size.height/2 , width: self.frame.size.width, height: self.frame.size.height);
        border = SKShapeNode(rect: location, cornerRadius: btnCornerRadius);//设置圆角
        border!.fillColor = m_BackgroundColor;//填充色
        border?.lineWidth = m_borderLineWidth;//边框宽度
        border?.strokeColor = borderColor;//边框颜色
        self.addChild(border!);
        
        m_ButtonLabel = SKLabelNode(text: m_LabelText);//添加文字label
        m_ButtonLabel?.position = CGPoint(x: 0, y: -((m_ButtonLabel?.frame.size.height)!/2));//尺寸
        m_ButtonLabel?.fontColor = m_fontColor;//字体颜色
        m_ButtonLabel?.fontName = m_FontName;//字体
        m_ButtonLabel?.fontSize = m_FontSize;//字体尺寸
        self.addChild(m_ButtonLabel!);
    }

便利构造方法常规写法,附上默认数值属性。
border使用了SKShapeNode,在自身周围画出边框。

再者就是点击事件方法
 public func touchUpInside(highLightBGColor:SKColor,highLightFontColor:SKColor){//传入高亮背景色,高亮文字颜色
        let oldBGColor = self.m_BackgroundColor;//保存原本的颜色
        let oldFontColor = self.m_fontColor;//保存原本的文字颜色
        self.m_BackgroundColor = highLightBGColor;//把传入的高亮颜色赋值
        self.m_fontColor = highLightFontColor;//把传入的高亮颜色赋值
        let waitTime = SKAction.wait(forDuration: 0.05);//按钮等待时间
        let bgcolor = SKAction.run {//动画
            self.m_BackgroundColor = oldBGColor;
            self.m_fontColor = oldFontColor;
        }
        self.run(SKAction.sequence([waitTime,bgcolor]));//运行动画
        clickEvent();//调用闭包点击事件
    }

这里就必须重点提一下了。因为按钮点击最好是有反馈。所以,运用SKSpritekit的动画特性,用SKAction的wait,来等待0.5s,来模拟按钮反馈。这是最关键的。

CustomButton类就完成了

如何使用这个类?

     //便利构造方法,初始化出一个100*50的button,带弧度为5的边框
      startButton = MeCustomButton(btnName: "start", btnSize:CGSize(width: 100, height: 50) , btnCornerRadius: 5);
        startButton?.position = CGPoint(x: 0, y: 5);//button的位置
        startButton?.m_fontColor = .white;//文字颜色默认为白色
        startButton?.m_BackgroundColor = .clear;//背景色为透明
        startButton?.m_FontName = "GB18030Bitmap";//设置字体,然而手机没这个字体,可以忽略
        startButton?.m_LabelText = "开始";//设置文字
        startButton?.m_FontSize = 35;//设置文字尺寸
        startButton?.borderColor = .white;//设置文字颜色
        startButton?.m_borderLineWidth = 1;//边框宽度
        startButton?.clickEvent = {//设置点击事件
            let firstScene = SKScene(fileNamed: "Third")!//这里我点击跳转第三个场景
            self.view?.presentScene(firstScene,transition: SKTransition.crossFade(withDuration: 0.5));
        };
        self.addChild(startButton!);//场景添加按钮

常规设置属性,点击事件也一目了然,不多说。

注意

  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for t in touches {
            let location = t.location(in: self);
            
            let mnode = nodes(at: location);
            
            for nnode in mnode{
                let na = nnode as? MeCustomButton;
                if(na?.name == "instructions"){
                    instructions?.touchUpInside(highLightBGColor: .white, highLightFontColor: .black);
                }else if(na?.name == "start"){
                    startButton?.touchUpInside(highLightBGColor: .white, highLightFontColor: .black);
                }
            }
        }
    }

与通常button不同的是,我们必须通过触摸事件来判断,你点的是哪个精灵。touchesBegan用法和常规也一样,找出你的精灵后,调用touchUpInside方法,传入你想要的高亮颜色。这时候,你的button就算是完成了。

总结

    怎么样,造轮子也挺不错的。我个人觉得还是没有完全把这个方法抽好,还是很麻烦。而且不支持图片,等过段时间有空了,把这个方法在完善一下,支持图片,方法命名什么的都根据UIButton来。各位看官,也试试看吧,喜欢给个赞哦。有问题请小心翼翼指出,心理承受能力弱,哈哈。预告一下,之后几天,会写一篇完整的swift游戏开发文章。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,198评论 6 514
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,334评论 3 398
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,643评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,495评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,502评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,156评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,743评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,659评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,200评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,282评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,424评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,107评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,789评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,264评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,390评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,798评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,435评论 2 359

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,117评论 4 61
  • 西冶民间文化五彩缤纷,戏曲,铁艺流传深远,扛妆抬妆,名扬晋豫,漆匠,席匠,木匠手工精湛!西冶扛妆有史为记:起源于明...
    心洁如玉阅读 1,678评论 1 1
  • 让自己活得开心点,不要被金钱所累。不要被他人所累,不要想的太明白,糊涂一点也行。
    木子兴阅读 91评论 0 0
  • 这个世界很多瑕疵 越说越欲盖弥彰 人海茫茫 高楼俯视 一边利欲熏心 一边绝望。
    穸玥阅读 189评论 5 1