Retro Invaders a space invaders clone by Chris Favreau. Written for the RetroMbuino development board from outrageouscircuits.com for the game programming contest.
This is a space invaders clone written for the Retro Mbuino from outrageous circuits.
Development board: http://www.outrageouscircuits.com/shop/product/15 ).
The game itself is basic space invaders. Shoot them before they get to the bottom of the screen. It has a UFO saucer which you can shoot for extra points. You get 4 shields and each shield can be hit up to 4 times before it is gone. Hmm... as each level increases the speed of the invaders shots goes up. The invaders only speed up when there is less of them. You complete the level when you shoot all the invaders. The game ends when a) you run out of lives (you start with 3) or the invaders get to the bottom.
The LEDs turned out to be a pretty cool addition to the game. I wrote a class that blinks them and turns them on for a specified amount of time. They add a nice extra to the game. I use them on the intro screen and when the UFO is present.
The sound turned out to be really difficult for a few reasons. The biggest was that I had never written a sound engine before. The interrupt service routine working off the timer was the easier part. I also had a lot of trouble because there is no filter to filter out the PWM frequency to the speaker... so I had to run the PWM frequency way up there 30 kHz.
The graphics turned out to be a bit of a bear too. Thanks to Chris Taylor for his really great LCD API. I picked up a couple of frames per second from that. I had modified the DisplayN18 class for blitting a single line buffer to the LCD panel however his is a little faster for some reason? I used a different approach to doing the graphics (as I have very little experience with anything other than double buffered displays). I have a tile map and a list of sprites. Each tile/sprite is 1 bit 8x8. They could be bigger. I ran out of time. That much is not special. What is different from what I can tell is that I use a 1 line buffer that is 160 shorts long. The render function first adds the tile map data into the line buffer first. Then the sprites are added over the existing data. You can have a great deal of different sprites and maps going to the screen and just have to rewrite the LCD memory once per frame. After each line is composited, the line is then drawn to the LCD. Kind of like an Atari 2600. Each sprite/tile has a foreground and background color and can be different from the other tiles/sprites. There is one color reserved for Transparency.
There are 16 colors to choose from. I chose a palette based on the Macintosh OS 4.1 palette I found on WikiPedia. It is a very nice mix of colors.
I found a sprite editor called SpriteX ( https://code.google.com/p/spritesx-ed/ )... it works nicely except that the 16x16 sprites are in a weird format. Time limited me to 8x8 sprites. Oh well.
I used nokring to make the music. It makes RTTTL formatted ring tones which my sound api can play. Here is a useful site that has lots of arcade/video game ring tones with a link to nokring in the utilities page. http://arcadetones.emuunlim.com/files.htm
Other than all that stuff I used state machines to do most of the game logic. Please excuse the horrible coding as I tried to comment a lot of it however it is not very nice to look at. Lots of long functions...
Display/display.cpp
- Committer:
- cfavreau
- Date:
- 2015-03-03
- Revision:
- 0:c79e1f29f029
File content as of revision 0:c79e1f29f029:
#include <stdarg.h> // va_list #include "display.h" #include "font8x8.h" // default 8x8 bitmap font #include "colors.h" // predefined colors #define COLOR(fore, back) ((fore << 4) | (back & 0x0F)) display::display() : LCD_ST7735(P0_19, P0_20, P0_7, P0_21, P0_22, P1_15, P0_2, LCD_ST7735::RGB) { // Fill out the default color palette - use the MSX/Coleco default 16 color palette // Found them here: http://theadamresource.com/articles/misc/wk970202.html memset(m_color_pal, 0, COLOR_PAL_LEN * sizeof(uint16_t)); /* m_color_pal[0] = RGB2SHORT(0, 0, 0); // BLACK - Transparent (support in display code) m_color_pal[1] = RGB2SHORT(0, 0, 0); // BLACK - Opaque m_color_pal[2] = RGB2SHORT(71, 183, 59); // Medium Green m_color_pal[3] = RGB2SHORT(124, 207, 111); // Light Green m_color_pal[4] = RGB2SHORT(93, 18, 255); // Dark Blue m_color_pal[5] = RGB2SHORT(128, 114, 255); // Light Blue m_color_pal[6] = RGB2SHORT(182, 91, 71); // Dark Red (maybe brown) m_color_pal[7] = RGB2SHORT(93, 200, 237); // Cyan m_color_pal[8] = RGB2SHORT(215, 107, 72); // Medium Red m_color_pal[9] = RGB2SHORT(251, 143, 108); // Light Red m_color_pal[10] = RGB2SHORT(195, 205, 65); // Dark Yellow m_color_pal[11] = RGB2SHORT(211, 218, 118); // Light Yellow m_color_pal[12] = RGB2SHORT(62, 159, 47); // Dark Green m_color_pal[13] = RGB2SHORT(182, 100, 199); // Magenta m_color_pal[14] = RGB2SHORT(204, 204, 204); // Grey m_color_pal[15] = RGB2SHORT(255, 255, 255); // White */ /* m_color_pal[0] = RGB2SHORT(0, 0, 0); // BLACK - Transparent (support in display code) m_color_pal[1] = RGB2SHORT(0, 0, 0); // BLACK - Opaque m_color_pal[2] = RGB2SHORT(32, 192, 32); // Medium Green m_color_pal[3] = RGB2SHORT(96, 224, 96); // Light Green m_color_pal[4] = RGB2SHORT(32, 32, 224); // Dark Blue m_color_pal[5] = RGB2SHORT(64, 96, 224); // Light Blue m_color_pal[6] = RGB2SHORT(160, 32, 32); // Dark Red (maybe brown) m_color_pal[7] = RGB2SHORT(64, 192, 224); // Cyan m_color_pal[8] = RGB2SHORT(224, 32, 32); // Medium Red m_color_pal[9] = RGB2SHORT(224, 96, 96); // Light Red m_color_pal[10] = RGB2SHORT(192, 192, 32); // Dark Yellow m_color_pal[11] = RGB2SHORT(192, 192, 128); // Light Yellow m_color_pal[12] = RGB2SHORT(32, 128, 32); // Dark Green m_color_pal[13] = RGB2SHORT(192, 64, 160); // Magenta m_color_pal[14] = RGB2SHORT(160, 160, 160); // Grey m_color_pal[15] = RGB2SHORT(255, 255, 255); // White */ // Mac OS4.1 16 Color Palette (modified for transparent) // Found here: http://upload.wikimedia.org/wikipedia/commons/5/57/Mac_16colors_palette.png m_color_pal[0] = RGB2SHORT(255, 255, 255); // White m_color_pal[1] = RGB2SHORT(255, 255, 0); // Yellow m_color_pal[2] = RGB2SHORT(255, 102, 0); // Orange m_color_pal[3] = RGB2SHORT(255, 0, 0); // Red m_color_pal[4] = RGB2SHORT(255, 0, 103); // Magenta m_color_pal[5] = RGB2SHORT(51, 0, 153); // Dark Blue m_color_pal[6] = RGB2SHORT(0, 0, 204); // Blue m_color_pal[7] = RGB2SHORT(0, 153, 255); // Light Blue m_color_pal[8] = RGB2SHORT(0, 255, 0); // Green m_color_pal[9] = RGB2SHORT(0, 102, 0); // Dark Green m_color_pal[10] = RGB2SHORT(102, 51, 0); // Brown m_color_pal[11] = RGB2SHORT(153, 102, 51); // Light Brown m_color_pal[12] = RGB2SHORT(187, 187, 187); // Light Grey m_color_pal[13] = RGB2SHORT(136, 136, 136); // Grey m_color_pal[14] = RGB2SHORT(0, 0, 0); // White m_color_pal[15] = RGB2SHORT(0, 0, 0); // Transparent (black) // Allocate our line buffer m_line_buffer = new uint8_t[LINE_BUFFER_LEN]; // Set our default colors m_fore_color = PAL_WHITE; m_back_color = PAL_TRANSPARENT; clear(); // Initialize our sprite list for (int i = 0; i < MAX_SPRITES; i++) memset(&sprite_list[i], 0, sizeof(SPRITE)); // Clear our user character buffer memset(user_char, 0, MAX_USER_CHAR_BUF_LEN); } display::~display() { } void display::clear() { // Clear our character map buffer memset(m_char_map, 0, CHAR_MAP_LEN); // Clear our color map buffer memset(m_color_map, COLOR(m_fore_color, m_back_color), CHAR_MAP_LEN); // Set the cursor position back to 0 m_cursor_x = 0; m_cursor_y = 0; } void display::bounds_check_and_scroll() { // Check to see if our Y cursor location is beyond our map height if (m_cursor_y >= CHAR_MAP_HEIGHT) { // Check to see if we are // Scroll everything up 1 line memcpy(m_char_map, &m_char_map[CHAR_MAP_WIDTH], CHAR_MAP_LAST_LINE); memcpy(m_color_map, &m_color_map[CHAR_MAP_WIDTH], CHAR_MAP_LAST_LINE); // Clear the bottom line memset(&m_char_map[CHAR_MAP_LAST_LINE], 0, CHAR_MAP_WIDTH); memset(&m_color_map[CHAR_MAP_LAST_LINE], COLOR(m_fore_color, m_back_color), CHAR_MAP_WIDTH); // Put the position of the cursor on the last line m_cursor_y = CHAR_MAP_HEIGHT - 1; m_cursor_x = 0; } } void display::crlf() { // Advance our cursor to the next line m_cursor_x = 0; m_cursor_y++; } void display::print(char *pString) { // Bounds check the cursor position (and do scrolling if we need to) // before we put any characters in the map bounds_check_and_scroll(); // Calculate the current linear cursor position int pos = get_linear_cursor_pos(); // Loop through the string and put it into the character map while (*pString) { char character = *pString; /* // Handle a carriage return if (character == 10) { m_cursor_x = 0; pos = get_linear_cursor_pos(); } else // Handle a line feed if (character == 13) { m_cursor_y++; bounds_check_and_scroll(); pos = get_linear_cursor_pos(); } else */ { if ((character < 32) || (character > 126)) { // Some other special character character = 95; // substitue a solid block if there is a special character } else { // Just subtract out the special character offset character -= 32; } // Place the character into the map m_char_map[pos] = character; // Copy the forecolor into the map m_color_map[pos] = COLOR(m_fore_color, m_back_color); // Next linear position pos++; // Advance the cursor position m_cursor_x++; if (m_cursor_x >= CHAR_MAP_WIDTH) { if (m_word_wrap) { // Next line crlf(); pos = get_linear_cursor_pos(); } else { // Stop putting the characters in the map // we have hit the end of the line break; } } } // Next character pString++; } } void display::print(int iNumber) { char sTemp[CHAR_MAP_WIDTH]; snprintf(sTemp, CHAR_MAP_WIDTH, "%d", iNumber); print(sTemp); } void display::print(float fNumber) { char sTemp[CHAR_MAP_WIDTH]; snprintf(sTemp, CHAR_MAP_WIDTH, "%0.2f", fNumber); print(sTemp); } void display::print(const char *format, ...) { char sTemp[CHAR_MAP_WIDTH]; va_list list; va_start(list, format); // Print something in the file vsnprintf(sTemp, CHAR_MAP_WIDTH, format, list); print(sTemp); } void display::println(char *pString) { print(pString); crlf(); } void display::println(int iNumber) { print(iNumber); crlf(); } void display::println(float fNumber) { print(fNumber); crlf(); } void display::println(const char *format, ...) { char sTemp[CHAR_MAP_WIDTH]; va_list list; va_start(list, format); // Print something in the file vsnprintf(sTemp, CHAR_MAP_WIDTH, format, list); println(sTemp); } void display::printat(uint8_t x, uint8_t y, char *pString) { // Bounds check the coordinates if (x >= CHAR_MAP_WIDTH) return; if (y >= CHAR_MAP_HEIGHT) return; // Get the starting linear position int pos = get_linear_pos(x, y); // Loop through the string and put it into the character map while (*pString) { char character = *pString; // Ignore CR and LF if ((character == 10) || (character == 13)) { pString++; continue; } if ((character < 32) || (character > 126)) { // Some other special character character = 95; // substitue a solid block if there is a special character } else { // Just subtract out the special character offset character -= 32; } // Place the character into the map m_char_map[pos] = character; // Copy the forecolor into the map m_color_map[pos] = COLOR(m_fore_color, m_back_color); // Next linear position pos++; // Advance the cursor position x++; // Check for out of bounds in which case we just exit if (x >= CHAR_MAP_WIDTH) return; if (pos >= CHAR_MAP_LEN) return; // Next character pString++; } } void display::printat(uint8_t x, uint8_t y, int iNumber) { char sTemp[CHAR_MAP_WIDTH]; snprintf(sTemp, CHAR_MAP_WIDTH, "%d", iNumber); printat(x, y, sTemp); } void display::printat(uint8_t x, uint8_t y, float fNumber) { char sTemp[CHAR_MAP_WIDTH]; snprintf(sTemp, CHAR_MAP_WIDTH, "%0.2f", fNumber); printat(x, y, sTemp); } void display::printat(uint8_t x, uint8_t y, const char *format, ...) { char sTemp[CHAR_MAP_WIDTH]; va_list list; va_start(list, format); // Print something in the file vsnprintf(sTemp, CHAR_MAP_WIDTH, format, list); printat(x, y, sTemp); } void display::setcharat(uint8_t x, uint8_t y, uint8_t character, uint8_t fore_color, uint8_t back_color) { // Bounds check the coordinates if (x >= CHAR_MAP_WIDTH) return; if (y >= CHAR_MAP_HEIGHT) return; // Get the starting linear position int pos = get_linear_pos(x, y); // Place the character into the map m_char_map[pos] = character; // Check the colors if (fore_color >= 16) fore_color = m_fore_color; if (back_color >= 16) back_color = m_back_color; // Copy the forecolor into the map m_color_map[pos] = COLOR(fore_color, back_color); } void display::blit_line(uint8_t line) { if (line >= LCD_HEIGHT) return; // LCD_ST7735 clip(0, line, 159, 0); write(0x2C, m_line_buffer, LINE_BUFFER_LEN); // DisplayN18 //setClippingArea(0, line, 159, 0); //writeCommand(0x2C); //writeData(m_line_buffer, LINE_BUFFER_LEN); } void display::render() { uint16_t *line_buf = (uint16_t *)m_line_buffer; uint8_t *char_buf = font8x8_basic; register uint8_t data = 0; int cindex = 0; int char_line = 0; int line_x = 0; for (int line = 0; line < LCD_HEIGHT; line++) { line_x = 0; cindex = (line >> 3) * CHAR_MAP_WIDTH; for (int map_x = 0; map_x < CHAR_MAP_WIDTH; map_x++) { register uint8_t data_index = m_char_map[cindex]; if (data_index < 128) data = char_buf[(data_index << 3) + char_line]; else data = user_char[((data_index - 128) << 3) + char_line]; register uint16_t fore_color = m_color_pal[m_color_map[cindex] >> 4]; register uint16_t back_color = m_color_pal[(m_color_map[cindex] & 0x0F)]; line_buf[line_x++] = (data & 0x01) ? fore_color : back_color; line_buf[line_x++] = (data & 0x02) ? fore_color : back_color; line_buf[line_x++] = (data & 0x04) ? fore_color : back_color; line_buf[line_x++] = (data & 0x08) ? fore_color : back_color; line_buf[line_x++] = (data & 0x10) ? fore_color : back_color; line_buf[line_x++] = (data & 0x20) ? fore_color : back_color; line_buf[line_x++] = (data & 0x40) ? fore_color : back_color; line_buf[line_x++] = (data & 0x80) ? fore_color : back_color; // Next character in our map cindex++; } char_line++; if (char_line >= CHAR_HEIGHT) char_line = 0; // Add in the sprites ... they are the TOP layer for (int iSprite = 0; iSprite < MAX_SPRITES; iSprite++) { // Check to see if the sprite is enabled if (!sprite_list[iSprite].enabled) continue; // Check to see if the sprite is within our current line if (line < sprite_list[iSprite].y) continue; if (line >= (sprite_list[iSprite].y + 8)) continue; // Get the row of the sprite we are blitting register uint8_t row = line - sprite_list[iSprite].y; // Get the x position register uint8_t x = sprite_list[iSprite].x; // Get the foreground color register uint16_t fc = m_color_pal[sprite_list[iSprite].fore_color]; register uint16_t bc = m_color_pal[sprite_list[iSprite].back_color]; // Get the starting index for the sprite into the user character buffer register uint8_t data = user_char[(sprite_list[iSprite].char_index << 3) + row]; if (sprite_list[iSprite].back_color != PAL_TRANSPARENT) { line_buf[x] = (data & 0x01) ? fc : bc; x++; line_buf[x] = (data & 0x02) ? fc : bc; x++; line_buf[x] = (data & 0x04) ? fc : bc; x++; line_buf[x] = (data & 0x08) ? fc : bc; x++; line_buf[x] = (data & 0x10) ? fc : bc; x++; line_buf[x] = (data & 0x20) ? fc : bc; x++; line_buf[x] = (data & 0x40) ? fc : bc; x++; line_buf[x] = (data & 0x80) ? fc : bc; x++; } else { if (data & 0x01) line_buf[x] = fc; x++; if (data & 0x02) line_buf[x] = fc; x++; if (data & 0x04) line_buf[x] = fc; x++; if (data & 0x08) line_buf[x] = fc; x++; if (data & 0x10) line_buf[x] = fc; x++; if (data & 0x20) line_buf[x] = fc; x++; if (data & 0x40) line_buf[x] = fc; x++; if (data & 0x80) line_buf[x] = fc; x++; } } // Draw the line blit_line(line); } } void display::AddSprite(int iSpriteNum, int iChar, int x, int y, int fore_color, int back_color, bool midhandle) { if (iSpriteNum < 0) return; if (iSpriteNum >= MAX_SPRITES) return; if (iChar >= MAX_USER_CHAR) return; sprite_list[iSpriteNum].char_index = iChar; sprite_list[iSpriteNum].x = x; sprite_list[iSpriteNum].y = y; sprite_list[iSpriteNum].fore_color = fore_color; sprite_list[iSpriteNum].back_color = back_color; sprite_list[iSpriteNum].midhandle = midhandle; // CHeck to see if we treat the X and Y coordinates as the middle of the sprite... if (midhandle) { // Redo the XY coordinates SetSpritePos(iSpriteNum, x, y); } // Set the enabled flag last just in case we get called from an interrupt or we are interrupted sprite_list[iSpriteNum].enabled = true; } void display::EnableSprite(int iSpriteNum, bool bEnable) { if (iSpriteNum < 0) return; if (iSpriteNum >= MAX_SPRITES) return; sprite_list[iSpriteNum].enabled = bEnable; } void display::RemoveSprite(int iSpriteNum) { EnableSprite(iSpriteNum, false); } void display::SetSpriteChar(int iSpriteNum, int iChar) { if (iSpriteNum < 0) return; if (iSpriteNum >= MAX_SPRITES) return; if (iChar >= MAX_USER_CHAR) return; sprite_list[iSpriteNum].char_index = iChar; } void display::SetSpritePos(int iSpriteNum, int x, int y) { if (iSpriteNum < 0) return; if (iSpriteNum >= MAX_SPRITES) return; if (sprite_list[iSpriteNum].midhandle) { x -= 4; y -= 4; } sprite_list[iSpriteNum].x = x; sprite_list[iSpriteNum].y = y; } void display::SetSpriteColor(int iSpriteNum, int fore_color, int back_color) { if (iSpriteNum < 0) return; if (iSpriteNum >= MAX_SPRITES) return; sprite_list[iSpriteNum].fore_color = fore_color; sprite_list[iSpriteNum].back_color = back_color; } void display::SetMidHandle(int iSpriteNum, bool bEnable) { if (iSpriteNum < 0) return; if (iSpriteNum >= MAX_SPRITES) return; sprite_list[iSpriteNum].midhandle = bEnable; } void display::SetCustomChar(int iCharNum, uint8_t *pBuf, int iNum, bool isMSX) { if (iCharNum >= MAX_USER_CHAR) return; if ((iNum + iCharNum) > MAX_USER_CHAR) return; for (int i = 0; i < iNum; i++) { if (isMSX) SetCustomChar8x8MSX(iCharNum + i, pBuf); else SetCustomChar8x8Norm(iCharNum + i, pBuf); pBuf += 8; } } void display::SetCustomChar8x8Norm(int iCharNum, uint8_t *pBuf) { if (iCharNum >= MAX_USER_CHAR) return; memcpy(&user_char[iCharNum * 8], pBuf, 8); } void display::SetCustomChar8x8MSX(int iCharNum, uint8_t *pBuf) { if (iCharNum >= MAX_USER_CHAR) return; // 8x8 MSX tiles have the bit order reversed for (int i = 0; i < 8; i++) { uint8_t temp2 = 0; uint8_t temp1 = pBuf[i]; for (int bit = 0; bit < 8; bit++) { temp2 = temp2 << 1; temp2 |= (temp1 & 0x01); temp1 = temp1 >> 1; } user_char[iCharNum * 8 + i] = temp2; } } void display::set_map(uint8_t char_index, uint8_t x, uint8_t y, uint8_t fore_color, uint8_t back_color) { if (x >= CHAR_MAP_WIDTH) return; if (y >= CHAR_MAP_HEIGHT) return; int pos = get_linear_pos(x, y); m_char_map[pos] = char_index; m_color_map[pos] = COLOR(fore_color, back_color); } void display::set_map_info(uint16_t tile_info, uint8_t x, uint8_t y) { if (x >= CHAR_MAP_WIDTH) return; if (y >= CHAR_MAP_HEIGHT) return; int pos = get_linear_pos(x, y); m_char_map[pos] = (tile_info >> 8); m_color_map[pos] = (tile_info & 0x00FF); } uint8_t display::get_map(uint8_t x, uint8_t y) { return (get_map_info(x, y) >> 8); } uint8_t display::get_map_color(uint8_t x, uint8_t y) { return (get_map_info(x, y) & 0x00FF); } uint16_t display::get_map_info(uint8_t x, uint8_t y) { if (x >= CHAR_MAP_WIDTH) return 0; if (y >= CHAR_MAP_HEIGHT) return 0; int pos = get_linear_pos(x, y); return ((m_char_map[pos] << 8) | m_color_map[pos]); } void display::shift_map(SHIFT_DIRECTION direction, int inc, bool clear_after_shift) { switch (direction) { case (eShiftUp): for (int i = 1; i < CHAR_MAP_HEIGHT; i++) { memcpy(&m_char_map[(i - 1) * CHAR_MAP_WIDTH], &m_char_map[i * CHAR_MAP_WIDTH], CHAR_MAP_WIDTH); memcpy(&m_color_map[(i - 1) * CHAR_MAP_WIDTH], &m_color_map[i * CHAR_MAP_WIDTH], CHAR_MAP_WIDTH); } if (clear_after_shift) { // Clear the bottom row memset(&m_char_map[CHAR_MAP_HEIGHT - 1], 0, CHAR_MAP_WIDTH); memset(&m_color_map[CHAR_MAP_HEIGHT - 1], COLOR(m_fore_color, m_back_color), CHAR_MAP_WIDTH); } break; case (eShiftDown): for (int i = (CHAR_MAP_HEIGHT - 1); i > 0; i--) { memcpy(&m_char_map[i * CHAR_MAP_WIDTH], &m_char_map[(i - 1) * CHAR_MAP_WIDTH], CHAR_MAP_WIDTH); memcpy(&m_color_map[i * CHAR_MAP_WIDTH], &m_color_map[(i - 1) * CHAR_MAP_WIDTH], CHAR_MAP_WIDTH); } if (clear_after_shift) { // Clear the top row memset(&m_char_map[0], 0, CHAR_MAP_WIDTH); memset(&m_color_map[0], COLOR(m_fore_color, m_back_color), CHAR_MAP_WIDTH); } break; case (eShiftLeft): for (int y = 0; y < CHAR_MAP_HEIGHT; y++) { for (int x = 1; x < CHAR_MAP_WIDTH; x++) { int pos = get_linear_pos(x, y); m_char_map[pos - 1] = m_char_map[pos]; m_color_map[pos -1] = m_color_map[pos]; } } if (clear_after_shift) { // Clear the right column for (int y = 0; y < CHAR_MAP_HEIGHT; y++) { m_char_map[get_linear_pos((CHAR_MAP_WIDTH - 1), y)] = 0; m_color_map[get_linear_pos((CHAR_MAP_WIDTH - 1), y)] = COLOR(m_fore_color, m_back_color); } } break; case (eShiftRight): for (int y = 0; y < CHAR_MAP_HEIGHT; y++) { for (int x = (CHAR_MAP_WIDTH - 1); x > 0; x--) { int pos = get_linear_pos(x, y); m_char_map[pos] = m_char_map[pos - 1]; m_color_map[pos] = m_color_map[pos - 1]; } } if (clear_after_shift) { // Clear the left column for (int y = 0; y < CHAR_MAP_HEIGHT; y++) { m_char_map[get_linear_pos(0, y)] = 0; m_color_map[get_linear_pos(0, y)] = COLOR(m_fore_color, m_back_color); } } break; } } bool display::SpriteCollision(int iSpriteNum1, int iSpriteNum2) { if (iSpriteNum1 < 0) return false; if (iSpriteNum1 >= MAX_SPRITES) return false; if (iSpriteNum2 < 0) return false; if (iSpriteNum2 >= MAX_SPRITES) return false; SPRITE *pSprite1 = &sprite_list[iSpriteNum1]; SPRITE *pSprite2 = &sprite_list[iSpriteNum2]; if (!pSprite1->enabled) return false; if (!pSprite2->enabled) return false; // Bounding box collision - might be broken /* int dx = pSprite1->x - pSprite2->x; if (dx < 0) dx *= -1; int dy = pSprite1->y - pSprite2->y; if (dy < 0) dy *= -1; return ((dx < 16) && (dy < 16)); */ // Circle based collision detection int dx = pSprite1->x - pSprite2->x; int dy = pSprite1->y - pSprite2->y; int dist = (dx * dx) + (dy * dy); int r = 3 + 3; // make the radius 4 - 1 return (dist < (r * r)); // TODO - perhaps after the circle detection maybe we can do pixel perfect detection... // OR - do detection when we are rendering??? }