I am making a simplistic turn-based space game. The player interacts with a 2D map which represents the galaxy/playable area. The map is made up of Sectors and each Sector may contain a number of Planets. Players can interact with the map by moving spacecraft to each sector and colonising as desired.
So, part of my model layer looks like this (I’m oversimplifying here just to be brief):
function Map() {
// An array of Sectors
this.sectors = [];
. . .
}
function Sector() {
// Array of Planets
this.planets = [];
// Array of player built space stations
. . .
this.spaceStations = [];
}
function Planet() {
// Array of player built buildings
this.structures = []
. . .
}
The game currently has two views, a MapView which renders the visible universe:
function MapView() {
// @param _map The game Map object
this.render = function(_map) {
this.canvas = new Canvas();
// Camera can examine the Map to find the part that is currently visible on screen
this.camera = new Camera();
. . .
foreach(_map.sectors as sector) {
LOTS of code and drawImage commands here to . . .
-ask camera if each sector is in currently in view (no point drawing the entire map)
-draw each sector background image (star field or nebula or whatever helps make the game look more natural)
-draw sector boundary lines so we end up with a nice nasty grid over the whole map
-determine what planet sprite image to draw depending on planet type (i.e ROCK, EARTH, GAS)
-draw every planet in each sector (the player can watch these planet sprites ‘orbit’ their sun)
-draw any player created structures in each sector
-draw any ships currently in each sector
}
}
}
and a ExamineSectorView, which renders a selected sector:
function ExamineSectorView() {
// @param _sector A game Sector object
this.render = function(_sector) {
this.canvas = new AnotherCanvas();
. . .
not-so-much-but-growing-suspiciously-large-amount-of-code here to . . .
- foreach { draw planets in currently selected sector (selected from Map) }
- draw space stations
- you get the idea
}
}
I just have one controller right now, MapController. It creates Event listeners on the keyboard/mouse so that the player can interact with the Map, i.e:
- player clicks on a sector in MapView -> view that sector in the ExamineSectorView
- player uses the arrow keys -> scroll the map camera.
At startup, the controller calls methods on the Map (to generate it), creates the views and starts a setInterval timer for view rendering.
What I would like help with is my two views.
I feel that they are both doing far too much.
They do contain logic, but it is view-relevant stuff only and required for the render - like a 10-switch statement to determine a planet type and draw the appropriate image or a little multiplication of a planet's '.size' property to work out how big to draw it. So I think that logic is in the correct place, in the view.
The trouble is that all this view-specific logic adds up to a lot. My view is getting out of hand and would like to separate the rendering of each aspect of the views somehow. For example, like this:
function MapView() {
this.render = function() {
this.canvas = new Canvas();
// Camera can examine the Map to find the part that is currently visible on screen
this.camera = new Camera();
. . .
foreach(_map.sectors as sector) {
mapSectorView = new MapSectorView();
mapSectorView.render(sector);
}
}
}
function MapSectorView() {
this.render = function(_sector) {
this.canvas = new Canvas();
. . .
foreach(sector.planets as planet) {
planetView = new MapSectorPlanetView();
planetView.render(planet);
}
}
}
function MapSectorPlanetView() {
this.render = function(_planet) {
this.canvas = new Canvas();
. . .
foreach(planet.structure as structure) {
structureView = new StructureView();
structureView.render(structure);
}
}
}
. . .
I’ve read other posts on this site that state views should not create one another. If so, an alternative to the above would be to create all required views in the controller and start passing them around; i.e
mapView.render(mapModelObject, mapSectorView, mapPlanetView);
I’m not too sure that is the way to solve this issue either.
I can imagine this game is going to get big fairly quickly and I know the view will get much more complex as I develop the game so I’d appreciate any advice on how to manage rendering in a MVC game like this, especially regarding separation of concerns in a JS/canvas environment.
I just found: MVC: Data Models and View Models
I'm wondering if that is a possible solution here; create some viewmodels i.e MapViewModel that holds all the views it needs and renders each one.
Thanks!