
利用S-Function,在simulink中实现了贪吃蛇。
前言
先看看实现的效果吧。

从视频中可以看到,仿真开始后,贪吃蛇开始运动,这是S-Function在发挥作用。
原谅我游戏画面的制作太过敷衍之后,也算得上是S-Function的又一个成功的应用范例了。
关于S-Function,前面已经花了两篇文章进行阐述举例。
土人:S-Function 实现红绿灯''实时仿真''zhuanlan.zhihu.com

上述两篇文章,均使用了Level-1 S-Function,其好处是简单,容易掌握,适合入门,可以调用matlab函数,对于基本的需求应该是够用了。比如这篇,我首先用level-2 S-Function实现了该游戏,后来又用Level-1 S-Function进行了实现,效果一样。但是,不得不指出,相比于Level-2 S-Function,Level-1 S-Function有很多缺陷,比如仅仅支持单个输入输出端口(port),虽然单个端口可以包含多个信号,然而信号不支持多维度;仅支持double数据类型,也就没必要支持代码生成了;不支持DWork向量等等。如果你觉得Level-1 S-Function可能无法助你实现你的策略,可以考虑转向Level-2 S-Function。
游戏制作几点总结:
1,游戏难点
游戏制作中大部分心血并非是码了200多行代码,而花在了比较关键性的地方,比如simulink对键盘的识别。
玩贪吃蛇游戏,需要四个方向,up/down/left/right,当按下键盘时,如何保证simulink识别到方向操控信息呢?
一度被这个问题难倒了。
去google上搜索,发现一种方案是,需要先创建一个figure,然后利用这个figure识别键盘输入。想了想,加入figure后,游戏画面太难看,一点也不简洁,就没有考虑采纳。记不清在google上搜索了几个小时了,无意间搜到了一段代码,对其稍加改动,我觉得很好用,如下所示:
function key=keyboard_check
% key=1 means left ;key=2 means up ;key=3 means right ;key=4 means down
NET.addAssembly('PresentationCore');
akey = System.Windows.Input.Key.A; %use any key to get the enum type
keys = System.Enum.GetValues(akey.GetType); %get all members of enumeration
%keynames = cell(System.Enum.GetNames(akey.GetType))';%right 32 Down 33 Up 31 Left30
iskeyvalid = true(4, 1);
iskeydown = false(4, 1);
for keyidx = 1:4
try
iskeydown(keyidx) = System.Windows.Input.Keyboard.IsKeyDown(keys(keyidx+29));
catch
iskeyvalid(keyidx) = false;
end
end
if iskeydown(1)==1
key=1;
elseif iskeydown(2)==1
key=2;
elseif iskeydown(3)==1
key=3;
elseif iskeydown(4)==1
key=4;
else
key=0;
end
end
2,游戏思路
游戏思路应该很简单了。主要就是利用了set_param和get_param这对好兄弟。
控制贪吃蛇关键在于控制蛇头,而控制蛇头,在于实现转弯。
其实不用管蛇身拐了几个弯啊,蛇头控制好了,那么第二节跟随蛇头就好了,第三节跟随第二节就好了.......对,就是用前一个模块上一个时间步长时位置更新当前时刻后一个模块位置。
3, 游戏改进
使用S-Function的缺陷是,必须在simulink仿真时才能执行,然而仿真进行中,无法使用add_block 向simulink中添加模块。所以,你可以注意到上一个视频左下角,我在初始化的时候,已经添加了一部分的outport模块。这就带来一个问题,如果添加模块较多,可能会导致初始化过程很慢,最终导致游戏体检变差。
后来想到了可以利用定时器timer,定时调用贪吃蛇函数。这样就可以避免上述问题。
mytimer = timer('TimerFcn','GreedySnakeForTimer',...
'StartDelay',0.2,'Period',0.01,'TasksToExecute',50000,'ExecutionMode','fixedSpacing');
start(mytimer);%开启定时器
那么模型不用开启仿真,游戏就可以跑起来了。看下画面,是不是简约了一些呢。

4,总结
这个例子,其实并不是用来说明S-Function有多强大,其实S-Function在这个例子中只是一个“空壳”或者"晶振"罢了,控制算法和S-Function没有什么关系。但是很多时候,就是需要利用S-Function这层壳帮我们做一些事情。