背景
前面游戏场景和视角转换都已经差不多了,接下来进入真正的游戏玩法阶段。原先设计时把方块叠加这块设计的过于复杂了,这次借助gpt对它进行一次大的优化改造。
目标
生成一个“剑诀”,滑动“剑诀”,可在场上进行叠加,剑诀叠满自动出鞘,对所有套在剑诀内的单位造成1点伤害。当前阶段先不产生额外特效。
开发过程
定义:
grid: 技能网格
block: 剑诀(有大概几种 O T F L Z S ,就是俄罗斯方块里面基础形状,目前无长条)
block的坐标gx,gy为网格内的网格(grid)格子数坐标。
1、网格的初始化
BattleGridSystem.initGrid(entity);
在游戏开始前,需要在 10 * 5 的网格中创建一个数组,用于存储方块的状态。可以将数组中的每个元素初始化为 0 或空。
static initGrid(entity: Entity) {
const comp = entity.getComponent(BattleGridComp);
if (comp) {
for (let i = 0; i < ROWS; i++) {
comp.gridData[i] = [];
for (let j = 0; j < COLS; j++) {
comp.gridData[i][j] = 0;
}
}
}
}
2、初始方块的生成
BattleGridSystem.initActiveBlock(entity);
static initActiveBlock(entity: Entity) {
const comp = ooxh.game.entity.getComponent(BattleGridComp);
if (comp) {
comp.activeBlock = new Block()
console.log("原始形状:");
console.log(comp.activeBlock.shape);
this.blockToGrid(comp, comp.activeBlock)
}
}
block是让GPT帮忙写的
class Block {
shape: number[][];
gx: number;
gy: number;
constructor() {
// 随机生成方块形状和颜色
const shapes = [
[[1, 1], [2, 2]],
[[1, 0], [2, 2], [0, 1]],
[[0, 1, 2], [2, 1, 0]],
[[1, 2, 2], [0, 1, 0]],
[[1, 0, 0], [2, 2, 1]],
];
this.shape = shapes[Math.floor(Math.random() * shapes.length)];
// 放到网格的顶部居中位置
this.gx = Math.floor(COLS / 2) - Math.floor(this.shape[0].length / 2);
this.gy = 0;
}
// 方块旋转
rotate() {
const newShape = [];
for (let i = 0; i < this.shape[0].length; i++) {
newShape[i] = [];
for (let j = 0; j < this.shape.length; j++) {
newShape[i][j] = this.shape[this.shape.length - 1 - j][i];
}
}
this.shape = newShape;
}
// 方块移动
move(dx: number, dy: number) {
this.gx += dx;
this.gy += dy;
}
}
3、方块的移动(这里只写了左移)
static blockToLeft() {
const comp = ooxh.game.entity.getComponent(BattleGridComp);
if (comp && comp.activeBlock) {
console.log('blockToLeft')
this.clearOwnGrid(comp)
let _is_can_move = BattleGridSystem.canMove(comp, comp.activeBlock, 1, 0)
if (_is_can_move) {
comp.activeBlock.move(1, 0)
this.blockToGrid(comp, comp.activeBlock)
} else {
console.error('can`t blockToLeft')
comp.gridData = [].concat(comp.tmpGridData) // 恢复成原先的
console.log('恢复成原先的', [].concat(comp.gridData))
}
}
}
4、方块的出击
static checkAndMove(comp) {
let _is_can_move = BattleGridSystem.canMove(comp, comp.activeBlock, 0, 1)
console.log('_is_can_move:' + _is_can_move)
if (_is_can_move) {
comp.activeBlock.move(0, 1);
console.log('block.move(0, 1)')
this.checkAndMove(comp)
} else {
console.log('stop at x:' + comp.activeBlock.x + ' y:' + comp.activeBlock.y)
this.blockToGrid(comp, comp.activeBlock)
console.log("zz场景=============");
if (BattleGridSystem.needChuQiao(comp)) {
console.error("达到临界,出鞘!")
return
}
console.log(comp.gridData);
comp.activeBlock = null
setTimeout(() => {
comp.activeBlock = new Block()
console.log("原始形状:");
console.log(comp.activeBlock.shape);
}, 1000)
}
}
5、查看console,看看数据效果
嘿嘿,有点俄罗斯方块的意思了
接下来就是要把数据层的东西,在视图层给体现出来,因为战斗区域就5*7=35个,为了重复利用就一次性生成好。
static initGrid(entity: Entity) {
let _block_prefab = resources.get("prefabs/battle/blockItem", Prefab)
const comp = entity.getComponent(BattleGridComp);
if (comp) {
for (let i = 0; i < ROWS; i++) {
comp.gridData[i] = [];
for (let j = 0; j < COLS; j++) {
comp.gridData[i][j] = 0;
// 记录到原始坐标里面
let v3pos = v3(200 - (j * 100), -600 + (i * 100), 0)
comp.posMap.set(i + '_' + j, v3pos)
// 记录到节点坐标里面
let _node = instantiate(_block_prefab);
_node.setPosition(v3pos)
_node.active = false
ooxh.game.gridsNode.addChild(_node);
comp.nodeMap.set(i + '_' + j, _node)
}
}
}
}
每次移动时,先用原先的缓动tween移动过去,完成后隐藏,回到原始位置
static tweenMoveBlock(comp, move_y, callback) {
let _s_num = 4;
for (let i = 0; i < 3; i++) {
for (let j = 0; j < COLS; j++) {
let _node = comp.nodeMap.get(i + '_' + j)
if (_node) {
tween(_node).to(0.3, {
position: v3(_node.position.x, _node.position.y + move_y * 100, _node.position.z)
}, { easing: easing.sineOut })
.call(() => {
// 隐藏,恢复到原位置
_node.active = false
_node.setPosition(comp.posMap.get(i + '_' + j))
_s_num--
if (_s_num == 0) {
callback && callback() // 全部完成回调
}
}).start();
}
}
}
}
接着加个伤害(暂时先隐藏)
static attackUnits(comp) {
// 转
let tmp_map = new Map();
for (let [key, _node] of comp.nodeMap.entries()) {
if (_node.active) {
let spacePos = NodeUtil.calculateASpaceToBSpacePos(_node.parent, ooxh.game.mapsNode, _node.position)
tmp_map.set(spacePos.x + '_' + spacePos.y, _node)
}
}
let unitMap = ooxh.game.entity.getComponent(BattleStateComp).unitMap
for (let [key, _node] of unitMap.entries()) {
let _at_grid_node: Node = tmp_map.get(_node.position.x + '_' + _node.position.y)
if (_at_grid_node) {
_node.active = false
}
}
this.clearBlock(comp)
tmp_map = null
}
测试效果
后续还需完善触控和单位显示生命点数
下一个开发计划
添加特效及额外打击特效