This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
en:orx:tutorials:community:grey:firstscene [2010/04/24 17:05 (16 years ago)] – grey | en: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' | ||
- | Right, let's to it! | ||
- | |||
- | We'll need a few files, I've copied these out of Iarwain' | ||
- | Drop the ' | ||
- | |||
- | Next we're going to create a new file, and call it ' | ||
- | |||
- | 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 ' | ||
- | |||
- | ==== StaticScene.ini ==== | ||
- | <code ini> | ||
- | [Scene] ; | ||
- | ChildList | ||
- | </ | ||
- | |||
- | And here it is... our [Scene] object. When we create new things to put in the scene, we simply add them to this object' | ||
- | Now, as you can see we're going to create a soldier. Lets do that now: | ||
- | |||
- | <code ini> | ||
- | [Soldier] ; | ||
- | ChildList | ||
- | </ | ||
- | |||
- | 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 " | ||
- | |||
- | <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' | ||
- | |||
- | [SoldierGraphics@SoldierPivot] ; | ||
- | Graphic | ||
- | |||
- | [StoppedFrame] ; | ||
- | Texture | ||
- | TextureSize | ||
- | </ | ||
- | |||
- | 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 ' | ||
- | |||
- | Thus [SoldierGraphics@SoldierPivot] is the same as saying 'Make [SoldierGraphics] with everything we've added AND everything from [SoldierPivot]. | ||
- | |||
- | <code ini> | ||
- | [SoldierNameTag] ; | ||
- | Graphic | ||
- | Position | ||
- | |||
- | [SoldierName] ; | ||
- | Text = SoldierNameString | ||
- | Color = (255, 255, 255) | ||
- | Pivot = center | ||
- | |||
- | [SoldierNameString] ; | ||
- | String | ||
- | </ | ||
- | |||
- | 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( " | ||
- | |||
- | // Our new static scene is loaded from the following file. | ||
- | orxConfig_Load( " | ||
- | |||
- | // We create the ' | ||
- | orxObject_CreateFromConfig( " | ||
- | </ | ||
- | |||
- | Simple aye? Let's compile this and see what happens! | ||
- | |||
- | {{http:// | ||
- | |||
- | 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 | ||
- | AnimationSet | ||
- | </ | ||
- | |||
- | First we modify our SoldierGraphics object, giving it access to our animation set. | ||
- | |||
- | <code ini> | ||
- | [AnimSet] ; | ||
- | AnimationList | ||
- | LinkList | ||
- | </ | ||
- | |||
- | This horrifying looking thing is actually very simple. The first item " | ||
- | The second item, is the list of all the ' | ||
- | |||
- | <code ini> | ||
- | [IdleRightLoop] ; | ||
- | Source | ||
- | Destination | ||
- | [IdleRight2Left] ; | ||
- | Source | ||
- | Destination | ||
- | Property | ||
- | [IdleRight2WalkRight] ; | ||
- | Source | ||
- | Destination | ||
- | Property | ||
- | </ | ||
- | |||
- | This is our first set of animation ' | ||
- | |||
- | <code ini> | ||
- | [WalkRightLoop] ; | ||
- | Source | ||
- | Destination | ||
- | [WalkRight2IdleRight] ; | ||
- | Source | ||
- | Destination | ||
- | Property | ||
- | Priority | ||
- | </ | ||
- | |||
- | 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 ' | ||
- | |||
- | <code ini> | ||
- | [IdleLeftLoop] ; | ||
- | Source | ||
- | Destination | ||
- | [IdleLeft2Right] ; | ||
- | Source | ||
- | Destination | ||
- | Property | ||
- | [IdleLeft2WalkLeft] ; | ||
- | Source | ||
- | Destination | ||
- | Property | ||
- | |||
- | [WalkLeftLoop] ; | ||
- | Source | ||
- | Destination | ||
- | [WalkLeft2IdleLeft] ; | ||
- | Source | ||
- | Destination | ||
- | Property | ||
- | Priority | ||
- | </ | ||
- | |||
- | 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, | ||
- | |||
- | |||
- | The engine now knows what it can and cannot link together, but it doesn' | ||
- | |||
- | <code ini> | ||
- | [IdleRight] ; | ||
- | KeyData1 | ||
- | KeyDuration1 | ||
- | </ | ||
- | |||
- | One whole frame here, delicious. We could put a few here and have the soldier ' | ||
- | |||
- | <code ini> | ||
- | [IdleLeft] ; | ||
- | KeyData1 | ||
- | KeyDuration1 | ||
- | </ | ||
- | |||
- | Left version, bet you didn't guess that! :) | ||
- | |||
- | <code ini> | ||
- | [WalkRight] ; | ||
- | DefaultKeyDuration | ||
- | KeyData1 | ||
- | KeyData2 | ||
- | KeyData3 | ||
- | KeyData4 | ||
- | KeyData5 | ||
- | KeyData6 | ||
- | |||
- | [WalkLeft] ; | ||
- | DefaultKeyDuration | ||
- | KeyData1 | ||
- | KeyData2 | ||
- | KeyData3 | ||
- | KeyData4 | ||
- | KeyData5 | ||
- | KeyData6 | ||
- | </ | ||
- | |||
- | Here's a longer example, with 6 frames ie: our walk-left and walk-right animations! | ||
- | Each ' | ||
- | |||
- | <code ini> | ||
- | [FullGraphic@SoldierPivot] ; | ||
- | Texture | ||
- | TextureSize | ||
- | </ | ||
- | |||
- | 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 | ||
- | |||
- | [AnimRight2@FullGraphic] ; | ||
- | TextureCorner | ||
- | |||
- | [AnimRight3@FullGraphic] ; | ||
- | TextureCorner | ||
- | |||
- | [AnimRight4@FullGraphic] ; | ||
- | TextureCorner | ||
- | |||
- | [AnimRight5@FullGraphic] ; | ||
- | TextureCorner | ||
- | |||
- | [AnimRight6@FullGraphic] ; | ||
- | TextureCorner | ||
- | </ | ||
- | |||
- | 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 " | ||
- | |||
- | <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 | ||
- | </ | ||
- | |||
- | See this... we've just made all our " | ||
- | |||
- | 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? :) | ||
- | |||
- | < | ||
- | Following is -very- work in progress, don't expect it to work yet. Just my thoughts being ' | ||
- | </ | ||
- | |||
- | ==== StaticScene.h ==== | ||
- | <code c> | ||
- | #include " | ||
- | #include < | ||
- | |||
- | class StandAlone | ||
- | { | ||
- | public: | ||
- | // Instance deals with ensuring we only have one copy of our StandAlone class. | ||
- | static StandAlone* Instance(); | ||
- | |||
- | // Init function sets up our default/ | ||
- | static orxSTATUS orxFASTCALL Init(); | ||
- | |||
- | // Run and Exit are both empty for now. | ||
- | static orxSTATUS orxFASTCALL Run(); | ||
- | static void orxFASTCALL Exit(); | ||
- | |||
- | // GetObjectByName compares the names of the objects loaded in memory, with a string we pass in | ||
- | // | ||
- | static orxOBJECT* orxFASTCALL GetObjectByName( std::string objectName ); | ||
- | |||
- | // Update is called on each ' | ||
- | static void orxFASTCALL Update( const orxCLOCK_INFO* clockInfo, void* context ); | ||
- | |||
- | // We currently use EventHandler to simply log when some of events happen, so we know they' | ||
- | static orxSTATUS orxFASTCALL EventHandler( const orxEVENT* currentEvent ); | ||
- | </ | ||
- | |||
- | 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 ' | ||
- | |||
- | ==== StaticScene.cpp ==== | ||
- | We're going to add three new functions to our StaticScene class now. | ||
- | |||
- | <code c> | ||
- | orxOBJECT* StandAlone:: | ||
- | { | ||
- | // This goes through the linked-list of all objects that have been loaded, and compares | ||
- | // their name with whatever string we pass in, returning the first match, | ||
- | // or a NULL if no match is found. | ||
- | std:: | ||
- | orxOBJECT* TempObject; | ||
- | |||
- | for( // Grab the first object in our linked list, which is an orxOBJECT, | ||
- | TempObject = orxOBJECT( orxStructure_GetFirst( orxSTRUCTURE_ID_OBJECT ) ); | ||
- | // Until we get one that's NULL, | ||
- | TempObject != orxNULL; | ||
- | // Continue onto the next object, | ||
- | TempObject = orxOBJECT( orxStructure_GetNext( TempObject ) ) ) | ||
- | { | ||
- | // Get the current object' | ||
- | TempName = orxObject_GetName( TempObject ); | ||
- | // Compare that to our input string (objectName), | ||
- | if( TempName.compare( objectName ) == 0 ) | ||
- | // and return that object if they' | ||
- | return TempObject; | ||
- | } | ||
- | |||
- | // or return a NULL instead. | ||
- | return orxNULL; | ||
- | } | ||
- | </ | ||
- | |||
- | GetObjectByName, | ||
- | |||
- | <code c> | ||
- | void orxFASTCALL StandAlone:: | ||
- | { | ||
- | // This is our update function, we're assigning this to our ' | ||
- | // so that whenever the clock ' | ||
- | // In our case we're going to make him use the 'walk right' animation. | ||
- | |||
- | // We use the orxOBJECT helper to ensure we get back the correct type, or a NULL pointer. | ||
- | orxOBJECT* Object = orxOBJECT( context ); | ||
- | |||
- | // Lets make sure we found the object before trying to do anything with it. | ||
- | if( Object != orxNULL ) | ||
- | { | ||
- | // We grab out the object name, to use the STD::String comparion function in a moment. | ||
- | std:: | ||
- | |||
- | // Next we handle different objects, essentially, | ||
- | // and if we've got the right one, we can go from there. | ||
- | if( ObjectName.compare( " | ||
- | { | ||
- | // For now, we only want our character to use his 'walk right' animation indefinitely | ||
- | // so we'll just ensure that the target animation is always the same. | ||
- | orxObject_SetTargetAnim( Object, " | ||
- | } | ||
- | } | ||
- | } | ||
- | </ | ||
- | |||
- | Update is the function that will be called whenever our clock " | ||
- | |||
- | <code c> | ||
- | orxSTATUS orxFASTCALL StandAlone:: | ||
- | { | ||
- | // We could just use a direct cast, but in case we expand this function later to deal | ||
- | // with different event types, we're going to be careful and make sure we're in the | ||
- | // | ||
- | switch( currentEvent-> | ||
- | { | ||
- | // This is for animation events, the only ones we handle in tutorial 3. | ||
- | case orxEVENT_TYPE_ANIM: | ||
- | { | ||
- | // Okay so we know we're dealing with an animation, lets grab the ' | ||
- | orxANIM_EVENT_PAYLOAD* EventPayload = (orxANIM_EVENT_PAYLOAD*)currentEvent-> | ||
- | |||
- | // Here we want the name of the animation playing (this is stored in the payload.) | ||
- | const orxCHAR* AnimationName = EventPayload-> | ||
- | // The name of the object who called this event. | ||
- | // (In tutorial 3, this will always be ' | ||
- | const orxCHAR* ObjectName = orxObject_GetName( orxOBJECT( currentEvent-> | ||
- | |||
- | // And finally the action which is this event. | ||
- | const orxCHAR* EventAct; | ||
- | |||
- | switch( currentEvent-> | ||
- | { | ||
- | case orxANIM_EVENT_START: | ||
- | case orxANIM_EVENT_STOP: | ||
- | case orxANIM_EVENT_CUT: | ||
- | case orxANIM_EVENT_LOOP: | ||
- | } | ||
- | |||
- | // Now we'll output this nicely to the console, so we can see exactly what animations | ||
- | // are being called, on what objects, and what they' | ||
- | orxLOG(" | ||
- | break; | ||
- | } | ||
- | |||
- | return orxSTATUS_SUCCESS; | ||
- | } | ||
- | </ | ||
- | |||
- | This is essentially a rewritten version of Iarwain' | ||
- | |||
- | Next we modify StandAlone:: | ||
- | <code c> | ||
- | orxSTATUS orxFASTCALL StandAlone:: | ||
- | { | ||
- | // 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( " | ||
- | |||
- | // Our new static scene is loaded from the following file. | ||
- | orxConfig_Load( " | ||
- | |||
- | // We create the ' | ||
- | orxObject_CreateFromConfig( " | ||
- | |||
- | // We're creating a clock here, this will be used later to update our animations. | ||
- | orxCLOCK* AnimationClock = orxClock_Create( 0.2f, orxCLOCK_TYPE_USER ); | ||
- | |||
- | // We grab our ' | ||
- | // It is important to remember, that the object we want to modify is the -animation object- | ||
- | // in our case, this is ' | ||
- | // | ||
- | orxOBJECT* Soldier = GetObjectByName( " | ||
- | |||
- | if( Soldier != orxNULL ) | ||
- | { | ||
- | // Seems we found the right object, so lets register the clock to our Soldier, and make him call | ||
- | // the Update function every ' | ||
- | orxClock_Register( AnimationClock, | ||
- | orxObject_SetTargetAnim( Soldier, " | ||
- | } | ||
- | |||
- | return orxSTATUS_SUCCESS; | ||
- | } | ||
- | </ | ||
- | |||
- | 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. |