#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#define OLED_RESET 4
#define SAVE_ADDR 0
Adafruit_SSD1306 oled(OLED_RESET);
#define block_r 16//弧形半径
#define enemy_amount 8
float block_length = 0.5*2*PI;//弧长
float block_deg = 0;//圆弧角度
//---------------------------------------
byte enemy_x[enemy_amount] = {};
byte enemy_y[enemy_amount] = {};//敌人坐标
float enemy_spd[enemy_amount] = {};//敌人速度
byte enemy_state[enemy_amount] = {};//敌人状态
uint32_t last_spawn = 0;
uint32_t start_time = 0;//游戏开始时间
byte life = 3;
unsigned int score = 0;
unsigned int highscore = 0;
void spawn_enemy(byte enemy_idx)//生成敌人--------------------------
{
enemy_spd[enemy_idx] = 2;
//在哪条边上生成
byte place = random(4);
if(place == 0)//left
{
enemy_x[enemy_idx] = 0;
enemy_y[enemy_idx] = 0;//random(64);
}
else if(place == 1)//right
{
enemy_x[enemy_idx] = 127;
enemy_y[enemy_idx] = random(64);
}
else if(place == 2)//up
{
enemy_x[enemy_idx] = random(128);
enemy_y[enemy_idx] = 0;
}
else//down
{
enemy_x[enemy_idx] = random(128);
enemy_y[enemy_idx] = 63;
}
}
float get_angle(float x, float y)//获取角度--------------------------
{
float ang = atan(y/x);
if (x >= 0)
return ang;
else
return ang + PI;
}
void centerDrawText(String text, byte cursor_y, byte f_size)
{
oled.setTextSize(f_size);
oled.setCursor(65 - text.length()*6*f_size/2, cursor_y);//*3 is *6pixel/2
oled.print(text);
}
void control_block()//控制小弧形--------------------------
{
//0~1023--->0~2*PI
float deg = analogRead(A0)/512.0 *2*PI;
if (deg >= 2*PI)
deg -= (2*PI);
block_deg = deg;
for(float i = deg; i <= deg + block_length; i += 0.05)
{
byte x = 64 - cos(i) * block_r;
byte y = 32 - sin(i) * block_r;
oled.drawPixel(x, y, WHITE);//绘制像素
}
}
void draw_time()//绘制时间--------------------------
{
score = (millis() - start_time)/1000;
centerDrawText(String(score), 30, 1);
}
void drawLife()//绘制生命--------------------------
{
for(byte i = 0; i < life; i += 1)
{
oled.drawFastHLine(58 + i * 5, 25, 3, WHITE);
oled.drawFastHLine(58 + i * 5, 26, 3, WHITE);
}
}
void gameOver()//游戏结束--------------------------
{
//最高分
String t = "";
if(score > highscore)
{
highscore = score;
EEPROM.put(SAVE_ADDR, highscore);
t = "NEW HIGHSCORE!";
}
else
{
t = "HIGHSCORE " + String(highscore);
}
//游戏结束转场
oled.setTextColor(BLACK);
for(byte i = 0; i <= 72; i += 6)
{
oled.fillCircle(64, 32, i, WHITE);
centerDrawText("GAME OVER", 10, 1);
centerDrawText(String(score), 25, 2);
centerDrawText(t, 48, 1);
oled.display();
}
delay(500);
//等待输入重新开始
int last_read = analogRead(A0);
while(true)
{
int this_read = analogRead(A0);
byte delta = abs(this_read - last_read);
if(delta >= 10)
{
break;
}
last_read = this_read;
delay(10);
}
//重新开始转场
for(byte i = 0; i <= 72; i += 6)
{
oled.fillCircle(64, 32, i, BLACK);
oled.display();
}
//参数重置
life = 3;
oled.setTextColor(WHITE);
for(byte i = 0; i < enemy_amount; i += 1)
{
enemy_state[i] = 0;//删除所有敌人
}
start_time = millis();
}
void update_enemy(byte enemy_idx)//更新敌人--------------------------
{
//更新坐标
float xx = 64 - enemy_x[enemy_idx];
float yy = 32 - enemy_y[enemy_idx];
float deg = get_angle(xx, yy);
float rr = sqrt(sq(xx) + sq(yy));
float spdx = enemy_spd[enemy_idx] * cos(deg);
float spdy = enemy_spd[enemy_idx] * sin(deg);
enemy_x[enemy_idx] += spdx;
enemy_y[enemy_idx] += spdy;
//检查碰撞
if(deg < 0)
deg += 2 * PI;
if(enemy_state[enemy_idx] == 1)//attack
{
if(rr <= block_r - 2)//in attack range---cant be block any more
enemy_state[enemy_idx] = 2;
else if(rr <= block_r + 2)//can be block
{
if(block_deg + block_length < 2 * PI)
{
if(deg >= block_deg and deg <= block_deg + block_length)
enemy_state[enemy_idx] = 0;
}
else
{
if(deg >= block_deg or deg <= block_deg + block_length - 2* PI)
enemy_state[enemy_idx] = 0;
}
}
}
else if(enemy_state[enemy_idx] == 2)//attack fin
{
if(rr <= 3)
{
enemy_state[enemy_idx] = 0;
life -= 1;
if (life == 0)
gameOver();//game over
}
}
}
///
void setup() {
oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);
oled.clearDisplay();
oled.display();
oled.setTextSize(1);
oled.setTextColor(WHITE);
pinMode(A0, INPUT);//定义电位器为输入
Serial.begin(9600);
randomSeed(analogRead(A1));
for(int i = 0; i < enemy_amount; i += 1)
{
enemy_state[i] = 0;
}
//最高分
EEPROM.get(SAVE_ADDR, highscore);
Serial.print(highscore);
}
void loop() {
oled.clearDisplay();
draw_time();
drawLife();
control_block();
uint32_t this_time = millis();
if (this_time - last_spawn >= 1000)
{
last_spawn = this_time;
for(int i = 0; i < enemy_amount; i += 1)
{
if(enemy_state[i] == 0)
{
spawn_enemy(i);
enemy_state[i] = 1;
break;
}
}
}
for(int i = 0; i < enemy_amount; i += 1)
{
if(enemy_state[i] != 0)
{
update_enemy(i);
oled.drawCircle(enemy_x[i], enemy_y[i], 2, WHITE);
}
}
oled.display();
}