Match objects with drawing lines (Bingo! Solved)

Started by Amir, Mon 06/06/2022 07:43:06

Previous topic - Next topic

Amir

Hello,

I still have my last puzzle in the game where you have to match objects (or hotspots), with an OK button you have to click on it when you have matched to see if it's wrong or right. I have a complicated idea how to do this, using lines as objects. But it's complicated and takes a lot of work and time. I thought differently, I could maybe do it with drawing lines. when the left mouse button is pressed the mouse moves while the button is still down, a line is drawn between where you clicked and you let go the mouse button.

Something like that here: (this is not my puzzle ;-D)
Spoiler
[close]

I found this ancient code in this thread, since 2004. It looks like it's right for my puzzle but it doesn't work anymore. https://www.adventuregamestudio.co.uk/forums/index.php?topic=12390.msg148534#msg148534

I tried to fix it but the commands are from the Jurassic period.
Has anyone written or used some similar code before, or maybe there's a module I haven't discovered yet?
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Pogwizd

#1
Not sure if this helps, but if you are going to have the pictures as objects in the room, I would, on mouse button click, loop through the objects and check their coordinates and dimensions of their sprites. Knowing the coordinates and dimensions, you can check if the click happened within the boundaries of one of the objects/sprites. If yes, you store the object's id and wait for the release of the mouse button. When the mouse button is released you do the same thing - check where the mouse button was released. If it was released within the boundaries of one of the images you grab its id. Then you can check what two objects/images have been linked (of course you would need to have an array of correct matches to compare against).

As for the drawing the line, once the mouse is pressed, you start drawing a line using dynamic sprites. As far as I remember, you do it by capturing the background before you start drawing the line, and every pixel the mouse is moved, you redraw the background and the new line (starting from the point where the mouse was pressed, and finishing at the current position of the mouse). Once the mouse button is released, you stop redrawing the background and the line.

I can't write the actual code at the moment, but I would probably try doing something along these lines.   

Amir

It doesn't matter if it's hotsopts or objects, I can change it.

thanks for explaining the method, I understand it but i think I wouldn't be able to do it because i've never handled this Drawing functions before, so I asked if anyone has any code already and that's why I tried Rick's code . This would take me longer and require more work than the complicated lines-as-objects method. I can't find any modules with drawings at all, I might set them up faster so that I can draw lines from mouse.x to mouse.y. I will look again today.
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Pogwizd

#3
I see. If you don't mind waiting, I will try to fish out my old code from my game in the evening and share it with you. This is a clip from my game, which also draws lines: https://youtu.be/9pksmHxbXnc?t (go to 48:00) If I am not mistaken, this is something similar you want to achieve?

Amir

Oh cool, yes, exactly, but with free moving mouse cursor. I see you have limited mouse x and y in this room. I think this is not difficult to change in your code. Take your time, I can wait. Now I have a worse problem with changing the translation. (I posted it in Beginners' Technical section)

Cool game, I like the graphics. I will definitely play it at some point.

Thank u  :)
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Pogwizd

#5
Right. I found the code and managed to pull out the bits that will hopefully shed some light. I haven't tested this particular code, so there might be some imperfections. But, in essence, this is the same logic that worked for me. It's possible you will have to tweak it here and there, though.

Code: ags

bool accept_input = true;
bool draw = false;
int line_count = 0;
int LINE_WIDTH = 5;
int start_x;
int start_y;
DrawingSurface *surface;
DynamicSprite *sprite;

function room_RepExec(){

  //if the left mouse button is down and the game accepts input, 
  //store x and y of the current mouse position
  //as well as copy the current view of the screen to sprite (so already drawn lines will stay)  
  if(Mouse.IsButtonDown(eMouseLeft) && accept_input){  
      accept_input = false;
      start_x = mouse.x;
      start_y = mouse.y;     
      sprite = sprite.CreateFromScreenShot();  
      line_count++;      
  }

  //if the mouse button is released and input set to false, reset accept_input and stop drawing lines
  if(!Mouse.IsButtonDown(eMouseLeft) && !accept_input ){
    accept_input = true;    
  }
  
  //if accept_input is false, this means the button is pressed, so draw the lines
  if(!accept_input){
    surface = Room.GetDrawingSurfaceForBackground();
    
    //if this is the first line/match to be drawn, draw the background from the 'clean' sprite
    //otherwise draw the background with already drawn lines
    if(line_count == 0) sprite = sprite.CreateFromExistingSprite(id_of_background_image);      
    
    //draw the sprite variable on the screen
    surface.DrawImage(0, 0,  sprite.Graphic);  
    
    //draw line from the place where the mouse was pressed to the current position of the mouse
    surface.DrawLine(start_x, start_y,  mouse.x, mouse.y, LINE_WIDTH);
    surface.DrawingColor = number_of_colour;   
    surface.Release();     
  }
}


Note that once you are finished, you should delete the sprite variable with
Code: ags
sprite.Delete();


Hope this helps, if not, give ma a shout.




Amir

Ok, thank you so much  ;-D I'll test it right away in my puzzle room.
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Amir

#7
I've only tested drawing so far, but there's a problem or two. Whenever I click to draw, the music stutters annoyingly and I have 2 buttons there, whenever I click to draw, the sprites of buttons become more pixelated and look aliased. Do u know why?  :-\  I doubted the width, I tried int LINE_WIDTH = 1; but that didn't help. My resolution is 1280 x 720.
I also doubt the mouse cursor because it stays there after you draw. Is there any way to prevent it?

And I cannt change the color surface.DrawingColor = 53248; I want it red but it's always black, but that doesn't matter, that's no problem.
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Pogwizd

Quote from: Amir on Wed 08/06/2022 15:40:55
I also doubt the mouse cursor because it stays there after you draw. Is there any way to prevent it?
The mouse stays because the game captures whatever is displayed on the screen. I didn't have that problem because the cursor was hidden in my room. I guess you could try hiding the cursor right before this line:
Code: ags
sprite = sprite.CreateFromScreenShot();

...and then showing it again afterwards.



Quote from: Amir on Wed 08/06/2022 15:40:55
And I cannt change the color surface.DrawingColor = 53248; I want it red but it's always black, but that doesn't matter, that's no problem.
Are you sure your colour code is correct? In my game it had the value of 13 and it worked fine. Have you tried any other colour numbers?


Quote from: Amir on Wed 08/06/2022 15:40:55
Whenever I click to draw, the music stutters annoyingly.
I didn't have that issue. Are you doing anything with the audio clips in the same room_RepExec() function?



Quote from: Amir on Wed 08/06/2022 15:40:55
the sprites of buttons become more pixelated and look aliased.
Are these buttons the only GUI elements shown in this puzzle room? I am not an expert, and I am not sure what may be the cause of that. I wonder if the same would happen if you hid the buttons for the time of capturing the screenshot from the background (just like with the cursor)?




Amir

#9
QuoteThe mouse stays because the game captures whatever is displayed on the screen. I didn't have that problem because the cursor was hidden in my room. I guess you could try hiding the cursor right before this line

I had tried this and Changemode of the mouse as well, in the code and in on_mouse_click but it dosn't work, it would work if you just click once, the mouse cursor disappears but you can no longer see where you draw the line. It doesn't matter, that's no problem, it doesn't look that bad.

QuoteAre you sure your colour code is correct? In my game it had the value of 13 and it worked fine. Have you tried any other colour numbers?
Yes and I tried many codes, it stays black  ;-D that's also no problem. I like black metal.

QuoteI didn't have that issue. Are you doing anything with the audio clips in the same room_RepExec() function?
No nothing, by the way it's in the Global script because of the buttons "OK" and "Reset" I have 3 Buttons there, ok reset and exit room, it won't look pretty if they keep disappearing and reappearing when you draw and finish drawing.  ;-D

I think I know now why this is happening, because of the screenshot the code takes. When I take a screenshot in the game, the music stutters the same as in this room. I don't think it's a good idea to draw with a screenshot at my resolution 1280 x 720. I think a Gui as BackgroundGraphic would be better in my case. Look at this link https://www.adventuregamestudio.co.uk/forums/index.php?topic=54958.0

I will try to mix your codes and do it with Gui, like I said, I have never written any code using Drawing Surface. If you can help with that, that would be very nice. (or someone else who reads and knows)
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Crimson Wizard

#10
You don't really need a screenshot here, as you may save the finished lines on a separate sprite.

Idea for this is:
Draw on a dynamic sprite, cleared to transparency.
Remember line coordinates, then on each "drawing" step clear the old line by drawing it with transparent color, and draw a new one with updated coordinates.

Assign that sprite to a room object or GUI, so that you don't have to repaint the background all the time either.

Since you have multiple lines, save them on a second sprite, and only paste finished lines there as soon as they are completed. Assign that sprite to another object or gui.

Amir

Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Crimson Wizard

Regarding color not working, I noticed that in the above script example DrawingColor is set after DrawLine. You need to swap these two commands.

Amir

Quote from: Crimson Wizard on Thu 09/06/2022 09:02:59
Regarding color not working, I noticed that in the above script example DrawingColor is set after DrawLine. You need to swap these two commands.

(laugh) your right, now it's red.
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Snarky

Quote from: Crimson Wizard on Thu 09/06/2022 08:30:53
on each "drawing" step clear the old line by drawing it with transparent color

Surely it's easier and probably more efficient to just wipe the whole sprite by calling DrawingSurface.Clear(COLOR_TRANSPARENT)?

Crimson Wizard

#15
Quote from: Snarky on Thu 09/06/2022 09:19:37
Quote from: Crimson Wizard on Thu 09/06/2022 08:30:53
on each "drawing" step clear the old line by drawing it with transparent color

Surely it's easier and probably more efficient to just wipe the whole sprite by calling DrawingSurface.Clear(COLOR_TRANSPARENT)?

Clear() sets every pixel on a sprite to certain value. DrawLine sets only necessary pixels, but does extra math to calculate how line is going. A speed test would be required to see the actual difference, which may also depend on the sprite resolution and average line length.

Crimson Wizard

Here's the working script, created by adjusting the above script by Pogwizd.
You only need 2 GUIs to make it work, called gGuiLine and gGuiAllLines.

Code: ags


bool accept_input = true;
bool draw = false;
int LINE_WIDTH = 5;
int sx, sy, ex, ey;
DynamicSprite *spriteForLine;
DynamicSprite *spriteForAll;
int line_color = 53248;

function room_Load()
{
  spriteForAll = DynamicSprite.Create(Room.Width, Room.Height);
  gGuiAllLines.BackgroundGraphic = spriteForAll.Graphic;
}

function room_Leave()
{
  if (spriteForLine) {
    spriteForLine.Delete();
  }
  if (spriteForAll) {
    spriteForAll.Delete();
  }
}
 
function room_RepExec(){
 
  bool mouse_down = Mouse.IsButtonDown(eMouseLeft);
  //if the left mouse button is down and the game accepts input, 
  //store x and y of the current mouse position
  if (mouse_down && accept_input){
    accept_input = false;
    draw = true;
    sx = mouse.x;
    sy = mouse.y;
    ex = sx;
    ey = sy;
    spriteForLine = DynamicSprite.Create(Room.Width, Room.Height);
    gGuiLine.BackgroundGraphic = spriteForLine.Graphic;
  //draw line from the place where the mouse was pressed to the current position of the mouse
  } else if (mouse_down && draw) {
    DrawingSurface *surface = spriteForLine.GetDrawingSurface();
    // first erase old line by repainting it with a transparent color
    surface.DrawingColor = COLOR_TRANSPARENT;
    surface.DrawLine(sx, sy, ex, ey, LINE_WIDTH);
    ex = mouse.x;
    ey = mouse.y;
    surface.DrawingColor = line_color;
    surface.DrawLine(sx, sy, ex, ey, LINE_WIDTH);
    surface.Release();
  // if the mouse button is released and input set to false, reset accept_input and stop drawing lines
  } else if (!mouse_down && !accept_input) {
    accept_input = true;
    draw = false;
    // paste resulting line onto the final sprite with many lines
    DrawingSurface *surface = spriteForAll.GetDrawingSurface();
    surface.DrawImage(0, 0, spriteForLine.Graphic);
    surface.Release();
    // don't display single-line sprite anymore
    gGuiLine.BackgroundGraphic = 0;
    spriteForLine.Delete();
  }
}

Amir

Oh cool, I'm trying to do it now with sprite.CreateFromExistingSprite(object[2].Graphic); but when you've already done it with guis, I'll take your code. (not yet tested)

But shouldn't it be in the Global Script? As I said, I have an OK button that the player has to click on if all the lines are correct. And the button is always in Global Script. It won't see the lines like that in the room 19.
Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

Crimson Wizard

Quote from: Amir on Thu 09/06/2022 09:51:26
But shouldn't it be in the Global Script? As I said, I have an OK button that the player has to click on if all the lines are correct. And the button is always in Global Script. It won't see the lines like that in the room 19.

You can put that anywhere you like. For example you may create a separate script module for that, and add functions that turn the line drawing on and off.

But it does not have to be in the global script only to let button do something. You may pass a "signal" into the room script using CallRoomScript command:
https://adventuregamestudio.github.io/ags-manual/Globalfunctions_General.html#callroomscript

Amir

Quote from: Crimson Wizard on Thu 09/06/2022 09:55:27
Quote from: Amir on Thu 09/06/2022 09:51:26
But shouldn't it be in the Global Script? As I said, I have an OK button that the player has to click on if all the lines are correct. And the button is always in Global Script. It won't see the lines like that in the room 19.

You can put that anywhere you like. For example you may create a separate script module for that, and add functions that turn the line drawing on and off.

But it does not have to be in the global script only to let button do something. You may pass a "signal" into the room script using CallRoomScript command:
https://adventuregamestudio.github.io/ags-manual/Globalfunctions_General.html#callroomscript


Thank u so much. It works like a charm. But I can't make this on_call. what am I doing wrong?
this is the reset button. All lines should be deleted.

Global scrip
Code: ags

function gReset_OnClick(GUI *theGui, MouseButton button)
{
if (cBerny.Room == 19)  
CallRoomScript(1);
}


Room 19
Code: ags

function on_call (int Lines)
{
  
if (Lines == 1)
{
  if (spriteForLine) {
    spriteForLine.Delete();
  }
  if (spriteForAll) {
    spriteForAll.Delete();
  }  
}
}


Truly, truly, I say to you, blessed are those who play adventure games, for theirs is the kingdom of heaven.

SMF spam blocked by CleanTalk