changing sprite dimension (width/height) with script...

Started by Filipe, Sun 17/03/2019 00:41:46

Previous topic - Next topic

Filipe

Hello again :)

Is it possible to change the sprites dimensions height, and width? like cEgo.height, and cEgo.width...

Or do I have to go to photoshop and then increase the image size of each frame? Please don't tell me I need it :(

I mean, I need to kind of get my character larger, after he drink some sort of potion. Do I need to resize all my frames again? I mean, my character walks, run, laughs, seats, speaks,  etc.... there are so many frames... snif.. snif.. :(

Crimson Wizard

#1
If multiplying image size is all you need, then Character.ManualScaling and Character.Scaling will work.

If you want more precise alteration, then you have to edit images.

Also it's possible to resize images in script and replace in all the view frames with DynamicSprites by writing not so complicated function, in case you want width and height scaled differently.

Filipe

Thanks a lot Wizard :),

...and yes, I do want to scale sprites differently, not with the same proportions, I mean. I want to be able to stretch them in height and not changing the width, for instances.

How can this be done? How do I use DynamicSprites? Can you give me an example? Suppose I want to change the height of my character and keep its width the same... Also can this be done with all the frames of a certain view? I mean, can I change the size of all the frames of a certain view altogether? Does this applys also to objects, or only to characters?

Again many thanks :)

Crimson Wizard

#3
Quote from: Filipe on Sun 17/03/2019 09:06:43
...and yes, I do want to scale sprites differently, not with the same proportions, I mean. I want to be able to stretch them in height and not changing the width, for instances.

How can this be done? How do I use DynamicSprites? Can you give me an example? Suppose I want to change the height of my character and keep its width the same... Also can this be done with all the frames of a certain view? I mean, can I change the size of all the frames of a certain view altogether? Does this applys also to objects, or only to characters?

DynamicSprites are a bit of larger topics, but basically they are like sprites only created from script and deleted as soon as the last pointer for them is lost. Because of that, if you need to keep dynamic sprites for a prolonged time, you have to store pointers to them in global variables, or array, for example like this:

Code: ags

DynamicSprite* modifiedViewSprites[];


This declares a dynamic array (which length is not fixed) of DynamicSprite pointers. It must be in global script or other modules, not room script, otherwise they will get deleted as soon as you leave the room (unless that's your intention).

Dynamic sprite may be created as a blank new sprite, or as a copy from existing one, for example:
Code: ags

DynamicSprite* newSpr = DynamicSprite.CreateFromExistingSprite(N); // where N is a sprite number

after this you can do what you like with it: resize, rotate, draw upon it.

Moving to the views, you may get any frame from a View in script and assign different sprite to it. Mind that this will change looks of every character or object that uses same View:
Code: ags

ViewFrame* frame = Game.GetViewFrame(V, L, F); // where V, L, F are view, loop and frame numbers
frame.Graphic = N; // where N is a sprite number

that simple


Now we combine dynamic sprites with the views. A basic example:
Code: ags

DynamicSprite* newSpr = DynamicSprite.CreateFromExistingSprite(N);
newSpr.Resize(newSpr.Width, newSpr.Height * 2); // make it 2 times taller
ViewFrame* frame = Game.GetViewFrame(V, L, F);
frame.Graphic = newSpr.Graphic;



One important note I have to make is that you'd need to keep a record of original sprite numbers found in the view, in case you'd need to restore them or modify differently.
This may be done in another dynamic array which stores integers. Perhaps its better to do this before even starting changing anything, and then refer to this array when creating dynamic sprites.

Code: ags

// Function saves all frame sprite numbers in the view into array of ints and returns it
// We make a trick here and save dynamic array length in the first element!
int[] SaveSpriteIndexesFromTheView(int view)
{
    // calculate total number of frames before anything else
    int total_frames = 0;
    int loop_count = Game.GetLoopCountForView(view);
    for (int loop = 0; loop < loop_count; loop++)
    {
        total_frames += Game.GetFrameCountForLoop(view, loop);
    }

    // now we know how many sprite IDs we need to store
    int sprnums[] = new int[total_frames + 1]; // remember we need  +1 number of slots because we also save length in 0th
    sprnums[0] = total_frames;

    // save sprite ids
    int spr_index = 1; // array will have sprite IDs from slot 1 and on
    for (int loop = 0; loop < loop_count; loop++)
    {
        int frame_count = Game.GetFrameCountForLoop(view, loop);
        for (int frame = 0; frame < frame_count ; frame++)
        {
            ViewFrame* vf= Game.GetViewFrame(view, loop, frame);
            sprnums[spr_index] = vf.Graphic;
            spr_index++;
        }
    }
    return sprnums;
}



And now we can write a function that does the frame transformation in a loop across all the view:
Code: ags

// Function creates dynamic sprites from original ones, resizes them and returns an array of created DynamicSprites
DynamicSprite[] ResizeAllFrames(int view, int original_sprites[], float mul_width, float mul_height)
{
    int total_frames = original_sprites[0]; // remember we saved array length in the first element? :)
    DynamicSprite* dyn_sprites[] = new DynamicSprite[total_frames];

    // create dynamic sprites and modify them
    for (int i = 0; i < total_frames; i++)
    {
        DynamicSprite *d = DynamicSprite.CreateFromExistingSprite(original_sprites[i + 1]);
        int new_width = FloatToInt(IntToFloat(d.Width) * mul_width);
        int new_height = FloatToInt(IntToFloat(d.Height) * mul_height);
        d.Resize(new_width, new_height);
        dyn_sprites[i] = d;
    }

    // now when we have the dynamic sprites, run over the view and assign them to frames
    int spr_index = 0;
    int loop_count = Game.GetLoopCountForView(view);
    for (int loop = 0; loop < loop_count; loop++)
    {
        int frame_count = Game.GetFrameCountForLoop(view, loop);
        for (int frame = 0; frame < frame_count ; frame++)
        {
            ViewFrame* vf= Game.GetViewFrame(view, loop, frame);
            vf.Graphic = dyn_sprites[spr_index];
            spr_index++;
        }
    }
    return dyn_sprites;
}




And this is how we use these functions:
Code: ags

// We need two dynamic arrays in the global script where we save original sprite IDs and new dynamic sprites
int originalSpriteNums[];
DynamicSprite* modifiedViewSprites[];

// We save original IDs at the game start
function game_start()
{
    originalSpriteNums = SaveSpriteIndexesFromTheView(player.NormalView);
}

// And then let's make it resize on some keypress for a test
function on_key_press(eKeyCode key)
{
    if (key == eKeySpace)
    {
        modifiedViewSprites = ResizeAllFrames(player.NormalView, originalSpriteNums, 0.5, 1.5); // make View half-wide and twice as high
    }
}



I did not have time to test the code yet, but we'll see how it will work...

Filipe

UPs!! Thanks wizard.... but.... I'm scared :( I thought it was simpler... Anyway, I think I'm gonna stick with character scalling :)

SMF spam blocked by CleanTalk