0%

退潮计划开发周记 0

0 项目起源

事情是这样的,在几周之前,大学同学开始了以前常常进行的英雄联盟 5v5 活动,某一天,我晚上看着掌上英雄联盟看了很多数据,我和其中一个学长 HG 讨论起来打法、胜率、搭配之类的问题。后来一想,如果可以分析我们的对局数据,会不会发现一些有趣的结论或者帮助我们赛区提升整体水平,于是这个项目就开始了,目前只是做了数据和胜率的相关分析,从分析结果和游戏时的感性感受,大家很容易发现有一些人 很影响游戏的胜负,包括正面和负面,因此 HG 灵光乍现,将本项目成为 退潮计划,网站已经部署:点击访问

1 数据处理

在想起来应该记录一下开发的进度时,退潮计划线上 1.0 版本已经上线了,功能包括 查看重要数据半自动化更新对局记录

重要数据目前每周都会变化,因为当前对局信息较少,每一周比赛之后,各个数据的变化可能都会很大,在做相关分析的时候,对胜率影响更大的因素也会随之变化,举例说明,开发的第一周只有 12 场对局记录,我们最后得出的结论是影响胜率的因素有:伤害转换率、小龙控制率、10-20分钟对位补刀差、KDA 等,而第二周因为打野表现太过出色,野区的影响就大幅上升,而对位补刀差、KDA 等因素就不再重要,随着对局记录的增加以及算法的选择不同,最后的重要数据应该趋于稳定。

1.1 数据收集

退潮计划目前是根据收集到的数据对胜率进行相关分析,分析到底哪些数据对对局的胜负影响更大,所以第一步就是收集数据,在网上查找有没有开放 api,我在几年前也找过相关的东西,印象中国服是没有这种接口的,没想到这么多年也确实没有,后来发现有一篇文章中提到了英雄联盟官网上是有详细的对局记录的,登录之后就可以通过接口获取对局的基本信息,也可以根据接口查找到对局的详细信息。

获取对局列表的接口长这样:https://lol.sw.game.qq.com/lol/api/?c=Battle&a=matchList&areaId=1&accountId=${你的id}

这里的 accountId 可以先在英雄联盟官网登录之后然后访问 https://lol.ams.game.qq.com/lol/Go/dollclip/GetUserGame?actid=12&SearchType=LOLRole&areaid=1 获取,这个接口会返回你登录的这个账户的信息,大概长这样:

1
var J_GetUserGame = {"LOLRole":{"accountId":"你的accountId","result":"0","summonerLevel":"382","summonerName":"你的名字"},"iRet":0,"sMsg":"SUCCESS","version":"1.0"}

将你从这里获取的 accountId 填到前面获取对局列表的 url 里,就可以看到你的对局列表了,当然,这里是要保持登录状态的。

1.2 数据分析

我们找了几个人,讨论我们应该对什么数据进行分析,最终我们确定了十几项比较有用的数据:

  • 胜率
    • 伤害转换率
    • 对位经济差
    • 视野分
    • 场均击杀数
    • 承伤占比
    • 伤害占比
    • KDA
    • 所在队伍控龙率
    • 所在队伍大龙击杀率
    • 所在队伍每场比赛先锋击杀数量
    • 分均对位补刀差

前两周我们对胜率进行相关分析,得出对胜利影响最大的因素,并在网页上对重要数据进行展示,可能是因为数据太少或者方法选择比较简单,前两周得出的结论有点互为因果的意思,比如第一周的数据大致如下:

第一周数据

有几个人是只有参加了少于 3 场比赛的,所以数据可能特别好或者特别不好,除此之外,可以看出来,前几名选手的数据会有 2 - 3 项的数据特别高,第 1 名甚至 4 项数据都特别高。我们得出的结论和模型如下:

预测变量 控制变量 自变量 显著性 △R²
胜率 场均对位经济差 KDA 0.05 0.22
胜率 KDA 场均对位经济差 0.021 0.12
场均对位经济差 KDA 场均对位补刀差(10-20min) 0.101 0.09
场均对位经济差 KDA 先锋小龙控制率 0.131 0.07
胜率 场均对位经济差 场均对位补刀差(10-20min) 先锋小龙控制率 不显著 ——

第一周模型

再来看第二周的数据,第二周数据因为某个科研人员看不懂数据库导致第一次有好看的图和表的数据是有问题的,因此没法展示,最后我们发现第二周的数据和野区有非常大的相关,而且第二周我们感性认识上打野确实表现非常出色。

第一周我们直接用每个数据的 排名进行相加,第二周我们改进为用 标准分 进行排名,这样也可以看出来每个选手的差距有多大。

我们得出的结论也引发我们思考:到底是因为掌控了野区打出了对位经济差还是因为线上有优势才能掌控野区 等一系列鸡蛋问题,这也是我们在后面的分析中需要思考的问题。

2 网站开发

退潮计划网站的开发是跟着数据和功能走的,也就是说我们得到了什么数据、有了什么结论或者需要什么功能就会做相应的页面,前两周的版本包括:重要数据展示 半自动化数据处理

2.1 功能介绍

我在开始规划的时候选用了 node 一套的技术栈,大致为 React + Express + MongoDB,这也是我第一次用这三个东西。

收集数据是在后端用 axios 附带手动加上的 cookie 进行数据爬取并存入 games 集合。收集之后对每一场游戏进行分析,将需要的数据按照选手重新组合存入 players

因为考虑到后面需要用到英雄的数据,所以也顺手给英雄数据存了一个集合 champions,英雄数据的收集是比较简单的,直接从这个 url 就可以获取到英雄的数据:https://game.gtimg.cn/images/lol/act/img/js/heroList/hero_list.js?ts=2759405,我还在网上看见别人分享的可以获取某个英雄详细信息的链接:https://game.gtimg.cn/images/lol/act/img/js/hero/1.js/${英雄ID}.js

重要数据

上图是数据展示的部分,我们对相关分析中得出的重要数据进行标准分的计算并进行表格的展示。

上面也说了,对局信息是需要登录后携带 cookie 才可以获取到的,之前的 cookie 是写在配置文件里的,现在有了网页之后,总不能每次更新系统都去登录服务器然后修改配置文件然后重启一下服务吧,所以需要做一个半自动获取数据的页面,功能就是手动输入 cookie,然后获取数据。还要有一个分析的按钮,因为数据获取完之后,我并没有让他直接开始分析,因为一些 js 的异步编程问题我不太熟悉,可能前面写出来的代码性能并没有那么好,也主要是因为数据获取是需要跟腾讯的服务器进行网络通讯的,如果在收集之后立马进行分析,可能好几秒过去了后端还没有返回结果,这样我们的网页就会出现信息更新不及时等 bug。

2.2 前端鉴权

数据更新页面也不是谁都可以进的,必须只有管理员才可以进,登录的接口我是写在另一个服务中的。这里还需要一个角色管理的功能,我的想法是用一个服务统一管理,需要后面进行更详细的设计。

但是我们这里需要实现一个比较简单的功能:根据网页是否需要登录判断登陆情况,如果登录了就判断是否是管理员,根据是不是管理员做出不同的反应。前端路由我使用了 React Router v6,这个版本的资料属实很少,只能自己拼拼凑凑,最终我使用了 useRoutes 这个 hook,在 src/app/App.js 中注册路由:

1
2
3
4
5
6
7
8
9
10
import { useRoutes } from 'react-router-dom'

import routes from './routes'

function App() {
const element = useRoutes(routes)
return <>{element}</>
}

export default App

注意不要忘了加上 <BrowserRouter><BrowserRouter /> 或者 <HashRouter><HashRouter />,我是加在 src/index.js 中的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'

import './index.css'
import App from './app/App'
import reportWebVitals from './reportWebVitals'

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
)

reportWebVitals()

然后就是配置路由,我写在了 src/app/routes/index.js 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import { Navigate, useNavigate } from 'react-router-dom'

import AppFrame from '../../layout/frame/AppFrame'
import Home from '../pages/Home'
import Login from '../pages/Login'
import Players from '../pages/Players'
import Match from '../pages/Match'
import Games from '../pages/Games'
import Rate from '../pages/Rate'
import Update from '../pages/Update'

import { checkLogin } from '../../utils'

// 用于显示页面标题和鉴权
const TitleAuth = ({ children, title, needLogin, roles }) => {
const navigate = useNavigate()
document.title = `${title} - ⚣ 数据`
// 如果页面需要登录,则判断登录情况
if (needLogin === true) {
const { userInfo, isLogin } = checkLogin()
// 验证登录和角色权限
if (isLogin === false) {
// 如果没有登录,跳转到登录页面
return <Navigate to="/login" />
} else if (roles !== undefined && roles.length !== 0) {
// 如果当前页面有指定权限,则需要验证角色
let check = false
for (let role of userInfo.roles) {
if (roles.includes(role)) {
check = true
}
}
if (!check) {
navigate(-1, { replace: true })
}
}
}
return <div>{children}</div>
}

const element = [
{
path: '/',
element: <AppFrame />,
children: [
{
path: '/home',
element: (
<TitleAuth title="首页">
<Home />
</TitleAuth>
)
},
{
path: '/players',
element: (
<TitleAuth title="重要数据">
<Players />
</TitleAuth>
)
},
{
path: '/update',
element: (
<TitleAuth title="更新数据" needLogin={true} roles={[99]}>
<Update />
</TitleAuth>
)
},
{
path: '/',
element: <Navigate to="/home" />
}
]
},
{
path: '/login',
element: (
<TitleAuth title="登录">
<Login />
</TitleAuth>
)
}
]

export default element

其中 TitleAuth 这个组件是用来进行页面 title 修改并进行鉴权的,这里也给大家提供一个鉴权的思路。

当然,导航栏也需要做相应的修改,可以读取路由的配置然后动态生成导航,也可以手动写判断语句生成导航。

最后做出来的更新页面如下:

更新数据

数据分析

3 后续开发计划

  • 用户登录、权限和角色设计
  • 数据更新更方便的方案(可能从 cookie 的获取入手)
  • 对选手进行组合,查看胜率,找出最佳/拉组合(匹配分析)
  • 根据匹配分析的结果进行更合理的分队
  • 复盘功能(评论和小作文)