Dynamic Sprite Error

Started by Deabriel, Sun 10/05/2020 07:30:33

Previous topic - Next topic

Deabriel

Hi, I'm trying to draw a sprite with the Dynamic Sprite function, but nothing happens (Except sprite error).

The code:
Code: ags
function room_Load()
{
  DynamicSprite* OptionButtonFix = DynamicSprite.Create(28, 28, true);
  DrawingSurface *OptionButtonSurface = OptionButtonFix.GetDrawingSurface();
  OptionButtonSurface.DrawImage(0, 0, 95);
  OptionButtonSurface.Release();
  btnShowOptions.NormalGraphic = OptionButtonFix.Graphic;
}

(I tryed to put in oApple.Graphic = OptionButtonFix.Graphic; and give me the same "error".)

This is the error:

Sprite in button/Sprite in object. When is the button it deleted the previous sprite and put it a new button text.

Another question is, I want to put that draw sprite in a gui button, is there a way to don't write the function in every room? Just one time forever.
And the last question is you can draw the sprite but resized? Something like if the sprite size is 20x20px making it 15x15?

Thanks.

Snarky

Quote from: Deabriel on Sun 10/05/2020 07:30:33
Another question is, I want to put that draw sprite in a gui button, is there a way to don't write the function in every room? Just one time forever.

Yes, you should put this code in the GlobalScript. If you want it to run once as soon as the game starts, you put it in the function game_start().

Quote from: Deabriel on Sun 10/05/2020 07:30:33I'm trying to draw a sprite with the Dynamic Sprite function, but nothing happens (Except sprite error).

When you declare a variable name (like OptionButtonFix) inside of a function (like room_Load() or game_start()), that name becomes invalid ("goes out of scope") when the function ends. And then the variable gets automatically deleted.

Spoiler
With one major wrinkle: When the variable is a pointer type, like this is, it only gets deleted if there aren't any other pointers to the same thing that are still valid. In this case there aren't any other pointers to the same DynamicSprite, so it doesn't help us.
[close]
So the problem is that the DynamicSprite is deleted as soon as room_Load() ends.

To stop this from happening, you need to declare it outside of the function. That way the name is valid for as long as the script is. (If you put it in a room script, that's as long as the player is in that room. If you put it in the global script, it's always.) Like this:

Code: ags
DynamicSprite* OptionButtonFix;

function game_start()
{
  OptionButtonFix = DynamicSprite.Create(28, 28, true);
  DrawingSurface *OptionButtonSurface = OptionButtonFix.GetDrawingSurface();
  OptionButtonSurface.DrawImage(0, 0, 95);
  OptionButtonSurface.Release();
  btnShowOptions.NormalGraphic = OptionButtonFix.Graphic;
}


Quote from: Deabriel on Sun 10/05/2020 07:30:33
And the last question is you can draw the sprite but resized? Something like if the sprite size is 20x20px making it 15x15?

Yes. In OptionButtonSurface.DrawImage(0, 0, 95) you can add width and height parameters to resize the image.

Snarky

BTW, I assume you have some particular reason why you want to do this with a DynamicSprite rather than just use sprite 95 that you already have, and assign it directly in the editor?

Deabriel

Thank you so much, it worked like a charm.
Quote from: Snarky on Sun 10/05/2020 08:01:21
BTW, I assume you have some particular reason why you want to do this with a DynamicSprite rather than just use sprite 95 that you already have, and assign it directly in the editor?
I was trying to do something like the Manual Scaling of the characters. I have a button sprite that goes big when the game is in fullscreen or scale x2 x3, etc. I want to do something like happens when you use Manual Scaling in characters, when the game is in fullscreen, etc; the resize works fine.

But now that I tryed with the dynamic sprite, the resize didn't work like the manual scaling in characters, the resize in dynamic sprite goes so misshaped. I guess it only works fine with characters.

Khris

You need to do the proper math for the dimensions. Show the code you've tried and we can try to fix it.

Deabriel

Quote from: Khris on Sun 10/05/2020 19:56:09
You need to do the proper math for the dimensions. Show the code you've tried and we can try to fix it.

This is the code:

Code: ags

DynamicSprite* OptionButtonFix;

function game_start() 
{
  OptionButtonFix = DynamicSprite.Create(28, 28, true);
  DrawingSurface *OptionButtonSurface = OptionButtonFix.GetDrawingSurface();
  OptionButtonSurface.DrawImage(0, 0, 95, 0, 18, 18);
  OptionButtonSurface.Release();
  btnShowOptions.NormalGraphic = OptionButtonFix.Graphic;
}


Graphical example/explanation of what happens:
Spoiler
What I said is when you use the Manual Scaling in windowed max round/stretch/fullscreen (I used ManualScaling = 70;) the character is resized fine:


Manual Scaling 70% vs Original Size in windowed/fullscreen

But when you do the resize in the Dynamic Sprite, it goes like this:

If I put the size in 18 x 18 like the code (But it happens too when I use 14 x 14) it's so misshapen:


This is the original size in windowed/fullscreen(So big):


And this is the original sprite size (28x28):


I like to do something like happens when you use manual scaling in characters (in my case when I use 70%, the characters get the size like it's only scaled x2).
[close]

I hope you can help me with this.

Crimson Wizard

#6
Ah, it's same game that had problems with camera scale.

I don't think there's a way to solve this with DrawImage at all, as it creates a new graphic with smaller resolution already.

The solution would be to assign an original image to button and scale the button (with "Render sprites in screen resolution" mode), but AGS currently does not support scaling GUIs.

The only option I can imagine is to draw 2 variants of button gfx and keep it artistically clean.

Also,
QuoteI have a button sprite that goes big when the game is in fullscreen or scale x2 x3, etc.

this confuses me. May I ask why are you doing this manual scaling between windowed/fullscreen when AGS scales whole game already?
Won't this result in game elements taking different percentage of game screen depending on mode?
I don't think I've ever seen anyone doing this before.

Deabriel

Quote from: Crimson Wizard on Mon 11/05/2020 00:48:25
this confuses me. May I ask why are you doing this manual scaling between windowed/fullscreen when AGS scales whole game already?
Won't this result in game elements taking different percentage of game screen depending on mode?
I don't think I've ever seen anyone doing this before.
I'm not using Manual Scaling, when I talked about the Manual Scaling is just an example of how AGS scales characters sprites in windowed max round/fullscreen. It's like AGS scales the character normally, and then when you use the Manual Scaling, the resize is of the already scaled sprite by AGS and not the original size.
Example: You have a game 320x180 and a character sprite of 25x50. When you use the AGS scale x2, x3, max round multiplier or fullscreen, AGS automatically scales the game (and the sprites). You use for example a scale multiplier x3. The character sprite now visually is 100 x 200 (but is 25x50). When you use the code cRoger.ManualScaling, AGS it's like it resize the sprite like is 100x200 and not 25x50. But when you resize the DynamicSprite or the button, it's like AGS resize only the original sprite (25x50). I hope you understand me (English is not my first language so there are probably confusions in my explanation)

I want to do the manual scaling only in the button, because when you are in fullscreen/max round multiplyer the sprite is big. And I know that I can draw a smaller sprite but it loses details. I want to have it smaller but with good details.

I didn't want to show a big image of the game but this is what I talking about:

Spoiler
The game button actually looks like this:



And this is how I want to look (I edited in photoshop):



[close]

Crimson Wizard

Ohh, makes sense now. So your problem is that AGS scales characters and objects smoothly, but does not do same to GUI. Unfortunately, GUI rendering is outdated compared to other things there.

Deabriel

Quote from: Crimson Wizard on Mon 11/05/2020 02:01:22
Ohh, makes sense now. So your problem is that AGS scales characters and objects smoothly, but does not do same to GUI. Unfortunately, GUI rendering is outdated compared to other things there.
Yes, that was what I talking about.
Mmm there's a way to transform a "character" into a button? Maybe with a character I can get what I want.

Crimson Wizard

Quote from: Deabriel on Mon 11/05/2020 02:08:41
Mmm there's a way to transform a "character" into a button? Maybe with a character I can get what I want.

Yes, you may try to place character or room object there and simulate a button. In my memory people used characters t emulate other stuff for this very purpose (free scaling).

In a common case you may need to set "Ignore walkable area scaling" for them, and their baseline = room height or even bigger to prevent anything covering them.
Also, you would have to update their position in "late_repeatedly_execute_always" to sync with camera movement in scrollable rooms.

But in your case, with camera zooming, it may be more complicated as you will also have to negate the room zoom.

Deabriel

Quote from: Crimson Wizard on Mon 11/05/2020 02:29:21
Quote from: Deabriel on Mon 11/05/2020 02:08:41
Mmm there's a way to transform a "character" into a button? Maybe with a character I can get what I want.

Yes, you may try to place character or room object there and simulate a button. In my memory people used characters t emulate other stuff for this very purpose (free scaling).

In a common case you may need to set "Ignore walkable area scaling" for them, and their baseline = room height or even bigger to prevent anything covering them.
Also, you would have to update their position in "late_repeatedly_execute_always" to sync with camera movement in scrollable rooms.

But in your case, with camera zooming, it may be more complicated as you will also have to negate the room zoom.

Ok, I made the button as a character and worked perfectly, but now I have some problems:
1) How can I send the character to the same room where the player goes without putting the character.ChangeRoom every time I send the player to another room.
2) How can I update the position to sync with the camera movement. In a normal room with the same size of the game is easy, I put the x and y that I want, but in scrollable rooms that position will not work.
3) How can I prevent the room zoom only in that character.

Thanks.

Deabriel

Ok, I think that I get how to follow the camera:
Code: ags
function late_repeatedly_execute_always() 
{
  cOption.x = Game.Camera.X + 416;
  cOption.y = Game.Camera.Y + 19;
}


I don't know if this is the proper way, but it's seems that works fine, the character now stay in the position that i want all the time.

But I still don't know how to prevent the room zoom and how to follow the player change room automatically

Crimson Wizard

#13
Quote from: Deabriel on Mon 11/05/2020 09:50:46
1) How can I send the character to the same room where the player goes without putting the character.ChangeRoom every time I send the player to another room.

First, you may make a custom function in a script module, and use it instead; e.g.:
Code: ags

void MyChangeRoom(int room) {
    player.ChangeRoom(room);
    buttonCharacter.ChangeRoom(room);
    ... anything else
}

Second option is to use on_event function and change button room and position at eEventEnterRoomBeforeFadein event.



Quote from: Deabriel on Mon 11/05/2020 10:09:33
Ok, I think that I get how to follow the camera:
Code: ags
function late_repeatedly_execute_always() 
{
  cOption.x = Game.Camera.X + 416;
  cOption.y = Game.Camera.Y + 19;
}


I don't know if this is the proper way

I answered another question recently, in a thread about DrawImage coordinate shift: https://www.adventuregamestudio.co.uk/forums/index.php?topic=58044.msg636620209#msg636620209
Same offset conversion could be used here, except you don't need to get ViewFrame as your character will always have same sprite, so you can get that sprite's width and height directly.

But, thing is, you must take zoom into account first before positioning it.
I need to think a little first before answering this further.

Snarky

Instead of these increasingly baroque workarounds, have you considered just making your game in higher resolution?

Or alternatively using an engine that has better support for mixed-resolution games, since that's what you're apparently aiming for.

Crimson Wizard

#15
Quote from: Snarky on Mon 11/05/2020 11:20:37
Instead of these increasingly baroque workarounds, have you considered just making your game in higher resolution?

Or alternatively using an engine that has better support for mixed-resolution games, since that's what you're apparently aiming for.


Yes, actually! Because, depending on what you want to have in game, using characters as buttons may bring other problems, as soon as you begin adding more effects to game that should normally affect characters but not GUI.


As AGS now supports camera zooms, one of the possibilities for you is to make game x2 or more native resolution, make GUI in that bigger resolution, but keep rooms and characters in small size and multiply camera zoom as necessary. This way you will have hires GUI and fonts, and rest of the game in low-res. Maybe that would be hell of a lot easier.



Anyway, since I wrote the answer to previous question already, only for the sake of record and technical curiosity, under spoiler
Spoiler

First of all, you may find a position in room corresponding to position on screen regardless of zoom or scroll using Screen.ScreenToRoomPoint function.

For example, if you know you like to have this object at 200,200 on screen:
Code: ags

Point* room_p = Screen.ScreenToRoomPoint(200, 200);
int width = Game.SpriteWidth[sprite];
int height = Game.SpriteHeight[sprite];
ButtonCharacter.x = room_p.x - width / 2;
ButtonCharacter.y = room_p.y - height;


So what remains is zoom. Zoom is Viewport  size / Camera size. But you need to negate that and take inverse relation:
Code: ags

float scaling_w = IntToFloat(Game.Camera.Width) / IntToFloat(Screen.Viewport.Width);
float scaling_h = IntToFloat(Game.Camera.Height) / IntToFloat(Screen.Viewport.Height);


But we only will use one dimension, like only width, here, because character scaling can be only uniform, as in you cannot set different scaling for width and height anyway.
In addition we need to convert between floating point scaling number and the scaling percentage used in ManualScaling property.

So, something like...
Code: ags

float anti_scaling = IntToFloat(Game.Camera.Width) / IntToFloat(Screen.Viewport.Width);
int manual_scaling = FloatToInt(anti_scaling * 100.0, eRoundNearest);


[close]

Deabriel

#16
First of all, thank you, this helped me alot. I decided to use a bigger resolution and I already got what I wanted using just a normal gui, without doing all this code things, saving me time and getting better results.

Anyway I decided to test your code, for the time you took to write/think on it.
Quote from: Crimson Wizard on Mon 11/05/2020 11:36:36
Code: ags

Point* room_p = Screen.ScreenToRoomPoint(200, 200);
int width = Game.SpriteWidth[sprite];
int height = Game.SpriteHeight[sprite];
ButtonCharacter.x = room_p.x - width / 2;
ButtonCharacter.y = room_p.y - height;

This worked like a charm, the only problem is when the room scrolls, the character slightly move to the right for a second and after back to the correct position.
I don't know why. But is not important now that I don't will use this.

Quote from: Crimson Wizard on Mon 11/05/2020 11:36:36
Code: ags
float anti_scaling = IntToFloat(Game.Camera.Width) / IntToFloat(Screen.Viewport.Width);
int manual_scaling = FloatToInt(anti_scaling * 100.0, eRoundNearest);

This worked really fine and didn't give me any problem.

I only have two questions, now that I use the bigger resolution, the only problem that I found is that the speech in zoomed room is drawn over the character:

Visual example:
Spoiler
[close]
(I tested the zoom camera in a normal low-resolution game and the speech is also drawn over the character)

The other question is more like a curiosity. It's possible to make the camera only scroll when the character walk close/near to the sides of the window?

Crimson Wizard

#17
Quote from: Deabriel on Tue 12/05/2020 03:16:54
Anyway I decided to test your code, for the time you took to write/think on it.
Quote from: Crimson Wizard on Mon 11/05/2020 11:36:36
Code: ags

Point* room_p = Screen.ScreenToRoomPoint(200, 200);
int width = Game.SpriteWidth[sprite];
int height = Game.SpriteHeight[sprite];
ButtonCharacter.x = room_p.x - width / 2;
ButtonCharacter.y = room_p.y - height;

This worked like a charm, the only problem is when the room scrolls, the character slightly move to the right for a second and after back to the correct position.
I don't know why. But is not important now that I don't will use this.

You have to put this code in function "late_repeatedly_execute_always" - this script callback is called after game update but before game drawing. "repeatedly_execute" and "repeatedly_execute_always" are called before game update and logicaly are 1 update behind.



Quote from: Deabriel on Tue 12/05/2020 03:16:54
I only have two questions, now that I use the bigger resolution, the only problem that I found is that the speech in zoomed room is drawn over the character:

(I tested the zoom camera in a normal low-resolution game and the speech is also drawn over the character)

I must test this myself, but this may be an oversight in the engine, in which case another 3.5.0 patch is due.


Quote from: Deabriel on Tue 12/05/2020 03:16:54
The other question is more like a curiosity. It's possible to make the camera only scroll when the character walk close/near to the sides of the window?

Absolutely, but you will have to script this behavior yourself, detecting when player approaches a threshold and setting new camera position in script.
There was a module that is doing similar thing, you may use it directly or for scripting reference: https://www.adventuregamestudio.co.uk/forums/index.php?topic=57489.0

Deabriel

Quote from: Crimson Wizard on Tue 12/05/2020 11:19:28
You have to put this code in function "late_repeatedly_execute_always" - this script callback is called after game update but before game drawing. "repeatedly_execute" and "repeatedly_execute_always" are called before game update and logicaly are 1 update behind.
I already put that code in the late_repeatedly_execute_always (but I put it in the goblal script, I found that there have the repeatedly_exectute and repeatedly_execute_always but not the late_repeatedly_execute_always so I added by myself, I don't know if that's why don't work right)

Quote from: Crimson Wizard on Tue 12/05/2020 11:19:28
I must test this myself, but this may be an oversight in the engine, in which case another 3.5.0 patch is due.
Oh, I see. Were you able to test it? I was planning to "fix it" using the say at, but if it will be fixed in the next patch I will use the normal say code and wait for the patch

Quote from: Crimson Wizard on Tue 12/05/2020 11:19:28
Absolutely, but you will have to script this behavior yourself, detecting when player approaches a threshold and setting new camera position in script.
There was a module that is doing similar thing, you may use it directly or for scripting reference: https://www.adventuregamestudio.co.uk/forums/index.php?topic=57489.0
Ooh thank you, I will test it or take it for reference to make my own.

Crimson Wizard

There's a temp build containing fixes speech position: https://cirrus-ci.com/task/4504037129191424
(may be downloaded as an archive or installer)

SMF spam blocked by CleanTalk