Sprite Animation

Discussions about Coding and Scripting
Post Reply
User avatar
ANUBITEK
Adept
Posts: 261
Joined: Sun Dec 28, 2014 1:10 am
Location: Anubitek

Sprite Animation

Post by ANUBITEK »

tl;dr I am having a. . . Bitmap issue I think?

Higor coded a SpriteAnimation actor and a SpriteAnimationManager. But I have a Type Mismatch error in SpriteAnimationManager, and he is making XC engine.

I'll post my understanding of the code, but first here is the issue I am having:

Code: Select all

Anims[i].Animated.Texture = Anims[i].Animation.GetByPosition(1); // Error, Type mismatch in '='
I am having a type mismatch error, in that an actor is attempting to set another actor's texture to a certain texture for each tick, conditions varying and applying.

If you're with me beyond that, here are the three actors:
SpriteAnimation

Code: Select all

class SpriteAnimation expands Object;

struct AnimNotify
{
    var name CallOnFrame;
    var int PlayOnFrame;
};
var float DefaultAnimTime;
var array<BitMap> AnimFrames;
var array<AnimNotify> AnimNotifies; // Accesses the data DIRECTLY FROM AnimNotify


final function BitMap GetByPosition( float InPos)
{
    local int aSize;
    aSize = Array_Size( AnimFrames);
    return AnimFrames[ int(InPos*float(aSize)) % aSize ];
}
SpriteAnimationManager

Code: Select all

//=============================================================================
// SpriteAnimationManager.
// In charge of updating the animations independantly, pooled into an animation manager.
//=============================================================================
class SpriteAnimationManager expands Actor;

struct AnimRegister
{
    var Actor Animated;
    var SpriteAnimation Animation;
    var float AnimRate;
    var float CurPosition;
    var int RepeatCount;
    var bool bLooping;
    var bool bNotify;
    var name FinishNotify;
}; // Establish an AnimRegister

var private array<AnimRegister> Anims;

event Tick( float DeltaTime)
{
    local int i, Max;
    local float OldPosition;
    local bool bRemove;

    Max = Array_Size( Anims);
    for ( i=0 ; i<Max ; i++ )
    {
        if ( Anims[i].Animated == none || Anims[i].Animated.bDeleteMe ) // Animated actor has been removed, so remove its Array.  This actor is instantiated pre or post begin play?
        {
REMOVE_ANIMATION:
            Array_Remove( Anims, i, 1);
            Max--;
            i--;
            continue;
        }
        bRemove = false;
        OldPosition = Anims[i].CurPosition; // This holds a value for animation playing, seen below.
        Anims[i].CurPosition += Anims[i].AnimRate * DeltaTime; // This is how an animation plays a cycle.
        if ( Anims[i].bNotify )
        {}    //PROCESS NOTIFIES!!!!
        if ( (abs(OldPosition) < 1) && (abs(Anims[i].CurPosition) >= 1) ) // Animation has completed a cycle
        {
            if ( !Anims[i].bLooping && (Anims[i].RepeatCount-- <= 0) )
            {
                Anims[i].Animated.Texture = Anims[i].Animation.GetByPosition(1); // Error, Type mismatch in '='
                goto REMOVE_ANIMATION;
            }
            Anims[i].CurPosition -= int(Anims[i].CurPosition); //Why not substract 1?... imagine the animation plays so fast it completes multiple cycles per frame... get it?
        }
        Anims[i].Animated.Texture = Anims[i].Animation.GetByPosition( Anims[i].CurPosition); // Error, Type mismatch in '='
    }
}

function bool StopAnimation( Actor sAnimated)
{
    local int Idx;
    Idx = GetByActor( sAnimated);
    if ( Idx >= 0 )
        Array_Remove( Anims, Idx, 1);
    return Idx >= 0;
}

function ChangeRate( Actor sAnimated);
function SetNotifyState( Actor sAnimated, bool bEnable, optional name NewOptNotify);

//RepeatCount = -1 means loop (default = 0, one shot)
// Rate is (1/Time) anim takes to complete, feel free to call the function like that
// EndNotify = '' (or unspecified) means no callback
function PlayAnimation( Actor sAnimated, SpriteAnimation sAnimation, float Rate, optional int RepeatCount, optional name EndNotify )
{
    local int Num;

    Num = GetByActor( sAnimated);
    if ( Num == -1 )
    {
        Num = Array_Size( Anims);
        if ( !Array_Insert( Anims, Num, 1) )
        {
            Log("ERROR: Failed to allocate animation register for "$sAnimated.Name);
            return;
        }
    }
    Anims[Num].Animated = sAnimated;
    Anims[Num].Animation = sAnimation;
    Anims[Num].AnimRate = Rate;
    Anims[Num].CurPosition = 0;
    Anims[Num].bLooping = (RepeatCount == -1);
    Anims[Num].RepeatCount = RepeatCount;
    Anims[Num].bNotify = (EndNotify != '');
    Anims[Num].FinishNotify = EndNotify;
	sAnimated.Texture = sAnimation.GetByPosition(0); // Error, Type mismatch in '='
}

// return -1 means no index, no animation for this actor
// Good way to see if an actor is being animated by THIS manager
final function int GetByActor( Actor sAnimated)
{
    local int i;

    for ( i=Array_Size(Anims)-1 ; i>=0 ; i-- )
        if ( Anims[i].Animated == sAnimated )
            return i;
    return -1;
}
DummyAnimActor

Code: Select all

class DummyAnimActor expands Actor;

#exec OBJ LOAD FILE=..\Textures\RPG_Test_Sprite.utx

var SpriteAnimationManager AnimManager;
var SpriteAnimation WalkTest;

//Actor has been summoned
event PostBeginPlay()
{
	ForEach AllActors (class'SpriteAnimationManager', AnimManager) //Find a animmanager
		break;
	if ( AnimManager == None ) //Create if not found
		AnimManager = Spawn(class'SpriteAnimationManager');

	//Hardcoded create
	WalkTest = new( None, 'DummyAnimationObj') class'SpriteAnimation'; // ERROR: Error, Type mismatch in 'new' parent object
	//Hardcoded time
	WalkTest.DefaultAnimTime = 0.8;
	//Hardcoded frames (dynamic arrays should allow this kind of accessors)
	WalkTest.AnimFrames[0] = Texture'DownRightWalk3';
	WalkTest.AnimFrames[1] = Texture'DownRightWalk4';
	WalkTest.AnimFrames[2] = Texture'DownRightWalk5';
	WalkTest.AnimFrames[3] = Texture'DownRightWalk6';
	WalkTest.AnimFrames[4] = Texture'DownRightWalk7';
	WalkTest.AnimFrames[5] = Texture'DownRightWalk8';
	WalkTest.AnimFrames[6] = Texture'DownRightWalk1';
	WalkTest.AnimFrames[7] = Texture'DownRightWalk2';
	//Hardcoded two notifies
	Array_Insert( WalkTest.AnimNotifies, 0, 2);
	WalkTest.AnimNotifies[0].PlayOnFrame = 2;
	WalkTest.AnimNotifies[0].CallOnFrame = 'FootstepSound';
	WalkTest.AnimNotifies[1].PlayOnFrame = 6;
	WalkTest.AnimNotifies[1].CallOnFrame = 'FootstepSound';
	SetTimer( 10, true);
}

event Timer()
{
	AnimManager.PlayAnimation( self, WalkTest, 1, 3, 'EndWalk' );
}
If my understanding of what he has written is correct, in this example DummyAnimActor spawns, SpriteAnimationManager is instantiated then SpriteAnimation. SpriteAnimationManager runs on tick, first establishing an array then either checking if an animation needs to be removed or if the animation should cycle. If it should cycle X amount of times, do so until X is met then terminate. You have a few functions that can be called, either choosing to StopAnimation() or PlayAnimation().

Now here we are at a part of where I feel my understanding of code is too shaky to be confident. SpriteAnimation is a smaller actor, which is supposed to contain an array of bitmaps and AnimNotifies (structs, containing a name [CallOnFrame] and int [PlayOnFrame]). This is where the issue lies, in SpriteAnimation with its only function, GetByPosition, which is supposed to return a float. At this point, I am left wondering what the issue is, but what should be happening is the current actor's texture is set to what ever should be occupying the result of GetByPosition's math, in its AnimFrames Bitmap Array. DummyAnimActor has set what should be in AnimFrames.

Can anyone help me? Otherwise what is basically the whole reason I began coding is on a shelf. He gave me this code and I was able to use it to study (led to a bunch of information on bitmaps, dynamic arrays, the new() function which is an interesting one, and some interesting things I can do with tick), but if I can't get it to work then we can't get into the next step of this.
<<| http://uncodex.ut-files.com/ |>>

Code reference for UGold, UT99, Unreal2, UT2k3, UT3
Additional Beyond Unreal Wiki Links
wiki.beyondunreal.com/Legacy:Console_Bar
wiki.beyondunreal.com/Exec_commands#Load
wiki.beyondunreal.com/Legacy:Exec_Directive#Loading_Other_Packages
wiki.beyondunreal.com/Legacy:Config_Vars_And_.Ini_Files
wiki.beyondunreal.com/Legacy:INT_File
User avatar
ANUBITEK
Adept
Posts: 261
Joined: Sun Dec 28, 2014 1:10 am
Location: Anubitek

Re: Sprite Animation

Post by ANUBITEK »

Well from first look, GetByPosition returns BitMap and not Texture. Since BitMap is a parent class of Texture, you need to metacast it to Texture:

Code: Select all

Anims[i].Animated.Texture = Texture(Anims[i].Animation.GetByPosition(1));
But then again, why use Bitmap in the first place since there is no practical use of it?

Also, at your dummy DummyAnimActor, why not instead of generating SpriteAnimation object in code, define it in defaultproperties:

Code: Select all

defaultproperties
{
    Begin Object Class=SpriteAnimation name=DummyAnimationObj
		DefaultAnimTime=0.8
		AnimFrames.Add(Texture'DownRightWalk3')
		AnimFrames.Add(Texture'DownRightWalk4')
		AnimFrames.Add(Texture'DownRightWalk5')
		AnimFrames.Add(Texture'DownRightWalk6')
		AnimFrames.Add(Texture'DownRightWalk7')
		AnimFrames.Add(Texture'DownRightWalk8')
		AnimFrames.Add(Texture'DownRightWalk1')
		AnimFrames.Add(Texture'DownRightWalk2')
		AnimNotifies.Add((PlayOnFrame=2,CallOnFrame='FootstepSound'))
		AnimNotifies.Add((PlayOnFrame=6,CallOnFrame='FootstepSound'))
    End Object
    WalkTest=DummyAnimationObj
}
This has led to the actor now working, so would anyone like to see an animated Xenogears character sprites in Unreal?
CbfaRsJwkD4
<<| http://uncodex.ut-files.com/ |>>

Code reference for UGold, UT99, Unreal2, UT2k3, UT3
Additional Beyond Unreal Wiki Links
wiki.beyondunreal.com/Legacy:Console_Bar
wiki.beyondunreal.com/Exec_commands#Load
wiki.beyondunreal.com/Legacy:Exec_Directive#Loading_Other_Packages
wiki.beyondunreal.com/Legacy:Config_Vars_And_.Ini_Files
wiki.beyondunreal.com/Legacy:INT_File
User avatar
papercoffee
Godlike
Posts: 10447
Joined: Wed Jul 15, 2009 11:36 am
Personal rank: coffee addicted !!!
Location: Cologne, the city with the big cathedral.
Contact:

Re: Sprite Animation

Post by papercoffee »

Looks interesting ... you can call all animation phases accordingly to the direction the sprite is moving?
This means one sprite has one utx file with all its animations?
User avatar
ANUBITEK
Adept
Posts: 261
Joined: Sun Dec 28, 2014 1:10 am
Location: Anubitek

Re: Sprite Animation

Post by ANUBITEK »

Not yet, honestly trying to determine what would be the best method to handle this. Right now, I am coding in a method for determining which sprite should be displayed depending on the camera's position to the actor that holds the sprites. I have the direction setting for PlayerPawns set up already, which I can throw a function into for playing animations depending on whether or not the player is walking. My problem is I am definitely not a math guy and I have to do a few things in order to determine what sprite should display:
> Get camera position/rotation
> Get pawn position/rotation
> Check positions/rotations/distances
Now while I can think of how this works (check relative positions with simple x/y checks), the problem is I have no idea how I would compare rotations of the camera and pawn. On top of this, I don't know how I could check scaled diagonal directions (scaled meaning how far away/close the actors are to each other). If you are not sure what I mean by this, click on this YouTube link and skip to 11:34 for an example of how sprites should rotate: https://youtu.be/AnNshgNlU8s?t=11m34s
<<| http://uncodex.ut-files.com/ |>>

Code reference for UGold, UT99, Unreal2, UT2k3, UT3
Additional Beyond Unreal Wiki Links
wiki.beyondunreal.com/Legacy:Console_Bar
wiki.beyondunreal.com/Exec_commands#Load
wiki.beyondunreal.com/Legacy:Exec_Directive#Loading_Other_Packages
wiki.beyondunreal.com/Legacy:Config_Vars_And_.Ini_Files
wiki.beyondunreal.com/Legacy:INT_File
User avatar
papercoffee
Godlike
Posts: 10447
Joined: Wed Jul 15, 2009 11:36 am
Personal rank: coffee addicted !!!
Location: Cologne, the city with the big cathedral.
Contact:

Re: Sprite Animation

Post by papercoffee »

Well as you can see did the developer cheat a little bit and gave the player fix camera positions each in 45° ...if the camera switches to the next position all the sprites (even those in the far background) switches on half the 45° rotation. They switch after the camera have reached 22,5° giving the illusion of a more fluid movement.
It's a pretty common method for those hybrid games half polygon half sprite. The maker of Grandia used the same trick.

Maybe using fix camera positions around the main sprite and switching all the other sprites accordingly to the camera angle could help you a lot.
User avatar
ANUBITEK
Adept
Posts: 261
Joined: Sun Dec 28, 2014 1:10 am
Location: Anubitek

Re: Sprite Animation

Post by ANUBITEK »

This could help me a bit more, but the problem is that this could potentially take away dynamic camera angles, like this:
EvW4Kzmf8cU
Instead, I am looking for something exactly like this:
juBmjE3PAbI

So I am left with calculating positions. That being said, all I need is a better understanding of how certain mathematical operators work and I think this is pretty easily solvable. But if anyone remembers my post about basic math operators, you'll know this will be a fun time for me. Up until now, I've just been doing a lot of variable changing and boolean checks. So this could turn out to be a pretty good exercise for me.
<<| http://uncodex.ut-files.com/ |>>

Code reference for UGold, UT99, Unreal2, UT2k3, UT3
Additional Beyond Unreal Wiki Links
wiki.beyondunreal.com/Legacy:Console_Bar
wiki.beyondunreal.com/Exec_commands#Load
wiki.beyondunreal.com/Legacy:Exec_Directive#Loading_Other_Packages
wiki.beyondunreal.com/Legacy:Config_Vars_And_.Ini_Files
wiki.beyondunreal.com/Legacy:INT_File
User avatar
Gustavo6046
Godlike
Posts: 1462
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Resident Wallaby
Location: Porto Alegre, Brazil
Contact:

Re: Sprite Animation

Post by Gustavo6046 »

Wait... first video. I RECOGNIZE THAT MUSIC!!! All I have to say is E1M8. :P
"Everyone is an idea man. Everybody thinks they have a revolutionary new game concept that no one else has ever thought of. Having cool ideas will rarely get you anywhere in the games industry. You have to be able to implement your ideas or provide some useful skill. Never join a project whose idea man or leader has no obvious development skills. Never join a project that only has a web designer. You have your own ideas. Focus on them carefully and in small chunks and you will be able to develop cool projects."

Weapon of Destruction
Post Reply