normalplay的地位

流程图如下所示:

整个足球机器人的比赛规则中如果没有发生犯规的话,SOM软件一直执行的就是normalplay脚本。其实,在正常比赛中,因为小型机器人并没有像人一样这么智能,人会自主最大程度上的避免犯规,但是机器不会,所有犯规还是很常见的,甚至可以说在1个小时的比赛中,有半个小时甚至是半个小时以上SOM软件都是在执行犯规脚本,因此normalplay固然重要,但是也要注重其他场景的脚本哦(尤其是角球脚本,这点我会在我的另外一篇博客中进行讲解),接下来我将从task层和skill层来进行normalplay场景的介绍。

Task层

一个Task脚本就是一个有限状态机,Task层可以形象的比喻成策略游戏中的玩家的对抗方法,放一下我的normalplay的Task里面的内容。

gPlayTable.CreatePlay{

firstState = "initState",
 
["initState"] = {
  switch = function()
    if CIsGetBall("Kicker") then
      return "initState"
    end
  end,
  Kicker  = task.KickerTask("superforward"),
  Receiver = task.ReceiverTask("receiverdef"),
  Tier = task.TierTask("tierdef"),
  Goalie  = task.GoalieTask("goalie")
},
 
name = "normalplay_1"
}

其实看我的normalplay的脚本可以发现这个场景里面我的策略很简单,在这个有限状态机中可以看出这个场景一直都是在一个状态中循环进行。仔细看就是我的前锋(Kicker),中场(Receiver),后卫(Tier),守门员(Goalie)一直在执行一个单一的动作,那么这些动作究竟是什么呢?我画一张图帮助大家理解一下。

用语言来表述的话就是守门员在禁区内作为防守的最后一道防线,而中场和后卫一直都贴在禁区线的外侧,作为对抗的第二道防线,守门员,中场和后卫都是会随着球然后前锋一直在外面做抢球->射门这个动作,因为守门员,中场和后卫的动作比较类似,所以我会在我的另外一篇博客作集中讲解,所以接下来我主要讲解前锋的skill思路和实现。 

Skill层

前锋主要有2个技术要点:1是接球路线;2是接球速度和射门动作,我们一个个来讲。

接球路线

首先是接球路线,我先画个示意图。

首先我们可以获取场上数帧里“足球”(也就是高尔夫球,接下来就用高尔夫球来称呼它),获取到了这些高尔夫球的位置之后,我们可以根据最小二乘法来拟合出这些足球的运行轨迹,最小二乘法的拟合示意图如下,可以看出,最小二乘法其实就是把一些离散的点经过数学方法进行拟合之后,找到一条离这些点距离误差最小的直线,因为高尔夫球在场上的运动也是直线的,所以这也就是高尔夫球的运行路径。

那我们得到这个运行路径有什么用呢?再看一下上面那个画了前锋的图,我们已经获得了小球的预期运行轨迹,并且可以根据图像帧与帧之间的时间差来得到小球运动的方向,那么现在我们得到了小球的运行轨迹和方向,接下来我们只需要把前锋的目标位置设定到小球运行的轨迹上而且将持球装置朝向小球来的方向就可以啦。

代码讲解

 这2个函数是为了求出直线y=kx+b里的k,b参数的: