Race around the city collecting the flags while avoiding those that stand in the way of your mission. Make no mistake you will need to be quick to outwit your opponents, they are smart and will try to box you in. I wrote this game to prove that writing a game with scrolling scenery is possible even with the limited 6kB of RAM available. I had to compromise sound effects for features, I wanted multiple opponents, I wanted to be able to drop smoke bombs to trap the opponents but all this required memory so the sound effects had to take a back seat.

Dependencies:   mbed

GameEngine/TileViewer.cpp

Committer:
taylorza
Date:
2015-02-01
Revision:
1:1b8125937f28
Parent:
0:d85c449aca6d

File content as of revision 1:1b8125937f28:

#include "mbed.h"
#include "TileViewer.h"
#include "GameEngine.h"

#define max(a, b) ((a < b) ? b : a)
#define min(a, b) ((a > b) ? b : a)


TileViewer::TileViewer(uint8_t viewTilesX, uint8_t viewTilesY) :
    _bitmap(viewTilesX * 8, viewTilesY * 8),    
    _canvas(&_bitmap),
    _viewTilesX(viewTilesX),
    _viewTilesY(viewTilesY),
    _map(NULL),
    _mapTilesX(0),
    _mapTilesY(0),
    _offsetX(0),
    _offsetY(0),
    _blocks(NULL),
    _sprites(NULL),
    _pTrackedGameObject(NULL)
{
}
        
void TileViewer::setMap(const uint8_t *map, uint8_t mapTilesX, uint8_t mapTilesY, const Block *blocks, Sprite *sprites)
{
    _map = map;
    _mapTilesX = mapTilesX;
    _mapTilesY = mapTilesY;
    _blocks = blocks;
    _sprites = sprites;
}

void TileViewer::addGameObject(GameObject *gameObject)
{
    for (int i = 0; i < MAX_GAMEOBJECTS; ++i)
    {
        if (_gameObjects[i] == NULL) 
        {
            _gameObjects[i] = gameObject;
            gameObject->setParent(this);
            break;
        }
    }
}

void TileViewer::removeGameObject(GameObject *gameObject)
{
    for (int i = 0; i < MAX_GAMEOBJECTS; ++i)
    {
        if (_gameObjects[i] == gameObject) 
        {
            gameObject->setParent(NULL);
            _gameObjects[i] = NULL;
            break;
        }
    }
}

void TileViewer::track(GameObject *pGameObject)
{
    _pTrackedGameObject = pGameObject;
}
        
const GameObject* TileViewer::detectCollision(GameObject *primary)
{
    for (int i = 0; i < MAX_GAMEOBJECTS; ++i)
    {
        GameObject *other = _gameObjects[i];
        if (other != NULL && other != primary)
        {
            if (detectCollision(primary, other))
            {
                return other;
            }
        }
    }
    return NULL;
}

bool TileViewer::detectCollision(GameObject *o1, GameObject *o2)
{
    Rect r1 = o1->getCollisionRect();
    Rect r2 = o2->getCollisionRect();
    
    return r1.left < r2.right &&
     r2.left < r1.right &&
     r1.top < r2.bottom &&
     r2.top < r1.bottom;       
}

const Block* TileViewer::detectBlock(GameObject *primary)
{
    return NULL;
}

void TileViewer::centerAt(int16_t x, int16_t y)
{
    _offsetX = x - (_viewTilesX / 2) * 8;
    _offsetY = y - (_viewTilesY / 2) * 8;
    
    int maxOffsetX = (_mapTilesX - _viewTilesX) * 8;
    int maxOffsetY = (_mapTilesY - _viewTilesY) * 8;
    
    if (_offsetX < 0) _offsetX = 0;
    if (_offsetX > maxOffsetX) _offsetX = maxOffsetX;
    
    if (_offsetY < 0) _offsetY = 0;
    if (_offsetY > maxOffsetY) _offsetY = maxOffsetY;
}

bool TileViewer::canEnter(uint16_t x, uint16_t y)
{
    const Block &block = getBlock(x, y);
    Block::Type type = block.getType();
    
    switch(type)
    {
        case Block::Background : return true;
        case Block::Solid : return false;
    }
    
    return true;
}

const Block& TileViewer::getBlock(uint16_t x, uint16_t y)
{
    uint8_t tileX = x / 8;
    uint8_t tileY = y / 8;
    uint8_t blockId = _map[(tileY * _mapTilesX) + tileX];
    return _blocks[blockId];        
}

void TileViewer::animate(uint8_t spriteId)
{
    Sprite &sprite = _sprites[spriteId];
    sprite.animate();
}

bool TileViewer::pickupObject(uint8_t tileX, uint8_t tileY)
{
    return false;
}

void TileViewer::drawSprite(uint8_t spriteId, int16_t x, int16_t y)
{
    const Sprite &sprite = _sprites[spriteId];
    const ImageFrame &frame = sprite.getFrame();
    
    _canvas.drawBitmap(x, y, (Bitmap2bpp&)frame.getBitmap(), frame.getX(), frame.getY(), frame.getWidth(), frame.getHeight(), true);
}

void TileViewer::update()
{
    for (int i = 0; i < MAX_GAMEOBJECTS; ++i)
    {
        GameObject *p = _gameObjects[i];
        if (p != NULL)
        {
            p->update();
        }
    } 
    
    if (_pTrackedGameObject != NULL)
    {
        Point &position = _pTrackedGameObject->getPosition();
        centerAt(position.X + 8, position.Y + 8);
    }   
}

void TileViewer::draw()
{    
    _canvas.clear();
    
    int firstTileX = max(0, _offsetX / 8);
    int firstTileY = max(0, _offsetY / 8);
    int lastTileX =  min(_mapTilesX, firstTileX + _viewTilesX + 1);
    int lastTileY =  min(_mapTilesY, firstTileY + _viewTilesY + 1);
    
    int adjustX = _offsetX % 8;
    int adjustY = _offsetY % 8;
    
    for (int y = -adjustY, yTile = firstTileY; yTile < lastTileY; ++yTile, y += 8)
    {
        int offset = yTile * _mapTilesX;
        for (int x = -adjustX, xTile = firstTileX; xTile < lastTileX; ++xTile, x += 8)
        {
            uint8_t blockId = _map[offset + xTile];
            if (blockId == 0) continue;
            
            const Block &block = _blocks[blockId];
            const ImageFrame &frame = block.getFrame();
            
            _canvas.drawBitmap(x, y, (Bitmap2bpp&)frame.getBitmap(), 
                frame.getX(), frame.getY(),
                frame.getWidth(), frame.getHeight(), false);
        }
    }
    
    for (int i = 0; i < MAX_GAMEOBJECTS; ++i)
    {
        GameObject *p = _gameObjects[i];
        if (p != NULL)
        {
            p->draw();
        }
    } 
    Game::Surface.drawBitmap(0, 0, _bitmap, 0, 0, _bitmap.getWidth(), _bitmap.getHeight());        
}