User Tools

Site Tools


en:orx:tutorials:community:grey:firstscene

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
en:orx:tutorials:community:grey:firstscene [2010/04/24 16:58 (16 years ago)] greyen:orx:tutorials:community:grey:firstscene [2011/01/16 15:30 (15 years ago)] (current) – removed grey
Line 1: Line 1:
-===== Static Scene ===== 
-Just to let you guys know, I've shamelessly ripped apart Iarwain's Tutorial 4 and a little of his Tutorial 2 for this, so feel free to take a look at what he's done in order to get a different perspective on what, why and how! 
  
-Right, let's to it! 
- 
-We'll need a few files, I've copied these out of Iarwain's tutorial data files, but have made just those I use available for download here [[http://grey.orx-project.org/tutorial_data/tutorial_3/data.zip|here]]. 
-Drop the 'data' folder from in this zip, into our project folder (For me, this is looks like "C:\MyProject\data".) 
- 
-Next we're going to create a new file, and call it 'StaticScene.ini', this will go in the same place as all the other ini files ("C:\MyProject\bin".) 
- 
-I'm going to describe each chunk of information as I go, and try to give a reason for it so that it (hopefully) makes a little more sense. 
- 
-Firstly, we're going to create a 'scene-graph', meaning our entire scene is a nice little hierarchy of objects. We'll have one object called our 'scene', and this will "contain" every other object. That way, when we want to load this scene in code, we'll only have to manually 'create' that one object, and the entire thing will just pop into existence for us. 
- 
-==== StaticScene.ini ==== 
-<code ini> 
-[Scene] ;===================================== 
-ChildList            = Soldier 
-</code> 
- 
-And here it is... our [Scene] object. When we create new things to put in the scene, we simply add them to this object's childlist. 
-Now, as you can see we're going to create a soldier. Lets do that now: 
- 
-<code ini> 
-[Soldier] ;=================================== 
-ChildList            = SoldierGraphics#SoldierNameTag 
-</code> 
- 
-This is another container object, essentially the same as our [Scene] above, however this one is specifically for our Soldier, we've already added two items to its childlist, which we'll create in a moment, and a position. We want to be able to move the "whole" soldier around (and his name tag) at once, so instead of having to move everything manually, we can 'just' move this container. 
- 
-<code ini> 
-[SoldierPivot] ;============================== 
-Pivot                = (16.0, 16.0, 0.0)     ; Move to centre of image on X axis, bottom of image on Y axis (Soldier's feet!) 
- 
-[SoldierGraphics@SoldierPivot] ;============== 
-Graphic              = StoppedFrame 
- 
-[StoppedFrame] ;============================== 
-Texture              = ../data/anim/soldier.png 
-TextureSize          = (32, 32, 0) 
-</code> 
- 
-This is the graphics for our soldier (or at least, the beginnings of them), this defines the default image that we'll see when the soldier is un-animated. 
-The Pivot is also defined so we have a logical point to move our guy around with. In this case, approximately the base of his feet. 
-We use @SomethingElse in the name of our object, to 'include' everything from the other object. 
- 
-Thus [SoldierGraphics@SoldierPivot] is the same as saying 'Make [SoldierGraphics] with everything we've added AND everything from [SoldierPivot]. 
- 
-<code ini> 
-[SoldierNameTag] ;============================ 
-Graphic              = SoldierName 
-Position             = (0.0, -32.0, 0.0) 
- 
-[SoldierName] ;=============================== 
-Text                 = SoldierNameString 
-Color                = (255, 255, 255) 
-Pivot                = center 
- 
-[SoldierNameString] ;========================= 
-String               = Soldier 
-</code> 
- 
-And this is our name-tag for the soldier. 
- 
-Right. Let's add some new code to our project. 
- 
-We need to make only one minor change: 
- 
-==== StandAlone.cpp ==== 
-<code c> 
- // Our automatically loaded configuration files include the data to make our camera 
- //   and our viewport, we need to initialise those here. 
- // The viewport will in turn create the camera, so we only need the one line of code. 
- orxViewport_CreateFromConfig( "Viewport" ); 
- 
- // Our new static scene is loaded from the following file. 
- orxConfig_Load( "StaticScene.ini" ); 
- 
-    // We create the 'root' object of our scene, which in turn creates it's children, and their children etc. 
- orxObject_CreateFromConfig( "Scene" ); 
-</code> 
- 
-Simple aye? Let's compile this and see what happens! 
- 
-{{http://grey.orx-project.org/tutorial_data/tutorial_3/1_firsttest.png}} 
- 
-Not very interesting so far... fine, lets get something happening! 
- 
-First, we're going to do the large job of adding our animation frames to our StaticScene.ini file: 
- 
-==== StaticScene.ini ==== 
-<code ini> 
-[SoldierGraphics@SoldierPivot] ;============== 
-Graphic              = StoppedFrame 
-AnimationSet         = AnimSet 
-</code> 
- 
-First we modify our SoldierGraphics object, giving it access to our animation set. 
- 
-<code ini> 
-[AnimSet] ;=================================== 
-AnimationList        = IdleRight#WalkRight#IdleLeft#WalkLeft 
-LinkList             = IdleRightLoop#IdleRight2Left#IdleRight2WalkRight#WalkRightLoop#WalkRight2IdleRight#IdleLeftLoop#IdleLeft2Right#IdleLeft2WalkLeft#WalkLeftLoop#WalkLeft2IdleLeft 
-</code> 
- 
-This horrifying looking thing is actually very simple. The first item "AnimationList" contains all the animations that our soldier can do. (Idle and walking back and forward.) 
-The second item, is the list of all the 'links' between animations, meaning we don't want our soldier to be able to switch from walking left, to walking right, without stopping and 'turning around' first. So we make lists of animations that are 'allowed' to connect together. 
- 
-<code ini> 
-[IdleRightLoop] ;============================= 
-Source               = IdleRight 
-Destination          = IdleRight             ; Loops back onto itself. 
-[IdleRight2Left] ;============================ 
-Source               = IdleRight 
-Destination          = IdleLeft 
-Property             = immediate             ; Immediately go to IdleLeft 
-[IdleRight2WalkRight] ;======================= 
-Source               = IdleRight 
-Destination          = WalkRight 
-Property             = immediate             ; Immediately go to WalkRight 
-</code> 
- 
-This is our first set of animation 'links'. Essentially this tells us that when we are in the 'idle and facing right' animation (IdleRight), we are allowed to -continue- playing IdleRight (the loop), we are allowed to switch to IdleLeft (essentially, turn around), and we are allowed to immediately start walking right. 
- 
-<code ini> 
-[WalkRightLoop] ;============================= 
-Source               = WalkRight 
-Destination          = WalkRight 
-[WalkRight2IdleRight] ;======================= 
-Source               = WalkRight 
-Destination          = IdleRight  
-Property             = immediate 
-Priority             = 9 
-</code> 
- 
-This is our list of links for our WalkingRight animation. Again, we're allowed to loop (walk forever), or, we're allowed to drop back to the 'IdleRight' animation. We're -not- being given permission to change into any other animation here! 
- 
-<code ini> 
-[IdleLeftLoop] ;============================== 
-Source               = IdleLeft 
-Destination          = IdleLeft 
-[IdleLeft2Right] ;============================ 
-Source               = IdleLeft 
-Destination          = IdleRight 
-Property             = immediate 
-[IdleLeft2WalkLeft] ;========================= 
-Source               = IdleLeft 
-Destination          = WalkLeft 
-Property             = immediate 
-  
-[WalkLeftLoop] ;============================== 
-Source               = WalkLeft 
-Destination          = WalkLeft 
-[WalkLeft2IdleLeft] ;========================= 
-Source               = WalkLeft 
-Destination          = IdleLeft 
-Property             = immediate 
-Priority             = 9 
-</code> 
- 
-Here are the left-facing versions of those same links. While I'm at it, the Priority value; The default value for this is 8. This is used to make the engine automatically step into this link when nothing else is asked for. In this case, what that means is that unless we -specifically- ask the animation to continue playing WalkLeft, it will finish its current playthrough, then switch to IdleLeft immediately afterwards. 
- 
- 
-The engine now knows what it can and cannot link together, but it doesn't yet know -what- it's supposed to be showing so next thing, we'll actually put the animation frames in! 
- 
-<code ini> 
-[IdleRight] ;================================= 
-KeyData1             = AnimRight6 
-KeyDuration1         = 0.1 
-</code> 
- 
-One whole frame here, delicious. We could put a few here and have the soldier 'fidget' while standing still, but for now, doing nothing is good enough. 
- 
-<code ini> 
-[IdleLeft] ;================================== 
-KeyData1             = AnimLeft6 
-KeyDuration1         = 0.1 
-</code> 
- 
-Left version, bet you didn't guess that! :) 
- 
-<code ini> 
-[WalkRight] ;================================= 
-DefaultKeyDuration   = 0.1 
-KeyData1             = AnimRight1 
-KeyData2             = AnimRight2 
-KeyData3             = AnimRight3 
-KeyData4             = AnimRight4 
-KeyData5             = AnimRight5 
-KeyData6             = AnimRight6 
- 
-[WalkLeft] ;================================== 
-DefaultKeyDuration   = 0.1 
-KeyData1             = AnimLeft1 
-KeyData2             = AnimLeft2 
-KeyData3             = AnimLeft3 
-KeyData4             = AnimLeft4 
-KeyData5             = AnimLeft5 
-KeyData6             = AnimLeft6 
-</code> 
- 
-Here's a longer example, with 6 frames ie: our walk-left and walk-right animations! 
-Each 'KeyData' value refers to a single frame of an animation, just in case you were wondering. 
- 
-<code ini> 
-[FullGraphic@SoldierPivot] ;================== 
-Texture              = ../data/anim/soldier_full.png 
-TextureSize          = (32, 32, 0) 
-</code> 
- 
-This is how we define where we are getting our image data from. We can either use a single image per frame 
- (in which case we'll have lots of these ) or as in our case, one image with lots of frames inside it. 
- 
-<code ini> 
-[AnimRight1@FullGraphic] ;==================== 
-TextureCorner        = (0, 0, 0) 
- 
-[AnimRight2@FullGraphic] ;==================== 
-TextureCorner        = (0, 32, 0) 
- 
-[AnimRight3@FullGraphic] ;==================== 
-TextureCorner        = (0, 64, 0) 
- 
-[AnimRight4@FullGraphic] ;==================== 
-TextureCorner        = (32, 0, 0) 
- 
-[AnimRight5@FullGraphic] ;==================== 
-TextureCorner        = (32, 32, 0) 
- 
-[AnimRight6@FullGraphic] ;==================== 
-TextureCorner        = (32, 64, 0) 
-</code> 
- 
-Because we're using a single image with lots of frames, we need to define where in that image we get each frame from. TextureCorner is the corner of each frame, combined with our earlier "FullGraphic", (which contained a texture size!) we can tell the engine to grab a 32x32 pixel 'frame' anywhere inside that entire image. 
- 
-<code ini> 
-[AnimLeft1@AnimRight1] ;====================== 
-Flip                 = x 
- 
-[AnimLeft2@AnimRight2] 
-Flip                 = x 
- 
-[AnimLeft3@AnimRight3] 
-Flip                 = x 
- 
-[AnimLeft4@AnimRight4] 
-Flip                 = x 
- 
-[AnimLeft5@AnimRight5] 
-Flip                 = x 
- 
-[AnimLeft6@AnimRight6] 
-Flip                 = x 
-</code> 
- 
-See this... we've just made all our "walkleft" frames. -Terrifying- isn't it! :) No?... okay. Fine, ruin all my fun :p 
- 
-aaaanyway... all that work, now means that we've got lots of walking animations... what next? Oh, yes... we should actually make the code -use- them, so that we don't just get a repeat of our last test run aye? :) 
- 
-<code> 
-Following is -very- work in progress, don't expect it to work yet. Just my thoughts being 'written' as I go. 
-</code> 
- 
-==== StaticScene.h ==== 
-<code c> 
-#include "orx.h" 
-#include <string> 
- 
-class StandAlone 
-{ 
-public: 
- static StandAlone* Instance(); 
- 
- static orxSTATUS orxFASTCALL Init(); 
- static orxSTATUS orxFASTCALL Run(); 
- static void orxFASTCALL Exit(); 
- 
- static orxOBJECT* GetObjectByName( std::string objectName ); 
- static void orxFASTCALL Update( const orxCLOCK_INFO* clockInfo, void* Context ); 
-        static orxSTATUS orxFASTCALL EventHandler( const orxEVENT* currentEvent ); 
-</code> 
- 
-Here we add the definitions of three new functions, GetObjectByName is a helper function so that we can search through the list of objects we have created earlier, and grab specific ones. (This is the function that will be using the string library.) 
- 
-The second is function that will be called whenever a orxCLOCK updates. We'll be putting our animation logic in here. 
- 
-The third is used to make something happen whenever an event goes off (Animations have 4 events, Start, Stop, Loop and Cut - Cut being a 'forced stop') 
- 
-==== StaticScene.cpp ==== 
-We're going to add three new functions to our StaticScene class now. 
- 
-<code c> 
-orxOBJECT* StandAlone::GetObjectByName( std::string objectName ) 
-{ 
- std::string TempName; 
- orxOBJECT* TempObject; 
- 
- for( TempObject = orxOBJECT( orxStructure_GetFirst( orxSTRUCTURE_ID_OBJECT ) ); 
- TempObject != orxNULL; 
- TempObject = orxOBJECT( orxStructure_GetNext( TempObject ) ) ) 
- { 
- TempName = orxObject_GetName( TempObject ); 
- if( TempName.compare( objectName ) == 0 ) 
- return TempObject; 
- } 
- 
- return orxNULL; 
-} 
-</code> 
- 
-GetObjectByName, simply goes through the list of all objects that have been loaded into memory, and compares their name, to the string we pass in, if it finds the correct item, it will return a pointer to that object for us, or a NULL value if it fails. 
- 
-<code c> 
-void orxFASTCALL StandAlone::Update( const orxCLOCK_INFO* clockInfo, void* context ) 
-{ 
-    orxOBJECT* Object = orxOBJECT( context ); 
-    if( Object != NULL ) 
-    { 
- std::string ObjectName = orxObject_GetName( Object ); 
- 
- if( ObjectName.compare( "SoldierGraphics" ) == 0 ) 
- orxObject_SetTargetAnim( Object, "WalkRight" ); 
-    } 
-} 
-</code> 
- 
-Update is the function that will be called whenever our clock "ticks". 
- 
-<code c> 
-orxSTATUS orxFASTCALL StandAlone::EventHandler( const orxEVENT* currentEvent ) 
-{ 
- // We could just use a direct cast, but in case we expand this handler later to deal with different event types, 
- //   we're going to be careful and make sure we're in the correct event type first. 
- switch( currentEvent->eType ) 
- { 
- case orxEVENT_TYPE_ANIM: 
- { 
- orxANIM_EVENT_PAYLOAD* EventPayload = (orxANIM_EVENT_PAYLOAD*)currentEvent->pstPayload; 
- 
- const orxCHAR* AnimationName = EventPayload->zAnimName; 
- const orxCHAR* ObjectName = orxObject_GetName( orxOBJECT( currentEvent->hRecipient ) ); 
- const orxCHAR* EventName; 
- 
- switch(currentEvent->eID) 
- { 
- case orxANIM_EVENT_START: EventName = "started"; break; 
- case orxANIM_EVENT_STOP: EventName = "stopped"; break; 
- case orxANIM_EVENT_CUT: EventName = "been cut"; break; 
- case orxANIM_EVENT_LOOP: EventName = "looped"; break; 
- } 
- 
- orxLOG("Animation <%s>@<%s> has %s!", AnimationName, ObjectName, EventName ); 
- break; 
- } 
- } 
- 
- return orxSTATUS_SUCCESS; 
-} 
-</code> 
- 
-This is essentially a rewritten version of Iarwain's event handling code from his tutorial 2. Animations send out many events to alert us what is going on, so we are logging this. (This code helped me debug while I was writing this tutorial, so it's very useful to have! ^_^) 
- 
-Next we modify StandAlone::Init() again. 
-<code c> 
-orxSTATUS orxFASTCALL StandAlone::Init() 
-{ 
- orxViewport_CreateFromConfig( "Viewport" ); 
- 
- // Our new static scene is loaded from this file: 
- orxConfig_Load( "StaticScene.ini" ); 
-        // And we create the 'root' object of our scene, which in turn creates it's children, and their children etc... 
- orxObject_CreateFromConfig( "Scene" ); 
- 
- // We're creating a clock here, this will be used later to update our animations. 
- orxCLOCK* AnimationClock = orxClock_Create( 0.2f, orxCLOCK_TYPE_USER ); 
- 
-        // Next we find the 'SoldierGraphics' object in our list of loaded objects, we get this because -that- is the object that holds the AnimationSet 
- orxOBJECT* Soldier = GetObjectByName( "SoldierGraphics" ); 
- 
-        // if we're sure we found him, we register the clock to the soldier (using the Update function!) 
-        //   and then set his default animation. 
- if( Soldier != NULL ) 
- { 
- orxClock_Register( AnimationClock, Update, Soldier, orxMODULE_ID_MAIN, orxCLOCK_PRIORITY_NORMAL ); 
- orxObject_SetTargetAnim( Soldier, "WalkRight" ); 
- } 
- 
- return orxSTATUS_SUCCESS; 
-} 
-</code> 
- 
-Okay, time to compile and test again. I won't screenshot this again this time, but by now your little soldier should be running like a madman. 
en/orx/tutorials/community/grey/firstscene.1272128327.txt.gz · Last modified: 2025/09/30 17:26 (7 days ago) (external edit)