Pixel Perfect Click Detection For Only Some Characters, Objects etc...

Started by ToothpasteBruva, Tue 29/03/2016 15:50:38

Previous topic - Next topic

ToothpasteBruva

Hi all,
I needed to turn off pixel perfect click detection so I could have a clickable transparent object for a puzzle in my game. This also works out for most other clickable objects, because now they're easier to click. The issue is now I'm finding the characters are unintentionally clicked because of how big their bounding box is. Is there a way to get the transparency of the clicked pixel to decide whether the mouse click passes through or not? I was thinking something like this.
Code: ags

function cCharacter_Talk()
int gettransparency = cCharacter.GetPixel(mouse.x, mouse.y);
{
    if (gettransparency == -1)
    {
        cCharacter.Clickable == false;
    }
    else
    {
    //Start talking
    }
{

I feel like I've seen something like this before. Let me know if it's already been solved.
Cheers

Vincent

I can't understand easily what do you want to achieve :(
However I believe there's a type mistake in the code..
Code: ags

function cCharacter_Talk()
int gettransparency = cCharacter.GetPixel(mouse.x, mouse.y);
{


It should be in this way
Code: ags

function cCharacter_Talk()
{
int gettransparency = cCharacter.GetPixel(mouse.x, mouse.y);
...



I am not sure if this could be helpful somehow but you could try to check GetLocationType or GetAtScreenXY (character)
example
Code: ags

if (GetLocationType(mouse.x,mouse.y) == eLocationCharacter)
    cCharacter.Clickable = false;



NOTE: Any characters with the "Clickable" property set to false will not be seen by this function.
Code: ags

if (Character.GetAtScreenXY(mouse.x, mouse.y) == cEgo) 
{
  Display("The mouse is over the main character");
}

Khris

Before implementing convoluted solutions, let's consider whether turning off pixel-perfect click detection is a good idea, because it seems like we should solve the original problem a different way instead.

Having an invisible but clickable object can be achieved by checking the mouse position against a rectangle. One could also use an arbitrary shape by comparing the position against the pixel color of a dynamic sprite.

If you want to keep ppcd turned off because your objects are easier to click, may I ask why they are hard to click in the first place? Are you using tiny objects? Or mouse cursors without clear hotspots? That shouldn't be the case in the first place and sounds like a design flaw.

Also, just fyi, while what you outline with example code is perfectly possible in theory, setting the character's .Clickable attribute to false at that point in time is way too late (and unnecessary anyway). Instead you'd simply not start the dialog / exit the function.

ToothpasteBruva

Thanks for the replies.:-D

Sorry if that wasn't clear Vincent. Basically I wanted pixel perfect click detection for some characters while ppcd was disabled in the general settings. I was hoping there was a way to measure whether the clicked pixel of a character was transparent, and if so then the click would pass through him/her to the objects behind. Otherwise it the character would talk. I'm not sure if GetAtScreen or GetLocation would help me in this case.

Perhaps I don't need to turn off ppcd. Very open to that, but I'm not sure if I'm following Kris. Are you suggesting I create a dynamic rectangle in game with an invisible colour that can be clicked? I think I need something like
Code: ags

function oTrigger_Interact() //trigger object
{
    dynamicrectangle.Clickable = true;
}

function dynamicrectangle_Interact () //screen size invisible clickable rectangle
{
    //do action
    dynamicrectangle.Clickable = false;
}

But I'm not sure if you can do that with dynamic sprites. I haven't used them before.
As far as design goes objects are easy enough to click for the most part. It's just times like these when players will click the window instead of the metal. I know there are ways around it like using hotspots, but I s'pose that's another topic.

Thanks

Danvzare

Quote from: ToothpasteBruva on Wed 30/03/2016 11:54:13
As far as design goes objects are easy enough to click for the most part. It's just times like these when players will click the window instead of the metal. I know there are ways around it like using hotspots, but I s'pose that's another topic.

Personally, I would solve that door problem through an alpha transparancy channel. I'd just make the window almost completeltly transparent.
Like this:
The only downside (if you could even call it that), is that your game would have to be in 32-bit.

Khris

Like I tried to explain, turning .Clickable on or off in the function that handles the click is useless, since it will only affect the next click, not climb into a DeLorean and change how the current one is handled.

If you want to leave ppcd off, you have to iterate through all characters in the current room, get their current ViewFrame, grab its Graphic, put that into a Dynamicsprite, translate the mouse coordinate into the character sprite's coordinate system, grab the respective pixel from the Sprite and check its color. Then you have to deal with the possibility that two or more characters are overlapping. You're basically manually replicating what the engine does when you leave ppcd activated.

The alternative is to do a simple coordinate check in the room's on_mouse_click:

Code: ags
// add this to the room script
function on_mouse_click(MouseButton button) {
  if (button != eMouseLeft) return;
  if (mouse.x < 120 || mouse.x > 160) return;
  if (mouse.y < 20 || mouse.y > 60) return;

  // at this point, the player left-clicked inside rectangle (120;20) - (160;60)
  ClaimEvent(); // prevent global processing of the click
  // custom click handling here
}

ToothpasteBruva

Thanks Danvzar, maybe it's time I upgrade to a 32 bit game. It would mean shadows would be possible as well.

You've convinced me to turn ppcd back on Kris. Your script is working pretty great. I didn't need to use a rectangle in the end because the player can click anywhere to interact with the puzzle provided other conditions are met. I understood .Clickable wouldn't affect the function at that point. It was just to make the invisible object unclickable after the function ended. Either way, unnecessary now. (I'll stay out of the hot tub time machine).

Here's what I got in the end.
Code: ags

function on_mouse_click(MouseButton button) 
{
  if (button != eMouseLeft) return;
  if (varShelfInteract == true)
  {
    if (varShelf == 8)// Just Puzzle conditions that need to be met 
    {
      if (varDirection == "left")
        {
          if (varBed != 7 && varBox != 7 && varCup != 7)//These probably don't need to be separate if statements, it's just neater for me.
          {
            //Puzzle interaction happens here
            ClaimEvent(); //Stops the player walking around
            //Ends puzzle interaction
          }
          else
          {
            In_The_Way();//Also ends puzzle interaction
          }
        }
      }
    }
  }

Thanks, I'm stoked this is working finally.

Dave Gilbert

A really cheap but effective way of achieving this is to add a background layer to the Sprite in Photoshop. Fill the layer with white and give it a 1% transparency. Save it as a PNG and import it with an alpha channel. I've used this trick often to increase the hotspot size of small objects. :)

Edit: I see this isn't a 32 bit game. So obviously this trick would not work. However, I will warn you that NOT making the game 32 bit will result in a lot of problems. We learned this lesson the hard way when we launched Gemini Rue. A lot of computers can't even handle 16 bit properly anymore and react very unpredictably.

SMF spam blocked by CleanTalk