JoyStick Shield连接Nokia 5110--Arduino

news2024/11/21 1:31:59

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
  • CE – 连接到 D9
  • CSN – 连接到 D10
  • SCK – 连接到 D13
  • MOSI – 连接到 D11
  • 味噌 – 连接到 D12
  • IRQ – 无连接

诺基亚 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--;
    }
  }
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/81634.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

非零基础自学Golang 第1章 走进Go 1.4 常用软件及网站 1.5 小结

非零基础自学Golang 文章目录非零基础自学Golang第1章 走进Go1.4 常用软件及网站1.4.1 开发工具【IDE 或编辑器】1.4.2 代码管理工具1.4.3 其他工具1.4.4 网站资源1.5 小结第1章 走进Go 1.4 常用软件及网站 1.4.1 开发工具【IDE 或编辑器】 工欲善其事必先利其器。 Go开发工…

基于java+springboot+mybatis+vue+mysql的电动车辆充电桩管理系统

项目介绍 随着我国汽车行业的不断发展&#xff0c;电动汽车已经开始逐步的领导整个汽车行业&#xff0c;越来越多的人在追求环保和经济实惠的同时开始使用电动汽车&#xff0c;电动汽车和燃油汽车最大的而不同就是 需要充电&#xff0c;同时我国的基础充电桩也开始遍及了大多数…

机器人开发--SICK激光雷达系列

机器人开发--SICK激光雷达系列1 介绍2 TiM系列2.1 TiM510参数测量方法协议请求一次数据&#xff08;应答直接携带数据&#xff09;请求持续数据&#xff08;应答收到指令&#xff0c;数据持续发送&#xff09;数据内容参考1 介绍 SICK 是国际先进的工业用传感器应用程序解决方…

016 | 乡村振兴战略下农村宅基地有偿退出现状 | 大学生创新训练项目申请书 | 极致技术工厂

&#xff08;一&#xff09;研究目的 随着国家城市化进程的加快&#xff0c;城市和农村的具体情况都发生了巨大变化&#xff0c;大量的问题随之产生&#xff0c;在农村经济中&#xff0c;宅基地的有偿退出矛盾尤为突出。在当前的时代发展背景下&#xff0c;我国农村宅基地有偿…

[附源码]Python计算机毕业设计宠物寄养平台设计Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

git cherry-pick命令用法详解

1、需求背景 想在某个稳定版本上&#xff0c;添加一个刚开发完成的版本中的功能。就可以使用 Cherry-pick 命令&#xff0c;将这个功能相关的 commit 提取出来&#xff0c;合入稳定版本的分支上。 对于多分支的代码库&#xff0c;将代码从一个分支转移到另一个分支是常见需求。…

VS2015+PCL1.8.1安装

VS2015+PCL1.8.1安装 一、下载PCL1.8.1二、PCL-1.8.1安装三、系统环境变量配置四、 vs2015配置PCL1.8.1一、下载PCL1.8.1 1.1 首先下载pcl1.8.1的库,地址在这:pcl1.8.1库链接。   1.2 打开网站,将页面拉到最下面,下载这个两个文件:PCL-1.8.1-AllInOne-msvc2015-win64.ex…

Windows下C语言程序和网络调试助手通信

网络调试助手之间进行UDP通信 前面一篇文章介绍了Windows下的网络调试助手&#xff0c;文章链接如下&#xff1a; Windows下的TCP/UDP网络调试工具-NetAssist以及Linux下的nc网络调试工具 下面我们简单介绍一下网络调试助手的使用。 这样两个网络调试助手之间就可以进行UDP通…

矩阵 的逆、 迹、 秩

矩阵的逆&#xff1a; 矩阵的逆有是三种方法可以求 1、系数待定法&#xff1a; 2、求伴随矩阵求逆 3、通过求增广矩阵求出逆 矩阵的迹 什么是矩阵的迹 矩阵的迹是特征值的加和&#xff0c;也即矩阵A的主对角线元素的总和。 案例 矩阵的秩 什么是矩阵的秩 设 AA 为 m\tim…

Vue 进阶一 | 系统性学习 | 无知的我费曼笔记

无知的我正在复盘Vue 该笔记特点是 重新整理了涉及资料的一些语言描述、排版而使用了自己的描述对一些地方做了补充说明。比如解释专有名词、类比说明、对比说明、注意事项提升了总结归纳性。尽可能在每个知识点上都使用一句话 || 关键词概括更注重在实际上怎么应用提出并回答…

20221212英语学习

今日单词&#xff1a; sweet adj.含糖的, 甜的, 香的, 芳香的 founding n.建立,成立 software n.软件 pour n.流出, 大雨, 【冶】浇注, (已熔金属的)一次浇注量 recipe n.烹饪法&#xff0c;食谱&#xff1b;方法&#xff0c;秘诀&#xff0c;诀窍 graph n.图, 图表, 曲线…

Vue2 插槽的使用【默认插槽、具名插槽、作用域插槽】

前言&#xff1a; 这篇文章我们一起来学习一下 Vue2 插槽的使用&#xff0c;文章大致分为两个模块&#xff0c;第一部分是什么是插槽&#xff0c;其作用是什么&#xff0c;第二部分为三种插槽的使用&#xff0c;分别为默认插槽&#xff0c;具名插槽&#xff0c;作用域插槽&…

Vue快速上门|虚拟DOM

直接操作DOM,DOM频繁变动会使得页面不停的布局、渲染,是很消耗性能的,虚拟DOM就是来解决这个问题的。虚拟DOM 就是先在内存中构建一个虚拟DOM结构(JS对象表示),批量操作完成后再一次性的更新到浏览器DOM树上。VUE中的虚拟DOM操作思路也是如此,只是为了更高效,实际要稍微…

[附源码]Node.js计算机毕业设计大数据与智能工程系教师档案管理系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

Docker之RUN、COMMAND、ENTRYPOINT辨析

一 回顾docker一些命令 ① run create start 的辨析 docker run 等价 docker create && docker start容器(动态) 镜像(静态) 读写层1&#xff09; create 命令为指定的镜像&#xff08;image&#xff09;添加了一个可读写层,构成了一个新的容器注意&#xff1…

RNA-seq 详细教程:详解DESeq2流程(9)

学习目标 了解 DESeq2 涉及的不同步骤了解变异的来源并检查 size factors检查基因水平的离散估计了解差异表达分析过程中离散的重要性DESeq2流程 前面&#xff0c;我们使用设计公式创建了 DESeq2 对象&#xff0c;并使用下面两行代码运行DESeq2&#xff1a; dds <- DESeqDat…

《野球少年》:王牌投手·棒球联盟

身为一名投手&#xff0c;原田巧是位拥有着拔群棒球才能的少年。在初中入学时移居的山间城镇新田市&#xff0c;巧与接住自己全力投球的捕手永仓豪相遇了。进入新田东中学棒球部的两人&#xff0c;被卷入部员间的摩擦以及教师们的大人事情&#xff0c;时而相互产生冲突&#xf…

喊一声“嘿!GitHub”,说出需求VS Code就能自己写代码了

喊一句“嘿&#xff01;GitHub”&#xff0c;说出你的需求&#xff0c;代码自动来&#xff01; Python中导入pandas库&#xff0c;只需说一句“import pandas”&#xff1a; 长句语音、一连串命令&#xff0c;都不在话下&#xff1a; 嗯&#xff0c;就是和Siri一个味儿&#x…

ETDR 0A 电缆故障测试仪 手持便携式 电缆故障脉冲反射仪 可测30KM

用途&#xff1a; ETDR 10A-3 采用低压脉冲反射技术&#xff0c;用于快速、 精确测试通信或电力电缆的故障距离。 多种测试模式&#xff0c;适用于断线、短路、低阻、间歇性等故障类型&#xff0c;并能测试接头的位置。 使用环路脉冲发生器(ES 2002)可以更容易测试有分支的电缆…

实验五、U_GSQ对共源放大电路电压放大倍数的影响

一、题目 UGSU_{GS}UGS​ 对共源放大电路 A˙u\dot A_uA˙u​ 的影响。 二、仿真电路 共源放大电路如图(ccc)所示&#xff0c;其中MOS场效应管型号为2N7000。 三、仿真内容 图1(a)为2N7000相关的参数&#xff0c;图1(b)为其转移特性&#xff0c;以作为参考&#xff08;需注…