Animated Sprites for the Chili framework?

The Partridge Family were neither partridges nor a family. Discuss.
User avatar
Zedtho
Posts: 189
Joined: February 14th, 2017, 7:32 pm

Re: Animated Sprites for the Chili framework?

Post by Zedtho » July 31st, 2017, 8:19 am

Just wanted to jump in here and tell people what to do to get this into their already existing project!
Spoiler:
  • Backup your project somewhere! This might go wrong if you screw up somewhere.
  • Open Albino's Framework and check if it is working (build & run it), retarget the solution if needed. (by rightclicking the solution file in Visual Studio and selecting retarget)
  • Be sure you don't have any files that have the same name as Albino's (Be sure to delete Albino's game.h/game.cpp files). I specifically had problems with Albino's Vec2 and my Vec2. I'd put your own Vec2 class in a "MyVec2.h" file (Don't forget to change all the #include "Vec2.h" to "MyVec2.h"!). Other files provided by the Chili Framework probably don't need tampering with, because they're pretty much the same in both Chili's and the modified version.
    (This includes Graphics.h/.cpp etc., although the Screen Size (those variables are located at the bottom of Graphics.h) will be reset to default again!)
  • Now that both solutions are in the same version and all, copy all of the files in Albino's Engine folder in to your Engine folder.
  • Now when you open your solution folder, you might find that some of your files aren't in the Solution Explorer tab anymore. These files haven't been deleted though. Just open the Engine folder and drag those on to the solution icon inside the Solution Explorer, which will automatically re-organize them in to their Header Files & Source Files folders.
  • Now you should be able to use the Framework. If you get any linker errors you might still have some problems with conflicting files.
  • ???
  • Profit.
  • Share what you did with this modified Framework with Albinopapa.
No but seriously, you can now use Animations, Sprites, Fonts, some kind of camera stuff, and if you hadn't added it yet, you also have Sound support now too!
If someone could write something like this for using the modified Framework that'd be awesome :D.

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Animated Sprites for the Chili framework?

Post by albinopapa » July 31st, 2017, 10:35 am

Haha, thanks for posting this Zedtho. Yes, make sure to use the modded Graphics.h and Graphics.cpp files. They have been altered a lot. One thing is I created an aligned_ptr class that wraps the pSysBuffer and has some added functionality. I also moved all the Direct3D stuff into a Direct3D nested class just because. The second biggest reason is the inclusion of PutPixelAlpha which is used for alpha blending.

The Colors.h and Colors.cpp files are needed as well.

There is a lot of added functionality in the Vec2 class, I would suggest using it if you plan on actually using vector math stuff. It looks like it came from the 2016 framework, but it could be from his previous framework. I want to say I only added the Reflect function and operator==, operator!= functions.

Keyboard class I think the only change I made was making Event public. Is kind of strange for it to be private when you need to get events from the keyboard. Using auto e = wnd.kbd.Read() seems to work for some reason, but without making it public, you can't functions that take a Keyboard::Event.

As for the other chili framework files ( mainwindow, mouse, etc... ) I don't believe I changed much of anything important.
-----------------------------------
Documentation...hmm. Perhaps I'll do that. I was hoping the examples I left in there in the Game.h/Game.cpp files would help others figure out how to use the new classes, but I will make an effort to write something up.

Again, thanks for writing up the instructions for adding to the project. I did forget to mention, I created all this in Visual Studio 2015. If you are just copying over the .h and .cpp files, you won't even have to worry about changing the build version. Since it's not a lib, you will have to import all the modded files into your project.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Animated Sprites for the Chili framework?

Post by albinopapa » July 31st, 2017, 10:43 am

Hey, next up is Particle emitters.

I've been working on this slowly over the weekend. I am trying to simulate fireworks and have something pretty basic working. Right now, the emitter spawns particles, then when the particles die, their position is recorded and eight new emitters are created at those locations pointing in eight different directions. Right now it's just colored circles ( they look like blobs because of shading ), but I plan on allowing them to use sprites as the particles. I'm not really looking forward to being able to dynamically scale things yet, so for now it will be something like drawing a sprite at the position of the particle. Perhaps I can use animated sprites.

The list of parameters for the emitters just keeps growing to allow for randomness in delay, radius of particles, color, how long the particles live and so on. I'd still like to allow for random directions. Anyway, be on the look out.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Animated Sprites for the Chili framework?

Post by albinopapa » July 31st, 2017, 10:07 pm

I've tried to make this as simple as possible, but here it goes.

Sprite/AlphaSprite:
In my mind, sprites are just the images that represent an object. So there is no update or move function. They are meant to be placed in another object that may or may not be controlled. The reason for this is simple, to save on resources. Say you have a 1,000 ships and they all use the same sprite. You wouldn't want to load the sprite 1,000 times. This way you can pass in a pointer to a sprite or alphasprite during the ship constructors and save on memory and possibly load times.
  • CREATING
    • Code: Select all

      		Sprite m_sprite = Sprite( "myImage.png" );
      		AlphaSprite m_alphaSprite = AlphaSprite("myTransparentImage.png");
      		// For now there is only one constructor, so you have to initialize them in the 
      		// Initializer list of a class, like Game.  This may change down the road.
      	
  • UPDATING
    • All updates to sprite position are handled by the object that owns the sprite as mentioned earlier. Sprites in my mind don't have a position to themselves, they are just drawn at whatever position the owning object is currently positioned.
  • DRAWING
    • There was an oversight in the version that is on GitHub. At the time I uploaded, I forgot to add the duplicate versions of the Sprite::Draw and Sprite::DrawReverse functions and their AlphaSprite counterparts. They will be updated after writing this, so I'll explain it from the point of view from the corrected version instead.
    • The first version of Draw/DrawReverse only takes in a single Rectf. This is the destination on the screen you want the sprite drawn to. This assumes you want the entire sprite to be drawn ( if it fits on screen ). I've done my best to clip the rectangles that don't fit on screen, so if your sprites do go off screen, it shouldn't crash.
    • The second version of those functions takes in a source and a destination Rectf. The source rect is the location on the sprite you want drawn and the destination is where on the screen to draw that region.

      Code: Select all

      		const Vec2i offset = 
      		{ 
      			( m_sprite.GetWidth() - Graphics::ScreenWidth ) / 2,
      			( m_sprite.GetHeight() - Graphics::ScreenHeight ) 
      		};
      		const auto rect = Graphics::ScreenRect.Translate( offset );
      		m_sprite.Draw( rect, Graphics::ScreenRect, m_graphics );
      	
      In this code, I have an image that is 1800x1534 and a window size of 800x600. The offset variable is where I want to translate my viewport ( which is the viewable rectangle of the screen ). In this case, I want to translate the viewport so that I'm in the middle of the image and at the bottom. I then translate the ScreenRect by the offset. This becomes the source rect and the ScreenRect is the destination rect. Since, ScreenRect is constant, the overloaded Translate function returns a new Recti at the translated position.
      The offset will depend on something like camera position or if you have a sprite that has tiles, you'd want to use the source rect to pick that tile.

      Code: Select all

      		const Recti rect = m_sprite.GetRect().Translate( car.GetPosition() );
      		m_sprite.DrawReverse(rect, m_graphics);
      	
      In this code, I get the sprite rect and translate it to the car's position. I only have to pass in the translated rect since I know that the entire car sprite is small enough to fit on screen, if it's in view. This would be the same for the Draw function as well.
  • DESTRUCTION
    Freeing resources ( the pixel data ) happens automatically when the Sprite object is out of scope, like then end of the program for instance. If you create a Sprite * by using new,you'll be responsible for deleting it yourself though. I would suggest either sticking with creating a Sprite object ( Sprite m_sprite("myImage.png") ) or using a smart pointer (std::unique_ptr<Sprite> m_pSprite = std::make_unique<Sprite>("myImage.png");
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Animated Sprites for the Chili framework?

Post by albinopapa » July 31st, 2017, 10:41 pm

class Frames
  • Before you can create an AnimatedController, you must load the images into a Frames object. The Frames class is responsible for loading an image series such as; image00.png, image01.png, etc... It's also used as a wrapper for the vector of Sprite smart pointers. It has two functions, GetFrame( size_t Idx ) and size_t Count()const;
    It doesn't hold a state like, current frame for instance.
  • CREATING

    Code: Select all

    		Frames m_walk = Frames( Frames::SpriteType::Alpha, 30, "Images/Walk", ".png");
    	
    • The Frames::SpriteType has two types, Alpha and Solid. Instead of making a separate class for solid and alpha sprites, I use polymorphism through inheritance ( treating a child pointer like a parent pointer).
    • The second parameter is the number of images in the sequence to load.
    • The third parameter is the basename of the file including location. In this example, I have my image series in a sub folder called Images.
    • The last parameter is the extension of the image series. (".bmp", ".jpg" and ".png" are all acceptable.)
  • UPDATING
    In this case, you don't interact with the Frames object at all. You store them somewhere and pass them on to an AnimationController constructor. All updating is done through the AnimationController.
  • DRAWING
    Drawing is handled by the AnimationController.
  • DESTRUCTION
    Just like with sprites, as long as the Frames object is around, so will the underlying sprites. Once the Frames object goes out of scope, the images are safely deleted.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Animated Sprites for the Chili framework?

Post by albinopapa » July 31st, 2017, 10:43 pm

class AnimationController
  • The AnimationController is the class that controls advancing the frames and drawing the current frame of the Frames object. This is the class that holds the state of the Frames object. You are able to use or reuse the same AnimationController object. So for instance, you can have just one AnimationController object and when you want to change the set of animations, you just assign a new AnimationController to the existing one, passing in a new Frames object.
  • CREATING

    Code: Select all

    		AnimationController m_animController( 1.f, m_stand );
    		m_animController = AnimationController( 30.f / 900.f, m_walk );
    	
    • The first parameter is the time to hold on the current frame before advancing to the next.
    • The second parameter is a Frames object you want the controller to control.
    The 30.f / 900.f was just trial and error to get as close as possible to make the animation and movement look correct. This equals out to be around 0.033f or close to two game frames for every animation frame change.
  • UPDATING

    Code: Select all

    		m_animController.Advance( DeltaTime );
    	
    To update the animation, just call the Advance function and pass in the delta time ( for debugging, you can pass in .016f for a 60 fps setup.) This updates the internal counter and when it's reached the hold time, the current frame is updated to the next frame or to the first frame of animation.
  • DRAWING

    Code: Select all

    		const Rectf dstRect = { 360.f, 336.f, 440.f, 464.f };
    		m_animController.Draw( dstRect, m_graphics );
    		// This version of the function, uses the entire sprite as it's source.
    	
    This has the same four drawing functions as Sprite and AlphaSprite and basically function the same. All the work is done in the underlying Sprite and AlphaSprite draw functions.
  • DESTRUCTION
    The AnimationController doesn't own any resources, it only holds a pointer to a Frames object. This class will be destroyed when it goes out of scope.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Animated Sprites for the Chili framework?

Post by albinopapa » July 31st, 2017, 11:12 pm

class Font
I've tried different ways of rendering fonts in the Chili framework. The approach I've come up with is by far the simplest. In the past, I've had to change the entire graphics class to use Direct2D instead of Direct3D. Chili has a version out that uses GDI+, though I don't remember which framework it's in. This version loads a system font and renders a sprite sheet to a WIC (Windows Imaging Component) bitmap. That bitmap is used for rendering the font to the screen. If you've read the forum thread, you'll notice I made creation a lot easier. Though, looking back now I could have simplified a little more.
  • CREATING

    Code: Select all

    	class TextFormat
    	{
    		struct Properties
    		{
    			std::wstring fontname = L"Consolas";
    			DWRITE_FONT_WEIGHT weight = DWRITE_FONT_WEIGHT_NORMAL;
    			DWRITE_FONT_STRETCH stretch = DWRITE_FONT_STRETCH_NORMAL;
    			DWRITE_FONT_STYLE style = DWRITE_FONT_STYLE_NORMAL;
    			float size = 16.f;
    			std::wstring locale = L"en-us";
    		};
    	};
    	
    You'll have to experiment with the enums that are in there such as DWRITE_FONT_STYLE, DWRITE_FONT_STRETCH and DWRITE_FONT_WEIGHT. The size variable is the vertical size for fixed width fonts, but doesn't match for other font types.
    The locale is the country code, the default is United States English.
    Consolas is a group of fixed width fonts. The fontname needs to match the font name that is in the Windows/Fonts folder. I don't think it's case sensitive. For instance, L"times" isn't the same as L"times new roman".

    Code: Select all

    		TextFormat::Properties props;
    		props.fontname = L"Consolas";
    		props.size = 28.f;
    		m_consola = Font{ props };
    	
    The only parameter for Font is a TextFormat::Properties object.
  • UPDATING
    Nothing to update.
  • DRAWING

    Code: Select all

    		m_consola.DrawString( 0.f, 300.f, "Your score: ", Colors::Red, m_graphics );
    	
    • First parameter is the X position.
    • Second is the Y position.
    • Third is the string you want to render.
    • Fourth is the color you want the font to be.
    • Fifth is the Graphics object.
  • DESTRUCTION
    Font class owns a FontSheet object and will automatically free those resources when the Font object goes out of scope.
I should make some more functions inside Font that would help determine how long a string would be on screen at the current size for instance. That would help someone implement word wrapping for instance.
Custom fonts aren't supported. If you want to be able to use custom fonts, you must install them so they are in the Windows/Fonts folder.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Animated Sprites for the Chili framework?

Post by albinopapa » July 31st, 2017, 11:30 pm

Hope this helps some.

I went ahead and merged all updates into the master branch. The other branches are still there for now, but I will be creating new stuff on branches until it works, then merging into master.

I created a Scene class which is an abstract class. Each of the demos are separated into child classes.
To check them out, just uncomment the one you want, and comment out the one you are finished with.

Code: Select all

Game::Game( MainWindow& wnd )
	:
	wnd( wnd ),
	gfx( wnd ),
	//m_scene( std::make_unique<Scene_Particles>( wnd.kbd, gfx ) )
	//m_scene( std::make_unique<Scene_Camera>( wnd.kbd, gfx ) )
	//m_scene( std::make_unique<Scene_AnimatedSprite>( wnd.kbd, gfx ) )
	//m_scene( std::make_unique<Scene_FontRendering>( wnd.kbd, gfx ) )
	m_scene( std::make_unique<Scene_Sprite>( wnd.kbd, gfx ) )
{
}
The Scene_Particles is the one I'm working on right now. Hopefully, I get to the point where creating particles and emitters isn't so complicated.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: Animated Sprites for the Chili framework?

Post by albinopapa » August 1st, 2017, 5:36 am

Added a SpriteSheet class which will load a sprite upon construction.
It has a few functions for creating Sprite, AlphaSprite and Frames objects.
Had to make some changes and additions to those classes to allow SpriteSheet to create them.
Added a new AnimationController child, called PendulumAnimController. It will advance through the frames going forward, then when it reaches the end, it counts backward.

Found a bug while testing. The sprites clip correctly going off the screen to the right, forgot to check the bottom, but they don't clip correctly going off the screen going left or up. I will look into this over the next couple of days.

Right now all SpriteSheet objects load in an alpha sprite, so you may only get alpha sprites even when creating solid sprites from the sheet. I'll have to take a look, this is also untested.

I don't have a demo for the sprite sheet stuff up on GitHub yet. I tested it out in Zedtho's Attack In the Forest project. Can't wait to see what he comes up with. I'll have to figure something out about these updates. I'm sure you all don't want to have to keep copying updated files into your projects.

One way around it for now, is instead of copying the files into your project folder then importing them into your Visual Studio solution, is leave them in the folder you originally downloaded them to like C:\Users\Source\chili-framework or whatever, and just drag them over into your Visual Studio solution. That way when I make changes, and you update your end, they will stay up to date with all the bug fixes. Any new files, you'll have to drag into your solution manually.

I'd like to turn this into a library, which might make this stuff easier, but everything relies so heavily on the Graphics class and knowing the screen size. I'll just add it to the things to look into.

EDIT: The SpriteSheet functions for creating solid and alpha sprites return std::uniqe_ptr<Sprite> instead of Sprite objects. This was for technical reason and worked out in the end to make the CreateFrames functions. Smart pointers like std::unique_ptr are used just like raw pointers, so just treat them as such and you'll be fine. The biggest difference though is they cannot be copies automatically. You have to move them using std::move. Since they can't be copied and Sprite/AlphaSprite both have them, they can't be copied either. This means if you pass them (Sprite or AlphaSprite) to functions you must pass them as const Sprite & or const AlphaSprite &. All the functions are const so you won't need to pass by non const reference.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

User avatar
Zedtho
Posts: 189
Joined: February 14th, 2017, 7:32 pm

Re: Animated Sprites for the Chili framework?

Post by Zedtho » August 1st, 2017, 7:46 am

Thanks a lot for the tutorial! Also, the speed of development is really stunning, keep it up!

Post Reply