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

Enemy.h

Committer:
taylorza
Date:
2015-01-28
Revision:
0:d85c449aca6d
Child:
1:1b8125937f28

File content as of revision 0:d85c449aca6d:

#include <climits>
#include "RallyCar.h"
#include "Player.h"

#ifndef __ENEMY_H__
#define __ENEMY_H__

class Enemy : public RallyCar
{
private:
    enum Action { Start, Chase, Scatter };
    
public:

    Enemy(Point startPosition, Point homePosition, Point targetOffset, Player &player) :
        _startPosition(startPosition),
        _homePosition(homePosition),
        _targetOffset(targetOffset),
        _player(player)
    {        
        reset();
    }            
    
    virtual void reset()
    {
        setPosition(_startPosition);
        
        setDirection(Up);
        setDesiredDirection(Up);
        setState(Driving);
        
        _action = Start;        
        
        setSpriteId(0);
        
        _actionCounter = 0;
        
        _startCount = 90;
        _scatterCount = 210;
        _chaseCount = 600;
    }
 
    virtual void update()
    {        
        ++_actionCounter;
           
        Point &position = getPosition();
        
        bool allowLeftRightTurn = position.Y % 8 == 0;
        bool allowUpDownTurn = position.X % 8 == 0;        
        
        if (getState() == Driving)
        {
            switch(_action)
            {
                case Start:
                    if (_actionCounter == _startCount) 
                    {
                        _action = Scatter;
                        _actionCounter = 0;
                    }
                    break;        
                    
                case Scatter:
                    if (_actionCounter == _scatterCount) 
                    {
                        _action = Chase;
                        _actionCounter = 0;
                    }
                    else
                    {
                        Direction direction = hunt(_homePosition);
                        setDesiredDirection(direction);
                    }
                    break;
                    
                case Chase:
                    if (_actionCounter == _chaseCount) 
                    {
                        _action = Scatter;
                        _actionCounter = 0;
                    }
                    else
                    {      
                        Point target = _player.getPosition();
                        
                        if (distanceToTarget(target) > 4096)
                        {
                            switch(_player.getDirection())
                            {
                                case Left: target.X -= _targetOffset.X; break;
                                case Right: target.X += _targetOffset.X; break;
                                case Up: target.Y -= _targetOffset.Y; break;
                                case Down: target.Y += _targetOffset.Y; break;
                            }
                        }              
                        
                        Direction direction = hunt(target);  
                        setDesiredDirection(direction);
                    }
                    break;
                
            }
            
            if (_action != Start)
            {
                if (getDirection() != getDesiredDirection())
                {            
                    if ((getDesiredDirection() == Left && allowLeftRightTurn && canGoLeft())
                    || (getDesiredDirection() == Right && allowLeftRightTurn && canGoRight())
                    || (getDesiredDirection() == Up && allowUpDownTurn && canGoUp())
                    || (getDesiredDirection() == Down && allowUpDownTurn && canGoDown()))
                    {
                         setDirection(getDesiredDirection());                         
                    }                
                }
            
                switch(getDirection())
                {
                    case Left : setSpriteId(3); moveLeft(); break;
                    case Right : setSpriteId(1); moveRight(); break;
                    case Up : setSpriteId(0); moveUp();break;
                    case Down : setSpriteId(2); moveDown(); break;
                }            
            }
        }
        else 
        {
            if (getState() == StartSpinning)
            {
                _actionCounter = (int)getDirection();
                setState(Spinning);
            }
            
            if (getState() == Spinning)
            {
                setSpriteId(_actionCounter % 4);                
            }
        }
        
        RallyCar::update();
    }
    
private:
    Direction hunt(Point &target)
    {
        Direction bestDirection = None;
        uint32_t minDistance = LONG_MAX;
        
        uint32_t leftDistance = distanceToTarget(target, Left);
        uint32_t rightDistance = distanceToTarget(target, Right);
        uint32_t upDistance = distanceToTarget(target, Up);
        uint32_t downDistance = distanceToTarget(target, Down);
         
        if (getDirection() != Right && canGoLeft() &&  leftDistance < minDistance)
        {
            minDistance = leftDistance;
            bestDirection = Left;
        } 
        
        if (getDirection() != Left && canGoRight() &&  rightDistance < minDistance)
        {
            minDistance = rightDistance;
            bestDirection = Right;
        }
               
        if (getDirection() != Up && canGoDown() &&  downDistance < minDistance)
        {
            minDistance = downDistance;
            bestDirection = Down;
        } 
        
        if (getDirection() != Down && canGoUp() &&  upDistance < minDistance)
        {
            minDistance = upDistance;
            bestDirection = Up;
        }
        
        return bestDirection;
    }
    
    uint32_t distanceToTarget(Point &target)
    {
        int16_t dx = target.X - getPosition().X;
        int16_t dy = target.Y - getPosition().Y;
        return (dx * dx) + (dy * dy);
    }
    
    uint32_t distanceToTarget(Point &target, Direction direction)
    {
        int16_t x = getPosition().X;
        int16_t y = getPosition().Y;
        
        switch(direction)
        {
            case Left   : x -= 16; break;
            case Right  : x += 16; break;
            case Up     : y -= 16; break;
            case Down   : y += 16; break;
        }
        
        int16_t dx = target.X - x;
        int16_t dy = target.Y - y;
        return (dx * dx) + (dy * dy);
    }
    
private:    
    Point       _startPosition;
    Point       _homePosition;
    Point       _targetOffset;
    Player     &_player;
    
    Action      _action;
    uint16_t    _actionCounter;    
    uint16_t    _startCount;
    uint16_t    _scatterCount;
    uint16_t    _chaseCount;       
};
#endif //__ENEMY_H__