arduino实现一个缓动动画库CxgAnimate

在javascript里有一些动画库,在c和单片机领域内没见过谁做个呼吸灯效果能抽象出,这个过程其实是一个动画。受js动画库animejs启发https://www.animejs.cn/documentation/#gridStaggering, 开发了这个缓动动画库。
缓动动画曲线参考自https://www.xuanfengge.com/easeing/easeing/
一切缓慢改变的动画过程,如呼吸灯渐变,舵机缓慢移动,oled屏幕字符移动等都可以使用动画的思想去实现。
该库仅提供开拓思路的作用。

动画组成要素结构体:


struct CxgAnimateStruct {
  unsigned long lastTickTime = 0;  //上次tick执行时间
  int id = 0;                      //分配的id,一定不会重复
  uint32_t startCount = 0;         //从play开始进行动画tick计数, isKeyFrameMode=true时, 累计帧数, isKeyFrameMode=false时,累计运行时间
  uint16_t durationTime = 0;       //一次动画持续时间
  uint16_t frameIntevalTime = 0;   //动画执行帧时间间隔
  uint16_t loopCount = 1;          //重复执行次数, 0为无限循环
  int8_t direction = 1;            //动画执行方向 1:正向执行,0:往返执行, -1:反向执行
  bool isSuspend = true;           //是否暂停运行, true:暂停, false:执行
  bool isKeyFrameMode = true;      //是否是帧模式 true:帧计数, false:时间计数
  float (*easingFunc)(float x);    //缓动函数, 变化时间比例与改变比例的函数公式 取值范围[0-1]
  void (*setChange)(float x);      //改变函数, 传入改变比例,取值范围[0-1]
  bool (*endCallback)(int id);     //动画执行完成回调, 返回true,立即销毁, 否则一直保留在内存中
};

 

demo:

#include <Arduino.h>
#include "cxg_JSTime.h"
#include "cxg_Animate.h"

//支持arduino uno, stm32, esp32
//测试于arduino uno
JSTime jsTime;
CxgAnimate animate;

//返回一个函数指针的函数
//获取缓动函数
float (*getEasingFunc(int i))(float x) {
  switch(i) {
  case 1:
    return Easings::linear;
    break;
  case 2:
    return Easings::easeInQuad;
    break;
  case 3:
    return Easings::easeOutQuad;
    break;
  case 4:
    return Easings::easeInOutQuad;
    break;
  case 5:
    return Easings::easeInCubic;
    break;
  case 6:
    return Easings::easeOutCubic;
  case 7:
    return Easings::easeInOutCubic;
  case 8:
    return Easings::easeInQuart;
  case 9:
    return Easings::easeOutQuart;
  case 10:
    return Easings::easeInOutQuart;
  case 11:
    return Easings::easeInQuint;
  case 12:
    return Easings::easeOutQuint;
  case 13:
    return Easings::easeInOutQuint;
  case 14:
    return Easings::easeInSine;
  case 15:
    return Easings::easeOutSine;
  case 16:
    return Easings::easeInOutSine;
  case 17:
    return Easings::easeInExpo;
  case 18:
    return Easings::easeOutExpo;
  case 19:
    return Easings::easeInOutExpo;
  case 20:
    return Easings::easeInCirc;
  case 21:
    return Easings::easeOutCirc;
  case 22:
    return Easings::easeInOutCirc;
  case 23:
    return Easings::easeInBack;
  case 24:
    return Easings::easeOutBack;
  case 25:
    return Easings::easeInOutBack;
  case 26:
    return Easings::easeInElastic;
  case 27:
    return Easings::easeOutElastic;
  case 28:
    return Easings::easeInOutElastic;
  case 29:
    return Easings::easeInBounce;
  case 30:
    return Easings::easeOutBounce;
  case 31:
    return Easings::easeInOutBounce;
    break;
  }
  return NULL;
}

int animateId = 0;
int easingId = 0;

void setup() {
  Serial.begin(115200);
  delay(3000);

  //创建一个动画,返回动画的id,如果返回id是0则说明有问题
  //创建成功后不会立即执行,需要调用animate.play或animate.restart来播放动画
  animateId = animate.create(
    //按照动画运行时间比例来执行缓动的动作函数
    [](float x) {
      //计算公式 y=a+(b-a)*x;
      //a:初始值
      //b:终止值
      //x:变化比例
      //y:实际值

      //例如:
      //按照一定规律输出 100HZ-1200HZ 的频率
      // tone(3, 100 + (1200 - 100) * x, 200);
      Serial.print(x);
      Serial.print(",");
    },
    //缓动函数, 内置了一些缓动函数都在Easings下 函数曲线图见: https://easings.net/ https://www.xuanfengge.com/easeing/easeing/
    //横坐标: 动画运行时间比例, 取值范围[0-1] 纵坐标: 返回目标改变比例, 取值范围[0-1]
    Easings::linear,
    //动画执行完毕后的回调, 返回false,该动画一直会保留到内存中,不释放, 返回true或未设置该回调,则释放内存
    [](int id) -> bool {
      easingId++;
      Serial.println("");
      Serial.print("next animate easings: ");
      Serial.println(easingId);
      CxgAnimateStruct* item = animate.getAnimate(id);
      if(item != NULL) {
        if(getEasingFunc(easingId)) {
          item->easingFunc = getEasingFunc(easingId);
          jsTime.setTimeout([]() {
            animate.restart(animateId, 20);
          },
            1000);
        } else {
          //销毁动画
          return true;
        }
      }
      //返回 false,保留该动画不被销毁
      return false;
    },
    //动画持续时间
    1500,
    //动画循环次数, 设置0为无限循环, 往返需要两次才能看出效果
    2,
    //动画执行方向 1:正向执行,0:往返执行, -1:反向执行
    0);

  animate.setKeyFrameMode(animateId, false);
}

void loop() {
  jsTime.refresh();
  animate.refresh();

  // delay(25);//循环模拟超时

  while(Serial.available()) {
    char a = Serial.read();
    if(a == 'a') {
      //延时一段时间运行动画
      animate.restart(animateId, 20);
    }
    if(a == 'b') {
      //延时一段时间运行动画
      animate.play(animateId, 20, true);
    }
    if(a == 'c') {
      //延时一段时间运行动画
      animate.pause(animateId);
    }
  }
}

 

下载见github

https://github.com/chengxg/cxg-arduino-lib

下面是一个简单的示例代码,演示了如何使用Processing和Arduino实现一个名为"点亮灯泡"的小游戏: Arduino端代码: ```arduino const int buttonPin = 2; const int ledPin = 13; void setup() { pinMode(buttonPin, INPUT_PULLUP); pinMode(ledPin, OUTPUT); Serial.begin(9600); } void loop() { int buttonState = digitalRead(buttonPin); // 按下按钮时发送信号给Processing if (buttonState == LOW) { Serial.println("buttonPressed"); digitalWrite(ledPin, HIGH); delay(500); digitalWrite(ledPin, LOW); delay(500); } delay(10); } ``` Processing端代码: ```java import processing.serial.*; Serial arduino; boolean isButtonPressed = false; void setup() { size(200, 200); // 根据需要修改串口号和波特率 arduino = new Serial(this, "COM3", 9600); } void draw() { background(0); // 检测从Arduino发送的按钮状态 while (arduino.available() > 0) { String data = arduino.readStringUntil('\n'); if (data != null) { data = data.trim(); if (data.equals("buttonPressed")) { isButtonPressed = true; } } } // 绘制游戏界面 if (isButtonPressed) { fill(255, 0, 0); ellipse(width/2, height/2, 100, 100); } else { fill(255); ellipse(width/2, height/2, 100, 100); } isButtonPressed = false; } ``` 这个示例中的游戏很简单,当你按下Arduino上的按钮时,Processing中的圆形会变成红色。当你松开按钮时,圆形会变回白色。 要运行这个示例,你需要将一个按钮连接到Arduino的引脚2(buttonPin),并将一个LED连接到引脚13(ledPin)。然后,在Arduino IDE中上传Arduino代码,并在Processing中运行Processing代码。 当你按下按钮时,Arduino会发送一个信号给Processing,Processing会根据接收到的信号来更新游戏界面。这个示例只是一个基础的小游戏,你可以根据需要扩展和改进它。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值