Hi Colin,
If you intend to let the OS in for anything at all, take a look at the thread in 'Programming discussion' called something like "Memory from &E00 to &1900", where I put a list of all the OS-safe memory areas you can use.
If you intend to shut the OS out completely, and reconfigure all the hardware your own way, then you can pretty much use EVERY BYTE of RAM, with the following exceptions:
$FC is corrupted by the OS IRQ entry point.
$204 and $205 are the IRQ jump vector, so you'll need to keep those for that purpose.
$258 should contain 2 and $287 should contain anything but $4C for a clean restart when Break is pressed.
$D00 should contain an RTI instruction as it's the NMI entry point.
Other than that, go wild
Of course in Mode 2, $3000-$8000 is screen memory. If you read up on the CRTC registers, you'll see that you can configure the screen dimensions on the Beeb, making them smaller and thus freeing up a little extra memory - this is fairly common practice, as a 20k screen is a LOT!
When loading the game, you'll have to load the executable to a higher address (anywhere above &1200 should be safe for any filesystem), and then, at its entry point, have a bit of stub code (which is discarded once run) which relocates it to the 'correct' address before JMPing to the correct place. I put my hardware configuration in this entry code too, so that it's discarded afterwards and doesn't take up valuable bytes! For safety, select the tape filing system before obliterating OS memory, and also make sure that interrupts are disabled, or being handled by your own code which doesn't return control to the OS.
Edit to say: $100...$1FF is the 6502 stack - but of course you can use as much of this as you dare too. I have LDX #31:TXS at the top of my code, which gives me 32 bytes of stack - doesn't sound much, but I tend not to use the stack for much, only JSRs and interrupts. If I want to preserve registers, I tend to use zp, or even self modify a LDA #xx at the end of the routine. Then I can use from $120 onwards for code. Also, in a 'debug build' in the main loop I check locations $1FE and $1FF contain what they should, so I can catch any stack overflows - but so far, I've never had a problem.