cocos creator |《合成大西瓜》源码 解读

更多源码请扫码关注公众号

编者荐语:

不辜负每一份热爱

以下文章来源于懒惰的An ,作者懒惰的An

懒惰的An

《合成大西瓜》原版开发者,cocos游戏开发小辣鸡,会发一些自己做的游戏源码或功能教程,搬运一些大老的技术分享~因为我比较懒,所以也可能不发~

大家好,我是An~wx公众号也申请了半年了,第一次写文,水平很低,凑活看吧

大西瓜火了,这两天也是在网上看到了各种模仿的大西瓜作品,可能也有朋友想知道这么简单的小游戏是怎么做的,今天我们也来模仿还原一下原版手感的合成大西瓜

正题:

第一步:打开CocosCreator,今天我们用2.4.3来制作

新建工程,导入素材~~

因为是竖屏游戏,Canvas参数设置成720*1288

在Canvas下加入一个新的精灵节点Sprite,size设置成720*1280,命名为BG

再把地板素材拖到BG下面,名字为Floor,在BG新建两个新的单色精灵Sprite节点,大小设置为20*1280,放在背景图片两侧

图片

同时给Floor,WallLeft,WallRight挂上RigidBody刚体组件和PhysicsBoxCollider碰撞器组件,RigidBody组件的Type设置为Static

图片

这样一个场景就做好了

下面做一个水果的预制体

在Canvas下新建一个空节点,用于存放我们下落的水果 名字就叫FruitNode,再新建一个空节点叫TargetFruitNode,用于存放我们当前控制的水果节点,我们从水果素材里随便拿出一个放在FruitNode节点下,改名叫FruitPre,同时给FruitPre加上RigidBody和PhysicalCircleCollider,参数也设置好

图片

还要记得设置好分组 墙壁设置成wall,水果设置成fruit

图片

然后把节点拖到Perfab文件夹里,这样预制体就做好了

图片

然后把场景里的FruitPre删掉

这样基本工作就做好了

下面我们写代码

在scripts创建一个ts脚本,名字为GameManager,脚本设置成单例

  •  
  •  
  •  
  •  
  •  
  •  
  •  
public static Instance: GameManager = null;onLoad () {       if (GameManager.Instance != null) {            GameManager.Instance.destroy();      }              GameManager.Instance = this;             cc.director.getPhysicsManager().enabled = true;//物理游戏,开启物理    }

脚本挂在Canvas上,首先获取到节点和预制体

  •  
  •  
  •  
  •  
  •  
  •  
  •  
@property(cc.Node)fruitNode: cc.Node = null;@property(cc.Node)targetfruitNode: cc.Node = null;@property(cc.Prefab)fruitPre: cc.Prefab = null;targetFruit: cc.Node = null;

然后写第一个方法,在屏幕上方生成一个水果,直接上代码

   

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
createOneFruit(_pos: cc.Vec2) {
   
           let fruit = cc.instantiate(this.fruitPre);//实例化一个预制体                fruit.setParent(this.targetfruitNode)//更改fruit父节点                fruit.setPosition(_pos);//设置坐标                fruit.setScale(0)//出生时scale设置为0                fruit.getComponent(cc.RigidBody).type = cc.RigidBodyType.Static;//刚体类型设置为Static防止下落                fruit.getComponent(cc.PhysicsCircleCollider).radius = 0;//碰撞器半径先设置位0,下落时再改到相应水果大小                fruit.getComponent(cc.PhysicsCircleCollider).apply();//保存碰撞器更改的参数                //水果生成时执行一个缩放动作                cc.tween(fruit)                    .to(0.5, { scale: 1 }, { easing: 'backOut' })                    .call(() => {                            this.targetFruit = fruit;//将我们控制的水果targetFruit设置为刚生成的fruit                    })                    .start()    }

在start()里调用一下

  •  
  •  
  •  
start() {          this.createOneFruit(cc.v2(0,500))    }

运行:

这样只能生成固定的一个水果,我们应该在代码里随意生成我们想要的水果,该怎么写呢。首先声明一个SpriteFrame数组,存放我们所有的水果素材

  •  
  •  
@property(cc.SpriteFrame)Allfruit: cc.SpriteFrame[] = [];

然后改一下生成水果的代码

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
/**     * 生成一个水果/只用于生成上方的水果     * @param _fruitNum 水果类型 0是葡萄 以此类推     * @param _pos 水果生成的位置     */    createOneFruit(_fruitNum: number, _pos: cc.Vec2) {
   
           let fruit = cc.instantiate(this.fruitPre);//实例化一个预制体        fruit.setParent(this.targetfruitNode)//更改fruit父节点                fruit.getComponent(cc.Sprite).spriteFrame = this.Allfruit[_fruitNum];//更改fruit的图片                fruit.getComponent("FruitCollision").fruitNumber = _fruitNum;//fruit碰撞回调脚本,里面有一个当前水果类型 如果是葡萄 fruitNumber为0 用于相同合成检测                fruit.setPosition(_pos);//设置坐标                fruit.setScale(0)//出生时scale设置为0                fruit.getComponent(cc.RigidBody).type = cc.RigidBodyType.Static;//刚体类型设置为Static防止下落                fruit.getComponent(cc.PhysicsCircleCollider).radius = 0;//碰撞器半径先设置位0,下落时再改到相应水果大小                fruit.getComponent(cc.PhysicsCircleCollider).apply();//保存碰撞器更改的参数                //水果生成时执行一个缩放动作                cc.tween(fruit)                    .to(0.5, { scale: 1 }, { easing: 'backOut' })                    .call(() => {                            this.targetFruit = fruit;//将我们控制的水果targetFruit设置为刚生成的fruit                    })                    .start()    }        

继续新建一个InputController脚本 挂在Canvas上 ,该脚本控制水果,点击哪里水果就会移动到那个位置的坐标x,滑动时水果会跟随,松开水果下落

直接上代码

    

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
    touchNum: number = 0;    // LIFE-CYCLE CALLBACKS:
    // onLoad () {}

    start() {
   
           this.openTouch();    }
    // update (dt) {}    openTouch() {
   
           this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);        this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);        this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);        this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);    }    onTouchStart(e) {
   
           if (GameManager.Instance.targetFruit != null) {//检测targetFruit是否为空 空就不执行任何动作            this.touchNum = 1;            let posx = this.node.convertToNodeSpaceAR(e.getLocation()).x;//获取点击位置的x值            let posy = GameManager.Instance.targetFruit.y;//获取上方水果的y值            cc.tween(GameManager.Instance.targetFruit)                .to(0.1, { position: cc.v3(posx, posy, 0) })                .start()        }
    }
    onTouchMove(e) {
   
           if (GameManager.Instance.targetFruit != null) {
   
               this.touchNum = 1;            GameManager.Instance.targetFruit.x = this.node.convertToNodeSpaceAR(e.getLocation()).x; //水果跟随鼠标移动        }    }
    onTouchEnd(e) {
   
           if (GameManager.Instance.targetFruit != null && this.touchNum == 1) { //this.touchNUm 是防止下落位置错误            this.touchNum = 0;            //  给targetFruit重新设置物理参数            //  碰撞器的半径为fruit高度的一半            GameManager.Instance.targetFruit.getComponent(cc.PhysicsCircleCollider).radius = GameManager.Instance.targetFruit.height / 2;            //  保存            GameManager.Instance.targetFruit.getComponent(cc.PhysicsCircleCollider).apply();            //  刚体类型改为动态            GameManager.Instance.targetFruit.getComponent(cc.RigidBody).type = cc.RigidBodyType.Dynamic;            //  给一个初始的下落线速度            GameManager.Instance.targetFruit.getComponent(cc.RigidBody).linearVelocity = cc.v2(0, -800)            //  属性改完后,targetFruit设置为空,防止连续操作            GameManager.Instance.targetFruit = null;            this.scheduleOnce(() => {
   
                   GameManager.Instance.createOneFruit(Math.floor(Math.random() * 5), cc.v2(0, 500));            }, 0.5)        }    }

运行起来:

下面就剩合成方法了,继续搞。。。好累

新建脚本FruitCollision,挂在水果预制体上

    

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
fruitNumber: number = 0;//代表自身是那种类型的水果    returnNumber: boolean = false;    getNumberTime: number = 0;    // LIFE-CYCLE CALLBACKS:    // onLoad () {}    start() {    }    update(dt) {        if (this.returnNumber) {
   
               this.scheduleOnce(() => {
   
                   this.getNumberTime = 0;            }, 0.25)            this.returnNumber = false;        }   }     //  防止多次碰撞     getNumber() {            let ad = this.getNumberTime;            this.getNumberTime++;           this.returnNumber = true;            return ad;      }     onBeginContact(contact, selfCollider, otherCollider) {
   
           if (otherCollider.node.group == "fruit") {
   
               //this.endCtrl = true;            //  只有下方的水果触发碰撞回调            if (selfCollider.node.y < otherCollider.node.y) {
   
                   return            }            //  水果一下落,放在FruitNode节点下            selfCollider.node.parent = cc.find("Canvas/FruitNode");            if (selfCollider.node.getComponent(cc.RigidBody) != null) {
   
                   selfCollider.node.getComponent(cc.RigidBody).angularVelocity = 0;                // 限制一下线速度            }
            let selfNum = this.fruitNumber;            let otherNum = otherCollider.node.getComponent("FruitCollision").fruitNumber;            //  水果类型相同的合成            if (selfNum == otherNum && selfNum < 9 && otherNum < 9) {
   
                   if (selfCollider.node.getComponent("FruitCollision").getNumber() == 0) {
   
                       otherCollider.node.getComponent(cc.PhysicsCircleCollider).radius = 0;                    otherCollider.node.getComponent(cc.PhysicsCircleCollider).apply()                    this.node.getComponent(cc.PhysicsCircleCollider).radius = 0;                    this.node.getComponent(cc.PhysicsCircleCollider).apply();                    cc.tween(selfCollider.node)                        .to(0.1, { position: otherCollider.node.position })                        .call(() => {
   
                               //生成下一个等级的水果                            GameManager.Instance.score += this.fruitNumber + 1;                            GameManager.Instance.createLevelUpFruit(this.fruitNumber + 1, otherCollider.node.position);                            otherCollider.node.active = false;                            selfCollider.node.active = false;                            otherCollider.node.destroy();                            selfCollider.node.destroy();                        })                        .start()                }            } else if (selfNum == otherNum && selfNum == 9 && otherNum == 9) {
   
                   if (selfCollider.node.getComponent("FruitCollision").getNumber() == 0) {
   
                       otherCollider.node.getComponent(cc.PhysicsCircleCollider).radius = 0;                    otherCollider.node.getComponent(cc.PhysicsCircleCollider).apply()                    this.node.getComponent(cc.PhysicsCircleCollider).radius = 0;                    this.node.getComponent(cc.PhysicsCircleCollider).apply();                    cc.tween(selfCollider.node)                        .to(0.1, { position: otherCollider.node.position })                        .call(() => {
   
                               GameManager.Instance.score += this.fruitNumber + 1;                            GameManager.Instance.createLevelUpFruit(this.fruitNumber + 1, otherCollider.node.position);                            otherCollider.node.active = false;                            selfCollider.node.active = false;                            otherCollider.node.destroy();                            selfCollider.node.destroy();                        })                        .start()
                }            }        }    }

再次运行,已经可以合成了,合成更高级的水果我换成了独立的方法 卸载GameManager里

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
/**     * 生成高一级的水果     * @param _fruitNum 水果     * @param _pos 位置     */    createLevelUpFruit(_fruitNum, _pos) {
   
           //AudioManager.Instance.Play(6, false, 1)        let fruit = cc.instantiate(this.fruitPre);        fruit.parent = this.fruitNode;
        fruit.getComponent(cc.Sprite).spriteFrame = this.Allfruit[_fruitNum];        fruit.getComponent("FruitCollision").fruitNumber = _fruitNum;        fruit.position = _pos;        fruit.scale = 0;        fruit.getComponent(cc.RigidBody).linearVelocity = cc.v2(0, -100);        fruit.getComponent(cc.PhysicsCircleCollider).radius = fruit.height / 2;        fruit.getComponent(cc.PhysicsCircleCollider).apply();        cc.tween(fruit)            .to(0.5, { scale: 1 }, { easing: 'backOut' })            .call(() => {
   
                   if (fruit.getComponent(cc.PhysicsCircleCollider) != null) {
   
                       fruit.getComponent(cc.PhysicsCircleCollider).radius = fruit.height / 2;                    fruit.getComponent(cc.RigidBody).type = cc.RigidBodyType.Dynamic;                    fruit.getComponent(cc.PhysicsCircleCollider).apply();                }
            })            .start()
        GameManager.Instance.fruitHeigth = GameManager.Instance.findHighestFruit();
    }

后面红线预警方法,结束检测方法,结束方法, 加分等,我会另外加上并打成压缩包。

可以关注我公众号“懒惰的An” 回复“大西瓜”获取代码

图片

也可以在本公众号回复关键字获取源码:

大西瓜

猜你喜欢

转载自blog.csdn.net/u010799737/article/details/113508485