Processing 状态机应用研究(线性转换)
状态机(State Machine)是一个抽象概念,是一个逻辑严谨的数学抽象。它的这种概念在现实生活中处处都有应用,或者说现实世界就充满状态机。要讨论状态机,就涉及到相关概念,比如:State 状态,Event 事件,Action 动作,Transition 转换。状态机是计算机科学的重要基础概念之一,也可以说是一种总结归纳问题的思想,应用范围非常广泛。[1]
如果要便于理解,那么举灯开关现象的例子是最合适不过的!灯有两种状态:开和关,而状态间的转换是瞬间完成的,由开关动作触发转换,而整个触发转换的过程就是事件,如图:

那么上述就是灯的“状态机”。它描述了灯运行时的情况,有了这个机,那么用程序逻辑就可以很好地解释它,模拟它,不然太过于具象了,很难用逻辑去表示它。
当然状态机还分类别,不同的事物抽象出来的状态机都不尽相同,而且结构都不一样。当然,它也有共通性[2]:
(1)可用“状态”来描述事物,并且任一时刻,事物总是处于一种状态
(2)事物拥有的状态总数是有限的,所以学名成为“有限状态机”(Finite-state machine, FSM)
(3)通过触发事物的某些行为,可以导致事物从一种状态过渡到另一种状态(自动机制)
(4)事物状态变化是有规则的,例如:A状态可以变换到B,B可以变换到C,A却不一定能变换到C
(5)同一种行为,可以将事物从多种状态变成同种状态,但是不能从同种状态变成多种状态
总之,它是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。看一些比较复杂的状态机模型:

<来自百度图片搜索>
笔者才疏学浅,就此对状态机介绍到这,读者感兴趣还想了解可自行查阅相关文档。
既然状态机很重要,那么在Processing的应用中也不可避免地会使用到相关概念和技术。早在2017年笔者就以状态量概念探讨了在Processing程序中的应用,见下文:
https://blog.csdn.net/fddxsyf123/article/details/62848357 ---Processing 状态量控制动画技巧
当然那没有机(系统)的概念。这次就以最简单的一种形式来初探-----线性的状态切换的情况。
情景设计:
【一个装置有三盏灯组成,依次标为A、B、C。只有一个按钮用于转换装置状态,该装置可通过按钮或者自行的触发器依次循环点亮A、B、C三盏灯。】
我们画一张状态机示例:

代码实现
State类:
class State
{
boolean canChange = true;
int temp = 0;
void Enter() {
temp = 0;
println(this.getClass().getName()+" - Enter !");
}
void Update() {
//println(this.getClass().getName()+" - Update !");
temp ++;
}
void Exit() {
println(this.getClass().getName()+" - Exit !");
}
}
设了Enter、Undate、Exit三个方法模拟状态的进入、执行(保持)、退出的过程,还有一个temp变量,只是临时为了调试方便设计的,方便查看Update方法的执行与否。这里其实可以设为抽象类,更科学。
StateMachine类:
class StateMachine
{
State currentState;
State lastState;
StateMachine(State initState)
{
SwitchTo(initState);
}
public void SwitchTo(State newState)
{
if (currentState!=null)
{
this.lastState = currentState;
lastState.Exit();
}
currentState = newState;
currentState.Enter();
}
public void Update()
{
this.currentState.Update();
}
}
存有当前状态和旧时状态,并赋予SwitchTo()、Update()两个方法,依次分别是切换状态方法和执行状态方法。
Operator类:
class Operator
{
public StateMachine stateMachine;
private ArrayList<State> states;
private boolean mousePressedThisFrame = false;
boolean ischecked = false;
Operator()
{
states = new ArrayList<State>();
this.states.add(new StageA());
this.states.add(new StageB());
this.states.add(new StageC());
stateMachine = new StateMachine(states.get(0));
}
void NextStage()
{
if (states.size() > 0)
{
State firstStage = states.remove(0);
states.add(firstStage);
stateMachine.SwitchTo(states.get(0));
}
}
void setChecked()
{
ischecked = true;
}
void Update()
{
if ((mousePressed && !mousePressedThisFrame) || ischecked)
{
mousePressedThisFrame = true;
ischecked = false;
if (stateMachine.currentState.canChange)
{
println("try Change To Next Stage.");
this.NextStage();
}
}
this.stateMachine.Update();
if (!mousePressed && mousePressedThisFrame)
{
mousePressedThisFrame = false;
}
}
}
这是操控的类,顾名思义是操作运行创建好的状态机。成员变量有状态链表、状态机等。还有转换下一个状态NextStage()的具体方法和实时检测刷新的方法Update()。
Light类:
class Light {
int cc;
PVector pos;
int alpha = 0;
boolean isopen;
Light(int _cc, int posx, int posy)
{
cc = _cc; //固定颜色
isopen = false;//默认关的状态
pos = new PVector(posx, posy);
}
//开关
public void update(boolean b)
{
isopen = b;
if( isopen == false ) //如果关了,亮度归位
alpha = 0;
}
//运行时
public void working()
{
if (isopen)
alpha += 1; //如果开着,慢慢变量
alpha = constrain(alpha, 0, 255);
//println(alpha);
}
public void draw()
{
if (isopen)//如果开,慢慢量
{
fill(cc, alpha);
} else//如果关,黑色的
{
fill(20, 250);
}
push();
translate(pos.x, pos.y);
rect(0, 0, 80, 150);//灯的表现形式
pop();
}
}
下面是三个state实现类:
class StageA extends State
{
StageA()
{
}
void Enter()
{
super.Enter();
light1.update(true);
}
void Update()
{
super.Update();
if (temp == 1)
println(this.getClass().getName()+" - Update !");
light1.working();
}
void Exit() {
println(this.getClass().getName()+" - Exit !");
light1.update(false);
}
}
class StageB extends State
{
StageB()
{
}
void Enter()
{
super.Enter();
light2.update(true);
}
void Update()
{
super.Update();
if (temp == 1)
println(this.getClass().getName()+" - Update !");
light2.working();
}
void Exit() {
println(this.getClass().getName()+" - Exit !");
light2.update(false);
}
}
class StageC extends State
{
StageC()
{
}
void Enter()
{
super.Enter();
light3.update(true);
}
void Update()
{
super.Update();
if (temp == 1)
println(this.getClass().getName()+" - Update !");
light3.working();
}
void Exit() {
println(this.getClass().getName()+" - Exit !");
light3.update(false);
}
}
最后是主程序:
Operator operSystem;
float timePassed;
float nextCheckTime;
float lastCheckTime;
float timeLapse = 1500;
Light light1;
Light light2;
Light light3;
void setup()
{
size(600,500);
timePassed = 0;
lastCheckTime = 0;
nextCheckTime = timeLapse*2; //首次计时长一点
light1 = new Light(color(240,20,20),100,100);
light2 = new Light(color(20,240,20),250,100);
light3 = new Light(color(20,20,240),400,100);
operSystem = new Operator();
}
void draw()
{
timePassed = millis() - lastCheckTime;
operSystem.Update(); //“操作系统” 实时运行
light1.draw();
light2.draw();
light3.draw();
//计时器 - 触发(转换)
if(timePassed > nextCheckTime)
{
//println("Check!");
lastCheckTime = millis();
//nextCheckTime = lastCheckTime + timeLapse;
nextCheckTime = timeLapse;
operSystem.setChecked();
}
}
void mouseClicked()
{
}
void keyPressed()
{
}
类的关系图参考:

总结
这是一个很好的有限状态机入门案例,一种线性的状态切换场景。下回我们来看看进一步的状态机,也就是离散的状态切换,其实有点像学数据结构的知识,那个状态机链表我们可以随意设计并调用。相信读者看到这,对状态机有个初步的认识了,并能在实际开发中尝试使用它,希望一切顺利,感谢您的阅读。
参考:
[1] https://zhuanlan.zhihu.com/p/47434856 ---- 什么是状态机
[2] https://www.zhihu.com/question/22363777/answer/652758029 -----什么是状态机?
[3] https://zhuanlan.zhihu.com/p/101020131 一生万物——Processing创意编程碎片
Processing 状态机应用研究(线性转换)的更多相关文章
- Qt状态机框架
The State Machine Framework 状态机框架提供了用于创建和执行状态图的类.概念和符号是基于Harel的Statecharts: A visual formalism for c ...
- 趣说游戏AI开发:对状态机的褒扬和批判
0x00 前言 因为临近年关工作繁忙,已经有一段时间没有更新博客了.到了元旦终于有时间来写点东西,既是积累也是分享.如题目所示,本文要来聊一聊在游戏开发中经常会涉及到的话题--游戏AI.设计游戏AI的 ...
- 基于FPGA的UART协议实现(通过线性序列机)
//////////////////2018/10/15 更新源代码: 实现uart这东西其实早就写了,不过不太完善,对于一个完美主义者来说,必须解决掉它. 1.什么是UART? 通用异 ...
- labview状态机
状态机主要由3部分组成,包括一个while循环,一个条件结构,以及while循环的移位寄存器,其中while循环用于保证程序的持续运行,条件结构用于处理不同状态的执行,移位寄存器用于实现从一个状态跳转 ...
- 通过spring statemmachine 自定义构建属于自己的状态机(两种方式)
spring 的stateMachine 相对于当前的版本,还是比较新颖的,但是对于合适的业务场景,使用起来还是十分的方便的.但是对于官网提供的文档,讲解的是十分的精简,要想更深入的了解其内部架构,只 ...
- matlab神经网络实验
第0节.引例 本文以Fisher的Iris数据集作为神经网络程序的测试数据集.Iris数据集可以在http://en.wikipedia.org/wiki/Iris_flower_data_set ...
- freemodbus-v1.5.0 源码分析
注:转载请注明出处 http://www.cnblogs.com/wujing-hubei/p/5935142.html FreeModbus协议栈作为从机,等待主机传送的数据,当从机接收到一帧完 ...
- 主元分析PCA理论分析及应用
首先,必须说明的是,这篇文章是完完全全复制百度文库当中的一篇文章.本人之前对PCA比较好奇,在看到这篇文章之后发现其对PCA的描述非常详细,因此迫不及待要跟大家分享一下,希望同样对PCA比较困惑的朋友 ...
- CABAC
CABAC(Context-based Adaptive Binary Arithmetic Coding),基于上下文的自适应二进制算术编码.CABAC是H.264/AVC标准中两种熵编码中的一种, ...
随机推荐
- svg & regex
svg & regex https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reg ...
- DOMParser & SVG
DOMParser & SVG js parse html to dom https://developer.mozilla.org/zh-CN/docs/Web/API/DOMParser ...
- js jsonParse
mdn const rx_one = /^[\],:{}\s]*$/; const rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g; // 匹配 ...
- 源码分析:Exchanger之数据交换器
简介 Exchanger是Java5 开始引入的一个类,它允许两个线程之间交换持有的数据.当Exchanger在一个线程中调用exchange方法之后,会阻塞等待另一个线程调用同样的exchange方 ...
- Django和Ueditor自定义存储上传文件的文件名
django台后默认上传文件名 在不使用分布式文件存储系统等第三方文件存储时,django使用默认的后台ImageField和FileField上传文件名默认使用原文件名,当出现同名时会在后面追加下随 ...
- 安装并运行Nacos
方式一:源码或者安装包 一.下载源码或者安装包 git clone https://github.com/alibaba/nacos.git 二.安装 cd nacos/ mvn -Prelease- ...
- 前端问题录——在导入模块时使用'@'时提示"Modile is not installed"
前情提要 为了尽可能解决引用其他模块时路径过长的问题,通常会在 vue.config.js 文件中为 src 目录配置一个别名 '@' configureWebpack: { resolve: { a ...
- 手把手教你手写一个最简单的 Spring Boot Starter
欢迎关注微信公众号:「Java之言」技术文章持续更新,请持续关注...... 第一时间学习最新技术文章 领取最新技术学习资料视频 最新互联网资讯和面试经验 何为 Starter ? 想必大家都使用过 ...
- 你们一般都是怎么进行SQL调优的?MySQL在执行时是如何选择索引的?
前言 过年回来的第二周了,终于有时间继续总结知识了.这次来看一下SQL调优的知识,这类问题基本上面试的时候都会被问到,无论你的岗位是后端,运维,测试等等. 像本文标题中的两个问题,就是我在实际面试过程 ...
- 重复代码的克星,高效工具 VSCode snippets 的使用指南
为什么要用 snippets(代码段)? 不管你使用何种编程语言,在我们日常的编码工作中,都会存在有大量的重复代码编写,例如: 日志打印: console.log,log.info('...') 输出 ...