Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: Knox on Tue 10/08/2010 22:04:01

Title: Drawing on cursors, but restoring the old version after **SOLVED**
Post by: Knox on Tue 10/08/2010 22:04:01
Hi guys,

I was able to use Calin's AGS Blend plugin to blend 2 alpha sprites together to make a "resume" cursor when my mouse hovers over the resume button in my inventory...it uses the item's cursor sprite and combines it with an arrow + resume text so the player knows he can resume with that item.

Everything is fine up until I try to restore the item's "normal" cursor sprite...so when the mouse cursor is no longer hovering over the resume button, I would like it to "revert" back to the item's normal cursor without the drawn "resume arrow" over it.

Im guessing I need to somehow store the item's cursor image somewhere? Does this mean I need to store copies of all my different item's cursors? (That would suck)...

Im using Calin's plugin so I dont have  to make new "resume" cursors for all the game's inventory items.

Im not too sure how to proceed  :-[
Title: Re: Drawing on cursors, but restoring the old version after
Post by: Khris on Wed 11/08/2010 01:50:44
I'm guessing you've imported the standard cursor images as sprites; all you'd need to do is populate a dynamic array (size: Game.InventoryItemCount) with the slots of the cursor images.

To revert to default, call player.ActiveInventory.CursorGraphic = def_curs[player.ActiveInventory.ID];

I don't know how the plugin works or what you're using to change the cursor image though, so I can merely guess whether this will work.
Title: Re: Drawing on cursors, but restoring the old version after
Post by: Knox on Thu 12/08/2010 14:22:27
Hey Khris!

Ok, Ill try that out sometime today and let you know what happens!
Title: Re: Drawing on cursors, but restoring the old version after
Post by: Knox on Thu 12/08/2010 20:49:26
Ok, well I went another route since I think it has the potental of being easier...although I ran into a problem and Ive tried for quite a while now to fix it:

1) What I decided to do is when I select an item, its cursor graphic gets drawn into temp sprite 132:

  if (mouse.Mode == eModeSelectInv || mouse.Mode == eModeUseinv) //save the "Resume with Item" cursor graphic to a variable
  {
    //clear sprite 132 so it can be drawn to
    clearThisSprite(iBufferItem132);
   
    //draw default cursor onto empty sprite 132, save it temporarily   
    DrawAlpha(iBufferItem132.Graphic, overItem.CursorGraphic, 0, 0, 0);
    bDrawn = false;
  }


2) In rep exec, if the mouse is over my "resume" button in the inv menu, drawResumeItemCursor gets called:

void clearThisSprite(InventoryItem *Buffer)
{
  DrawAlpha(Buffer.Graphic, 1827, 0, 0, 0);
 
  //clearSprite = DynamicSprite.CreateFromExistingSprite(Buffer.Graphic);
  //DrawingSurface *surface = clearSprite.GetDrawingSurface();
  //surface.Clear();
  //Buffer.Graphic = clearSprite.Graphic;
  //surface.Release(); 
}
 
void drawResumeItemCursor()
{
  clearThisSprite(iBufferItem133);

  //draw 132 default item image onto empty sprite 133
  DrawAlpha(iBufferItem133.Graphic, 132, 0, 0, 0); 

  //draw Resume Arrow over the item's cursor into sprite 133
  DrawAlpha(iBufferItem133.Graphic, 1826, 0, 0, 0);

  mouse.ChangeModeGraphic(eModePointer, iBufferItem133.Graphic);
  mouse.ChangeModeHotspot(eModePointer, 65, 34);


Anyways, it works fine if the sprite image in "clearThisSprite" is opaque (1827)...Of course I dont want that...If I make sprite 1827 a fully transparent png, it wont really "replace" the other sprite with itself, it just draws "nothing" over it...

How can I "clear" a sprite to nothing?

ps: I checked the "clear" command in the manual and tried it but it doesnt seem to work in this case(dynamic sprites not existing):


void clearThisSprite(InventoryItem *Buffer)
{
  //DrawAlpha(Buffer.Graphic, 1827, 0, 0, 0);
 
  clearSprite = DynamicSprite.CreateFromExistingSprite(Buffer.Graphic);
  DrawingSurface *surface = clearSprite.GetDrawingSurface();
  surface.Clear();
  Buffer.Graphic = clearSprite.Graphic;
  surface.Release(); 
}


Im really not sure how to proceed here!
Title: Re: Drawing on cursors, but restoring the old version after
Post by: Khris on Thu 12/08/2010 23:26:40
Do you get an error message?
What's the exact wording and which line does it refer to?
Title: Re: Drawing on cursors, but restoring the old version after
Post by: Knox on Fri 13/08/2010 00:29:31
Ok, if I use the first solution for "void clearThisSprite": (DrawAlpha(Buffer.CursorGraphic, 1827, 0, 0, 0);)I get 99% of what I want, except of course the opaque background of sprite 1827.

Now, if on the other hand I use the other solution for "void clearThisSprite":

 clearSprite = DynamicSprite.CreateFromExistingSprite(Buffer.Graphic);
 DrawingSurface *surface = clearSprite.GetDrawingSurface();
 surface.Clear();
 Buffer.Graphic = clearSprite.Graphic;
 surface.Release();


...this is where I get errors...First of all, the pointer's cursor becomes the arrow image over an invisible background (doesnt show the arrow over the item's cursor, just the arrow)...and secondly, when I go back into the inventory window with that "only the arrow" cursor, and I try clicking on another item, I get an error like this:

Error: DynamicSprite.CreateFromExistingSprite: sprite 1834 does not exist


**EDIT**
ps: The error pop-up box didnt give me any lines, its one of those internal errors (not the kind that gives an error message in the ouput window).

**EDIT**
Ok, well I got it to work finally, the way I wanted...the only thing is, the result of the blended sprites is much nicer if instead of clearing the sprite to be drawn on, I put an opaque sprite and then draw my alpha arrow over it...if the sprite being drawn to is fully transparent, the result of the combination with DrawAlpha seems to be a bit "blocky"....as in, the gradient shadows arent smooth, but just black, and blotchy/blocky.

Here is what I did:


void clearThisSprite(InventoryItem *Buffer)
{
 //DrawAlpha(Buffer.CursorGraphic, 1827, 0, 0, 0);

 clearSprite = DynamicSprite.CreateFromExistingSprite(Buffer.CursorGraphic);
 DrawingSurface *surface = clearSprite.GetDrawingSurface();
 surface.Clear();
 Buffer.CursorGraphic = clearSprite.Graphic;
 surface.Release();
}
 
void drawResumeItemCursor()
{
 clearThisSprite(iBufferItem132);
 DrawAlpha(iBufferItem132.CursorGraphic, player.ActiveInventory.CursorGraphic, 0, 0, 0);

 //draw Resume Arrow over the item's cursor into sprite iBufferItem132.CursorGraphic
 DrawAlpha(iBufferItem132.CursorGraphic, 1826, 0, 0, 0);
 mouse.ChangeModeGraphic(eModePointer, iBufferItem132.CursorGraphic);
 mouse.ChangeModeHotspot(eModePointer, 65, 34);
}  



Arrow drawn onto a transparent sprite (with the "clear" function):

(http://www.2dadventure.com/ags/blocky.PNG)

Arrow drawn on an opaque sprite:

(http://www.2dadventure.com/ags/smooth.png)


All that is left to figure out is why is the combined sprite nicer when the background is opaque...and then trying to fix that!
Title: Re: Drawing on cursors, but restoring the old version after
Post by: Khris on Fri 13/08/2010 02:00:52
Alright, let's start over.
This seems to be getting way to complicated otherwise.

All we need to do is assign a DynamicSprite to the UseInv cursor.
When the mouse moves over the button, redraw the sprite using .CursorGraphic & resume sprite.
When the mouse leaves the button, redraw sprite using .CursorGraphic.

DynamicSprite*inv_curs;

bool mouse_was_over_resume = true;  // force sprite initialization

void RedrawInvCursor(bool resume) {

  int cg = player.ActiveInventory.CursorGraphic;

  // init DynamicSprite (once, when an inv item is selected for the first time)
  if (inv_curs == null) {
    inv_curs = DynamicSprite.CreateFromExistingSprite(cg, true);   // create sprite
    mouse.ChangeModeGraphic(eModeUseinv, inv_curs.Graphic);  // assign sprite to mouse mode
  }
  else inv_curs.Resize(Game.SpriteWidth[cg], Game.SpriteHeight[cg]);   // remove if all inv cursor sprites are of same size

  // clear it
  DrawingSurface*ds = inv_curs.GetDrawingSurface();
  ds.Clear(Game.GetColorFromRGB(255, 0, 255));   // clear with magic pink i.e. make it transparent
  ds.Release();

  // redraw it
  DrawAlpha(inv_curs.Graphic, cg, 0, 0, 0);
  if (resume) DrawAlpha(inv_curs.Graphic, 1826, 0, 0, 0);
}

// rep_ex_always

  GUIControl*gc = GUIControl.GetAtScreenXY(mouse.x, mouse.y);
  Button*b;
  if (mouse.Mode == eModeUseinv && gc != null) {
    b = gc.AsInt;
    if (b == bResume && !mouse_was_over_resume) {
      mouse_was_over_resume = true;
      RedrawInvCursor(true);
    }
    else if (b != bResume && mouse_was_over_resume) {
      mouse_was_over_resume = false;
      RedrawInvCursor(false);
    }
  }


(The code assumes that the button's script name is "bResume".
NOT TESTED.)

The "trick" is never to delete the sprite that's used by the cursor. It is just redrawn as necessary.
Title: Re: Drawing on cursors, but restoring the old version after
Post by: Knox on Fri 13/08/2010 04:07:02
Well Holy CRAP, this works SUPER nicely...now the newly drawn cursors have perfect alpha blending!

This will save me from having to draw many cursor sprites individually...like close to a hundred, serious :P

You made my day,

Thanks Khris!!
Title: Re: Drawing on cursors, but restoring the old version after **SOLVED**
Post by: Khris on Fri 13/08/2010 10:45:32
Great, glad it finally worked!

Don't thank me, thank the magic pink ;)