⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tetrislib.c

📁 compiled for AtMega32 The source, to compile with AVR-G
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Title        : tetrislib - part of scopetris
// Author       : Lars Pontoppidan 
// Date         : Aug. 2007
// Version      : 0.1
// Target MCU   : AtMega32 at 8 MHz
//
//
//                       TETRIS LIBRARY
//
//           with vector rendering and animation effects
//
//                 with naive or real gravity
//
//                        for the AVR
//
//
// DESCRIPTION:
// Tetrislib contains game logic, game state and graphics rendering using 
// drawlib for a tetris game.
//
// CREDITS:
// Tetrislib was created by Lars Pontoppidan in August 2007.
//
// COMPILER INFO:
// This code compiles with avr-gcc v.4.1.2
// 
// DISCLAIMER:
// The author is in no way responsible for any problems or damage caused by
// using this code. Use at your own risk.
//
// LICENSE:
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//



#include <string.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/pgmspace.h>

#include "drawlib.h"
#include "vectorfont.h"
#include "tetrislib.h"


////////////////////////////////////////////////////////////////////////////////
// GAME DEFINITIONS AND DECLARATIONS
////////////////////////////////////////////////////////////////////////////////

//
// PLAYGROUND MATRIX is 10 cubes wide, 20 cubes high
// NOTE: The game might break if these defines are changed...
//
#define MATRIX_WIDTH 10
#define MATRIX_HEIGHT 20
// 
// Coordinate definition (x,y)
//
//   (0,20)     (10,20)
//     +----------+
//     |x        x|
//     |          |
//     .          .
//     .          .
//     |x        x|
//     +----------+
//   (0,0)      (10,0)
//


//
// CUBE OCCUPATION is stored as bits in a 16 bit var for each row
//
// NOTE: LSB is leftmost cube!
unsigned short occupancy[MATRIX_HEIGHT];

// NOTE: sentinel cubes on each side!
// NOTE: MSB in occupancy is used temporarily for animation
#define OCCUPANCY_FREE (1|(1<<(MATRIX_WIDTH+1)))
#define OCCUPANCY_NONE 0xFFF


// BRICKS
//  
// The actual state of the game is stored as an array of bricks.
// 
// The cubes of a brick are described in 4 bytes:
//
// 4 bytes:   brick[3]:   LSB X X X X... 
//            brick[2]:   LSB X X X X... 
//            brick[1]:   LSB X X X X... 
//            brick[0]:   LSB X X X X... 
//  
// For instance:        . . . .   =>   brick[3] = 0
//                      x . . .   =>   brick[2] = 1
//                      x x . .   =>   brick[1] = 3
//                      x . . .   =>   brick[0] = 1
//
// The coordinates of the brick indicate position of lower left cube 

struct Brick_Type {
  unsigned char brick[4];  
  unsigned char x;    // high nibble of x is used for y offset (pixels)
  signed char y;
};

//
// BRICKS IN GAME
// 
// The player controlled falling brick:
struct Brick_Type falling_brick;

// The pending brick
struct Brick_Type pending_brick;

// The array of bricks currently active in the game:
#define MAX_BRICKS 100
struct Brick_Type active_brick[MAX_BRICKS];

unsigned char active_bricks;



//
// BRICK TEMPLATES
//
// When a new brick is entering, it is randomly selected from one of these:
//
#define BRICK_TEMPLATES 7

const unsigned char brick_template[BRICK_TEMPLATES][2] PROGMEM = {
 {15,0},
  {7,1},
  {7,4},
  {3,3},
  {3,6},
  {7,2},
  {6,3}};
  
  
//
// GRAPHICS
//
// The graphics rendering reacts to graphics_status
// 
#define SHOW_FALLING_BRICK 1
#define SHOW_ZAPPED_ROWS   2
#define SHOW_ZAP_COUNT     4
unsigned char graphics_status;

//
// Graphics definitions
//
#define BRICK_SIZE 10

#define X_OFFSET 50
#define Y_OFFSET 5

#define BRICK_INSET 2

//   |         |         |
//   |         |         |
// 2 | x       | x     x |
//   |         |         |
// 0 +---------+---------+
//   0 2       10
//     |
//  brick inset


// Tetris game statemachine. 
//
#define TETRIS_IDLE          0
#define TETRIS_NEW_BRICK     1
#define TETRIS_BRICK_FALLING 2
#define TETRIS_TRY_ZAP       3
#define TETRIS_DO_GRAVITY    4
#define TETRIS_SHOW_ZAPPED   5
#define TETRIS_GAME_OVER     255
//
unsigned char tetris_state;


// Tetris mode is an external bitflag variable and specifies: 
//
//   TETRIS_MODE_SPEEDUP  1    // falling brick speedup
//   TETRIS_MODE_GRAVITY  2    // for real gravity. If not set, naive gravity
//
unsigned char tetris_mode;


//
// Game and animation timing
//
// tetris_draw_frame is called with 100 Hz (tf = 10ms)
//
// tetris_speed defines how fast the brick is falling and is defined: 
//
// each frame brick moves pixels:      = tetris_speed / 64
// => each frame brick moves grids:    = tetris_speed / (64 * 10)
// => each sec   brick moves grids:    = tetris_speed / (64 * 10 * tf)
// => brick moves one grid each (sec): = (64 * 10 * tf) / tetris_speed
//                                     = 6.4(s) / tetris_speed
// for example: tetris_speed = 255   =>  tbg ~ 0.025 sec  (max speed)
// for example: tetris_speed = 128   =>  tbg = 0.050 sec
// for example: tetris_speed = 64    =>  tbg = 0.100 sec
// for example: tetris_speed = 32    =>  tbg = 0.2 sec
// for example: tetris_speed = 16    =>  tbg = 0.4 sec
// for example: tetris_speed = 8     =>  tbg = 0.8 sec
// for example: tetris_speed = 4     =>  tbg = 1.6 sec
// 
unsigned char tetris_speed;
 
#define SPEEDUP_SPEED 255     // The speed of speedup mode


//
// Falling brick pixel offset
//
signed short falling_pixels;  // this is stored in /256 fixpoint
                              // thus 2560 means 10 pixel offset

unsigned char animation_frame;

unsigned char lines_zapped;


//
// Score keeping
//
// Total number of lines zapped
unsigned short tetris_stats_lines;                              
//
// Number of zap-rounds
unsigned short tetris_stats_zapcount;                              



////////////////////////////////////////////////////////////////////////////////
// BRICK MANAGEMENT IMPLEMENTATION
////////////////////////////////////////////////////////////////////////////////
  
void inline copy_brick(struct Brick_Type *dest, struct Brick_Type *src)
{
  memcpy(dest, src, sizeof(struct Brick_Type));
}

// Expand array of bricks
void new_brick(struct Brick_Type *brick)
{
  if (active_bricks < MAX_BRICKS) {
    copy_brick(&(active_brick[active_bricks]), brick);
    active_bricks++;
  }
  
}

// Delete element from array of bricks
void delete_brick(unsigned char index)
{
  if (index < (active_bricks-1)) {
    copy_brick(&(active_brick[index]), &(active_brick[active_bricks-1]));
  }
  
  active_bricks--;
}
  
// New brick from template
void init_brick_template(struct Brick_Type *dest, unsigned char tno)
{

}



// Rotate brick
void rotate_brick(struct Brick_Type *dest, struct Brick_Type *src, unsigned char ccw)
{
  unsigned char c,b;
  
  if (ccw) {
    b=1;
    for (c=0; c<4; c++) {
      dest->brick[c] = ((src->brick[3] & b)?1:0) | ((src->brick[2] & b)?2:0) | 
                       ((src->brick[1] & b)?4:0) | ((src->brick[0] & b)?8:0);
      b = b<<1;
    }
  }
  else {
    b=8;
    for (c=0; c<4; c++) {
      dest->brick[c] = ((src->brick[0] & b)?1:0) | ((src->brick[1] & b)?2:0) | 
                       ((src->brick[2] & b)?4:0) | ((src->brick[3] & b)?8:0);
      b = b>>1;
    }
  }
  
  dest->x = src->x;
  dest->y = src->y; 
  
  // left adjust
  while (((dest->brick[0] & 1) | (dest->brick[1] & 1) |
          (dest->brick[2] & 1) | (dest->brick[3] & 1)) == 0) {
    dest->brick[0] >>= 1;
    dest->brick[1] >>= 1;
    dest->brick[2] >>= 1;
    dest->brick[3] >>= 1;
  }
  
  // down adjust
  while (dest->brick[0] == 0) {
    dest->brick[0] = dest->brick[1];
    dest->brick[1] = dest->brick[2];
    dest->brick[2] = dest->brick[3];
    dest->brick[3] = 0;
  }  

}

// Split brick in two. Splitrow refers to either 0,1,2,3 of source brick
void split_brick(struct Brick_Type *lower, struct Brick_Type *upper, 
                 struct Brick_Type *src, unsigned char splitrow)
{
  unsigned char c;
  
  copy_brick(upper, src);
  copy_brick(lower, src);
  
  for (c=0; c<=splitrow; c++) {
    upper->brick[c] = 0;
  }
   
  for (c=splitrow; c<4; c++) {
    lower->brick[c] = 0;
  }
 
}

// This function fixes a brick to have row 0 occupied, returns false if brick
// is empty
unsigned char fix_brick(struct Brick_Type *brick)
{
  // check emptiness
  if ((brick->brick[0]|brick->brick[1]|brick->brick[2]|brick->brick[3])==0) 
    return 0;
    
  // fix brick
  while (brick->brick[0] == 0) {
    brick->brick[0] = brick->brick[1];
    brick->brick[1] = brick->brick[2];
    brick->brick[2] = brick->brick[3];
    brick->brick[3] = 0;
    brick->y++;
  }
  
  return 1;
      
}

// Calculate occupancy grid according to active_brick array
void calc_occupancy_grid(void)
{
  unsigned char i;
  unsigned char c,y;
  signed char s;
  
  // clear occupancy grid (only sentinel cubes)
  for (i=0; i<MATRIX_HEIGHT; i++) {
    occupancy[i] = OCCUPANCY_FREE;
  }
  
  // or each brick into grid
  for (i=0; i<active_bricks; i++) {
    s = active_brick[i].x+1;
    y = active_brick[i].y;
    
    for (c=0; c<4; c++) {
      occupancy[c+y] |= (unsigned short)active_brick[i].brick[c] << s;
    }
  }
}

// Xors the brick's cubes in occupancy grid 
void occupancy_xor_brick(struct Brick_Type *brick) 
{
  unsigned char c,y;
  signed char s;
  
  s = brick->x+1;
  y = brick->y;
  
  for (c=0; c<4; c++) {
    occupancy[c+y] ^= (unsigned short)brick->brick[c] << s;
  }
}

// Test if brick fits in occupancy grid
unsigned char test_if_brick_fits(struct Brick_Type *brick) 
{
  unsigned char c,y;
  signed char s;
  unsigned short ret=0;
  
  s = brick->x+1;
  y = brick->y;
  
  for (c=0; c<4; c++) {
    ret |= occupancy[c+y] & ((unsigned short)brick->brick[c] << s);
  }
  
  return (ret==0);
}

// Changes brick positions according to naive gravity, as in traditional tetris
// Returns false if no changes
// Assumes up-to-date occupancy grid, and updates occupancy also.
//
unsigned char apply_naive_gravity(void)
{
  // To emulate naive gravity, the occupancy grid is checked from down to up
  // for any completely cleared rows. If found, all bricks above the cleared
  // row are moved down with animation.
  
  unsigned char i,y;
  unsigned char moving = 0;
  
  // First, check if bricks are currently moving in animation
  for (i=0; i<active_bricks; i++) {
    if (active_brick[i].x & 0xF0) {
      active_brick[i].x -= 1 << 4;
      moving = 1;
    }
  }
    
  if (!moving) {
    // Find first free row in occupancy grid
    y = 0;
    while (occupancy[y] != OCCUPANCY_FREE) {
      if (++y == MATRIX_HEIGHT)
        return 0;
    }
  
    // Find all bricks above this row
    for (i=0; i<active_bricks; i++) {
      if (active_brick[i].y > y) {
        // Remove brick from occupancy grid
        occupancy_xor_brick(&active_brick[i]);
        // Move down and start animation
        active_brick[i].y--;
        // Add brick to occupancy grid in new position
        occupancy_xor_brick(&active_brick[i]);
        // Start animation
        active_brick[i].x |= 10 << 4 ;
        moving = 1;
      }
    }
  }
  
  return moving;
}


// Changes brick positions according to gravity, returns false if no changes
// Assumes up-to-date occupancy grid, and updates occupancy also.
//
unsigned char apply_gravity(void)
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -