# 足球小将

# 足球小将(一)

# 课程目标

通过趣味练习,来强化对于 JavaScript 的熟悉

练习如何对于问题进行抽象,应用面向对象或者各种设计模式进行问题的解决

# 创建一个足球场

需求

通过 Canvas 或者 SVG 绘制一片绿色矩形,就像是我们从高空俯视绿色草坪足球场看见的一样。

有余力的同学,可以把足球场上的各种边线画上。

设计

应用工厂模式,设计一个生成足球场的类

足球场包括长度,宽度的属性,长度宽度创建时候以模拟真实单位的“米”为参数,同时以容器宽度和高度进行对应换算。

验证 在不同像素高宽的容器中生成同样长宽米的球场,看球场是否进行了对应的自适应变换

在同样像素高宽的容器中,生成不同长宽米的球场

# 创建一个足球运动员

需求

通过 Canvas 或者 SVG 或者 DOM 创建一个足球运动员。

我们将足球运动员抽象为一个实心圆,不需要考虑他的方向问题。

  • 参考 (opens new window) 创建球员的时候,需要将球员创建到某个球场中,球员圆形的大小默认为2米,按照和球场的大小进行对应像素的换算。

球员有很多关于足球运动能力的属性,比如速度,力量,技术,射门等等。我们先添加一个属性,叫做速度。

速度 VNum 为一个在1-99范围内的整数,随机生成。对应物理概念可以假设为:

速度值为 99 的,最高速度为 12米每秒

速度值为 1 的,最高速度为 3米每秒

假设速度值和最高速度是线性关系,我们推导出如下公式:

最高速度VMax = 3 + (VNum - 1) * ( 9 / 98 )

# 让球员跑起来

需求

给球员增加一个方法,奔跑,指定一个终止点(相对于球场左上角的米的坐标),球员向那个终止点跑去。

使用上一个需求中的球员速度,以及和球场实际大小进行计算,模拟一个球员奔跑中,球员圆圈移动的动画。

为了测试方便,再给球员设置一个方法,设定球员所在位置,参数为相对于球场左上角的用米为单位的坐标,需要转换为像素

注意:球员不可能一直按着最高速度进行奔跑,球员有起步,加速到全速,到终点后降速的过程

阅读

设计

根据上面的阅读,实现球员的奔跑方法,球员有起步,逐渐加速,全速,到达终点后,再逐渐降速并继续向前再移动一小段距离

验证

  • 生成一个速度为 100 的球员,奔跑吧
  • 生成一个速度为 1 的球员,奔跑吧
  • 生成好多速度随机的球员,一起跑步比赛吧

# 让球员跑得更真实

需求

我们知道,球员跑步速度不仅仅和最高速度有关系,还和体力,爆发力相关

爆发力强,则加速到最快速度会比较快,体力好,坚持在最高速度会比较久

所以给球员增加这两个属性,然后再让大家奔跑看看

设计

爆发力和体力依然用 1-99 范围内的整数来设定,假设有如下物理意义:

  • 爆发力为 99 表示能够在 1 秒就达到最高速度

  • 爆发力为 1 表示需要 4 秒才能达到最高速度

假设爆发力和需要多长时间达到最高速度是线性关系,请自行推导公式

  • 体力为 99 表示能够在最高速度上坚持 15 秒
  • 体力为 1 表示能够在最高速度上坚持 10 秒 假设体力和能够在最高速度上坚持的时间是线性关系,请自行推导公式

验证

生成不同的怪异数值球员进行比赛吧,也可以根据比赛结果适当调整各种数值的物理计算公式

# 足球小将(二)

# 课程目标

通过趣味练习,来强化对于 JavaScript 的熟悉

持续练习如何对于问题进行抽象,应用面向对象或者各种设计模式进行问题的解决

# 创建一个足球

需求

创建一个足球,用一个圆形表示,足球大小的直径假设为 0.5 米(不太真实,但为了看清),实际显示大小按照球场像素进行对应变化。

足球不妨找一个图片做贴图

足球有一个方法是移动,参数为运动方向、初速度、加速度,先假设足球只在草地平面移动。加速度为全局常量。

验证

创建足球,尝试各种参数的搭配,观察足球在运动场上的运动轨迹。

# 跑向足球

跑向静止的足球

实现运动员跑向足球并停球的行为。

随机生成足球和运动员的位置,然后运动员向足球跑去,直到运动员和足球相接后,运动员和足球停下来

跑向移动的足球

随机生成足球和运动员的位置,并让足球开始移动,接下来让运动员进行一个预判,并开始向足球可能接到的位置跑去,跑的过程中可能需要定期调整运动员奔跑的方向。

# 踢出足球

简单地踢出足球

给足球运动员增加一个踢出足球的方法,参数为期望球运动的方向,期望足球初速度。

我们先简单实现踢出足球的实现,按照给定的参数,踢出足球。

实现以下踢球:

  • 球员在球场中心向球门踢出足球
  • 球员从小禁区向球场中心踢出足球
  • 球员从角球区向点球点踢出足球
  • 球员从大禁区角附近,向球门踢出足球
  • 球员从本方禁区附近向对方半场边线踢出足球

给球员增加两个属性

现在,我们稍微模拟一下真实情况,我们给球员增加两个属性:技术、力量

技术决定运动员踢球方向的准确性和力量控制的准确性,力量决定踢球的最大速度。

两个属性依然都是 1-99 的正整数。

对于力量的设定可以为:

  • 力量为 1 的静止运动员踢出静止足球的最大初速度为 5米/秒
  • 力量为 99 的静止运动员踢出静止足球的最大初速度为 50米/秒
  • 力量和静止态踢出静止足球的最大初速度为线性关系
  • 运动状态的球员可以提升或减小踢出足球的最大初速度,以球员运动方向和踢出足球方向来计算,方向完全相同,加速最大,方向完全相反,减速最大。范围为 -40% 到 40%

对于技术的设定可以为:

  • 技术对于方向及力量的控制符合正态分布
  • 技术值越低,实际踢出的方向越容易出现和期望方向角度偏离的情况
  • 技术值越高,实际踢出的方向越不容易出现和期望方向角度偏离的情况
  • 技术值越低,实际踢出的初速度越容易出现和期望初速度偏离的情况,注意实际初速度不能超过最大初速度
  • 技术值越高,实际踢出的初速度越不容易出现和期望初速度偏离的情况,注意实际初速度不能超过最大初速度
  • 技术值越低,正态分布的方差越大
  • 技术高越低,正态分布的方差越小
  • 技术值与方差大小可以为线性关系,也可以自定义

阅读

实现具体以下内容

  • 在页面中增加一个球员生成器,可以设置球员的各种属性
  • 在页面中可填写球员、球的位置
  • 在页面中可填写球员的动作及对应参数,然后有按钮进行对应动作执行

# 再复杂一些

我们知道,运动员大部分时候是在运动过程中踢球,不同的角度,运动状态,会导致踢出足球的速度,角度都有偏差

静止地踢静止的球

这是我们上面做的情况,所有参数以运动员自身属性来决定

运动地踢静止的球

运动员的运动方向和球需要踢出的方向的夹角,对于最后实际踢出球的方向及初速度有一定影响,我们假设有以下影响,你也可以根据自己经验重新设定这些影响。当然我们更建议你在页面中实现参数的配置,来动态实现参数的调整,并实时进行预览

  • 运动员的运动方向和球需要踢出的方向的夹角,会对方向控制的方差产生一定影响,我们假设夹角为 a(区间为 0° 到 360°)。
  • 假设方向影响因子为 b,这个 b 会对计算概率的方差进行一个乘积的影响,即 方差 = 原方差 * b
  • 夹角 a 为 0° 时候,b = 1(参考值,可自定)
  • 夹角 a 为 180° 时候,b = 2(参考值,可自定)
  • a 与 b 可以为线性关系
  • 对力量的控制同理

静止地踢运动的球

有时候踢侧面来的球,踢出的球大概率会有一个原始方向的偏移,所以球的运动方向也会对踢出球的方向有影响,我们假设影响如下

  • 球原本运动的方向和踢出足球的方向的夹角为 a(区间为 0° 到 360°),踢出方向的正态分布概率密度函数均值 μ 会因为 a 而产生向球运动的方向进行一定量的偏移 c
  • 当 a 为 0° 或者 180° 时,踢出的期望方向不受球的运动方向影响,c 为 0
  • 当 a 为 90° 或者 270° 时,踢出的期望方向最受球的运动方向影响,c 为偏 30°对应的偏差(参考值,可自定)
  • a 与 c 可以为线性关系
  • 计算出 c 后,是否真实产生偏差,还和球员技术相关,根据球员技术,根据正态分布,计算出不会出现偏差 c 的概率,最后实际出现的偏差为 c * (1 - 不会出现偏差的概率)。所以,当球员技术很好时,c 大概率为 0,或者是个极小值,对最后方向影响最小。

运动地踢运动的球

结合上面两者,进行最复杂的踢球的实现,运动的球员踢出运动的球。

实现各种参数的可视化配置,然后不断调参,找到最模拟真实的参数配置吧。

# 足球小将(三)

# 课程目标

通过趣味练习,来强化对于 JavaScript 的熟悉

持续练习如何对于问题进行抽象,应用面向对象或者各种设计模式进行问题的解决

# 课程描述

我们在前两个子任务中完成了运动员的运动,足球的运动,接下来我们来实现具体的足球运动的行为。

# 踢球行为

停球

停球,就是将运动向自己的足球控制在自己的一定范围内。

将上一任务中的踢球封装为父类,停球继承踢球。

我们定义停球的行为,是将足球踢向一个距离自己很近的位置,甚至距离为0。比如:

  • 球员在原地停球时,需要将球停到自己脚下
  • 球员在前插奔跑中停球,需要将球停到自己奔跑方向 2 米远的地方,便于下一步射门
  • 球员在摆脱防守队员中停球,有时候需要将球停到自己当前方向反方向 1 米远的地方,便于摆脱

为了简化需求,我们将停球动作抽象为以下规则:

  • 当球员静止时,球停在原地
  • 当球员运动时,球停到 1 秒后球员在的位置

传球

传球就是将球传给另外一个运动员,依然是继承踢球的父类

最简单的传球,就是看目标运动员在哪里,然后传给他,但在实际比赛中,我们往往会把球传给目标运动员的运动方向,或者躲开防守队员,将球传到空档区域。

为了简化需求,我们将传球抽象为以下规则:

  • 对于传球目标静止的,我们将球直接传给他
  • 对于传球目标在运动中,我们需要通过计算,算好提前量,把球传到目标球员运动方向的前方,正好是目标球员跑到那个位置的时候,球也传到那个位置

带球

带球是不断地踢球的过程,每次踢一小步,让球向前滚动一小段距离,然后奔跑跟上。

我们简化需求,假设带球过程中,触球的频率是固定的,假设每秒触球一次,所以带球过程中,每次触球踢球的距离为,运动员按照当前速度 1 秒后到达的距离。

射门

射门在这其中是最好处理的,朝向球门射去即可。

为了简化射门中的参数传递,我们把射门抽象为以下几种:

  • 射向球门左上角
  • 射向球门左下角
  • 射向球门右上角
  • 射向球门右上角
  • 射向球门正上方
  • 射向球门正下方

验证 如前面的任务,创建一系列的参数可视化配置,及方法执行按钮,验证如上行为的实现和效果验证。

# 提交

把你的代码放在 Github 后进行提交

# 总结

依然把今天的学习用时,收获,问题进行记录