(SOLVED) surface.DrawImage able to be detected? (player drops item)

Started by Vault15, Fri 26/10/2012 11:32:27

Previous topic - Next topic

Vault15

This is the code that makes my character "drop" their grabbed inventory item onto the ground 10 pixels below (removed from inventory, then drawn smaller).

Code: AGS

if(GUIControl.GetAtScreenXY(mouse.x, mouse.y) == DropItem && Mouse.Mode == eModeUseinv)
  {
     if(cEgo.Room == 1 && dropmap1x1 == -5000)
     {
       dropmap1x1 = XTarget;
       dropmap1y1 = YTarget + 10;
     }
     
     Citem1 = player.ActiveInventory.Graphic;
     DrawingSurface *surface = Room.GetDrawingSurfaceForBackground();
     surface.DrawImage(dropmap1x1 - GetViewportX(), dropmap1y1, Citem1, 0, 35, 25);
     surface.Release();
     player.LoseInventory(player.ActiveInventory);
     gInventory.Visible = false;
     gInventory2.Visible = false;
     gInventory3.Visible = false;
    
  }


I can't figure out how to detect the sprite drawn to re-equip the item again. I know there's a way. Yes, I realize the main method people use is creating a character per item that is stored on the map. I wanted to try this way. Here is the code I'm using that doesn't work. The script never activates to pick up the item. I'm not sure if my coordinates system is all screwy.

Code: AGS

if(Mouse.Mode == eModeInteract && mouse.x == dropmap1x1 && mouse.y == dropmap1y1)
  {
    
    
    
    gInventory.Visible = true;
    gInventory2.Visible = true;
    gInventory3.Visible = true;
    cEgo.ActiveInventory = iSMG;
    DrawingSurface *surface = Room.GetDrawingSurfaceForBackground();
    surface.DrawImage(dropmap1x1, dropmap1y1, 164, 0, 35, 25);
    surface.Release();
  }



Note: Without moving my character it reads as:
player coordinates: 1502,265
item dropped at: 1502,275
viewport: 495,0

I tried to make it where the coordinates of the sprite drawn were saved so that if you position the mouse back over those coordinates then the mouse will change so that you can grab at the sprite, which would then kick in the script to write over that item (with a blank, transparent surface aka: sprite 164) and then add that stored item. I'm starting to see why people just go with the character as inventory item option. Am I crazy or is this method possible?

Crimson Wizard

#1
Is there just any rational reason you want to make it that way?
You are basically on a path to invent a new class of room objects, that you have to manually process: store data in memory, (re)draw, detect interaction, etc, while there is already a solution which makes engine do that.

By the way, did you know that:
Quote from: AGS manual
GetDrawingSurfaceForBackground
<...>
Any changes you make will only last until the player leaves the room, at which point they will be lost.

Vault15

Quote from: Crimson Wizard on Fri 26/10/2012 11:47:46
Is there just any rational reason you want to make it that way?
You are basically on a path to invent a new class of room objects, that you have to manually process: store data in memory, (re)draw, detect interaction, etc, while there is already a solution which makes engine do that.

By the way, did you know that:
Quote from: AGS manual
GetDrawingSurfaceForBackground
<...>
Any changes you make will only last until the player leaves the room, at which point they will be lost.

Well, I can sortof see what you're saying, but I feel like it's a bit simpler than that. Bear with me if I sound like a moron, but all I'm doing is saving coordinates. Let's say I drop an item at (200,400) and it's just a drawing of the gun. I can then walk around the map, go to another map, come back to map1 and all items can be redrawn at their coordinates (stored in dropmap1x1,dropmap1y1 then dropmap1x2,dropmap1y2, up to a max of 10 items dropped per map).

I just can't, for the life of me, get the mouse to detect those coordinates stored in (dropmap1x1,dropmap1y1) to where the item was drawn. I walk up to the little gun drawn on the ground with the interact hand and it just won't detect the coordinates. Is it too exact since it's 1 pixel on the screen?

The reason why I resorted to this is because I couldn't figure out the RoomInv Module. I'll give that a try again.
http://www.adventuregamestudio.co.uk/yabb/index.php?topic=28770.0

Crimson Wizard

Quote from: Vault15 on Fri 26/10/2012 12:00:41
I just can't, for the life of me, get the mouse to detect those coordinates stored in (dropmap1x1,dropmap1y1) to where the item was drawn. I walk up to the little gun drawn on the ground with the interact hand and it just won't detect the coordinates. Is it too exact since it's 1 pixel on the screen?
I'd say it is not a good idea to store only one pixel. Try to store a rectangle bounds instead; you may get Graphic metrics by using Game.SpriteHeight[index] and Game.SpriteWidth[index].

More, you are making the mistake when you try to erase your sprite with transparent rectangle. Drawing transparent rect over image will result in nothing.
If you want to do this properly, you should copy and store an underlying piece of background and redraw that on same coordinates.

Vault15




Thanks for your help. I'll probably need help with the RoomInv Module so I'm sure I will post a new topic if I scrap this idea completely. Either that or just have chests/shelves in each map (set as characters) that you can store items in. It would be the easy way out  :)

Vault15

Quote from: Crimson Wizard on Fri 26/10/2012 12:04:34
I'd say it is not a good idea to store only one pixel. Try to store a rectangle bounds instead; you may get Graphic metrics by using Game.SpriteHeight[index] and Game.SpriteWidth[index].

More, you are making the mistake when you try to erase your sprite with transparent rectangle. Drawing transparent rect over image will result in nothing.
If you want to do this properly, you should copy and store an underlying piece of background and redraw that on same coordinates.

I managed to get it to work with this, but it still doesn't solve converting the stored graphic ID into the inventory item ID. I laughed when this horrible code worked. Note: I didn't implement the erase drawn image fix you mentioned yet.
Code: AGS

if(Mouse.Mode == eModeInteract && mouse.x == dropmap1x1 || mouse.x == dropmap1x1+1
  || mouse.x == dropmap1x1+2 || mouse.x == dropmap1x1+3 
  || mouse.x == dropmap1x1+4 && mouse.y == dropmap1y1+1 ||
  mouse.y == dropmap1y1+2 || mouse.y == dropmap1y1+3 || mouse.y == dropmap1y1+4 && dropmap1x1 != -5000 && gInventory.Visible == false
  && gInventory2.Visible == false && gInventory3.Visible == false)
  {
    
    
    
    
    cEgo.AddInventory(iSMG);
    
    DrawingSurface *surface = Room.GetDrawingSurfaceForBackground();
    surface.DrawImage(dropmap1x1, dropmap1y1, 164, 0, 35, 25);
    
    surface.Release();
    
    gInventory.Visible = true;
    gInventory2.Visible = true;
    gInventory3.Visible = true;
  }

Khris

Regardless of the method, this:
surface.DrawImage(dropmap1x1 - GetViewportX(), ...
shouldn't work.
You subtract GetViewportX() when you want to get from a room coordinate to a screen coordinate, but surface is the room's background surface and thus wider than the screen, ie. drawing to it is done using room coordinates.

Also keep in mind that as opposed to using Characters, drawing dropped items to the background makes them ignore scaling, lighting, walkbehinds and other characters and objects.

As far as I understand, the player clicks a GUIControl while holding an item, and it is dropped to the ground in front of the player, right?

Edit:
No, this code doesn't work.
First of all you need to use brackets to group the conditions, and furthermore, testing for the coordinates like that, apart from being a horrible way of doing it, won't produce a rectangle but a "cross".
You need to use:
Code: ags
  bool inside = (mouse.x >= dropmap1x1 && mouse.x <= dropmap1x1 + 4 && mouse.y >= dropmap1y1 && mouse.y <= dropmap1y1 + 4);
  if (inside && gInventory.Visible != true) ...

Vault15

Quote from: Khris on Fri 26/10/2012 12:42:27

You subtract GetViewportX() when you want to get from a room coordinate to a screen coordinate, but surface is the room's background surface and thus wider than the screen, ie. drawing to it is done using room coordinates.

Thanks, I needed to clear that up some. I feel like I've tried everything to get accurate coordinates, including just using room coordinates. I'll try again.



Quote from: Khris on Fri 26/10/2012 12:42:27
Also keep in mind that as opposed to using Characters, drawing dropped items to the background makes them ignore scaling, lighting, walkbehinds and other characters and objects.

As far as I understand, the player clicks a GUIControl while holding an item, and it is dropped to the ground in front of the player, right?
Yes. And thank you, I figured most of that would be the case but wanted to try it out.


Quote from: Khris on Fri 26/10/2012 12:42:27
You need to use:
Code: ags
  bool inside = (mouse.x >= dropmap1x1 && mouse.x <= dropmap1x1 + 4 && mouse.y >= dropmap1y1 && mouse.y <= dropmap1y1 + 4);
  if (inside && gInventory.Visible != true) ...


Wow, that is really simplified. I knew I wasn't doing it the intended way so I appreciate you showing me how to do the box search rather than my goofy way.

It doesn't work though. I'm not sure if I did something wrong but I logically replaced my garbage with your nice code. Hmm...trying to get it working again.

Edit: I wanted to clarify that I know your code works, but implemented in my game right now it's not working...yet. I'm trying.

Also am I able to convert "player.ActiveInventory.Graphic" stored in Citem1 back into the inventory item number?

Edit2: I got the item to drop infront of the player anywhere on the map now (thanks), but the "inside" function isn't working still.

Crimson Wizard

Quote from: Vault15 on Fri 26/10/2012 13:04:02
Also am I able to convert "player.ActiveInventory.Graphic" stored in Citem1 back into the inventory item number?
You may do that - by iterating all inventory items and finding one that has same graphic.
But easier way would to be to remember actual inventory item pointer instead of item's graphic.

You may also use custom structs to store information on dropped items, something like this:
Code: ags

struct DroppedItem
{
   int Room;
   int x;
   int y;
   int Graphic; // sprite to use to draw dropped item
   InventoryItem *InvItem; // pointer to actual inventory item, use it to give item to player
};

Khris

Yes, you can convert player.ActiveInventory.Graphic back into an InventoryItem.ID, assuming that no two items ever have the same sprite:
Code: ags
int FindInvIDUsingSpriteSlot(int slot) {
  int i = 1;
  while (i <= Game.InventoryItemCount) {
    if (inventory[i].Graphic == slot) return inventory[i].ID;
    i++;
  }
  return 0;
}

However, this is needlessly convoluted and error prone, and should never be done like that. You always store a pointer to the object, not one of its properties.

As far as my code not working, what I posted was meant to show the proper way of doing it, it's not necessarily ready to implement as-is.
For instance I assume that the dropmap coordinates are room coordinates, while the mouse coordinates are screen coordinates.

The bottom line is:
You're constantly biting off more than you can chew, and every time you ask for help, we have to wade through messy code.
I'm sorry, but that's the way I see it. I'm not sure what can be done about that, you seem very ambitious about what I assume is a pretty complex fallout type game, so I guess the positive thing is that you're developing your coding skills. I'm just a hesitant about providing in-depth help because you keep starting off in a bad way, and I'd rather tear everything down and rebuild it properly instead of putting duct tape all over it.

Vault15

Quote from: Khris on Fri 26/10/2012 13:39:15
The bottom line is:
You're constantly biting off more than you can chew, and every time you ask for help, we have to wade through messy code.
I'm sorry, but that's the way I see it. I'm not sure what can be done about that, you seem very ambitious about what I assume is a pretty complex fallout type game, so I guess the positive thing is that you're developing your coding skills. I'm just a hesitant about providing in-depth help because you keep starting off in a bad way, and I'd rather tear everything down and rebuild it properly instead of putting duct tape all over it.

I appreciate your patience as I'm exploring some new territory and magnifying some fuzzy areas. I'm working as quickly as I can to get where I need to be, and although I have some lazy moments, (as seen earlier throwing together the "dropmap1x1+1 ||" list) I'm almost always giving it 100% effort unless I've stayed up until 8AM (like now). So yea I'm a bit tired, lol.

I took Java and C++ many years ago so all of this is coming back to me. I love piecing it all together, and this forum (especially you two) are incredibly knowledgeable and have much more important things to attend to, I'm sure. Sometimes I know what I want to do but I just can't churn out the code like second nature quite yet. I'll get there.


Quote from: Khris on Fri 26/10/2012 13:39:15
As far as my code not working, what I posted was meant to show the proper way of doing it, it's not necessarily ready to implement as-is.
For instance I assume that the dropmap coordinates are room coordinates, while the mouse coordinates are screen coordinates.

I didn't just copy and paste it. I was trying to implement your strategy of the box search method vs the cross (as I had it). I see how yours works and I guess basically it should work but I have some little thing wrong I'm sure.


Quote from: Crimson Wizard on Fri 26/10/2012 13:36:15
You may do that - by iterating all inventory items and finding one that has same graphic.
But easier way would to be to remember actual inventory item pointer instead of item's graphic.

You may also use custom structs to store information on dropped items, something like this:
Code: ags

struct DroppedItem
{
   int Room;
   int x;
   int y;
   int Graphic; // sprite to use to draw dropped item
   InventoryItem *InvItem; // pointer to actual inventory item, use it to give item to player
};


Thanks, I'll keep structs in mind. I hadn't used them before, but I get the idea.


Bottom Line: I completely agree; I don't want to do more work than I have to. That being said, I should just learn to use the RoomInv Module.

Vault15

Got it.
Code: AGS

bool inside = (mouse.x + GetViewportX() >= dropmap1x1 && mouse.x + GetViewportX() <= dropmap1x1 + 10 && mouse.y + GetViewportY() >= dropmap1y1 && mouse.y + GetViewportY() <= dropmap1y1 + 10);

SMF spam blocked by CleanTalk