Tuesday 20th October 2009 at 13:44 = CyberspaceView ~ the Realm-Maker module
Addendum written: Monday 9th November 2009 at 12:41.
Realm-Maker for usage as a Real-Time Strategy simulator or game
Realm-Maker is the only module within the CyberspaceView project to use a plan or aerial view throughout. It is referred to as “Above View” to prevent the ambiguity that terms such as “plan” or “aerial” could cause. The view is always a direct over-head view of a given section of land and/or water. It always displays the X-axis with the negative direction running leftward and the positive direction rightward, and the Z-axis with negative running bottomward and positive topward. The Y-axis of any Object shown is used to determine the Object's visibility on the map. For instance, a geo-stationary refuelling station might be 1 kilometre above the ground, underneath it might be a building. If the Realm-Maker view height is set to a Stage of “Building” or “Continent”, the refuelling station will not show because the view is underneath the station. If the Stage was set to “Planet”, the refuelling station would show, with the building beneath it partially obscured. If the Stage was set to “Galaxy” or higher, the refuelling station would probably not show because it would have been designed to be smaller than a planet, and therefore too small to see. A side-view of this example situational view follows.
Diagram of side-on (XY) view of a galaxy, planet, station, continent, and buildings:
V = viewpoint example
“Galaxy” Stage * * * * *= stars
* * * * * *
“Planet” Stage ________________________= troposphere
SSSS = refuelling station (about 4 metres across)
“Continent” Stage _/\___ /|/\__ __|\/\__= mountains
\/ | \/
“Area”-“Subplace” Stages = any sub-tropospheric Object (often same Y-axis)
“Building” Stage ________ = building roof (about 8 metres across)
“Level” Stage |______| = building second floor (approx. 2 metres high)
“Level” Stage |______| = building first/ground floor
The direct over-head view perspective is set to be map-style rather than eye-style. This means that viewing a building in the centre of the map will look exactly the same as a building near an edge. It is intended as a mapping and bearings reference rather than a flying-over, looking down type of view. The User can achieve the latter view by using Location-Viewer to fly upwards, then orientating themselves downward.
Although this map-style view is intended as a mapping reference for the User, the screen updates in real-time. Because of this characteristic, it is well suited to be used to form Real-Time Strategy (RTS) simulators or games.
Most RTS games use a map, usually in the top-right of the screen, to show the player where they are. The main game area uses an isometric view with the X-axis running diagonally from bottom-left to top-right, the Y-axis foreshortened, and the Z-axis running diagonally from bottom-right to top-left. This means that a land vehicle (a “sprite”) would be viewed with its front-right corner at the lowest point of its image. Generally, the view is slightly rotated toward the Z-axis, so that the right side of the vehicle is the longest, often this is on a 30-degree basis.
Artistic work done for such games has often been very difficult, it becomes more like technical drawing, and, because of the small size of the sprites, needs careful scaling to avoid looking disproportionate.
CyberspaceView models, however drawn, are stored with three dimensions, so all of the rendering data is available to automatically calculate an effective sprite. The algorithm to convert from filled-vector model to bitmap images is used because bitmapped sprites are far faster to render than the model, and do not need constant alteration. Vehicles can of course move in multiple directions, but an RTS game never uses more than eight orientations, and most use four. This means only four sprites are needed for each model, using just Kibibytes to store, rather than the Mebibytes a full 3D rendering would need. Animation would be set by serialised sprite usage, e.g. tank number one's frames 13 and 22 would be accessed via the memory array cells
tank[1,13],
tank[1,22].
A strategy game like chess could be played within Realm-Maker. The whole game could be played within a ground area of 80x80 metres, every piece (Object sprite) moving 10 metres at a time. Only one sprite per piece would be needed, totalling 32 black and white pieces for each of 4 Rooks, 4 Knights, 4 Bishops, 2 Queens, 2 Kings, and 16 Pawns. Similarly for draughts, but with a sprite for each colour of draught, and extra sprites for crowning.
Chess and draughts are of course turn-based strategy games. For many real-time strategy games, there are no turns. Choosing to have a turn-based system is fairly straightforward by setting every “Happening” event control to depend on an end-of-turn Action. End-of-turn could be set according to one move made, or several. Turn-based strategy was used for games until processing power became fast enough that a more realistic “real-time” game could be written for the commercial market.
Statistics are used in RTS games to show inventory and to measure success. The numbers that these are based on can be linked to Objects as Properties, or as Equations or Instructions within a Happening control. An example piece of AI would be the Instruction:
“statistic['energyNeeded[side1]'] = vehiclesNumber['side1'] * vehiclesPowerConsumption['side1']”
This Happening control could be linked to a status box Object using the heading “Energy needed”.
The main advantage of using Realm-Maker to create an RTS game would be that there are no restrictions on freedom of movement. Pixel-by-pixel movement is inherent, and there is no need to “grid up” the playing area. The inbuilt CyberspaceView system of a 2-metre cubed virtual gridspace can be used to simplify Actions such as movement incrementation, but is not necessary. The inherent convenience of using a pixel-based system within Realm-Maker is that rendering calculations can be reduced to integer mathematics, as nothing is ever 3.15 pixels wide. The original model may have been 3.15 metres wide, but automatic scaling can be used to average out the whole playing “field” and the Objects within it to 0.05 metres per pixel, thus such a model can be a convenient 63 pixels wide.
Consistent with CyberspaceView architecture, Designers using Location-Viewer and Object-Maker, Realm-Maker can use the same Instructions and properties to create their own “Happenings” event controls.
Among the Instruction properties used within Happenings are:
.acc = a calculation of an Object's rate of acceleration.
.areaXY = an Object's X-Y area, also
areaXZ and
areaYZ.
.circX = an Object's circumference in the X-axis, also
circY and
circZ.
.rangeX = an Object's movement distance between origin and destination in the X-axis,
also
rangeY and
rangeZ.
.surf = an Object's total surface area.
.vel = an Object's current velocity.
.vol = an Object's total volume.
As an example, the following Instruction could be used in a Happening to calculate damage to a targetted tank by a tank ramming into it:
'tank[targetNow]"shielding" = tank[targetNow].surf - tank[attackNow](acc*vol*vel)'
The
targetNow and
attackNow values would be the numbers of the tanks being used. This simplifies the order of processing by sequencing events to match movement of the tanks.
tank[1] would be the first tank fielded in the game.
attackNow would be whichever tank was selected to carry out the ramming.
Within the artificial intelligence phase of designing the game, some economies can be used, taking advantage of fast mathematical processing in order to simplify game design. I will describe one such example in detail here. A sprite of a tank moving North-North-East fifty-four metres is easier to describe as a vector-based Instruction within a Happening than as an iterative Instruction. For an iterative Equation, the lengths of the X- and Z-axis would need pre-calculation, using the sine rule for triangles. The calculations would start with the sine rule as follows:
x/sin(22.5) = 54/sin(90) = z/sin(67.5)
sin(90) = 1 [90 is the angle opposite the 54-metre side]
sin(22.5) = 0.382683432 [22.5 is the angle for North-North-East opposite the x side]
sin(67.5) = 0.923879533 [67.5 is the angle remaining (180-90-22.5) opposite the z side]
For the opposite 54-metre angle of 90 degrees:
54 = 54/sin(90) = 54/1
For the opposite x angle of 22.5 degrees:
x / sin(22.5) = (x / 0.382683432) = 54
x = (54 * 0.382683432) = 20.664905348
For the opposite z angle of 67.5 degrees:
z / sin(67.5) = (z / 0.923879533) = 54
z = (54 * 0.923879533) = 49.889494782
As a check, a right-angled triangle is used, so Pythagoras' theorem applies:
54^2 is approximately equal to 49.889494782^2 + 20.664905348^2
2916 is approximately equal to 2488.961689603 + 427.038313042
is approximately equal to 2916.000002645
On-screen, using a scale of 1 metre = 2 pixels (variable
scaleScn set to
2), this becomes a total horizontal movement of 42 pixels (20.664905348 metres) and a total vertical movement of 100 pixels (49.889494782 metres).
So comparing the construction of these Instructions:
Iterative Instruction for the Happening (
distX being used as a variable for the horizontal distance of
x):
“distX = 20.664905348*scaleScn; distZ=49.889494782*scaleScn;
tank[1].dir[x] = tank[1].dir[x] + 1; tank[1].dir[z] = tank[1].dir[z] + 2;
(tank[1].dir[x]<distX)?repeat|exit; (tank[1].dir[z]<distZ)?repeat|exit”
Versus:
Vector-based Instruction for the Happening:
“tank[1].vec[22.5,54m]”
or the longer form:
“tank[1].vec[x+1,z+2].end[54m]”
Clearly, it is simpler to write and understand either of the latter two, the computer can calculate the distances and angles rather than the game's Designer doing it. In terms of speed, it would seem that the Iterative Instruction would process faster, but because in the first Instruction so much is having to be used in terms of conversion of CyberspaceView Happening Instructions into assembly language instructions, it is faster to have the computer increment horizontally and vertically, re-calculating the diagonal distance so far using Pythagoras' theorem (
sqrt(1^2+2^2)=2.236067977, then
sqrt(2^2+4^2)=4.472135955, then
sqrt(3^2+6^2)=6.708203932, then
sqrt(4^2+8^2)=8.94427191, etc.), until the 54-metre diagonal destination point is reached, never needing to calculate the horizontal or vertical distances.
In pseudo-code the Iterative Instruction would look like this:
CELL "distX" = 20.664905348 * "scaleScn";
CELL "distZ" = 49.889494782 * "scaleScn";
Instruction1:
{
CELL "tank"[1]"direction"["x"] = CELL "tank"[1]"direction"["x"] + 1;
CELL "tank"[1]"direction"["z"] = CELL "tank"[1]"direction"["z"] + 2;
}
IF CELL "tank"[1]"direction"["x"] < CELL "distX" THEN REPEAT Instruction1;
// IF CELL "tank"[1]"direction"["z"] < CELL "distZ" THEN REPEAT Instruction1; // Spare instruction.
In pseudo-code the Vector-based Instruction would look like this:
CELL "distScnDiag" = 54 * "scaleScn";
Instruction1:
{
CELL "tank"[1].vector["x"] = CELL "tank"[1].vector["x"] + 1;
CELL "tank"[1].vector["z"] = CELL "tank"[1].vector["z"] + 2;
}
IF CELL "tank"[1].vector < CELL "distScnDiag" THEN REPEAT Instruction1;
Obviously, the vector property reduces the processor load by on-the-fly calculation of the diagonal distance reached so far. It does so by using Pythagoras' theorem as described above.
Artificial Intelligence Within A Real-Time Strategy Game Or Simulation
Books on artificial intelligence programming often have directly applicable algorithms that can be used within Realm-Maker, partly because Realm-Maker is based on a simple cyclical process flow which means that heuristics can be processed using a variety of levels of recursion or iteratively at any point.
Strategic elements are easily programmed because each Object can be assigned a Happening event control. Here is an example playing scenario of a good firing solution by User A in a basic tactical battle arrangement:
A1--->--\
\-->---B1
A2
A3 \
\ \>B2
\---------------B3
Here is the same arrangement, but where User A has chosen a bad firing solution:
A1--->--\
\-->---B1
A2-----<----/
A3 \
\<B2
B3
In the first example, User B has not had a chance to fire anything because each of his/her units has been targetted. In the second example, User A has not only not used A3 to target B3, but also not used A2 so is getting fired upon by B2, and, if A1 misses B1, by B1 as well.
In the “heat of battle”, such decisions are made very quickly, either player can go wrong, but the speed of processing by the software has to be consistent to prevent any unfair advantages. However temporary unfair advantages are, they detract from the gameplay, making it unrealistic. It is therefore crucial to apportion the heurstic processing equally among all Objects (in this case the Objects are the Users' units). By allowing assignment of heuristic and deterministic “Happening” event controls to each individual unit/Object, gameplay can be fair. The six Objects above would each have their own attack and defence Happening heuristics, probably based on proximity, but also allowing for testing whether each Object's target is untargetted by any other OF THEIR OWN Objects. If the latter part in capitals was not allowed for, a game situation could be created where one User has more units than the other, and chooses to target but not fire at each of his/her own units, so that the other User cannot fire upon them, while the User can still attack or counter-attack any of the other's units.
Weaponry:
The ammunition of a weapon can be treated as separate Objects. This allows far more flexibility and realism within a game. This way, area-effect weapons can be programmed with Happenings that affect any Object within a given space. Also, line-of-sight can be allowed for more easily, something which is important in the scenario described above.