The problem may be in a calling function; check the call stack [Semi-Solved]

Started by Knox, Wed 21/11/2012 17:41:57

Previous topic - Next topic

Knox

I get this error "Script appears to be hung (a while loop ran 150001 times). The problem may be in a calling function; check the call stack."when I try to run the code below:

Code: ags

  while (iY1 < dsSourceGraphic.Height) //768
  {
    while (iX1 < sSourceGraphic.Width) //1024
    {
      //iAlpha = GetAlpha(dsLongGrass.Graphic, iY1, iX1);
      //ds.DrawingColor = Game.GetColorFromRGB(iAlpha,iAlpha,iAlpha); //this is a grey color representing the alpha.
      //ds.DrawPixel(iX1,iY1); // draw the alpha to the copy.
      iX1++;
    }
    iY1++;
    iX1 = 0;
  }


I've been using that "while snippet" throughout my game, but it only works when the dynamic sprite "dsSourceGraphic" is square (70x70, for example). How do I get it to work with a rectangle? (1024x768)

Its being used to go through the dynamic sprite's pixels to copy the alpha channel.
--All that is necessary for evil to triumph is for good men to do nothing.

DoorKnobHandle

You put dsSourceGraphic.Height but sSourceGraphic.Width, so maybe it's referencing a different, much larger sprite? That's off the top of my head, just looking at the code for a sec as I'm strapped for time, but maybe that's it!

Crimson Wizard

768 * 1024 = 786432

And that is larger than 150001, is it.

Thing is, that AGS counts consecutive loops as one loop. That is because it is not loop iterations on their own that matters, but the time that it takes to make one pass in script and return back to engine. Engine wants to be sure that it does not hang, making game to halt completely.
Add "noloopcheck" keyword to the function declaration:
Code: ags

function noloopcheck function_name

Knox

@DKH: Oups, I made a typo while transcribing it to the forums, thanks for catching that :)

@Crimson Wizard: Wow, cool! Didnt know that. It definitely fixed the error problem, although I now have a new problem related to the AGSBlend plugin...plus its way too slow processing the whole screen pixel by pixel for what I want it to do...I believe I need to rethink this :)

Im gonna try to debug that part, but might post a follow-up question if I cant figure it out.

Thanks for your help guys!
--All that is necessary for evil to triumph is for good men to do nothing.

Crimson Wizard

Quote from: General_Knox on Thu 22/11/2012 02:29:14
I now have a new problem related to the AGSBlend plugin...plus its way too slow processing the whole screen pixel by pixel for what I want it to do...
Yes, I was going to mention this, such pixel by pixel processing is really slow if done in script.
That's what plugins are for. You may make one on your own and put all tough drawing there.

Knox

Crap, I know I can't program my own plugin, so I'll have to figure out another solution for this I think. I'm thinking maybe make the surface area for the "cut grass mini-game"  alot smaller than 1024x768.

I wish there was an easier/faster way to "paint" onto a sprite's alpha channel, using another sprite as the "brush" shape. I got it to work fine with the DrawLine though. Too bad I can't use "magic pink" with the DrawAlpha() function...it just draws to the RGB. DOh!

--All that is necessary for evil to triumph is for good men to do nothing.


Knox

Hehe...well maybe I will if I cant figure something out!

Ill even pay him if he wants...but guys keep refusing here! :)
--All that is necessary for evil to triumph is for good men to do nothing.

Knox

Hey guys!

I found a solution for another problem I was fixing at the same time, and I think I can use that solution for this one (cutting the grass effect):

I wrote some scripts to enable shadows in multiply mode on the tractor (which I will re-use for the player character and driving module, yay). I can post them if anyone wants it.

I realized drawing all this stuff to a large 1024x768 sprite every loop is way too heavy + slow, so I divided up the "grass area" into 6 pieces of 340x340 each on its own object. Then I wrote a script that detects what zone (object) the tractor is in/over. If the tractor is in 4 zones (over 4 objects) at once (maximum), then redraw the shadow for those zones...obviously if the tractor is over just 1 zone, then that's when the script works the fastest.

For a non-programmer like me, man it feels good to get something like this to work, hehe! Very rewarding. Took me a whole freakin 3 days to figure it out, I bet Monkey/Khris/Wizard and the like would have taken 5 min.

Here is a video of the results, which now I will try to apply the same thing to "cutting the grass away"

View My Video

Almost there!! :)
--All that is necessary for evil to triumph is for good men to do nothing.

Crimson Wizard

Umm, can you elaborate, you mean you are redrawing the whole screen (or quarter of the screen) only to place that vehicle's shadow over? Am I missing something?

Knox

No, before I was doing that and getting 30fps drops!! Thats why now I decided to divide the screen into 6 zones of 340x340 objects. I just redraw the graphic of whatever object the tractor is currently over with the shadow in multiply mode.

Is there a even better way? Right now with this solution Im only  getting a 5-10fps drop, so it seems much more efficient than before!
--All that is necessary for evil to triumph is for good men to do nothing.

Crimson Wizard

Usually, when there's a sprite moving around the screen and you do not want to redraw whole screen, there's this solution: remember previous coordinates of the tractor, and after it moves redraw only that small background piece, which was covered by tractor prior to movement. Then draw the tractor with shadow on a new place.

Basic algorythm is this:
1. Create a "buffer" sprite at the start of the game (or room).
2. Copy a part of background behind the tractor in its initial position on that buffer sprite, and draw the shadow.
Game loop:
3. Do not redraw if the tractor did not move.
4. If tractor moved,
4a. use buffer to redraw a small strip, which is a difference from position previously covered by tractor and not covered now,
4b. copy new part of background (behind new tractor position) to the buffer
4c. draw shadow on a new place.
Repeat.

E: hmm, actually, since it sounds like you have the background stored somewhere anyway, you may skip the buffer part.

Calin Leafshade

What kind of spec is your PC? Per pixel calculation on the CPU is *very* slow and you need to be sure that your game will actually run on normal hardware.

Knox

@Calin:
Specs:
HP Workstation z400 Zeon W3530 2.8GHz
12 GB of RAM
NVIDIA GeForce GTX 560HP
I'm really trying to make "heavy" features toggable in the game settings, like turning off shadows, certain effects, etc...I really dont want to exclude low end/normal machines!!

@Wizard:
I've got a check that if the (!player.IsMoving), I dont redraw. I'm pretty sure Im already doing steps 1 to 4, but instead of drawing the shadow on the background, I draw the shadow to the object's graphic because Im guessing drawing the a smaller sprite 340x340 is better/fster than redrawing to the whole screen (?) Perhaps I dont understand something so forgive my ignorance!

Here is my code (without the global variables, small functions here and there, etc):

Code: ags

function room_RepExec()
{
  if (bMoving) player.GetZones();
  cShadow.Loop = player.Loop;
  
  if (bShadowInitialize && !(player.Moving))
  {
    //in the game settings you can turn shadows on/off, when set to on, query the zone the player is over
    if (bActivate_ZoneA) cShadow.ShadowInitialize(oLongGrass_A, 1);
    if (bActivate_ZoneB) cShadow.ShadowInitialize(oLongGrass_B, 2);
    if (bActivate_ZoneC) cShadow.ShadowInitialize(oLongGrass_C, 3);
    if (bActivate_ZoneD) cShadow.ShadowInitialize(oLongGrass_D, 4);
    if (bActivate_ZoneE) cShadow.ShadowInitialize(oLongGrass_E, 5);
    if (bActivate_ZoneF) cShadow.ShadowInitialize(oLongGrass_F, 6);
  }
  if (player == cTractor && player.Moving)
  {
    if (!bMoving) bMoving = true;
    iLoop = player.GetCharacterDirection(); //get the direction so we can adjust the mower's cutting width
    if (bShowShadow && !bShadowOff)
    {
      if (bActivate_ZoneA) oLongGrass_A.DrawOnShadowReceiver(4769, 1);
      if (bActivate_ZoneB) oLongGrass_B.DrawOnShadowReceiver(4779, 2);
      if (bActivate_ZoneC) oLongGrass_C.DrawOnShadowReceiver(4780, 3);
      if (bActivate_ZoneD) oLongGrass_D.DrawOnShadowReceiver(4781, 4);
      if (bActivate_ZoneE) oLongGrass_E.DrawOnShadowReceiver(4782, 5);
      if (bActivate_ZoneF) oLongGrass_F.DrawOnShadowReceiver(4783, 6);
    }
  }
  
  if (!bShowShadow) 
  {
      if (bShadowOff && player.Moving)
      {
        if (bActivate_ZoneA) oLongGrass_A.ClearShadowReceiver(4769);
        if (bActivate_ZoneB) oLongGrass_B.ClearShadowReceiver(4779);
        if (bActivate_ZoneC) oLongGrass_C.ClearShadowReceiver(4780);
        if (bActivate_ZoneD) oLongGrass_D.ClearShadowReceiver(4781);
        if (bActivate_ZoneE) oLongGrass_E.ClearShadowReceiver(4782);
        if (bActivate_ZoneF) oLongGrass_F.ClearShadowReceiver(4783);
      }
  } 

void ShowShadow(this Character*, Object* onWhat, int iZone)
{
  if (bShowShadow == true)
  {

    cShadow.Loop = player.Loop;
    //first clear any shadows on surface by reverting back to original object surface's sprite...in room script

    dsSource = DynamicSprite.CreateFromExistingSprite(onWhat.Graphic, true);
    if (iZone == 1) dsApplyShadow_A = DynamicSprite.CreateFromExistingSprite(onWhat.Graphic, true);
    else if (iZone == 2) dsApplyShadow_B = DynamicSprite.CreateFromExistingSprite(onWhat.Graphic, true);
    else if (iZone == 3) dsApplyShadow_C = DynamicSprite.CreateFromExistingSprite(onWhat.Graphic, true);
    else if (iZone == 4) dsApplyShadow_D = DynamicSprite.CreateFromExistingSprite(onWhat.Graphic, true);
    else if (iZone == 5) dsApplyShadow_E = DynamicSprite.CreateFromExistingSprite(onWhat.Graphic, true);
    else if (iZone == 6) dsApplyShadow_F = DynamicSprite.CreateFromExistingSprite(onWhat.Graphic, true);
    
    player.GetShadowSprite();

    iShadowSpriteBkp = iShadowSprite;
    
    iShadowAreaW = Game.SpriteWidth[iShadowSprite];
    iShadowAreaH = Game.SpriteHeight[iShadowSprite];
    
    getZoneAdjustment(iZone);
    
    int iX = this.x - (iShadowAreaW/2) + iXzoneAdjust; //substract the length of the sprite + ifactor
    int iY = this.y - (iShadowAreaH/2) + iYzoneAdjust + iYadjust;
    
    if (iZone == 1) DrawSprite(dsApplyShadow_A.Graphic, iShadowSprite, iX, iY, eBlendMultiply, 0); //draw shadow on top 
    else if (iZone == 2) DrawSprite(dsApplyShadow_B.Graphic, iShadowSprite, iX, iY, eBlendMultiply, 0); //draw shadow on top 
    else if (iZone == 3) DrawSprite(dsApplyShadow_C.Graphic, iShadowSprite, iX, iY, eBlendMultiply, 0); //draw shadow on top 
    else if (iZone == 4) DrawSprite(dsApplyShadow_D.Graphic, iShadowSprite, iX, iY, eBlendMultiply, 0); //draw shadow on top 
    else if (iZone == 5) DrawSprite(dsApplyShadow_E.Graphic, iShadowSprite, iX, iY, eBlendMultiply, 0); //draw shadow on top 
    else if (iZone == 6) DrawSprite(dsApplyShadow_F.Graphic, iShadowSprite, iX, iY, eBlendMultiply, 0); //draw shadow on top 
    
    if (iZone == 1) onWhat.Graphic = dsApplyShadow_A.Graphic;
    else if (iZone == 2) onWhat.Graphic = dsApplyShadow_B.Graphic;
    else if (iZone == 3) onWhat.Graphic = dsApplyShadow_C.Graphic;
    else if (iZone == 4) onWhat.Graphic = dsApplyShadow_D.Graphic;
    else if (iZone == 5) onWhat.Graphic = dsApplyShadow_E.Graphic;
    else if (iZone == 6) onWhat.Graphic = dsApplyShadow_F.Graphic;
    iShadowSprite = iShadowSpriteBkp;
  }
}

--All that is necessary for evil to triumph is for good men to do nothing.

Crimson Wizard

Quote from: General_Knox on Mon 26/11/2012 16:20:32
@Wizard:
I've got a check that if the (!player.IsMoving), I dont redraw. I'm pretty sure Im already doing steps 1 to 4, but instead of drawing the shadow on the background, I draw the shadow to the object's graphic
That does not matter, by saying "background" I meant anything beyond. Sorry for any confusion.

Quote from: General_Knox on Mon 26/11/2012 16:20:32
because Im guessing drawing the a smaller sprite 340x340 is better/fster than redrawing to the whole screen
Ofcourse it is, but redrawing an even smaller piece of about tractor's size is even faster.
What I mean is, you may have only 1 object for all room (this object represents long grass, right?) and don't redraw all of it, but redraw only small piece at previous tractor's position.

[imgzoom]http://img28.imageshack.us/img28/3843/tractork.png[/imgzoom]

You copy the object's graphic piece beyond the tractor.
When tractor moves you:
1. Paste stored graphic into zone 1.
2. Copy object's graphic piece from zone 2.
3. Draw shadow over zone 2.
And repeat.

Knox

Oooohhhh!! Ah ok now I see :)

Wow, yeah, thats even better! Ok, gonna try that out now.
Thanks!
--All that is necessary for evil to triumph is for good men to do nothing.

SMF spam blocked by CleanTalk