For this game, I'd have a cGrid with arrays (or similar) of cTiles, each with a cImage and some flags indicating solidity. That way, your walls are just tiles with different images and a boolean state solid = true.
I'd subclass cTile to cSprite and cItem. I'd subclass cSprite to cEnemy and cPlayer, put automated control code in the cEnemy ( along with a vector of movement direction ), and I'd put manual control code in the player. Using the grid, you can work out whether the player or enemy is able to move into different positions... i.e, say the grid squares are 20x20 units, take the sprites global position, divide the topleft and bottomright points of the player by 20, chop off the fractional part, and the x and y are x and y indices into the grid, then you can see whether the player can or can't move into a given piece of space.
You can use the same principle to check player collisions with enemy and item sprites, by temporarily assigning sprites to cells in the grid.. in some circumstances it can be faster, however, in this circumstance, I'd say it'd be faster to check physical distances between each sprite every cycle.. if you had a bigger space with more sprites though, it might be faster to assign them into the grid. It will certainly be faster to store the walls into the grid; since the walls don't move. Instead of having to check player position against every wall cell, you only have to look at the tile that the player is about to move onto. So, I would make the walls as 'tiles' with solidity, and the enemies as 'sprites'.
Between the player and certain items ( i'd make the door an item ), you want to monitor 'objectives' i.e., your objective is to collect all tokens and reach the door, i suppose in that order. I'd make a few modifications to the cItem class, so that each cItem has a unique ID, and the player has a list of collected IDs. Each cItem can also have a list of required IDs, thus, the tokens would have no required IDs, and the door would have required IDs for the tokens. When the player touches an item, check the collected IDs of the player against the required IDs of the item, if they match, allow the player to collect the item.
In your 'game loop' you'll have something like:
grid.<strong>draw</strong>
foreach enemy
enemylocationtemp = enemy.location + enemy.direction
if grid.<strong>getcell(</strong>enemylocationtemp<strong>)</strong>.issolid
enemy.direction *= -1
else
enemy.location = enemylocationtemp
endif
if enemy.location <strong>distancebetween</strong> player.location is approx ( player.radius + enemy.radius )
fail
endif
enemy.<strong>draw</strong>
end foreach
foreach item
if item.location <strong>distancebetween</strong> player.location is approx ( player.radius + item.radius )
if player <strong>hasallitemsrequiredby</strong> item
player.<strong>additem(</strong> item <strong>)</strong>
item.<strong>removefrommap</strong>
endif
endif
item.<strong>draw</strong>
end foreach
player.<strong>draw</strong>
if player.<strong>hasallitems</strong>
win
endif That's quite oversimplified, the player needs movement code, and personally, I would put the enemy movement code into the enemy class, and give each enemy a pointer to the grid and the player. Perhaps the same with the 'item' class. Alternatively, I'd give the enemy a pointer to the grid only, and the player a pointer to the enemies, and items, and make the player authoritative in each cycle [i.e, have the player check distances to items and enemies , and if neccessary, invoke 'fail' or 'win'] that way, it's easier to imagine multiple players. It's nice to give all sprites a 'run' and 'draw' method, and let them all do their own thing every cycle; this can be done easily, but you need to 'connect everything up' beforehand.
That's how I'd do it.