手把手教你实现《花园特工队》的背包整理,附部分源码

今年大热的新玩法 ,小游戏平台上已经很多这类游戏。这次来拆解下背包玩法怎么实现,难度比上次的植物大战僵尸要大一些。那废话不多说,手把手教你实现一个背包整理,这个功能算是整个游戏的核心亮点。还是老规矩,先看效果。因为传不了视频,详细的可以看我的公众号文章:传送门

玩法理解

如果你还不知道这个是怎么实现,或者对这个玩法没有太深的概念,那最简单的办法就是去玩一下这个游戏,就可以总结一些要点。以下是我个人的一些归纳:

1、5*7的网格背包地图(你也可以根据你的需求定义格子数量)

2、默认3*3已经激活可用的网格

3、武器有很多种,相同类型和等级的武器可以合并升级

4、武器栏默认出现三个,还可以出现激活的格子(控制概率,不是每次都出现)

5、新增激活的格子可以拖拽到地图网格上,必须与已有的网格相邻才能合并成新的大网格。

6、任一组合激活格子可以自由放置,但不能超出网格地图,放置会吸附到最近的地图网格上

7、放置的武器时候可以挤下已经占位的武器

8、武器可以随意摆放,也遵循吸附到网格上

9、武器占据的网格大小可以自由定义,根据武器的样式决定

10、放置组合网格会进入编辑网格模式,此时不能放置武器。

以上是一些比较容易总结出来的点,还有一些细节,需要多多体验才能知道,在实现过程中把握细节,我就不一一罗列。

下图是一个游戏模块总览:

下面的讲解围绕几大类来进行:

脚本类

1、基础网格 BagTile

2、组合激活网格 TilePattern

3、武器 Weapon

最基础的就是这三个类。

1b4dc8ee-2c28-43d2-9eb1-723934d07459

图层

1、背包皮肤 BagBackground

2、网格地图 TileContainer

3、主网格 DraggableTile

4、武器图层 WeaponsContainer

5、 新增武器栏 PatternArea

层级关系如下:

屏幕快照 2024-09-06 下午3.38.57

BagBackground 没有太多的逻辑,主要功能是,随着网格大小改变背包的外观。

左边是武器编辑模式,右边是地图网格编辑模式。

从地图编辑模式切换的时候背包大小会发生变化,动态改变这个节点的大小就行。背包的装饰元素,利用Widget组件采用相对定位,就可以做到这种效果。先看下实际效果:

背包的装饰元素有很多,需要一个一个的调试,针对几个角(左上、左下、右上、右下)进行相对定位。另外对齐模式 Align Mode要选择图上那种ALWAYS ,否则装饰元素不会跟随背包大小刷新而变化。

屏幕快照 2024-09-09 上午8.56.12

背包装饰元素

网格

游戏中的主要操作对象,网格有几种显示状态,在逻辑中根据不同的状态改变外观,用来给玩家反馈。

1、可以放置武器(改变节点颜色,绿色可放置)

2、不可放置武器(改变节点颜色,红色不可放置)

3、可以放置网格(绿虚线框)

4、不可以放置网格(红虚线框)

5、普通模式(咖啡色)

6、编辑模式(白色底+黑线框)

网格还要存放一下当前的行列信息,在编码过程中用得到。

网格地图

1、初始化5*7个网格,网格要有间隙

2、新建一个二维数组存放网格是否激活的信息

3、新建一个二维数组存放网格的武器信息

this.activeGridNodeMap = [
    [0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0],
    [0, 1, 1, 1, 0],
    [0, 1, 1, 1, 0],
    [0, 1, 1, 1, 0],
    [0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0]
];
// 武器初始化,没有类型,没有等级
initWeapons(){
    for (let row = 0; row < this.numRows; row++) {
        let weapons = [];
        for (let col = 0; col < this.numCols; col++) {
            weapons.push({type: -1, level: -1})
        }
        this.weaponsMap.push(weapons)
    }
},

具体逻辑就是要围绕上面两个二维数组(实际一个二维数组也够了,就是对象上多几个key),不断的去更新两个二维数组,有任何操作网格、武器、位置的变动都要更新两个二维数组。

基础的网格节点位置是不会变动,可以理解为一个基础锚点,激活的格子锚定底层的网格,武器锚定激活的网格,一共三个层次。

主激活网格

根据activeGridNodeMap信息创建主激活网格,位置信息根据网格大小乘以坐标,可以得到布局。因为激活网格可以移动,为了方便处理,将激活的网格塞进DraggableTile这个节点。DraggableTile的宽高尺寸要根据网格数量动态的调整。根据激活网格信息可以算出DraggableTile边界,同理之前的基础网格地图也有边界。

calculateActiveBound(grid, tileWidth, tileHeight) {
        // 省略算边界的逻辑
        return {
            left: leftBound,
            right: rightBound,
            top: topBound,
            bottom: bottomBound,
            width: rightBound - leftBound,
            height: topBound - bottomBound
        };
    }

那么在移动激活网格的时候,限定DraggableTile不超过边界即可。

需要注意的是,移动DraggableTile时,因为武器也是依附在激活网格上。所以武器图层WeaponsContainer也要跟随一起移动。做法就是给他们绑定同样的事件:

setupDraggableTile() {
        this.draggableTile.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.draggableTile.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.draggableTile.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.draggableTile.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);

        this.weaponsContainer.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.weaponsContainer.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.weaponsContainer.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.weaponsContainer.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
    },

在事件处理的方法里面,同时改变两个节点的position

onTouchMove(event) {
    // 非编辑模式不让拖拽
    if(!this.isGridMapEditing){
        return
    }
    const touchLocation = event.getLocation();
    const delta = touchLocation.sub(this.startTouchPosition);
    const newPosition = this.startTilePosition.add(delta);
    // 限制拖拽范围
    let position = this.clampPosition(newPosition);
    this.draggableTile.position = position
    // 编辑武器模式拖动,武器图层一起动
    this.weaponsContainer.position = position;
},

另外还需要注意的是,因为移动的是DraggableTile节点,它的子网格坐标没有变化。但是子网格对应基础网格地图坐标是发生变化了,因此要更新activeGridNodeMap这个二维数组。

通过DraggableTile的位置偏移量,除以网格的宽高,可以计算出子网格的行列变化大小,方向决定数字的正负。通过换算更新一下activeGridNodeMap。

以上就是主激活网格的大体逻辑。

添加激活网格

![屏幕快照 2024-09-09 上午9.06.37|472x166]

玩家可以对网格地图进行编辑,在武器栏PatternArea会呈现三个图案,最多会出现一个激活网格图案。网格图案类型很多,可以做一个配置表,如下代码。是不是有点像俄罗斯方块啊,对的, 添加激活网格图案就是跟俄罗斯方块一毛一样 。你要是会写俄罗斯方块,这个就是小菜一碟。通过二维数组,创建对应的图案。

export const Patterns = {
    [PatternType.SINGLE]: [
        [1]
    ],
    [PatternType.TWO_TILES]: [
        [1, 1]
    ],
    [PatternType.THREE_TILES]: [
        [1, 1],
        [1, 0]
    ],
    [PatternType.T_SHAPE]: [
        [1, 1, 1],
        [0, 1, 0]
    ],
    [PatternType.FOUR_TILES]: [
        [1, 1],
        [1, 1]
    ],
    [PatternType.L_SHAPE]: [
        [1, 0],
        [1, 0],
        [1, 1]
    ],
    [PatternType.F_SHAPE]: [
        [1, 1],
        [0, 1],
    ],
    [PatternType.ONEV_SHAPE]: [
        [1],
        [1]
    ],
    [PatternType.ONEH_SHAPE]: [
        [1, 1, 1]
    ]
};

然后就是放置图案,逻辑很简单很粗暴。

遍历图案的所有子网格,找到最近的非激活网格,判断条件就是 距离不能超过自己的大小 。如果数量完全找到,说明可以放置,如果找不到则不能放置,同时改变颜色提示玩家该位置可以放置。

需要注意的是,添加激活网格的时候,不能添加武器,二者是互斥的。编辑地图网格的效果如下:

添加武器

添加武器的逻辑跟添加激活网格的逻辑差别不太大。

添加激活网格,落点是在网格地图上,只要满足有空余网格就可以放置。

添加武器,落地是激活网格上,只要激活网格上有满足条件的位置就行。

添加武器的几点细节:

1、相同类型、相同等级的可以合并升级(碰撞检测)

2、不同类型的武器,可以挤下原有位置的武器,被挤下的武器回到待添加区。

3、武器可以放置到任意位置,只要激活网格可以容纳下。

4、武器可以全部放回到待添加区。

基本要处理的就是上面几个要点,首先要给武器定义网格类型

export const WeaponType = {
    wallet: {
        pattern: PatternType.SINGLE // 钱包
    },  
    longSword: {
        pattern: PatternType.ONEV_SHAPE // 长剑
    },
    darts: {
        pattern: PatternType.SINGLE // 飞镖
    },
    dagger:{
        pattern: PatternType.TWO_TILES // 短剑
    },
    gloves: {
        pattern: PatternType.SINGLE // 手套
    },
    bow: {
        pattern: PatternType.ONEV_SHAPE // 弓箭
    },
    blueBottle: {
        pattern: PatternType.ONEV_SHAPE // 蓝
     },
    shield: {
        pattern: PatternType.SINGLE // 盾
    },
    ax: {
        pattern: PatternType.F_SHAPE // 斧头
    },
}

类型跟之前定义的激活网格图案是一样的,在最终渲染的时候,只渲染武器皮肤,把网格的皮肤隐藏掉。本质就是包装了武器信息的激活网格。

每次移动武器,添加武器都需要更新武器的二维数组weaponsMap。

添加武器、升级武器具体效果看下面视频:

以上就是背包玩法的整体思路,说实话二维数组会比较难写一点,但只要拆分好模块,一步一步写下来也是可以的,一些通用的逻辑可以让AI来完成,但是要用AI来完整实现这个,还是不太现实。

《花园特工队》的战斗场景就不展开了,其实跟植物大战僵尸是类似,发射武器,杀掉怪物。有兴趣可以看看我之前写的文章。

PS:游戏中用到的素材来源于网络,仅学习使用。如有侵权请告知

欢迎关注我的公众号【入门游戏开发】,获取更多游戏开发知识和游戏源码,手把手教你做游戏。

2赞

图片看不了

谁把图片404了~~

怎么图裂了

他人可能在国外

图全挂了 大佬

图已经好了