波次与技能更新

前言

本次更新是敌人的波次和干员撤退、释放技能的更新。下一次是数据库更新。我估计下一周就可以去弄前端了。学学unity,之后再自研引擎。

波次更新

首先我们要配置一些相关数据,并在快照保存中新增加波次下标、当前波次已生成数量、距离下一只生成时间、敌人ID。

Go 复制代码
// Wave 一波敌人的配置
type Wave struct {
	Count       int     // 本波敌人数量
	HP          int32   // 每只敌人血量
	Speed       float64 // 移动速度(格/秒)
	IntervalSec float64 // 同波内相邻两只的出场间隔(秒)
}

// waves 波次表:按顺序生成,全部波次生成完且场上清空才算通关
var waves = []Wave{
	{Count: 3, HP: 100, Speed: 1.2, IntervalSec: 2.0},
	{Count: 5, HP: 120, Speed: 1.4, IntervalSec: 1.5},
}

// 关卡数值(硬编码,暂不读配置表)
const (
	enemyConfigID = 1   // 敌人配置ID(下发 EnemyId 用)
	baseMaxHP     = 1   // 基地生命,漏一只怪即失败
	operatorMaxHP = 100 // 干员血量(当前不会被攻击,仅展示)
	attackRange   = 2.5 // 干员攻击半径(格)
	attackDamage  = 12  // 干员每帧伤害
	deployCost    = 4   // 部署干员消耗
	initCost      = 10  // 开局费用
	maxOperators  = 1   // 场上干员上限

	retreatRefund       = deployCost / 2 // 撤回干员返还的费用
	skillCost           = 3              // 释放技能消耗的费用
	skillCooldownFrames = 15             // 技能冷却(帧)
	skillDamage         = 60             // 技能对射程内敌人造成的一次性伤害
)

按波次表生成敌人,每帧最多生成一只;调用方需持有 r.mu。首先我们要检测当前波次是否小于波次总长,以及这波敌人是否生成完毕。如果都是True则进入下一波。

go 复制代码
for r.waveIndex < len(waves) && r.spawned >= waves[r.waveIndex].Count {
		r.waveIndex++
		r.spawned = 0
	}

如果当前波次大于总长则return。

如果这波敌人没有出完,就先减去一帧时间(0.2s)。减去后,生成的冷却时间没过完(时间>0)也是retuen。否则读取当前波次的数据,生成敌人,重置冷却时间。

Go 复制代码
    w := waves[r.waveIndex]
	r.instanceSeq++
	r.enemies = append(r.enemies, &Enemy{
		InstanceID: r.instanceSeq,
		HP:         w.HP,
		Speed:      w.Speed,
	})
	r.spawned++
	r.spawnTimer = w.IntervalSec

干员撤退与释放技能

撤回干员,要返还部分费用;返回错误码、提示与剩余费用

我们可以直接将第i个干员(要撤退的)以后的位置都向前移动一位,覆盖掉第i个干员。然后返还费用。这个简单

go 复制代码
r.operators = append(r.operators[:i], r.operators[i+1:]...)
r.cost += retreatRefund

释放干员技能:校验在场、冷却与费用,对射程内敌人造成一次性伤害。

先循环检测到对应发干员,然后检测是否能放技能。

go 复制代码
    var op *Operator
	for _, o := range r.operators {
		if o.ID == opID {
			op = o
			break
		}
	}
	if op == nil {
		return codeBadParam, "干员不在场上", r.cost, 0, 0
	}
	if r.frame < op.SkillReadyFrame {
		return codeBadParam, "技能冷却中", r.cost, 0, 0
	}
	if r.cost < skillCost {
		return codeBadParam, "费用不足", r.cost, 0, 0
	}

如果能放,减去对应的费用(暂时用费用代替技能条,方便点),并给予在范围内的敌人伤害。

Go 复制代码
    var damage, hits int32
	for _, e := range r.enemies {
		if e.HP <= 0 {
			continue
		}
		p := pointAtDistance(e.Dist)
		if math.Hypot(p.X-float64(op.X), p.Y-float64(op.Y)) <= attackRange {
			e.HP -= skillDamage
			damage += skillDamage
			hits++
		}
	}

对于客户端的更新,今后就不多说了,因为都是一些简陋的临时测试代码。没什么技术含量。下周见,bey。