JoyStick Shield连接Nokia 5110--Arduino

2023-11-05

SpaceTrash游戏是一个简单的射击游戏,您可以在其中控制宇宙飞船,并通过移动或爆破(使用激光)来避免漂浮在周围的小行星的碰撞。该游戏是u8g2图形库附带的示例,该图形库通常用于连接具有SPI或I2C协议的各种单色8位显示器。

对于此游戏,只需要 3 个操作:

  • 上升
  • 下移
  • 火灾

在默认程序中,游戏使用3个单独的按钮来控制每个动作。但是,对于我们的示例,我们将向上/向下运动与操纵杆连接,按钮 B(最右边的按钮)被指定为射击动作。

组件

  • Arduino Uno
  • JoyStick Shield
  • 诺基亚 5110 显示屏(请注意引脚排列)

请注意诺基亚 5110 显示屏引脚排列,因为有许多可供选择的变体。在本教程中,我们将使用具有以下引脚排列的显示器:

JoyStick Shield:

它增加了一个nRF24L01射频接口和诺基亚5110 LCD接口,便于二次游戏开发。因为这款射频模块性能稳定,支持6合1游戏,让开发者可以自由玩。诺基亚5110 LCD广泛应用于各种开发平台,具有极高的性价比和强大的库支持。 在这里,我们添加了增强的诺基亚5110显示库,包括显示位图,绘制点线圆翻转等。
它还增加了一个蓝牙模块接口, 方便蓝牙无线串行通信, 和一个用于I2C设备连接的I2C通信接口.
同时,JoyStick Shield有一个带按钮的十字形PS2操纵杆。有四个圆形按钮,2个小按钮,为Arduino操纵杆和按钮提供输入扩展。板载滑动开关可在 3.3V 和 5V 之间切换。

规范

  • 与UNO R3和MEGA 2560控制板兼容。
  • 带有操纵杆按钮:X-(连接到A0);Y-(连接到 A1);按钮(连接到 D8)。
  • 4个带盖的圆形按钮:按钮A(D2);按钮 B (D3);按钮 C (D4);按钮 D (D5)。
  • 2个小按钮:按钮E(D6);按钮 F (D7)
  • 滑动开关:控制V端输出电压为3.3V或5V(注:V端也可为操纵杆元件通电)
  • 添加 nRF24L01 接口
  • 添加诺基亚 5110 液晶屏接头
  • 添加蓝牙模块接口

轴操纵杆:

操纵杆的 X 轴电位计连接到 A0。Y 轴电位计连接到 A1。微控制器上的模拟输入读取0-1023范围内的值(对于典型的10位ADC输入)。当控件处于静止状态时,X 轴和 Y 轴控件的读数应约为 512(中点)。移动操纵杆时,一个或两个控件将记录更高或更低的值,具体取决于控件的移动方式。操纵杆还有一个按钮“K”,通过按下操纵杆即可激活。此按钮连接到 D8

按钮:

板上共有 6 个按钮(不包括操纵杆上的按钮),标有 A-F。4个大按钮通常用于上/下/左/右或类似功能。两个较小的按钮通常用于不太常用的功能,例如“选择”或“开始”,因为它们不太容易访问/不太可能被意外按下。所有按钮都有上拉电阻,按下时拉到地。

  • 按钮 A – 连接到 D2
  • 按钮 B – 连接到 D3
  • 按钮 C – 连接到 D4
  • 按钮 D – 连接到 D5
  • 按钮 E – 连接到 D6
  • 按钮 F – 连接到 D7

蓝牙连接器:

RX/TX线路与3.3V和接地一起连接到单独的4引脚母头。这可用于连接 4 针 3.3V 蓝牙设备或其他 TTL 串行设备。

I2C 连接器:

I2C SDA 和 SCL 线路与 5V 和接地一起连接到单独的 4 引脚公头接头。这是对这些线路的正常 A4/A5 位置的补充。这允许轻松连接 I2C 设备。

nRF24L01 连接器:

此连接器允许插入 nRF24L01 射频收发器模块。

2 x 4 母头

  • 接地 – 接地。
  • 可变电流转换器 – 3.3V
  • CLK(CE) (SCLK)– 连接到 D9
  • DIN(DATA) (MOSI)– 连接到 D10
  • D/C(DC) – 连接到 D11
  • RST(REST) – 连接到 D12
  • CE(CS)(SCE) – 连接到 D13

诺基亚 5110 液晶连接器:

此母头连接器设计用于安装最初为诺基亚手机设计的诺基亚 5110 LCD,并提供 48×84 像素矩阵。

此接口占用与 nRF24L01 相同的 D9-D13 引脚,因此不能同时使用两者。如果不使用这些器件中的任何一个,这些引脚可用于通用用途。

修改

打开 下的 SpaceTrash 示例。我们需要进行以下修改:Examples > U8g2 > Games > SpaceTrash

将 u8g2 对象声明为 U8G2_PCD8544_84X48_F_4W_SW_SPI

诺基亚使用PCD8544作为图形驱动程序,以下引脚aa连接在游戏手柄扩展板上。我们将使用软件SPI,因为引脚未连接到Arduino的默认SPI引脚。

U8G2_PCD8544_84X48_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 9, /* data=*/ 10, /* cs=*/ 13, /* dc=*/ 11, /* reset=*/ 12);  // Nokia 5110 Display

按钮设置

我们将使用一个引脚作为操纵杆,另一个引脚用于按钮:(第 237 行)

uint8_t pin_updown = A1;
uint8_t pin_fire = 3;

将使用 A1 引脚,因为它控制操纵杆的 y 轴。

注意:我们将使用pin_updown而不是单独的引脚进行向上和向下,因为操纵杆将能够通过设置阈值覆盖两种状态。

之后,我们将使用模拟读取而不是数字读取来修改运动接口。(1678行)

 if ( analogRead(pin_updown) > 600) {
      y++;
    }
    if ( analogRead(pin_updown) <= 300) {
      y--;
    }

如果宇宙飞船在不接触操纵杆的情况下自行移动,则可以更改向上/向下的阈值。

最终代码:

/*
  SpaceTrash.ino
  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
  Copyright (c) 2016, olikraus@gmail.com
  All rights reserved.
  Redistribution and use in source and binary forms, with or without modification,
  are permitted provided that the following conditions are met:
    Redistributions of source code must retain the above copyright notice, this list
    of conditions and the following disclaimer.
    Redistributions in binary form must reproduce the above copyright notice, this
    list of conditions and the following disclaimer in the documentation and/or other
    materials provided with the distribution.
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <Arduino.h>
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
// U8g2 Contructor
U8G2_PCD8544_84X48_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 9, /* data=*/ 10, /* cs=*/ 13, /* dc=*/ 11, /* reset=*/ 12);  // Nokia 5110 Display
/* button setup for Arduboy Production */
uint8_t pin_updown = A1;
uint8_t pin_fire = 3;
#define ST_FP 4
/* object types */
struct _st_ot_struct
{
  /*
    missle and hit:
      bit 0: player missle and trash
      bit 1: trash, which might hit the player
  */
  uint8_t missle_mask;    /* this object is a missle: it might destroy something if the target is_hit_fn says so */
  uint8_t hit_mask;     /* if missle_mask & hit_mask is != 0  then the object can be destroyed */
  uint8_t points;
  uint8_t draw_fn;
  uint8_t move_fn;
  /* ST_MOVE_FN_NONE, ST_MOVE_FN_X_SLOW */
  uint8_t destroy_fn;   /* object can be destroyed by a missle (e.g. a missle from the space ship) */
  /* ST_DESTROY_FN_NONE, ST_DESTROY_FN_SPLIT */
  uint8_t is_hit_fn;    /* is hit procedure */
  /* ST_IS_HIT_FN_NONE, ST_IS_HIT_BBOX */
  uint8_t fire_fn;
  /* ST_FIRE_FN_NONE, ST_FIRE_FN_X_LEFT */
};
typedef struct _st_ot_struct st_ot;
/*
  objects, which are visible at the play area
*/
struct _st_obj_struct
{
  uint8_t ot;       /* object type: zero means, object is not used */
  int8_t tmp;     /* generic value, used by ST_MOVE_IMPLODE */
  /* absolute position */
  /* LCD pixel position is x>>ST_FP and y>>ST_FP */
  int16_t x, y;
  int8_t x0, y0, x1, y1; /* object outline in pixel, reference point is at 0,0 */
};
typedef struct _st_obj_struct st_obj;
#define ST_DRAW_NONE 0
#define ST_DRAW_BBOX 1
#define ST_DRAW_TRASH1 2
#define ST_DRAW_PLAYER1 3
#define ST_DRAW_TRASH2 4
#define ST_DRAW_PLAYER2 5
#define ST_DRAW_PLAYER3 6
#define ST_DRAW_GADGET 7
#define ST_DRAW_BACKSLASH 8
#define ST_DRAW_SLASH 9
#define ST_DRAW_BIG_TRASH 10
#define ST_MOVE_NONE 0
#define ST_MOVE_X_SLOW 1
#define ST_MOVE_PX_NORMAL 2
#define ST_MOVE_PX_FAST 3
#define ST_MOVE_PLAYER 4
#define ST_MOVE_PY 5
#define ST_MOVE_NY 6
#define ST_MOVE_IMPLODE 7
#define ST_MOVE_X_FAST 8
#define ST_MOVE_WALL 9
#define ST_MOVE_NXPY 10
#define ST_MOVE_NXNY 11
#define ST_IS_HIT_NONE 0
#define ST_IS_HIT_BBOX 1
#define ST_IS_HIT_WALL 2
#define ST_DESTROY_NONE 0
#define ST_DESTROY_DISAPPEAR 1
#define ST_DESTROY_TO_DUST 2
#define ST_DESTROY_GADGET 3
#define ST_DESTROY_PLAYER 4
#define ST_DESTROY_PLAYER_GADGETS 5
#define ST_DESTROY_BIG_TRASH 6
#define ST_FIRE_NONE 0
#define ST_FIRE_PLAYER1 1
#define ST_FIRE_PLAYER2 2
#define ST_FIRE_PLAYER3 3
#define ST_OT_WALL_SOLID 1
#define ST_OT_BIG_TRASH 2
#define ST_OT_MISSLE 3
#define ST_OT_TRASH1 4
#define ST_OT_PLAYER 5
#define ST_OT_DUST_PY 6
#define ST_OT_DUST_NY 7
#define ST_OT_TRASH_IMPLODE 8
#define ST_OT_TRASH2 9
#define ST_OT_PLAYER2 10
#define ST_OT_PLAYER3 11
#define ST_OT_GADGET 12
#define ST_OT_GADGET_IMPLODE 13
#define ST_OT_DUST_NXPY 14
#define ST_OT_DUST_NXNY 15
/*================================================================*/
/* graphics object */
/*================================================================*/
u8g2_t *st_u8g2;
u8g2_uint_t u8g_height_minus_one;
#define ST_AREA_HEIGHT (st_u8g2->height - 8)
#define ST_AREA_WIDTH (st_u8g2->width)
/*================================================================*/
/* object types */
/*================================================================*/
const st_ot st_object_types[] U8X8_PROGMEM =
{
  /* 0: empty object type */
  { 0, 0,  0, ST_DRAW_NONE, ST_MOVE_NONE, ST_DESTROY_DISAPPEAR, ST_IS_HIT_NONE, ST_FIRE_NONE },
  /* 1: wall, player will be destroyed */
  { 2, 1, 30, ST_DRAW_BBOX, ST_MOVE_WALL, ST_DESTROY_DISAPPEAR, ST_IS_HIT_WALL, ST_FIRE_NONE },
  /* ST_OT_BIG_TRASH (2) */
  { 2, 1,  0, ST_DRAW_BIG_TRASH, ST_MOVE_X_SLOW, ST_DESTROY_BIG_TRASH, ST_IS_HIT_BBOX, ST_FIRE_NONE },
  /* 3: simple space ship (player) missle */
  { 1, 0,  0, ST_DRAW_BBOX, ST_MOVE_PX_FAST, ST_DESTROY_DISAPPEAR, ST_IS_HIT_NONE, ST_FIRE_NONE },
  /* ST_OT_TRASH1 (4): trash */
  { 2, 1,  0, ST_DRAW_TRASH1, ST_MOVE_X_SLOW, ST_DESTROY_TO_DUST, ST_IS_HIT_BBOX, ST_FIRE_NONE },
  /* ST_OT_PLAYER (5): player space ship */
  { 0, 2,  0, ST_DRAW_PLAYER1, ST_MOVE_PLAYER, ST_DESTROY_PLAYER, ST_IS_HIT_BBOX, ST_FIRE_PLAYER1 },
  /* ST_OT_DUST_PY (6): Last part of trash  */
  { 0, 0,  0, ST_DRAW_BBOX, ST_MOVE_PY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE },
  /* ST_OT_DUST_NY (7): Last part of trash  */
  { 0, 0,  0, ST_DRAW_BBOX, ST_MOVE_NY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE },
  /* ST_OT_TRASH_IMPLODE (8): trash was hit */
  { 0, 0,  5, ST_DRAW_TRASH1, ST_MOVE_IMPLODE, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE },
  /* ST_OT_TRASH2 (9): trash */
  { 2, 1,  0, ST_DRAW_TRASH2, ST_MOVE_X_SLOW, ST_DESTROY_TO_DUST, ST_IS_HIT_BBOX, ST_FIRE_NONE },
  /* ST_OT_PLAYER2 (10): player space ship+1x enhancement */
  { 0, 2,  0, ST_DRAW_PLAYER2, ST_MOVE_PLAYER, ST_DESTROY_PLAYER_GADGETS, ST_IS_HIT_BBOX, ST_FIRE_PLAYER2 },
  /* ST_OT_PLAYER3 (11): player space ship+2x enhancement */
  { 0, 2,  0, ST_DRAW_PLAYER3, ST_MOVE_PLAYER, ST_DESTROY_PLAYER_GADGETS, ST_IS_HIT_BBOX, ST_FIRE_PLAYER3 },
  /* ST_OT_GADGET (12): adds enhancements */
  { 0, 1,  0, ST_DRAW_GADGET, ST_MOVE_X_FAST, ST_DESTROY_GADGET, ST_IS_HIT_BBOX, ST_FIRE_NONE },
  /* ST_OT_GADGET_IMPLODE (13) */
  { 0, 0, 20, ST_DRAW_GADGET, ST_MOVE_IMPLODE, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE },
  /* ST_OT_DUST_NXPY (14): Last part of trash  */
  { 0, 0,  0, ST_DRAW_BACKSLASH, ST_MOVE_NXPY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE },
  /* ST_OT_DUST_NXNY (15): Last part of trash  */
  { 0, 0,  0, ST_DRAW_SLASH, ST_MOVE_NXNY, ST_DESTROY_NONE, ST_IS_HIT_NONE, ST_FIRE_NONE },
};
/*================================================================*/
/* list of all objects on the screen */
/*================================================================*/
/* use AVR RAMEND constant to derive the number of allowed objects */
#if RAMEND < 0x300
#define ST_OBJ_CNT 25
#else
//#define ST_OBJ_CNT 45
#define ST_OBJ_CNT 60
#endif
st_obj st_objects[ST_OBJ_CNT];
/*================================================================*/
/* about players space ship*/
/*================================================================*/
/* player position */
uint8_t st_player_pos;
/* points */
#define ST_POINTS_PER_LEVEL 25
uint16_t st_player_points;
uint16_t st_player_points_delayed;
uint16_t st_highscore = 0;
/*================================================================*/
/* overall game state */
/*================================================================*/
#define ST_STATE_PREPARE 0
#define ST_STATE_IPREPARE 1
#define ST_STATE_GAME 2
#define ST_STATE_END 3
#define ST_STATE_IEND 4
uint8_t st_state = ST_STATE_PREPARE;
/*================================================================*/
/* game difficulty */
/*================================================================*/
uint8_t st_difficulty = 1;
#define ST_DIFF_VIS_LEN 30
#define ST_DIFF_FP 5
uint16_t st_to_diff_cnt = 0;
/*================================================================*/
/* bitmaps */
/*================================================================*/
const uint8_t st_bitmap_player1[]  =
{
  /* 01100000 */ 0x060,
  /* 11111000 */ 0x0f8,
  /* 01111110 */ 0x07e,
  /* 11111000 */ 0x0f8,
  /* 01100000 */ 0x060
};
const uint8_t st_bitmap_player2[] =
{
  /* 01100000 */ 0x060,
  /* 01111100 */ 0x078,
  /* 01100000 */ 0x060,
  /* 11100000 */ 0x0e0,
  /* 11111000 */ 0x0f8,
  /* 01111110 */ 0x07e,
  /* 11111000 */ 0x0f8,
  /* 01100000 */ 0x060
};
const uint8_t st_bitmap_player3[] =
{
  /* 01100000 */ 0x060,
  /* 01111100 */ 0x078,
  /* 01100000 */ 0x060,
  /* 11100000 */ 0x0e0,
  /* 11111000 */ 0x0f8,
  /* 01111110 */ 0x07e,
  /* 11111000 */ 0x0f8,
  /* 11100000 */ 0x0e0,
  /* 01100000 */ 0x060,
  /* 01111100 */ 0x078,
  /* 01100000 */ 0x060
};
const uint8_t st_bitmap_trash_5x5_1[] =
{
  /* 01110000 */ 0x070,
  /* 11110000 */ 0x0f0,
  /* 11111000 */ 0x0f8,
  /* 01111000 */ 0x078,
  /* 00110000 */ 0x030,
};
const uint8_t st_bitmap_trash_5x5_2[] =
{
  /* 00110000 */ 0x030,
  /* 11111000 */ 0x0f8,
  /* 11111000 */ 0x0f8,
  /* 11110000 */ 0x0f0,
  /* 01110000 */ 0x070,
};
const uint8_t st_bitmap_trash_7x7[] =
{
  /* 00111000 */ 0x038,
  /* 01111100 */ 0x07c,
  /* 11111100 */ 0x0fc,
  /* 11111110 */ 0x0fe,
  /* 11111110 */ 0x0fe,
  /* 01111110 */ 0x07e,
  /* 01111000 */ 0x078,
};
const uint8_t st_bitmap_gadget[] =
{
  /* 01110000 */ 0x070,
  /* 11011000 */ 0x0d8,
  /* 10001000 */ 0x088,
  /* 11011000 */ 0x0d8,
  /* 01110000 */ 0x070,
};
/*================================================================*/
/* forward definitions */
/*================================================================*/
uint8_t st_rnd(void) U8X8_NOINLINE;
static st_obj *st_GetObj(uint8_t objnr) U8X8_NOINLINE;
uint8_t st_GetMissleMask(uint8_t objnr);
uint8_t st_GetHitMask(uint8_t objnr);
int8_t st_FindObj(uint8_t ot) U8X8_NOINLINE;
void st_ClrObjs(void) U8X8_NOINLINE;
int8_t st_NewObj(void) U8X8_NOINLINE;
uint8_t st_CntObj(uint8_t ot);
uint8_t st_CalcXY(st_obj *o) U8X8_NOINLINE;
void st_SetXY(st_obj *o, uint8_t x, uint8_t y) U8X8_NOINLINE;
void st_FireStep(uint8_t is_auto_fire, uint8_t is_fire) U8X8_NOINLINE;
void st_InitTrash(uint8_t x, uint8_t y, int8_t dir);
void st_NewGadget(uint8_t x, uint8_t y);
void st_NewPlayerMissle(uint8_t x, uint8_t y) ;
void st_NewTrashDust(uint8_t x, uint8_t y, int ot);
void st_NewTrashDustAreaArgs(int16_t x, int16_t y, int ot);
void st_SetupPlayer(uint8_t objnr, uint8_t ot);
/*================================================================*/
/* utility functions */
/*================================================================*/
char st_itoa_buf[12];
char *st_itoa(unsigned long v)
{
  volatile unsigned char i = 11;
  st_itoa_buf[11] = '\0';
  while ( i > 0)
  {
    i--;
    st_itoa_buf[i] = (v % 10) + '0';
    v /= 10;
    if ( v == 0 )
      break;
  }
  return st_itoa_buf + i;
}
uint8_t st_rnd(void)
{
  return rand();
}
/*
  for the specified index number, return the object
*/
static st_obj *st_GetObj(uint8_t objnr)
{
  return st_objects + objnr;
}
/*
  check, if this is a missle-like object (that is, can this object destroy something else)
*/
uint8_t st_GetMissleMask(uint8_t objnr)
{
  st_obj *o = st_GetObj(objnr);
  return u8x8_pgm_read(&(st_object_types[o->ot].missle_mask));
}
/*
  check, if this is a missle-like object (that is, can this object destroy something else)
*/
uint8_t st_GetHitMask(uint8_t objnr)
{
  st_obj *o = st_GetObj(objnr);
  return u8x8_pgm_read(&(st_object_types[o->ot].hit_mask));
}
/*
  search an empty object
*/
int8_t st_FindObj(uint8_t ot)
{
  int8_t i;
  for ( i = 0; i < ST_OBJ_CNT; i++ )
  {
    if ( st_objects[i].ot == ot )
      return i;
  }
  return -1;
}
/*
  delete all objects
*/
void st_ClrObjs(void)
{
  int8_t i;
  for ( i = 0; i < ST_OBJ_CNT; i++ )
    st_objects[i].ot = 0;
}
/*
  search an empty object
*/
int8_t st_NewObj(void)
{
  int8_t i;
  for ( i = 0; i < ST_OBJ_CNT; i++ )
  {
    if ( st_objects[i].ot == 0 )
      return i;
  }
  return -1;
}
/*
  count number of objectes of the provided type
  st_CntObj(0) will return the number of empty objects, that means if
  st_CntObj(0) > 0 then st_NewObj() will return  a valid index
*/
uint8_t st_CntObj(uint8_t ot)
{
  uint8_t i;
  uint8_t cnt = 0;
  for ( i = 0; i < ST_OBJ_CNT; i++ )
  {
    if ( st_objects[i].ot == ot )
      cnt++;
  }
  return cnt;
}
/*
  calculate the pixel coordinates of the reference point of an object
  return rhe x value
*/
uint8_t st_px_x, st_px_y; /* pixel within area */
uint8_t st_CalcXY(st_obj *o)
{
  //st_obj *o = st_GetObj(objnr);
  st_px_y = o->y >> ST_FP;
  st_px_x = o->x >> ST_FP;
  return st_px_x;
}
void st_SetXY(st_obj *o, uint8_t x, uint8_t y)
{
  o->x = ((int16_t)x) << ST_FP;
  o->y = ((int16_t)y) << ST_FP;
}
/*
  calculate the object bounding box and place it into some global variables
*/
int16_t st_bbox_x0, st_bbox_y0, st_bbox_x1, st_bbox_y1;
void st_CalcBBOX(uint8_t objnr)
{
  st_obj *o = st_GetObj(objnr);
  st_bbox_x0 = (uint16_t)(o->x >> ST_FP);
  st_bbox_x1 = st_bbox_x0;
  st_bbox_x0 += o->x0;
  st_bbox_x1 += o->x1;
  st_bbox_y0 = (uint16_t)(o->y >> ST_FP);
  st_bbox_y1 = st_bbox_y0;
  st_bbox_y0 += o->y0;
  st_bbox_y1 += o->y1;
}
/*
  clip bbox with the view window. requires a call to st_CalcBBOX
  return 0, if the bbox is totally outside the window
*/
uint8_t st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1;
uint8_t st_ClipBBOX(void)
{
  if ( st_bbox_x0 >= ST_AREA_WIDTH )
    return 0;
  if ( st_bbox_x0 >= 0 )
    st_cbbox_x0  = (uint16_t)st_bbox_x0;
  else
    st_cbbox_x0 = 0;
  if ( st_bbox_x1 < 0 )
    return 0;
  if ( st_bbox_x1 < ST_AREA_WIDTH )
    st_cbbox_x1  = (uint16_t)st_bbox_x1;
  else
    st_cbbox_x1 = ST_AREA_WIDTH - 1;
  if ( st_bbox_y0 >= ST_AREA_HEIGHT )
    return 0;
  if ( st_bbox_y0 >= 0 )
    st_cbbox_y0  = (uint16_t)st_bbox_y0;
  else
    st_cbbox_y0 = 0;
  if ( st_bbox_y1 < 0 )
    return 0;
  if ( st_bbox_y1 < ST_AREA_HEIGHT )
    st_cbbox_y1  = (uint16_t)st_bbox_y1;
  else
    st_cbbox_y1 = ST_AREA_HEIGHT - 1;
  return 1;
}
/*================================================================*/
/* universal member functions */
/*================================================================*/
uint8_t st_IsOut(uint8_t objnr)
{
  st_CalcBBOX(objnr);
  if ( st_bbox_x0 >= ST_AREA_WIDTH )
    return 1;
  if ( st_bbox_x1 < 0 )
    return 1;
  if ( st_bbox_y0 >= ST_AREA_HEIGHT )
    return 1;
  if ( st_bbox_y1 < 0 )
    return 1;
  return 0;
}
void st_Disappear(uint8_t objnr)
{
  st_obj *o = st_GetObj(objnr);
  st_player_points += u8x8_pgm_read(&(st_object_types[o->ot].points));
  o->ot = 0;
}
/*================================================================*/
/* type dependent member functions */
/*================================================================*/
void st_Move(uint8_t objnr)
{
  st_obj *o = st_GetObj(objnr);
  switch (u8x8_pgm_read(&(st_object_types[o->ot].move_fn)))
  {
    case ST_MOVE_NONE:
      break;
    case ST_MOVE_X_SLOW:
      o->x -= (1 << ST_FP) / 8;
      o->x -= st_difficulty;
      o->y += (int16_t)o->tmp;
      if ( o->y >= ((ST_AREA_HEIGHT - 1) << ST_FP) || o->y <= 0 )
        o->tmp = - o->tmp;
      break;
    case ST_MOVE_X_FAST:
      o->x -= (1 << ST_FP) / 2;
      o->y += (int16_t)o->tmp;
      if ( o->y >= ((ST_AREA_HEIGHT - 1) << ST_FP) || o->y <= 0 )
        o->tmp = - o->tmp;
      break;
    case ST_MOVE_PX_NORMAL:
      o->x += (1 << ST_FP) / 4;
      break;
    case ST_MOVE_PX_FAST:
      o->x += (1 << ST_FP);
      break;
    case ST_MOVE_PLAYER:
      o->y = st_player_pos << ST_FP;
      break;
    case ST_MOVE_PY:
      o->y += 3 * ST_FP;
      break;
    case ST_MOVE_NY:
      o->y -= 3 * ST_FP;
      break;
    case ST_MOVE_NXPY:
      o->y += 3 * ST_FP;
      o->x -= 3 * ST_FP;
      break;
    case ST_MOVE_NXNY:
      o->y -= 3 * ST_FP;
      o->x -= 3 * ST_FP;
      break;
    case ST_MOVE_IMPLODE:
      o->tmp++;
      if ( (o->tmp & 0x03) == 0 )
      {
        if ( o->x0 != o->x1 )
          o->x0++;
        else
          st_Disappear(objnr);
      }
      break;
    case ST_MOVE_WALL:
      o->x -= 1;
      o->x -= (st_difficulty >> 1);
      break;
  }
}
void st_DrawBBOX(uint8_t objnr)
{
  uint8_t y0, y1;
  /*st_obj *o = st_GetObj(objnr);*/
  st_CalcBBOX(objnr);
  if ( st_ClipBBOX() == 0 )
    return;
  /* st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1; */
  // w = st_cbbox_x1-st_cbbox_x0;
  // w++;
  // h = st_cbbox_y1-st_cbbox_y0;
  // h++;
  //dog_SetVLine(st_cbbox_x0, st_cbbox_y0, st_cbbox_y1);
  //dog_SetVLine(st_cbbox_x1, st_cbbox_y0, st_cbbox_y1);
  //dog_SetHLine(st_cbbox_x0, st_cbbox_x1, st_cbbox_y0);
  //dog_SetHLine(st_cbbox_x0, st_cbbox_x1, st_cbbox_y1);
  u8g2_SetDrawColor(st_u8g2, 1);
  y0 = u8g_height_minus_one - st_cbbox_y0;
  y1 = u8g_height_minus_one - st_cbbox_y1;
  u8g2_DrawFrame(st_u8g2, st_cbbox_x0, y1, st_cbbox_x1 - st_cbbox_x0 + 1, y0 - y1 + 1);
  //dog_SetBox(st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1);
  /*
    if ( o->ot == ST_OT_PLAYER )
    {
    dog_DrawStr(0, 26, font_4x6, st_itoa(st_cbbox_y0));
    dog_DrawStr(10, 26, font_4x6, st_itoa(st_cbbox_y1));
    }
  */
}
#ifdef FN_IS_NOT_IN_USE
void st_DrawFilledBox(uint8_t objnr)
{
  st_CalcBBOX(objnr);
  if ( st_ClipBBOX() == 0 )
    return;
  /* st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1; */
  dog_SetBox(st_cbbox_x0, st_cbbox_y0, st_cbbox_x1, st_cbbox_y1);
}
#endif
void st_DrawBitmap(uint8_t objnr, const uint8_t * bm, uint8_t w, uint8_t h)
{
  /* st_obj *o = st_GetObj(objnr); */
  st_CalcBBOX(objnr);
  /* result is here: int16_t st_bbox_x0, st_bbox_y0, st_bbox_x1, st_bbox_y1 */
  //dog_SetBitmapP(st_bbox_x0,st_bbox_y1,bm,w,h);
  u8g2_DrawBitmap(st_u8g2, st_bbox_x0, u8g_height_minus_one - st_bbox_y1, (w + 7) / 8, h, bm);
}
void st_DrawObj(uint8_t objnr)
{
  st_obj *o = st_GetObj(objnr);
  switch (u8x8_pgm_read(&(st_object_types[o->ot].draw_fn)))
  {
    case ST_DRAW_NONE:
      break;
    case ST_DRAW_BBOX:
      st_DrawBBOX(objnr);
      break;
    case ST_DRAW_TRASH1:
      st_DrawBitmap(objnr, st_bitmap_trash_5x5_1, o->x1 - o->x0 + 1, 5);
      break;
    case ST_DRAW_TRASH2:
      st_DrawBitmap(objnr, st_bitmap_trash_5x5_2, o->x1 - o->x0 + 1, 5);
      break;
    case ST_DRAW_BIG_TRASH:
      st_DrawBitmap(objnr, st_bitmap_trash_7x7, o->x1 - o->x0 + 1, 7);
      break;
    case ST_DRAW_PLAYER1:
      st_DrawBitmap(objnr, st_bitmap_player1, 7, 5);
      break;
    case ST_DRAW_PLAYER2:
      st_DrawBitmap(objnr, st_bitmap_player2, 7, 8);
      break;
    case ST_DRAW_PLAYER3:
      st_DrawBitmap(objnr, st_bitmap_player3, 7, 11);
      break;
    case ST_DRAW_GADGET:
      /* could use this proc, but... */
      /* st_DrawBitmap(objnr, st_bitmap_gadget,o->x1-o->x0+1, 5); */
      /* ... this one looks also funny. */
      st_DrawBitmap(objnr, st_bitmap_gadget, 5, 5);
      break;
    case ST_DRAW_BACKSLASH:
      {
        uint8_t x;
        uint8_t y;
        x = st_CalcXY(o);
        y = st_px_y;
        // dog_SetPixel(x,y);
        // x++; y--;
        // dog_SetPixel(x,y);
        // x++; y--;
        // dog_SetPixel(x,y);
        u8g2_SetDrawColor(st_u8g2, 1);
        u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y);
        x++; y--;
        u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y);
        x++; y--;
        u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y);
      }
      break;
    case ST_DRAW_SLASH:
      {
        uint8_t x;
        uint8_t y;
        x = st_CalcXY(o);
        y = st_px_y;
        // dog_SetPixel(x,y);
        // x++; y++;
        // dog_SetPixel(x,y);
        // x++; y++;
        // dog_SetPixel(x,y);
        u8g2_SetDrawColor(st_u8g2, 1);
        u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y);
        x++; y++;
        u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y);
        x++; y++;
        u8g2_DrawPixel(st_u8g2, x, u8g_height_minus_one - y);
      }
      break;
  }
}
uint8_t st_IsHitBBOX(uint8_t objnr, uint8_t x, uint8_t y)
{
  st_CalcBBOX(objnr);
  if ( st_ClipBBOX() == 0 )
    return 0; /* obj is outside (not visible) */
  if ( x < st_cbbox_x0 )
    return 0;
  if ( x > st_cbbox_x1 )
    return 0;
  if ( y < st_cbbox_y0 )
    return 0;
  if ( y > st_cbbox_y1 )
    return 0;
  return 1;
}
void st_Destroy(uint8_t objnr)
{
  int8_t nr;
  st_obj *o = st_GetObj(objnr);
  switch (u8x8_pgm_read(&(st_object_types[o->ot].destroy_fn)))
  {
    case ST_DESTROY_NONE:      /* only usefull for missels or walls which stay alife */
      break;
    case ST_DESTROY_DISAPPEAR:  /* this should be the default operation */
      st_Disappear(objnr);
      break;
    case ST_DESTROY_GADGET:
      nr = st_FindObj(ST_OT_PLAYER2);
      if ( nr >= 0 )
        st_SetupPlayer(nr, ST_OT_PLAYER3);
      else
      {
        nr = st_FindObj(ST_OT_PLAYER);
        if ( nr >= 0 )
          st_SetupPlayer(nr, ST_OT_PLAYER2);
      }
      st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_PY);
      st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_NY);
      o->ot = ST_OT_GADGET_IMPLODE;
      o->tmp = 0;
      break;
    case ST_DESTROY_TO_DUST:
      st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_PY);
      st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_NY);
      o->ot = ST_OT_TRASH_IMPLODE;
      o->tmp = 0;
      break;
    case ST_DESTROY_BIG_TRASH:
      st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_PY);
      st_NewTrashDustAreaArgs(o->x, o->y, ST_OT_DUST_NY);
      st_InitTrash((o->x >> ST_FP) - 1, (o->y >> ST_FP) + 3, 2 + (st_rnd() & 3));
      st_InitTrash((o->x >> ST_FP) - 2, (o->y >> ST_FP) - 3, -2 - (st_rnd() & 3));
      st_Disappear(objnr);
      break;
    case ST_DESTROY_PLAYER:
      st_Disappear(objnr);
      st_state = ST_STATE_END;
      o->tmp = 0;
      break;
    case ST_DESTROY_PLAYER_GADGETS:
      /* o->ot = ST_OT_PLAYER; */
      st_SetupPlayer(objnr, ST_OT_PLAYER);
      break;
  }
}
/*
  check if the target (objnr) has been hit.
  st_IsHit() must also destroy the target.
  return value:
    0: do not destroy the missle
    1: destroy the missle
*/
uint8_t st_IsHit(uint8_t objnr, uint8_t x, uint8_t y, uint8_t missle_mask)
{
  uint8_t hit_mask = st_GetHitMask(objnr);
  st_obj *o;
  if ( (hit_mask & missle_mask) == 0 )
    return 0;
  o = st_GetObj(objnr);
  switch (u8x8_pgm_read(&(st_object_types[o->ot].is_hit_fn)))
  {
    case ST_IS_HIT_NONE:
      break;
    case ST_IS_HIT_BBOX:
      if ( st_IsHitBBOX(objnr, x, y) != 0 )
      {
        st_Destroy(objnr);
        return 1;
      }
      break;
    case ST_IS_HIT_WALL:
      if ( st_IsHitBBOX(objnr, x, y) != 0 )
      {
        o->x0++;
        if ( o->x0 < o->x1 )
        {
          st_NewTrashDust(x, y, ST_OT_DUST_NXPY);
          st_NewTrashDust(x, y, ST_OT_DUST_NXNY);
        }
        else
        {
          st_Destroy(objnr);
          st_NewTrashDust(x, y, ST_OT_DUST_NXPY);
          st_NewTrashDust(x, y, ST_OT_DUST_NXNY);
          st_NewTrashDust(x, y, ST_OT_DUST_NY);
          st_NewTrashDust(x, y, ST_OT_DUST_PY);
        }
        return 1;
      }
      break;
  }
  return 0;
}
/* update all fire counters */
uint8_t st_fire_player = 0;
uint8_t st_fire_period = 51;
uint8_t st_manual_fire_delay = 20;
uint8_t st_is_fire_last_value = 0;
/*
  is_auto_fire == 1
    is_fire will be ignored, autofire enabled
  is_auto_fire == 0
    a transition from 1 to 0 on the is_fire variable will issue a missle
*/
void st_FireStep(uint8_t is_auto_fire, uint8_t is_fire)
{
  if ( is_auto_fire != 0 )
  {
    st_fire_player++;
    if ( st_fire_player >= st_fire_period )
      st_fire_player = 0;
  }
  else
  {
    if ( st_fire_player < st_manual_fire_delay )
    {
      st_fire_player++;
    }
    else
    {
      if ( st_is_fire_last_value == 0 )
        if ( is_fire != 0 )
          st_fire_player = 0;
    }
    st_is_fire_last_value = is_fire;
  }
}
void st_Fire(uint8_t objnr)
{
  st_obj *o = st_GetObj(objnr);
  uint8_t x;
  uint8_t y;
  switch (u8x8_pgm_read(&(st_object_types[o->ot].fire_fn)))
  {
    case ST_FIRE_NONE:
      break;
    case ST_FIRE_PLAYER1:
      if ( st_fire_player == 0 )
      {
        /* create missle at st_px_x and st_px_y */
        x = st_CalcXY(o);
        y = st_px_y;
        st_NewPlayerMissle(x , y );
      }
      break;
    case ST_FIRE_PLAYER2:
      if ( st_fire_player == 0 )
      {
        /* create missle at st_px_x and st_px_y */
        x = st_CalcXY(o);
        y = st_px_y;
        st_NewPlayerMissle(x , y );
        st_NewPlayerMissle(x , y + 4 );
      }
      break;
    case ST_FIRE_PLAYER3:
      if ( st_fire_player == 0 )
      {
        /* create missle at st_px_x and st_px_y */
        x = st_CalcXY(o);
        y = st_px_y;
        st_NewPlayerMissle(x , y );
        st_NewPlayerMissle(x , y + 4 );
        st_NewPlayerMissle(x , y - 4 );
      }
      break;
  }
}
/*================================================================*/
/* object init functions */
/*================================================================*/
/*
  x,y are pixel coordinats within the play arey
*/
void st_NewGadget(uint8_t x, uint8_t y)
{
  st_obj *o;
  int8_t objnr = st_NewObj();
  if ( objnr < 0 )
    return;
  o = st_GetObj(objnr);
  st_SetXY(o, x, y);
  o->ot = ST_OT_GADGET;
  o->tmp = 8;
  //o->x = (x)<<ST_FP;
  //o->y = (y)<<ST_FP;
  o->x0 = -3;
  o->x1 = 1;
  o->y0 = -2;
  o->y1 = 2;
}
/*
  x,y are pixel coordinats within the play arey
  dir: direction
    0: random
   != 0 --> assigned
*/
void st_InitTrash(uint8_t x, uint8_t y, int8_t dir)
{
  st_obj *o;
  int8_t objnr = st_NewObj();
  if ( objnr < 0 )
    return;
  o = st_GetObj(objnr);
  if ( (st_rnd() & 1) == 0 )
    o->ot = ST_OT_TRASH1;
  else
    o->ot = ST_OT_TRASH2;
  if ( dir == 0 )
  {
    o->tmp = 0;
    if ( st_rnd() & 1 )
    {
      if ( st_rnd() & 1 )
        o->tmp++;
      else
        o->tmp--;
    }
  }
  else
  {
    o->tmp = dir;
  }
  st_SetXY(o, x, y);
  //o->x = (x)<<ST_FP;
  //o->y = (y)<<ST_FP;
  o->x0 = -3;
  o->x1 = 1;
  o->y0 = -2;
  o->y1 = 2;
  if ( st_difficulty >= 5 )
  {
    if ( (st_rnd() & 3) == 0 )
    {
      o->ot = ST_OT_BIG_TRASH;
      o->y0--;
      o->y1++;
      o->x0--;
      o->x1++;
    }
  }
}
/*
  x,y are pixel coordinats within the play arey
*/
void st_NewTrashDust(uint8_t x, uint8_t y, int ot)
{
  st_obj *o;
  int8_t objnr = st_NewObj();
  if ( objnr < 0 )
    return;
  o = st_GetObj(objnr);
  o->ot = ot;
  st_SetXY(o, x, y);
  //o->x = (x)<<ST_FP;
  //o->y = (y)<<ST_FP;
  o->x0 = 0;
  o->x1 = 0;
  o->y0 = -2;
  o->y1 = 2;
}
void st_NewTrashDustAreaArgs(int16_t x, int16_t y, int ot)
{
  st_NewTrashDust(x >> ST_FP, y >> ST_FP, ot);
}
void st_NewWall(void)
{
  st_obj *o;
  int8_t objnr = st_NewObj();
  int8_t h;
  if ( objnr < 0 )
    return;
  o = st_GetObj(objnr);
  o->ot = ST_OT_WALL_SOLID;
  h = st_rnd();
  h &= 63;
  h = (int8_t)(((int16_t)h * (int16_t)(ST_AREA_HEIGHT / 4)) >> 6);
  h += ST_AREA_HEIGHT / 6;
  o->x0 = 0;
  o->x1 = 5;
  o->x = (ST_AREA_WIDTH - 1) << ST_FP;
  if ( (st_rnd() & 1) == 0 )
  {
    o->y = (ST_AREA_HEIGHT - 1) << ST_FP;
    o->y0 = -h;
    o->y1 = 0;
  }
  else
  {
    o->y = (0) << ST_FP;
    o->y0 = 0;
    o->y1 = h;
  }
}
void st_NewPlayerMissle(uint8_t x, uint8_t y)
{
  st_obj *o;
  int8_t objnr = st_NewObj();
  if ( objnr < 0 )
    return;
  o = st_GetObj(objnr);
  o->ot = ST_OT_MISSLE;
  st_SetXY(o, x, y);
  //o->x = x<<ST_FP;
  //o->y = y<<ST_FP;
  o->x0 = -4;
  o->x1 = 1;
  o->y0 = 0;
  o->y1 = 0;
}
void st_SetupPlayer(uint8_t objnr, uint8_t ot)
{
  st_obj *o = st_GetObj(objnr);
  switch (ot)
  {
    case ST_OT_PLAYER:
      o->ot = ot;
      o->y0 = -2;
      o->y1 = 2;
      break;
    case ST_OT_PLAYER2:
      o->ot = ot;
      o->y0 = -2;
      o->y1 = 5;
      break;
    case ST_OT_PLAYER3:
      o->ot = ot;
      o->y0 = -5;
      o->y1 = 5;
      break;
  }
}
void st_NewPlayer(void)
{
  st_obj *o;
  int8_t objnr = st_NewObj();
  if ( objnr < 0 )
    return;
  o = st_GetObj(objnr);
  o->x = 6 << ST_FP;
  o->y = (ST_AREA_HEIGHT / 2) << ST_FP;
  o->x0 = -6;
  o->x1 = 0;
  st_SetupPlayer(objnr, ST_OT_PLAYER);
}
/*================================================================*/
/* trash creation */
/*================================================================*/
void st_InitDeltaWall(void)
{
  uint8_t i;
  uint8_t cnt = 0;
  uint8_t max_x = 0;
  uint8_t max_l;
  uint8_t min_dist_for_new = 40;
  uint8_t my_difficulty = st_difficulty;
  if ( st_difficulty >= 2 )
  {
    max_l = ST_AREA_WIDTH;
    max_l -= min_dist_for_new;
    if ( my_difficulty > 30 )
      my_difficulty = 30;
    min_dist_for_new -= my_difficulty;
    for ( i = 0; i < ST_OBJ_CNT; i++ )
    {
      if ( st_objects[i].ot == ST_OT_WALL_SOLID )
      {
        cnt++;
        if ( max_x < (st_objects[i].x >> ST_FP) )
          max_x = (st_objects[i].x >> ST_FP);
      }
    }
    /* if ( cnt < upper_trash_limit ) */
    if ( max_x < max_l )
    {
      st_NewWall();
    }
  }
}
void st_InitDeltaTrash(void)
{
  uint8_t i;
  uint8_t cnt = 0;
  uint8_t max_x = 0;
  uint8_t max_l;
  uint8_t upper_trash_limit = ST_OBJ_CNT - 7;
  uint8_t min_dist_for_new = 20;
  uint8_t my_difficulty = st_difficulty;
  if ( my_difficulty > 14 )
    my_difficulty = 14;
  min_dist_for_new -= my_difficulty;
  for ( i = 0; i < ST_OBJ_CNT; i++ )
  {
    if ( st_objects[i].ot == ST_OT_TRASH1 || st_objects[i].ot == ST_OT_TRASH2 || st_objects[i].ot == ST_OT_GADGET  || st_objects[i].ot == ST_OT_BIG_TRASH )
    {
      cnt++;
      if ( max_x < (st_objects[i].x >> ST_FP) )
        max_x = (st_objects[i].x >> ST_FP);
    }
  }
  max_l = ST_AREA_WIDTH;
  max_l -= min_dist_for_new;
  if ( cnt < upper_trash_limit )
    if ( max_x < max_l )
    {
      if (  (st_difficulty >= 3)  && ((st_rnd() & 7) == 0) )
        st_NewGadget(ST_AREA_WIDTH - 1, rand() & (ST_AREA_HEIGHT - 1));
      else
        st_InitTrash(ST_AREA_WIDTH - 1, rand() & (ST_AREA_HEIGHT - 1), 0 );
    }
}
void st_InitDelta(void)
{
  st_InitDeltaTrash();
  st_InitDeltaWall();
  /*
    uint8_t cnt;
    cnt = st_CntObj(2);
    if ( cnt == 0 )
    st_InitBrick1();
  */
}
/*================================================================*/
/* API: game draw procedure */
/*================================================================*/
void st_DrawInGame(uint8_t fps)
{
  uint8_t i;
  /* draw all objects */
  for ( i = 0; i < ST_OBJ_CNT; i++ )
    st_DrawObj(i);
  //dog_ClrBox(0, ST_AREA_HEIGHT, st_u8g2->width-1, ST_AREA_HEIGHT+3);
  u8g2_SetDrawColor(st_u8g2, 0);
  u8g2_DrawBox(st_u8g2, 0, u8g_height_minus_one - ST_AREA_HEIGHT - 3, st_u8g2->width, 4);
  u8g2_SetDrawColor(st_u8g2, 1);
  u8g2_DrawHLine(st_u8g2, 0, u8g_height_minus_one - ST_AREA_HEIGHT + 1, ST_AREA_WIDTH);
  u8g2_DrawHLine(st_u8g2, 0, u8g_height_minus_one, ST_AREA_WIDTH);
  u8g2_SetFont(st_u8g2, u8g_font_4x6r);
  u8g2_DrawStr(st_u8g2, 0, u8g_height_minus_one - ST_AREA_HEIGHT, st_itoa(st_difficulty));
  u8g2_DrawHLine(st_u8g2, 10, u8g_height_minus_one - ST_AREA_HEIGHT - 3, (st_to_diff_cnt >> ST_DIFF_FP) + 1);
  u8g2_DrawVLine(st_u8g2, 10, u8g_height_minus_one - ST_AREA_HEIGHT - 4, 3);
  u8g2_DrawVLine(st_u8g2, 10 + ST_DIFF_VIS_LEN, u8g_height_minus_one - ST_AREA_HEIGHT - 4, 3);
  /* player points */
  u8g2_DrawStr(st_u8g2, ST_AREA_WIDTH - 5 * 4 - 2, u8g_height_minus_one - ST_AREA_HEIGHT, st_itoa(st_player_points_delayed));
  /* FPS output */
  if ( fps > 0 )
  {
    //i = dog_DrawStr(ST_AREA_WIDTH-5*4-2-7*4, ST_AREA_HEIGHT, font_4x6, "FPS:");
    i = u8g2_DrawStr(st_u8g2, ST_AREA_WIDTH - 5 * 4 - 2 - 7 * 4, u8g_height_minus_one - ST_AREA_HEIGHT, "FPS:");
    //dog_DrawStr(ST_AREA_WIDTH-5*4-2-7*4+i, ST_AREA_HEIGHT, font_4x6, st_itoa(fps));
    u8g2_DrawStr(st_u8g2, ST_AREA_WIDTH - 5 * 4 - 2 - 7 * 4 + i, u8g_height_minus_one - ST_AREA_HEIGHT, st_itoa(fps));
  }
  /*dog_DrawStr(60+i, ST_AREA_HEIGHT, font_4x6, st_itoa(st_CntObj(0)));*/
}
void st_Draw(uint8_t fps)
{
  switch (st_state)
  {
    case ST_STATE_PREPARE:
    case ST_STATE_IPREPARE:
      //dog_DrawStr(0, (st_u8g2->height-6)/2, font_4x6, "SpaceTrash");
      u8g2_SetFont(st_u8g2, u8g_font_4x6r);
      u8g2_SetDrawColor(st_u8g2, 1);
      //dog_DrawStrP(0, (st_u8g2->height-6)/2, font_4x6, DOG_PSTR("SpaceTrash"));
      u8g2_DrawStr(st_u8g2, 0, u8g_height_minus_one - (st_u8g2->height - 6) / 2, "SpaceTrash");
      //dog_SetHLine(st_u8g2->width-st_to_diff_cnt-10, st_u8g2->width-st_to_diff_cnt, (st_u8g2->height-6)/2-1);
      u8g2_DrawHLine(st_u8g2, st_u8g2->width - st_to_diff_cnt - 10, u8g_height_minus_one - (st_u8g2->height - 6) / 2 + 1, 11);
      break;
    case ST_STATE_GAME:
      st_DrawInGame(fps);
      break;
    case ST_STATE_END:
    case ST_STATE_IEND:
      u8g2_SetFont(st_u8g2, u8g_font_4x6r);
      u8g2_SetDrawColor(st_u8g2, 1);
      //dog_DrawStr(0, (st_u8g2->height-6)/2, font_4x6, "Game Over");
      //dog_DrawStrP(0, (st_u8g2->height-6)/2, font_4x6, DOG_PSTR("Game Over"));
      u8g2_DrawStr(st_u8g2, 0, u8g_height_minus_one - (st_u8g2->height - 6) / 2, "Game Over");
      //dog_DrawStr(50, (st_u8g2->height-6)/2, font_4x6, st_itoa(st_player_points));
      u8g2_DrawStr(st_u8g2, 50, u8g_height_minus_one - (st_u8g2->height - 6) / 2, st_itoa(st_player_points));
      //dog_DrawStr(75, (st_u8g2->height-6)/2, font_4x6, st_itoa(st_highscore));
      u8g2_DrawStr(st_u8g2, 75, u8g_height_minus_one - (st_u8g2->height - 6) / 2, st_itoa(st_highscore));
      //dog_SetHLine(st_to_diff_cnt, st_to_diff_cnt+10, (st_u8g2->height-6)/2-1);
      u8g2_DrawHLine(st_u8g2, st_to_diff_cnt, u8g_height_minus_one - (st_u8g2->height - 6) / 2 + 1, 11);
      break;
  }
}
void st_SetupInGame(void)
{
  st_player_points = 0;
  st_player_points_delayed = 0;
  st_difficulty = 1;
  st_to_diff_cnt = 0;
  st_ClrObjs();
  st_NewPlayer();
  /* st_InitBrick1(); */
}
/*================================================================*/
/* API: game setup */
/*================================================================*/
void st_Setup(u8g2_t *u8g)
{
  st_u8g2 = u8g;
  u8g2_SetBitmapMode(u8g, 1);
  u8g_height_minus_one = u8g->height;
  u8g_height_minus_one--;
}
/*================================================================*/
/* API: game step execution */
/*================================================================*/
/*
  player_pos: 0..255
*/
void st_StepInGame(uint8_t player_pos, uint8_t is_auto_fire, uint8_t is_fire)
{
  uint8_t i, j;
  uint8_t missle_mask;
  /* rescale player pos */
  //st_player_pos = ((uint16_t)player_pos * (uint16_t)ST_AREA_HEIGHT)/256;
  if ( player_pos < 64 )
    st_player_pos = 0;
  else if ( player_pos >= 192 )
    st_player_pos = ST_AREA_HEIGHT - 2 - 1;
  else
    st_player_pos = ((uint16_t)((player_pos - 64)) * (uint16_t)(ST_AREA_HEIGHT - 2)) / 128;
  st_player_pos += 1;
  /* move all objects */
  for ( i = 0; i < ST_OBJ_CNT; i++ )
    st_Move(i);
  /* check for objects which left the play area */
  for ( i = 0; i < ST_OBJ_CNT; i++ )
    if ( st_objects[i].ot != 0 )
      if ( st_IsOut(i) != 0 )
        st_Disappear(i);
  /* missle and destruction handling */
  for ( i = 0; i < ST_OBJ_CNT; i++ )
  {
    missle_mask = st_GetMissleMask(i);
    if ( missle_mask != 0 )           /* should we apply missle handling? */
      if ( st_CalcXY(st_objects + i) != 0 )         /* yes: calculate pixel reference point (st_px_x, st_px_y) */
        for ( j = 0; j < ST_OBJ_CNT; j++ )    /* has any other object been hit? */
          if ( i != j )             /* except missle itself... */
            if ( st_IsHit(j, st_px_x, st_px_y, missle_mask) != 0 )    /* let the member function decide */
            { /* let the member function destroy the object if required */
              st_Destroy(i);
            }
  }
  /* handle fire counter */
  st_FireStep(is_auto_fire, is_fire);
  /* fire */
  for ( i = 0; i < ST_OBJ_CNT; i++ )
    st_Fire(i);
  /* create new objects */
  st_InitDelta();
  /* increase difficulty */
  st_to_diff_cnt++;
  if ( st_to_diff_cnt == (ST_DIFF_VIS_LEN << ST_DIFF_FP) )
  {
    st_to_diff_cnt = 0;
    st_difficulty++;
    st_player_points += ST_POINTS_PER_LEVEL;
  }
  /* update visible player points */
  if ( st_player_points_delayed < st_player_points )
    st_player_points_delayed++;
}
void st_Step(uint8_t player_pos, uint8_t is_auto_fire, uint8_t is_fire)
{
  switch (st_state)
  {
    case ST_STATE_PREPARE:
      st_to_diff_cnt = st_u8g2->width - 10; /* reuse st_to_diff_cnt */
      st_state = ST_STATE_IPREPARE;
      break;
    case ST_STATE_IPREPARE:
      st_to_diff_cnt--;
      if ( st_to_diff_cnt == 0 )
      {
        st_state = ST_STATE_GAME;
        st_SetupInGame();
      }
      break;
    case ST_STATE_GAME:
      st_StepInGame(player_pos, is_auto_fire, is_fire);
      break;
    case ST_STATE_END:
      st_to_diff_cnt = st_u8g2->width - 10; /* reuse st_to_diff_cnt */
      if ( st_highscore < st_player_points)
        st_highscore = st_player_points;
      st_state = ST_STATE_IEND;
      break;
    case ST_STATE_IEND:
      st_to_diff_cnt--;
      if ( st_to_diff_cnt == 0 )
        st_state = ST_STATE_PREPARE;
      break;
  }
}
void setup(void) {
  u8g2.begin();
}
uint8_t a;
uint8_t b;
uint8_t y = 128;
void loop(void) {
  u8g2.setFont(u8g2_font_6x10_tr);
  u8g2.setFontDirection(0);
  u8g2.setFontRefHeightAll();
  st_Setup(u8g2.getU8g2());
  for (;;)
  {
    st_Step(y, /* is_auto_fire */ 0, /* is_fire */ digitalRead(pin_fire));
    u8g2.firstPage();
    do
    {
      st_Draw(0);
    } while ( u8g2.nextPage() );
    if ( analogRead(pin_updown) > 600) {
      y++;
    }
    if ( analogRead(pin_updown) <= 300) {
      y--;
    }
  }
  }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JoyStick Shield连接Nokia 5110--Arduino 的相关文章

  • 【学习分享】全志平台TWI子系统源码分析(1)从设备树到寄存器

    全志平台TWI子系统源码分析 1 从设备树到寄存器 前言 一 名词解释 二 从设备树入手看源码 1 TWI设备树 2 TWI源码位置 3 TWI总线相关寄存器 总结 前言 这次开坑主要是想把全志平台TWI子系统在源
  • printf 的包装

    我在Arduino下编码 我想开发串行打印格式化功能 所以我尝试使用sprintf未知大小的缓冲区 基本上 我们可以避免谈论 Arduino 及其串行输出 并考虑将文本写入缓冲区 然后使用printf 我试过这个 include
  • Mac OS 10.9 不显示 Arduino 的 USB 调制解调器

    我正在尝试选择 dev tty usbmodem on my Arduino Lenardo设备 操作系统是Mac OSX 10 9 问题是它没有显示 我什至尝试安装FTDI http www ftdichip com Drivers VC
  • Arduino I2S 正弦波

    我正在开发一个项目 我想通过组合不同的正弦波来生成 简单 声音 我使用的是 arduino mkrZero 因为它内置了 I2S 接口 并且似乎有足够的处理能力来满足我的需求 I have wired my system exactly l
  • Android 和 Arduino 都通过蓝牙接收奇怪的值

    我正在 Android 端使用 BluetoothChat 代码使用聊天框向 Arduino UNO 发送开 关信号 我发送 110 119 或下面定义的其他情况 但是当我显示接收到的值时 它显示奇怪的Arduino 串行监视器中的值 即
  • 经典蓝牙 (2.1) 设备可实现的最小数据包延迟是多少?

    我正在使用 RN42 http www microchip com wwwproducts en RN42 http www microchip com wwwproducts en RN42 蓝牙模块以 115200 波特率 UART S
  • C++ Linux (Ubuntu) 正确写入串行(对于 Arduino)

    我想知道是否有一种标准方法可以与高效的串行设备进行通信 我应该使用标准库吗 如果有 是哪一个 现在我正在摆弄让 LED 根据输入的数字以给定的量亮起 Arduino 代码如下 只是练习一些东西 看我过于简单且低效的测试 include
  • 是否有通用 I2C 命令来查看设备是否仍然存在于总线上?

    是否有通用的 I2C 命令来查看设备在初始化一次后是否仍然存在于总线上 例如 OLED 显示器 我问这个的原因是为了避免主程序由于库代码中存在无限循环而冻结 当设备断开连接时 例如 Wire 库 在 MCU 启动时 我想检查设备是否可用 并
  • Arduino:连接字符串时崩溃和错误

    我尝试将 AES 256 加密的输出连接到一个字符串 将此字符串与从 Android 手机发送的加密字符串进行比较 基本上 连接似乎有效 但在几次运行后会出现错误 不可读的字符 字符串变得更短而不是更长 或崩溃 它是可重现的 重启后在同一点
  • pySerial 与 python 2.7 和 3.4 的差异

    我正在开发一个项目 需要通过串口将一些数字从 Windows 10 中的 python 发送到 arduino uno 作为一个简单的测试 我只想通过发送 2 来打开 LED 并通过从命令提示符发送 4 来关闭 LED 尽管我希望最终能够将
  • 如何使用GSM模块SIM800和Arduino Uno发送短信?

    我正在尝试通过 SIM800 GSM 模块从 Arduino 发送短信 消息到达给定号码 但格式不正确 它显示 消息格式不支持 我在这里添加了我的代码 非常感谢您的快速回复 include
  • 在 Arduino 上将整数/小数转换为十六进制?

    如何将整数或小数变量转换为十六进制字符串 我可以做相反的事情 将十六进制转换为整数 但我无法找出其他方法 这是为了Serial print 数组中的十六进制值 查看 Arduino 字符串教程here http arduino cc en
  • Arduino C++ 析构函数?

    我知道在Arduino中你不能使用delete 那么什么时候调用 C 类中定义的析构函数呢 同样 如果我想创建一个指向数组的指针 我必须使用malloc and free 当对象被销毁时 析构函数被调用 对于自动 堆栈上 变量 它在离开其作
  • 从 iBeacon 接收 BLE 信号到 Bluno(arduino with BLE)

    我想从 iBeacon 到 Bluno 接收 rssi 信号和 UUID Arduino 板具有 BLE 对此有一些疑问 有没有从 BLE 到 BLE 接收 UUID 和 rssi 的解决方案 两个BLE设备可以互相通信吗 我想找一些网站来
  • Python串口通信

    我正在开发一个 Arduino 项目 由于内存限制 我将其与 Python 脚本连接起来 在Python方面 我有一个二维矩阵 其中包含各自的x y坐标值 并且在此列表中有26000个坐标对 因此 为了向大家澄清数据结构 pathlist
  • 是否值得为 EEPROM 实现小型文件系统

    我买了一个I2C EEPROM 我想存储传感器和电压数据 我假设该值可以大于一个字节 并且可以有很多数据 在这种情况下是否值得实现具有小文件分配表的文件系统 例如 这会让我更容易查看 EEPROM 我发现 EEPROM 上出现 FAT 有两
  • PHP 通过 TCP/IP 发送消息

    我尝试通过 TCP IP 从 PHP 网站向 Arduino 发送消息 使用以下代码我可以从 php 网站发送消息 问题是 当第一次调用该网站时 消息不会立即发送 网站刷新几次后 消息就会到达 但逻辑上很多次 就像网站刷新量一样 已经尝试将
  • Arduino 上的串行消息到整数

    我希望我的 Arduino 通过串行通信接收一个整数 你能帮我解决这个问题吗 它应该是这样的形式 int value strtoint Serial read 有多种方法可以读取整数Serial 很大程度上取决于数据发送时的编码方式 Ser
  • 使用 avr-gcc 编译器/链接器对链接 avrfix 库中函数的未定义引用

    我正在尝试使用avrfix 库 http avrfix sourceforge net 在一个项目中 使用Eclipse v4 2 2 作为IDE avr gcc作为编译器 头文件 avrfix h 和库文件 libavrfix a 都包含
  • 多次客户端打印后,Arduino (Uno) 以太网客户端连接失败

    我正在使用带有以太网扩展板的 Arduino Uno 发送多次 HTTP 请求后 客户端 println 客户端连接时开始失败 故障时间似乎是随机的 并且循环中的序列读数可能在 1000 和 7000 之间变化 该错误与以太网发送缓冲区溢出

随机推荐

  • 数仓 面试题(离线)实战解答

    无意间翻到以前的数仓面试题 今天把它整理出来 方便你我他 数仓分层 为什么要对数仓进行分层 1 说说对数据仓库的理解 数据仓库是面向主题进行组织的 数据是集成的 不可更新的 随时间变化的的 数据仓库经历了这样三个阶段 简单报表阶段 数据集市
  • Go语言中如何在range循环中修改数组/切片内容

    在go语言中 我们经常会使用到range来帮助我们遍历一些数据 通常情况下都是查看操作多一些 但是当我们需要对其原地址上的内容进行变更时 通常都是使用 for i 0 i
  • mac下统计代码行数方法

    使用cloc工具统计 1 首先在终端执行命令下载cloc brew install cloc 没有brew的先下载brew 这个后面写一个 这里先占位 2 cloc使用 进入想要查询的项目文件夹 然后执行下面的命令查询 cloc 如下图所示
  • 【深入理解C++】调用父类的拷贝构造函数

    文章目录 1 默认的拷贝操作 2 调用父类的拷贝构造函数 3 用子类对象初始化父类对象 1 默认的拷贝操作 默认情况下 继承体系下类对象的拷贝是每个成员变量逐个拷贝 include
  • 下采样方法

    AntiAliasInterpolation2d代码解读 注记 最近在看一些视频驱动的代码时 常见一种特殊的下采样方法 故在这里记录一下 Class AntiAliasInterpolation2d nn Module 初始化 def in
  • 两个有序序列的中位数 (25 分)

    已知有两个等长的非降序序列S1 S2 设计函数求S1与S2并集的中位数 有序序列A 0 A 1 A N 1 的中位数指A N 1 2 的值 即第 N 1 2 个数 A 0 为第1个数 输入格式 输入分三行 第一行给出序列的公共长度N 0
  • Hive 中常用的查询语句解读及应用(分组、Join、排序语句)

    文章目录 Hive 中常用的查询语句 2 分组 2 1 Group By 语句 2 2 Having 语句 3 Join 语句 3 1 等值 Join 3 2 表的别名 3 3 内连接 3 4 左外连接 3 5 右外连接 3 6 满外连接
  • mysql数据库使用between and 的不包含右边界问题

    最近在公司经常支持业务部门数据提取 遇到了一个提取时间间隔的问题 想到了between and比较方便 之前经常用这个关键字 但是从来没思考过它的边界问题 所以趁这次研究了一下 废话不多说 直接上例子 select from user se
  • 【机器学习】支持向量机SVM及实例应用

    机器学习 支持向量机 1 分类超平面与最大间隔 2 对偶问题与拉格朗日乘子法 3 核函数 4 软间隔与正则化 5 实例应用 python使用支持向量机SVM 准备 数据集 导入SVM模块 步骤 1 读取数据集 2 划分训练样本与测试样本 3
  • cool使用es教程

    cool使用es教程 安装es8 1 0 将elasticsearch head文件运行至浏览器插件可以看到运行情况 安装ik分词器 将目录名称改名放置es安装目录plug目录 版本一定cool5 安装es8 1 0 官网 github下载
  • Flask03_路由传参

    encoding utf 8 1 app route 路由匹配 代表资源在服务器上的位置 1 路由 Flask根据http请求的url在路由表中和定义好的进行匹配 找到对应的函数处理这个请求 此过程保存一个url到函数的映射关系称之为路由r
  • (zxing.net)二维码Aztec的简介、实现与解码

    一 简介 Aztec Code是1995年 由Hand HeldProducts公司的Dr Andrew Longacre设计 它是一种高容量的二维条形码格式 它可以对ASCII和扩展ASCII码进行编码 当使用最高容量和25 的纠错级别的
  • pyqt多窗口设计(2步实现,嘴对嘴教学,源码复制可用)

    本文涉及 PyQt5 Qt Designer PyCharm 目录 先看下完成效果 步骤1 用Qt Designer创建2个窗体 步骤2 将子窗体和主窗体上的按钮控件进行关联 完整代码 先看下完成效果 视频里我只设计了1个主窗口和1个子窗口
  • MyBatis(2):MyBatis标签以及对应的属性用法讲解

    通过上一章的讲解 大家应该对MyByatis的基本用法有了一定的了解 这一章主要是讲一下MyBatis的各种标签以及对应的属性 它们的用法以及用的时候应该注意一些什么 下面的讲解时结合当前主流框架 Spring Spring MVC MyB
  • linux 给文件替换字符串/替换内容/替换某行 (shell,sed)

    本文是要讲linux 不打开文档 文件的情况下 替换文本内容 打开文档 在文档 文件内替换内容的 可以用vim 可参考这篇文章vim 替换文本 话题相关 linux 文件替换字符串 sed 字符串替换 shell 文件替换某行 linux
  • Blender-烘焙动画,解除约束父子级,导入UE4

    问题1 烘焙动画 解除约束父子级 导入UE4 注意 blender 里 走路动画1 32帧 第1和32帧重复姿势 如果播放选择1 32帧 会因为重复播放而卡最后一帧 所以要流畅播放 在blender里应该设置为1 31帧 来查看预览 但是导
  • hadoop无法启动 INFO ipc.Client: Retrying connect to server

    18 01 07 02 05 32 INFO ipc Client Retrying connect to server master 192 168 157 10 9000 Already tried 0 time s retry pol
  • QT入门Containers之QToolBox

    目录 一 QToolBox界面相关 1 布局介绍 2 界面测试 3 添加分组测试 4 添加图标 5 添加展开缩进不同效果图标 二 Demo展示 此文为作者原创 创作不易 转载请标明出处 一 QToolBox界面相关 1 布局介绍 先从界面拖
  • UNITY获取物体速度的方法

    unity中如果用navmesh 里面有内置的方法可以获取速度 其他目前发现好像只能自己算了 float Speed curpos gameObject transform position 当前点 float speed Vector3
  • JoyStick Shield连接Nokia 5110--Arduino

    SpaceTrash游戏是一个简单的射击游戏 您可以在其中控制宇宙飞船 并通过移动或爆破 使用激光 来避免漂浮在周围的小行星的碰撞 该游戏是u8g2图形库附带的示例 该图形库通常用于连接具有SPI或I2C协议的各种单色8位显示器 对于此游戏