home *** CD-ROM | disk | FTP | other *** search
- <head>
- <title="...forever...">
- <font=monaco10.fnt>
- <font=newy36.fnt>
- <font=time24.fnt>
- <image=back.raw w=256 h=256 t=-1>
- <buf=3562>
- <bgcolor=-1>
- <background=0>
- <link_color=253>
- <module=console.mod>
- <pal=back.pal>
- colors:
- 251 - black
- </head>
- <body>
- <frame x=0 y=0 w=640 h=3562 b=-1 c=-1>
-
-
- FRAMES OF REFERENCE
- -------------------
- Local screen and global world
- This basic idea, about which many programmers in 80' never heard before. Lucky
- enough in our times this subject is well known. That's because it is used in 3D
- games. Objects in game exist even if player doesn't see them! Their coordinates
- are dependant to the game world, not the screen. In old times people stored all
- the creatures as offsets to screen and updated them while scrolling the screen.
- It was not good, screen should be treated as a window which covers part of the
- game world. If we set view on the specified area then all the object located in
- given region will be displayed. Those outside are invisible, because they are
- outside of the screen. The coordinates of the world can be translated to screen
- coordinates by using transformation matrix. For platform games it can be
- without scaling or rotation to simplyfy things like adding offset to both
- coordinates.
- Panel objects can be treated in another way and can depend on screen
- coordinates, because they do not apply to the game world, but to our view.
-
- Orthogonal systems - independent treatment of the coordinates
- Carthesian coordinates are orthogonal. They are beautyful, because they can be
- treated seperately without affecting each other. That means every time we do
- some things (we add friction for example) in one dimension (like X), we can do
- everything in similar way with other axis (Y and Z), without worry how they
- will interact with each other.
-
- Transformation matrix - conversion between frames of reference
- In 2D, there is possibility to transform frames of reference by multiplying by
- 2x2 matrix and adding two element vector:
- screenX = a*X+b*Y+e
- screenY = c*X+d*Y+f
-
- Interesting are values of constants a,b,c,d,e,f. For translation (only
- scrolling) a and c are 1, b and c are 0, d is scaling ratio (it's a identity
- matrix), e anf f are scrolling offsets. In case of scaling b and c are 0, a and
- d are scaling ratio.
-
- For rotation, angle is an angle of screen rotation depending on the world,
- scale is a scale of screen relative to screen coordinates, e and f still
- represent scrolling offsets, but they need to be adjusted to the rotation if
- you don't exchange X,Y coordinates before include them into the equation.
-
- a = scale * sin(angle)
- b = scale * cos(angle)
- c = scale * cos(angle)
- d = scale * - sin(angle)
-
- A cool thing is that when using matrices to coordinates transformation,
- different transformations can be used one after another by multiplying of two
- matrices. In 3D 4x4 matrix can hold everything you need to know about the
- transformations (viewing fustrum or fish-eyed camera, method of perspective
- calculation (like rotation, scaling ) ) needed to render the scene.
-
-
- ITERATION
- ---------
- Computers are very good at all the boring tasks like repeating over and over
- sets of instructions in FOR, WHILE etc. loops. Temporal discreetness in games
- forces us to writing all the code in different manner than in utility programs.
- Interactivity of game requires absence of long pauses during play while
- computer tries to estimate what to do next. The best solution is to split all
- of the calculating tasks and execute the outcoming parts one by one. When we do
- it, then we have to estabilish how we force the computer to execute everything
- in right order, because in easy way we can wreak havoc in our internal memory
- destroying everything. The main tools in hands of programmer are states or
- threads (only available on operating systems like Magic/MiNT, they additionaly
- require synchronisation).
-
- States - Controlling movement
- The idea of Turing'a Machine states that computer consists of the state,
- program and access to given amount of variables. In original Turing's machine
- there was serial access to R/W location on the long tape, but we exchange it to
- the random access to given amount of variables. Program is a simple set of
- rules, which tells in which state it must go if machine has given state and
- when some initial variables were found. Unstable or "virtual" states can be
- useful under several circumstances, but they require a little extra time of
- attention to avoid infinite loops. In this state, every time when change of
- state occured, program control is passed immadiately to starting code of
- changed state. The same code can decide that it once again needs to change
- state, before the exit from the routine. It's very important to prevent
- processor from "caughting in the loop", because it will be constantly switching
- between the states without passing control to the main loop. With a little of
- thought is possible to reduce the amont of code required for simulating of
- intelligent behaviour.
-
- List of states for simple enemy:
-
- --------------------------------------------------------------------
- MARCH :
- Init - move in random direction
- Control - If player near then aim else march on
- Action - Hit the obstacle, reverse movement
- ---------------------------------------------------------------------
- AIM:
- Init - face to the player
- Control - If player above then jump, else charge
- Action - ------------------------------
- ----------------------------------------------------------------------
- JUMP:
- Init - Increase the initial speed
- Control - if landed charge, else further jump
- Action - fall under gravity
- ---------------------------------------------------------------------
- CHARGE:
- Init - move in direction of player
- Control - If player is too far then march else charge on
- Action - If Hit the obstacle, reverse movement
- ----------------------------------------------------------------------
-
- In this case AIM is unstable state which can lead to another states. It can be
- a starting point of changes to many states. Keeping track of states is very
- important (which variables were stored during various function calls). If AI
- procedure will return, all variables on stack will be destroyed, so pointer to
- variables of given object is needed. Using pointers directly to functions is
- much more efficient than digging throught enumerated states with giant
- switch (or case) instruction.
-
- States ( not United States ;))) ) can be implemented in code or as markers. In
- game based on markers, each AI object is controlled by the list of markers
- representing commands. It is very similar to byte codes in Java, but markers
- are on higher level and are more game specific.
-
- Threads - let the operating system do all the dirty stuff for you. Tracking of
- the object states mustn't be pain in all cases. There is a solution for
- generating of "anonymous states", which push all the work to game's operating
- system (there are rather low level task planning procedures than main operating
- system) instead of code for each object state.
-
- This method is sleep command - form of non-preemptive multitasking. You simply
- write the sleep function, which uses as a parameter an amount of game frames
- you want to miss or handle to the state, which will wake up the function, e.g
- the player will be closing in to object on given distance. When sleep function
- call occurs, the control is passed from AI function to the game planner. That
- means each object runs in it's own thread. The Round-Robin method can be used
- to give enough time to the processor for all AI routines of objects or threads
- can be put in linked lists depending in which game frame they will awake. You
- have to decide which variables need to be stored while using sleep command. For
- example we don't save all of the registers, but frequently store stack (all
- local variables and state of each called function). To do it we can assign
- local stack for each object and switch stack pointer (assembly languge required
- !!!) This method requires a lot of additional memory than the method with
- states, because it's hard to estimate how big stack area will be needed for
- each routine. Programmer should be also cautious to switch to system stack,
- each time hardware interrupt will occur to prevent the massacre on object's
- local stack. Another techniques can be used to more efficient use of memory -
- some processors can detect stack overflow and this feature can be used for
- allocating local stacks with variable lenght. It is too risky option, if it
- comes about guaranteed time of reply, for use it in games.
-
- Functions in background: revenge of complex calculations
- Using of threads let's using time consuming calculations in background, if they
- are preemptive of course. If we haven't preemptive threads, the use of hardware
- interrupts is required.
- For example game can be splitted onto 3 parts: display thread, AI main thread
- and strategy thread. Main AI thread is used once per earlier defined time
- period to make game function at reasonable, constant pace. Display thread is
- called less frequently (ehm, maybe not if you have extremely fast machine) to
- update the screen to reflect what is going on currently in the game. Startegy
- threads are working on low-level in background and occasinally talk to the main
- AI thread, to perform some complex calculations without slowing down
- everything. Most important thing in all preemptive multi-threaded games is
- correct handling of synchronisation between the processes. This subject is
- covered well in all computer science courses. To remaind some things: double
- buffering of variables until "transaction" (game frame) is completed.
- "Transaction" must be "atomic", unbreakable (it can be achieved in hardware by
- switching off all interrupts for a short time or in program - banker
- algorythm). Errors in synchronisation are very hard to remove, so building of
- error free multithread systems is very important from the beginning.
-
- PITFALLS
- - " Never assume anything what can't always be true ". False assertion can lead
- to many problems. Always check everything before you will depend on something.
- For example if you assume that number cannot be zero or negative (in
- simplifications connected with square roots), then if you accidentally put zero
- or negative number, the right action will not be performed. The assert()
- function is just for that (very useful when we are launching DEBUG version of
- our program). We can wipe out any possible problems, and it can be handy while
- beta-testing (the beta-tester can tell you where and when problem occurs and
- possibly the name of the function which causes trouble.)
-
- - overflow: numbers too big or to small Check and watch the range of numbers
- you are using. If you will exceed the range, then some unpredictable things can
- happen. This can bring disaster:
-
- for unsigned values:
- unsigned short int ourNumber = 0;
- ourNumber = 65535;
- ourNumber++; // out of range!!!! (ourNumber = 0) !!
- ourNumber++; // (ourNumber =1)
-
- and for signed values:
- signed short int ourNumber = 0;
- ourNumber = 32767;
- ourNumber++; // out of range!!!! (ourNumber = -32768)!
- ourNumber++; // (ourNumber = -32767)
-
- - Lack of precision: the numbers are too similar
- Two nubers which should be different are throwed into one sack, eg. numbers 2.1
- and 2.2 can be treated as 2. If the difference is important then this may cause
- problems. The difficulty of finding error increases when everything is inside
- complex statement. Especially when one number is divided by second one and
- before it is multiplied by another number. The problem can be solved by
- performing the multiplication before the division. But most frequently used
- solution is changing the scale of the number system. In this task, the fixed
- point math is very helpful.
-
- The floating point numbers are another tale, they are very rarely identical, so
- checking of their equality is rather risky business. So before checking we do:
- (abs(a-b)<c) instead of standard (a==b).
- The b variable can be earlier defined constant (0,001) when values will never
- be very small or proportion (like 0,01%) of chosen number.
-
- Reference:
- ----------------
- "Math in games" by Carl Muller, Gamasutra 1st June 1997
- available online at www.gamasutra.com
-
-
- -- - --- -- -------------------------------------------------------------------
- CHOSNECK 4th appearance contact us:
- done by the dream survivors greymsb@poczta.fm
- ----------------------------------------------------------------- -- - --- ----
- </frame>
- </body>
-