【搬运工】M5StickC手表应用分享-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 3678|回复: 2

【搬运工】M5StickC手表应用分享

[复制链接]
发表于 2019-10-12 11:12 | 显示全部楼层 |阅读模式
    项目地址 https://github.com/phillowcompiler/WatchInvader_M5StickC 321.jpg
    本项目基于M5StickC制作,内置一个打蜜蜂游戏,和基于NTP的时间显示。上传程序前需要更改watchinvader.h文件以下内容
[mw_shl_code=arduino,true]#define SSIDNAME  "your-ssid"
#define WIFIPASS  "your-pass"

#define NTPSERVER "0.cn.pool.ntp.org"
#define TIMEZONE  8 [/mw_shl_code]
在第一次使用时需要按下B按键网络校准时间
312.jpg

再次按下B键回到主页面,A键进入游戏。
游戏通过感应手臂的运动或者按键进行射击,体感只支持MPU6886,否则无法移动。游戏中途是无法退出的。游戏胜利会显示60秒时间,按下B键返回主页(该项目偶尔娱乐一下,不适合日常使用)
123.jpg


具体代码如下:
[mw_shl_code=arduino,true]#include <M5StickC.h>
#include <WiFi.h>
#include "time.h"
#include "watchinvaders.h"

RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;

// Prototype
void enterIntro();
void enterWatch();



// DISPLAY
void clearBuffer(){
  memset((void *)sBuffer, 0, sizeof(sBuffer));
}

void setZeroBuffer(int x, int y, int w, int h){
  byte *p;
  byte c;
  for(int yy = 0; yy < h; yy++){
    for(int xx = 0; xx < w; xx++){
      p = &sBuffer[((y + yy)*WIDTH + x + xx)/8];
      c = (1 << (x+xx)%8);
      if(*p & c){
        *p ^= c;
      }
    }
  }
}

void drawBuffer(int x, int y, int w, int h, byte *in){
  byte *p, *q;
  byte c;
  for(int yy = 0; yy < h; yy++){
    for(int xx = 0; xx < w; xx++){
      p = in + xx + yy/8 * w;
      c = ( *p & (1<<(yy%8)) ) ? 1 : 0;
      q = &sBuffer[((y + yy)*WIDTH + x + xx)/8];
      *q |= (c << (x+xx)%8);
    }
  }
}

void dispBuffer(){
  M5.Lcd.drawXBitmap(4, 4, sBuffer, WIDTH, HEIGHT, TFT_WHITE, BLACK);
}


// GAME
int chkRange(int in, int min, int max){
  if( in < min ){return 0;}
  if( in > max ){return 0;}
  return -1;
}

void drawVaders(){
  T_VADER *v;
  for(int i = 0; i < sVaders.live; i++){
    v = &sVaders.mVader;
    if(v->sts != -1){
      drawBuffer(v->x, v->y, VADERW, VADERH, (byte *)&chrVader[v->sts*VADERW]);
    }
  }
}

void setVaders(){
  T_VADER *v;
  for(int i = 0; i < VADERSNUM; i++){
    v = &sVaders.mVader;
    v->sts = (i%2) ? 4:2;
    v->x = (i%VADERCOL)*(VADERW + VADERMARGIN);
    v->y = ((VADERRAW-1) - i/VADERCOL)*(VADERH + VADERMARGIN) + 8;
  }
  sVaders.live = VADERSNUM;
  sVaders.dir = 1;
  sVaders.current = 0;
  sVaders.turn = 0;
  sVaders.down = 0;
}

void destroyVader(){
  static int count = 0;
  T_VADER *v, *w;
  if(++count < 3){return;}
  count = 0;
  for(int i = 0; i < sVaders.live; i++){
    v = &sVaders.mVader;
    if(v->sts < 9){continue;}
    if(++v->sts < 12){continue;}
    int d = i;
    while(d < sVaders.live - 1){
      v = &sVaders.mVader[d];
      w = &sVaders.mVader[d+1];
      v->sts = w->sts;
      v->x = w->x;
      v->y = w->y;
      d++;
    }
    if(--sVaders.live < 1){
      // GAME WIN
      sMain.mode = MODE_WATCH;
    }
    if(sVaders.current >= sVaders.live){
      sVaders.current = 0;
    }
  }
}

void moveVaders(){
  T_VADER *v;
  v = &sVaders.mVader[sVaders.current];  
  if(v->sts >= 0){
    v->x += sVaders.dir;
    if(v->x <= 0 || v->x >= (WIDTH-VADERW)){sVaders.turn = 1;}
    if(sVaders.down && v->y < HEIGHT-SHIPH-VADERH){v->y += 4;}
          if(v->sts < 9){
                  v->sts ^= 1;
                  if(v->y >= HEIGHT-SHIPH-VADERH){
        if(chkRange(v->x, sShip.x, sShip.x + SHIPW - 1) || chkRange(v->x + VADERW, sShip.x, sShip.x + SHIPW - 1)){
                            //deadShip();
          sMain.mode = MODE_LOSE;
                            return;
        }
                  }
          }
  }
  if(++sVaders.current < sVaders.live){return;}
  sVaders.down = 0;
  if(sVaders.turn){
    sVaders.dir = -sVaders.dir;
    sVaders.turn = 0;
    sVaders.down = 1;
  }
  sVaders.current = 0;
}


void drawShip(){
  drawBuffer(sShip.x, HEIGHT-SHIPH, SHIPW, SHIPH, (byte *)chrShip);
}

void moveShip(){
  float pitch, roll, yaw;
  M5.Mpu6886.getAhrsData(&pitch, &roll, &yaw);
  float dx = 12 * sin(roll/180);
  if(sShip.realx + dx < 0){
      sShip.realx = 0;
  }
  else if(sShip.realx + dx > (WIDTH-SHIPW)){
      sShip.realx = WIDTH-SHIPW;
  }
  else{
      sShip.realx += dx;
  }
  sShip.x = sShip.realx;
}

void launchShoot(){
  if(sShip.shootx >= 0){return;}
  float accX,accY,accZ;
  M5.Mpu6886.getAccelData(&accX,&accY,&accZ);
  //M5.Lcd.setCursor(0, 45);
  //M5.Lcd.printf("%.2f   %.2f   %.2f      ",accX * 1000,accY * 1000, accZ * 1000);
  if(accX*1000 >= 1200 || digitalRead(M5_BUTTON_HOME) == LOW){
    //M5.Lcd.fillScreen(RED);
    //delay(500);
    sShip.shootx = sShip.x + (SHIPW/2);
    sShip.shooty = HEIGHT - SHIPH - 4;
  }
}


void chkShoot(){
  if(sShip.shootx < 0){return;}
  T_VADER *v;
  for( int i = 0; i < VADERSNUM; i++ ){
    v = &sVaders.mVader;
    if(v->sts < 0 || v->sts > 8){continue;}
    if(chkRange(sShip.shootx, v->x, v->x + VADERW) && chkRange(sShip.shooty, v->y, v->y + VADERH)){
        v->sts = 9;
        sShip.shootx = -1;
    }
  }
}

const byte chrShoot [] PROGMEM =  {0x0f,};
void drawShoot(){
  //M5.Lcd.setCursor(0, 45);
  //M5.Lcd.printf("shootx=%d",sShip.shootx);
  if(sShip.shootx < 0){return;}
  sShip.shooty -= 1;
  if(sShip.shooty < 0){sShip.shootx = -1;}
  drawBuffer(sShip.shootx, sShip.shooty, 1, 4, (byte *)chrShoot);
}

void initShip(){
  sShip.x = (WIDTH - SHIPW)/2;
  sShip.realx = (float)sShip.x;
  sShip.shootx = -1;
}

// Move mode
void enterIntro(){
  M5.Lcd.fillScreen(TFT_BLACK);
  M5.Lcd.setTextSize(1);
  M5.Lcd.drawCentreString("WATCH INVADERS",80,15,2);
  M5.Lcd.drawCentreString("PUSH[A] START TO BEAT!",80,50,1);
  M5.Lcd.drawCentreString("PUSH[B] ADJUST BY NTP ",80,60,1);
  //M5.Lcd.setCursor(30,50);
  //M5.Lcd.println("PUSH[A] START TO BEAT!");
  //M5.Lcd.setCursor(30,60);
  //M5.Lcd.println("PUSH[B] NTP ADJUST");
  //clearBuffer();
  //M5.Lcd.drawXBitmap(16, 14, intro, 128, 55, TFT_WHITE, BLACK);
  sMain.entrtime = millis();
  sMain.release = 0;
  sMain.mode = MODE_INTRO;
}

void enterGame(){
  M5.Lcd.fillScreen(TFT_BLACK);
  setVaders();
  initShip();

  while(1){
    if(digitalRead(M5_BUTTON_HOME) ==HIGH && digitalRead(M5_BUTTON_RST) == HIGH){break;}
    delay(10);
  }
  sMain.mode = MODE_GAME;
}

// TIME ADJUST
void getNTP(){
  const char* ssid       = SSIDNAME;
  const char* password   = WIFIPASS;
  int count = 0;
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0,4);
  M5.Lcd.setTextSize(1);
  M5.Lcd.println(" Adjust by NTP");
  M5.Lcd.println(" Wifi Conecting...");

#ifdef SMARTCONFIG
  WiFi.begin();
#else
  WiFi.begin(ssid, password);
#endif

  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      if(++count > 60){
        M5.Lcd.println("No Wifi");
        delay(1000);
        enterIntro();
        return;   
      }
  }
  M5.Lcd.println(" CONNECTED!");
  
  //init and get the time
  configTime(TIMEZONE * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp");
  struct tm timeInfo;
  if (getLocalTime(&timeInfo)) {
    // Set RTC time
    RTC_TimeTypeDef TimeStruct;
    TimeStruct.Hours   = timeInfo.tm_hour;
    TimeStruct.Minutes = timeInfo.tm_min;
    TimeStruct.Seconds = timeInfo.tm_sec;
    M5.Rtc.SetTime(&TimeStruct);

    RTC_DateTypeDef DateStruct;
    DateStruct.WeekDay = timeInfo.tm_wday;
    DateStruct.Month = timeInfo.tm_mon + 1;
    DateStruct.Date = timeInfo.tm_mday;
    DateStruct.Year = timeInfo.tm_year + 1900;
    M5.Rtc.SetData(&DateStruct);
  }

  //disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  delay(2000);
  enterIntro();
}

void enterWatch(){
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextSize(1);
  M5.Lcd.drawCentreString("U Get the Time!",80,15,2);
  M5.Lcd.drawCentreString("PUSH[B] BACK TO TOP ",80,60,1);
  sMain.entrtime = millis();
  sMain.release = 0;
  sMain.mode = MODE_WATCH;
}

void deadShip(){
  for(int i = 9; i < 12; i++){
    setZeroBuffer(sShip.x, HEIGHT-SHIPH, SHIPW, SHIPH);
    drawBuffer(sShip.x, HEIGHT-SHIPH, SHIPW, SHIPH, (byte *)&chrVader[i*VADERW]);
    dispBuffer();
    delay(300);
  }
  M5.Lcd.fillScreen(TFT_BLACK);
  M5.Lcd.setTextSize(1);
  M5.Lcd.drawCentreString("U MISS THE TIME...",80,30,2);
  //M5.Lcd.setCursor(20,45);
  //M5.Lcd.println("PRESS:");
  //M5.Lcd.setCursor(30,60);
  M5.Lcd.drawCentreString("PUSH[B] BACK TO TOP ",80,60,1);
  sMain.entrtime = millis();
  sMain.release = 0;
}


void chkTimeOut(){
  ulong time = millis();
  if(time - sMain.entrtime > 1000*60 || time < sMain.entrtime){
    switch(sMain.mode){
      case MODE_INTRO:
        M5.Axp.ScreenBreath(0);
        esp_light_sleep_start();
        sMain.release = 0;
        M5.Axp.ScreenBreath(8);
        sMain.entrtime = millis();
        break;    // Sleep
      case MODE_WATCH:enterIntro();break;
      case MODE_LOSE:enterIntro();break;
    }
  }
}

void modeIntro(){
  chkTimeOut();
  if(!sMain.release){
          if(digitalRead(M5_BUTTON_HOME) ==HIGH && digitalRead(M5_BUTTON_RST) == HIGH){sMain.release = 1;}
          return;
  }
  if(digitalRead(M5_BUTTON_HOME) == LOW){
    enterGame();
  }//enterGame();}
  if(digitalRead(M5_BUTTON_RST) == LOW){getNTP();}
}

void modeGame(){
  moveShip();
  launchShoot();
  chkShoot();
  moveVaders();
  destroyVader();

  clearBuffer();
  drawVaders();
  drawShip();
  drawShoot();
  dispBuffer();

  /* Mode Chnage? */
  switch(sMain.mode){
    case MODE_WATCH:enterWatch();break;
    case MODE_LOSE:deadShip();break;
  }
}

void modeWatch(){
  chkTimeOut();
  if(!sMain.release){
          if(digitalRead(M5_BUTTON_HOME) ==HIGH && digitalRead(M5_BUTTON_RST) == HIGH){sMain.release = 1;}
          return;
  }
  M5.Rtc.GetTime(&RTC_TimeStruct);
  M5.Lcd.setCursor(35,35);
  M5.Lcd.setTextSize(2);
  M5.Lcd.printf("%02d:%02d:%02d\n",RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes, RTC_TimeStruct.Seconds);
  if(digitalRead(M5_BUTTON_RST) == LOW){enterIntro();}
}

void modeLose(){
  chkTimeOut();
  if(!sMain.release){
          if(digitalRead(M5_BUTTON_HOME) ==HIGH && digitalRead(M5_BUTTON_RST) == HIGH){sMain.release = 1;}
          return;
  }
  if(digitalRead(M5_BUTTON_RST) == LOW){enterIntro();}
}

//
//  Arduino function
//
void setup() {
  // put your setup code here, to run once:
  M5.begin();
  M5.Axp.ScreenBreath(8);
  M5.Mpu6886.Init();
  M5.Lcd.setRotation(1);
  M5.Lcd.fillScreen(BLACK);
  
  M5.Lcd.setTextSize(1);
  //M5.Lcd.setCursor(40, 0, 2);
  //M5.Lcd.println("RTC TEST");
/***
  RTC_TimeTypeDef TimeStruct;
  TimeStruct.Hours   = 18;
  TimeStruct.Minutes = 56;
  TimeStruct.Seconds = 10;
  M5.Rtc.SetTime(&TimeStruct);
  RTC_DateTypeDef DateStruct;
  DateStruct.WeekDay = 3;
  DateStruct.Month = 3;
  DateStruct.Date = 22;
  DateStruct.Year = 2019;
  M5.Rtc.SetData(&DateStruct);
***/
  pinMode(M5_BUTTON_HOME, INPUT);
  pinMode(M5_BUTTON_RST, INPUT);

  gpio_wakeup_enable(GPIO_NUM_37, GPIO_INTR_LOW_LEVEL);
  gpio_wakeup_enable(GPIO_NUM_39, GPIO_INTR_LOW_LEVEL);

  // GPIOをウェイクアップソースとして有効にする
  esp_sleep_enable_gpio_wakeup();

  enterIntro();
}


void loop() {
  switch(sMain.mode){
  case MODE_INTRO:modeIntro();break;
  case MODE_GAME:modeGame();break;
  case MODE_WATCH:modeWatch();break;
  case MODE_LOSE:modeLose();break;
  }
  delay(10);
}[/mw_shl_code]
213.jpg
发表于 2020-1-17 21:08 | 显示全部楼层
谢谢分享!~很棒
发表于 2020-4-10 14:49 | 显示全部楼层
laai 发表于 2020-1-17 21:08
谢谢分享!~很棒

大爷,库文件呢?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-11-30 23:43 , Processed in 0.178023 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表