The subject says it all:
Can I replace the sprite in a sprite slot with a dynamic sprite on the fly?
What I'm trying to do:
- Take sprite from slot X, create new dynamic sprite from that sprite.
- Rotate and fuss about with the sprite
- Save the sprite so that the player's current sprite (has only 1 sprite) is overwritten
Can this be done, or do I need to go for some kind of sorcery?
You can't overwrite sprite slots afaik, but you can change the frames in a view.
ViewFrame*vf = Game.GetViewFrame(player.NormalView, player.Loop, 0);
vf.Graphic = dyn_sprite.Graphic;
This changes the frame's sprite slot permanently.
I get a seemingly uninformative exeption error and a crash now. :D
My guess is I still need to do something to prep the dynamic sprite, but so far no idea. Will keep reading the manual, but since the thread is already started...
Below is some code with one specific line commented to clarify situation.
DynamicSprite* Dsprite = DynamicSprite.CreateFromExistingSprite(9, true);
if (rotateangle > 359) {
rotateangle = rotateangle - 359;
}
Dsprite.Rotate(rotateangle, 50, 50);
ViewFrame*vf = Game.GetViewFrame(player.NormalView, player.Loop, 0);
vf.Graphic = Dsprite.Graphic; // <--- THIS LINE CRASHES THE GAME, IF COMMENTED OUT, NO CRASH
Dsprite.Delete();
Viewframes start at 1 i think, not 0
No, they start at 0.
Why do I have the feeling I can't edit the viewframe while it is being displayed?
It shouldn't matter whether the frame is currently displayed; you're simply changing AGS's internal "database", a view is just a collection of numbers after all, and when the screen is redrawn at the end of the loop, the new sprite slot is used.
However, you can't declare the DynamicSprite inside the function; if you do that, it's a local variable and will get destroyed at the end of the function, including the sprite data.
Well that should have been obvious even to me...
Changed the dynamicsprite into a global one, no more crashing. :)
EDIT: Nevermind, still crashing like a pro. Here is the entire function, which I have tried running (agains manual instruction) in repeatedly execute, as well as on keypress, both with same results. The players view only has 1 frame to it.
---------------------------
Illegal exception
---------------------------
An exception 0xC0000005 occurred in ACWIN.EXE at EIP = 0x004140CC ; program pointer is +3330, ACI version 3.21.1115, gtags (0,150)
AGS cannot continue, this exception was fatal. Please note down the numbers above, remember what you were doing at the time and post the details on the AGS Technical Forum.
function RotateChar() {
Dsprite = DynamicSprite.CreateFromExistingSprite(9, true);
while (rotateangle > 359) {
rotateangle = rotateangle - 359;
}
Dsprite.Rotate(rotateangle, 50, 50);
ViewFrame *vf = Game.GetViewFrame(player.NormalView, player.Loop, 0);
vf.Graphic = Dsprite.Graphic;
rotateangle += FloatToInt(Gspeed / 20.0, eRoundNearest);
Dsprite.Delete();
}
EDIT 2: Been fiddling for a while now, I have no idea whatsoever why that crash is happening.
If I assign the rotated sprite to a different loop (created for that purpose), no crash. The above code works just well, but when I later set the player character to use that loop, same crash.
Just for the hell of it, try adding at least one frame to the other three loops (so that player.NormalView has at least one frame in each of its first four loops).
Done, no change in situation.
I am already pondering on the amount of work involved in having 180 or-so sprites of the character, and then spinning it by animating the loop(s). :D
What I mean to say is: HALP!
vf.Graphic = Dsprite.Graphic;
Dsprite.Delete();
Does this not occur to anyone else as being problematic?
Yes, excuse me AGS, could you display on-screen that sprite that I just told you to blow up? kthx
Sure, it did (http://www.adventuregamestudio.co.uk/forums/index.php?topic=46743.msg628842#msg628842). :)
The problem is, with that issue out of the way, why is AGS still crashing.
It's the dreaded "exception 0xC0000005"; maybe somebody who's familiar with the source can take a look (EIP = 0x004140CC)?
No, I did see where you pointed that out, but when WHAM responded to you, and included what is presumably the latest code snippet, it would appear that he is still deleting the sprite:
Quote from: WHAM on Tue 04/09/2012 20:35:30Changed the dynamicsprite into a global one, no more crashing. :)
EDIT: Nevermind, still crashing like a pro. Here is the entire function...
function RotateChar() {
Dsprite = DynamicSprite.CreateFromExistingSprite(9, true); // DynamicSprite* is defined globally...
// ...
ViewFrame *vf = Game.GetViewFrame(player.NormalView, player.Loop, 0);
vf.Graphic = Dsprite.Graphic; // assign dynamic sprite into view frame, to be drawn on the next game loop
// ...
Dsprite.Delete(); // delete the sprite we just asked to have drawn, even though it's still in use
}
Quote from: Khris on Wed 05/09/2012 02:52:37The problem is, with that issue out of the way...
The code that WHAM has posted still suggests that "that issue" is very much
not "out of the way". If that code was just outdated and he did already remove that line (or rather, do the
correct thing and check if the pointer is null at the beginning of the function, if it's not, assign 0 to the view frame and delete the sprite), then it warrants further investigation. Still looks like a user programming error to me (despite the lack of a meaningful error message).
Sorry, you're right of course, I didn't even check the amended code. And I missed what your post was actually about to boot. Guess I should have rather gone to bed hours ago like I had planned and not roam around here while being severely sleep-deprived :-D
Aye, mr Monkey was righ about that one.
I forgot to remove the delete line from the end after making the dynamicsprite global.
No more crashy-crashy, and the code works like a charm now. :)
Sorry to bother, just a small note FYI.
Quote from: Khris on Wed 05/09/2012 02:52:37
It's the dreaded "exception 0xC0000005"; maybe somebody who's familiar with the source can take a look (EIP = 0x004140CC)?
In the engine crash message the "program pointer" and "gtags" are more useful, these values are AGS debug helpers, they are being set throughout the code. Specifically program pointer = 3330 is pointing at this section of code:
Spoiler
coldept = bitmap_color_depth(spriteset[sppic]);
// adjust the sppic if mirrored, so it doesn't accidentally
// cache the mirrored frame as the real one
if (views[chin->view].loops[chin->loop].frames[chin->frame].flags & VFLG_FLIPSPRITE) {
isMirrored = 1;
specialpic = -sppic;
}
Well, the issue was resolved without all this info, telling just in case.
A crash like that is clearly a bug though. AGS should crash much more gracefully with regards to a missing sprite.