If i'm not mistaken that Idea is generally considered and Anti-Pattern named Anemic Domain Model, but if you use it wisely it can be beneficial. I Prefer one big function if you are not going to implement many controllers with different behaviors, but if you are going to have more than one controller and decide in runtime what that controller should do, it's not a very bad idea to use them but you have to be very careful to prevent possible errors (like controllers call order).
--EDIT--
I guess if change your function to this way there won't be any problem, and you'll get smaller functions:
class workerA
{
static point nextPos(point currentPos, ...)
{
}
};
class workerB
{
.
.
.
};
class player
{
void move()
{
pos = workerA.nextPos(pos,...);
}
}
I'm not sure if this is a valid design pattern or not but at least classes doesn't have bidirectional pointers, and player class can always guaranty its members, since it's move that calls other methods.
--EDIT2--
This is the best way I could describe my architecture. It's a complete code, with all the thing available in every game. I'm not sure if this is like your previous style or not or if you can convert your code (or even if you are willing to). if you still think there is anything unclear or want to discuss about this code, I think I'll be available in chatroom in 12 hours meaning something around 1:00 GMT.
#include <iostream>
#include <vector>
class Keyboard;
class RenderTarget;
struct Point
{
int x,y;
}
class Rendereable
{
protected :
RenderTarget* mRenderTarget
public:
virtual void draw() = 0;
void setRenderTarget(RenderTarget* pRenderTarget);
}
class world;
class Entity
{
protected:
Point mPosition;
Point mRadius;
public:
virtual void update(world* pWorld) = 0;
void setPosition(Point pPosition);
Point getPosition() const;
bool isColliding(const Entity* pOther) const;
bool isColliding(Point pOther) const;
};
class world
{
protected:
vector<entity*> mEntitys;
int mWidth,mHeight;
public:
void update();
void draw();
void addEntity(const Entity* pEntity);
void removeEntity(const Entity* pEntity);
bool isFree(const Entity* pEntity);
bool isFree(Point* pPoint);
};
class KeyboardController
{
protected:
Keyboard* mKeyboard;
public:
Point getNextPosition(const pEntity* pTarget,World* pWorld);
void setKeyboard(KeyBoard* pKeyboard);
};
class Player : public Entity
{
protected:
KeyboardController* mController;
public:
void setController(KeyBoardController* pController);
virtual void update(World* pWorld);
virtual void draw();
};
class Game
{
World* mWorld;
RenderTarget* mRenderTarget;
Keyboard* mKeyboard;
public:
bool init();
bool update();
void draw();
void shut();
};
int main()
{
Game* game = new Game;
if (game->init())
{
while (game->update())
game->draw();
game->shut();
return 0;
}
return 1; //this means error! only useful when your program is going to be used in batch files!
}
void Renderable::setRenderTarget(RenderTarget* pRenderTarget)
{
mRenderTarget = pRenderTarget;
}
void Entity::setPosition(Point pPosition)
{
mPosition = pPosition;
}
Point Entity::getPosition() const
{
return mPosition;
}
bool Entity::isColliding(const Entity* pOther) const
{
int deltaX = mPosition.x - pOther->mPosition.x;
int deltaY = mPosition.y - pOther->mPosition.y;
int sumRadius = mRadius + pOther->mRadius;
if (sumRadius * sumRadius < deltaX * deltaX + deltaY * deltaY)
return true;
else
return false;
}
bool Entity::isColliding(Point pOther) const
{
int deltaX = mPosition.x - pOther.x;
int deltaY = mPosition.y - pOther.y;
if (mRadius * mRadius < deltaX * deltaX + deltaY * deltaY)
return true;
else
return false;
}
void World::Update()
{
for (auto i = mEntitys.begin();i != mEntity.end();i++)
i->update(this);
}
void World::draw()
{
for (auto i = mEntitys.begin();i != mEntity.end();i++)
i->draw();
}
void World::addEntity(const Entity* pEntity)
{
for (auto i = mEntitys.begin();i != mEntity.end();i++)
if(*i == pEntity)
throw Exception("Entity is already in world");
mEntitys.push_back(pEntity);
}
void World::removeEntity(const Entity* pEntity)
{
for(auto i = mEntitys.begin();i != mEntitys.end();i++)
if(*i == pEntity)
{
mEntitys.erase(i);
return;
}
throw Exception("Entity is not in world");
}
bool World::isFree(const Entity* pEntity)
{
if (pEntity->x < pEntity->radius || pEntity->x > width - pEntity->radius)
return true;
if (pEntity->y < pEntity->radius || pEntity->y > height - pEntity->radius)
return true;
for(auto i = mEntitys.begin();i != mEntitys.end();i++)
if(*i != pEntity)
if(i->isColliding(pEntity))
return true;
return false;
}
bool World::isFree(Point* pPoint)
{
if (pPoint.x < 0 || pPoint.x > mWidth)
return true;
if (pPoint.y < 0 || pPointy > mHeight)
return true;
for(auto i = mEntitys.begin();i != mEntitys.end();i++)
if(i->isColliding(pPoint))
return true;
return false;
}
Point KeyboardController::getNextPosition(const pEntity* pTarget,World* pWorld)
{
Entity x(*pTarget);
if (mKeyboard->isKeyDown(K_UP))
{
y --;
if (pWorld->isFree (x))
return x.getPosition();
y ++;
}
// same function goes for other directions
}
void KeyboardController::setKeyboard(KeyBoard* pKeyboard)
{
mKeyBoard = pKeyBoard;
}
void Player::setController(KeyBoardController* pController)
{
mController = pController;
}
virtual void Player::update(World* pWorld)
{
mPosition = pController->getNextPosition(this, pWorld);
}
virtual void Player::draw()
{
mRenderTarget->Circle(mPosition.x, mPosition.y, mRadius); // a simple drawing function
}
bool Game::init()
{
mWorld = new World;
mKeyboard = new KeyBoard;
mRenderTarget = new RenderTarget;
Player* player = new Player;
KeyBoardController* controller = new KeyBoardController;
player->setController(controller);
player->setRenderTarget(RenderTarget);
mWorld->addEntity(player);
}
bool Game::update()
{
mWorld->update();
}
void Game::draw()
{
mRenderTarget->clearDevice();
mWorld->draw();
}
void Game::shut()
{
}