Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - Crimson Wizard

#2901
Quote from: Amir on Sat 11/06/2022 13:12:18
Yes with if (GUI.GetAtScreenXY(mouse.x, mouse.y) != gGuiLine) return;// I can click on OK gui but not gGuiline, gGuiline is gone. That's good, but when I change ZOrder and put gGuiline behind the other and click on OK gui, wrong answer, like I said, like I'm drawing an invisible line outside of the gui and that's why it doesn't work.

That should not happen. What are zorder values of these guis?
There's also gGuiAllLines, it should perhaps be made non-clickable to not interfere with anything.
#2902
Quote from: Amir on Sat 11/06/2022 08:20:09
Good morning, it doesn't work, I've tried many things, like this for example.

This may be because the line drawing code draws lines even when you click on buttons. So when you click on a button, it draws a small line anyway.
The solution may be to either restrict drawing to certain coordinates, or coordinates of gui that you put sprites on, if you make it not cover whole screen but only area where it is allowed to draw.
Or use ZOrder to put gGuiLine below other controls and test GUI.GetAtScreenXY to see if the mouse is above it before starting to draw.

Code: ags

  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){
    if (GUI.GetAtScreenXY(mouse.x, mouse.y) != gGuiLine) // <--------- add this
      return;// <--------- 
   <...>
#2903
Quote from: Amir on Sat 11/06/2022 00:49:40I want to make it so that if you click the OK button and haven't dragged anything yet, nothing happens. I mean if there are no lines there nothing happens when you click OK.

I think it might work if you simply move the "line_count" check up and merge with "if (event == 2)":
Code: ags
if (event == 2 && line_count > 0)

as if there are no lines drawn, then no need to also call TestLines and other things.
#2904
Quote from: Amir on Fri 10/06/2022 20:39:33
Aha this TestLines(); function probably makes a big difference but it doesn't work for me  ???
I have to import the 2 new functions, right?

It's not only 2 new functions, there are other differences, compared to the last code you posted above. I guess you could compare the code side by side to see what is different. Or simply paste full code over, and then adjust to your needs.
#2905
This is my room code that works:

Note that when making tests, I check both directions, because player could draw line from hotspot 2 to 1 too.

Code: ags

// room script file

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

struct Line {
    int sx,sy,ex,ey;
};
 
#define MAX_LINES 100
Line Lines[MAX_LINES];
int line_count;

// Line linking results
bool VBaer;


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

// ResetLines function clears lines up, clears results too.
// pass "true" if you want to delete full sprite, or only clear it
function ResetLines(bool delete_all)
{
  if (spriteForLine) {
    spriteForLine.Delete();
    spriteForLine = null;
  }

  // delete full lines sprite or only clear it
  if (delete_all) {
    spriteForAll.Delete();
    spriteForAll = null;
  } else {
    DrawingSurface *surface = spriteForAll.GetDrawingSurface();
    surface.Clear();
    surface.Release();
  }
  
  // Reset saved lines and results
  line_count = 0;
  VBaer = false;
}

function room_Leave()
{
  ResetLines(true);
}
 
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;
  } 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);
    //draw line from the place where the mouse was pressed to the current position of the mouse
    ex = mouse.x;
    ey = mouse.y;
    surface.DrawingColor = line_color;
    surface.DrawLine(sx, sy, ex, ey, LINE_WIDTH);
    surface.Release();
  } else if (!mouse_down && !accept_input) {
    //if the mouse button is released and input set to false, reset accept_input and stop drawing lines
    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();
    // save line
    Lines[line_count].sx = sx;
    Lines[line_count].sy = sy;
    Lines[line_count].ex = ex;
    Lines[line_count].ey = ey;
    line_count++; // increase line counter
  }
}

// Perform line link tests and save results in boolean variables
function TestLines()
{
  for (int i = 0; i < line_count; i++) {
    Hotspot* h1 = Hotspot.GetAtScreenXY(Lines[i].sx, Lines[i].sy);
    Hotspot* h2 = Hotspot.GetAtScreenXY(Lines[i].ex, Lines[i].ey);
    if ((h1 == hotspot[1]) && (h2 == hotspot[2]) ||
        (h1 == hotspot[2]) && (h2 == hotspot[1]))
      VBaer = true;
    // ..... and more pair tests here
  }
}

function on_call(int event)
{
  // reset lines
  if (event == 1) {
    ResetLines(false);
  }
  // check lines
  else if (event == 2) {
    // test all lines and save bools
    TestLines();
    // now final test(s)
    if (VBaer == true)
      player.Say("Bingo");
    ResetLines(false);
  }
}
#2906
Quote from: Amir on Fri 10/06/2022 17:39:22
No nothing, Lines array just like you wrote me. I didn't change anything.

The thing is, what I wrote about Lines was just a starting example + tips of how you may approach this, it was not a complete code.
I am not explaining this well.

Let's discuss the logic first.

1) Each time the player finishes drawing the line, the line should be remembered.
2) When player presses the button to check the puzzle, two things should be performed:
2.1) first we check all the remembered lines, and find out what hotspots they connect. Each time there's a good connection, we save that result in corresponding bool.
2.2) second we check the resulting bools, to find out the actual state of the puzzle, and do something about it (display the message, and so on).
3) When we reset the line sprites we should also reset the line counter.


Now, let's look at the RepExec where we draw the line. The code responsible for finishing the line is this:
Code: ags

  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();
  }


We need to save the line coordinates right there, under this "if", and increase the line counter to know how many lines are drawn:
Code: ags

     ..............
     // don't display single-line sprite anymore
     gGuiLine.BackgroundGraphic = 0;
     spriteForLine.Delete();
     // save line
     Lines[line_count].sx = sx;
     Lines[line_count].sy = sy;
     Lines[line_count].ex = ex;
     Lines[line_count].ey = ey;
     line_count++; // increase line counter


Now, we may go to on_call and put line tests there; but on another thought, it may be more convenient to write a separate function for that, to keep code tidy. So we create our own function that just test lines and saves bools:
Code: ags

function TestLines() {
    for (int i = 0; i < line_count; i++) {
        if ((Hotspot.GetAtScreenXY(Lines[i].sx, Lines[i].sy) == hotspot[1]) && (Hotspot.GetAtScreenXY(Lines[i].ex, Lines[i].ey) == hotspot[2]))
          VBaer = true;
        // ..... and more pair tests here
    }
}


And then in on_call we just call TestLines and perform final test:
Code: ags

function on_call (int event) 
{
    // LinesOk event
    if (event== 2) {
         // test all lines and save bools
         TestLines(); 
         // now final test(s)
         if (VBaer == true) cBerny.SayBubble("Bingo");
    }
}


We also may need to reset line counter along with the sprites. We need to do this in both room_Leave() and on_call where you reset the lines.
E.g. in on_call:
Code: ags

  if (event == 1) // lines reset
  {
     if (spriteForLine) {
       spriteForLine.Delete();
     }
 
     DrawingSurface *surface = spriteForAll.GetDrawingSurface();
     surface.Clear();
     surface.Release();

     line_count = 0; // <---- reset lines counter
  }
#2907
Actually,.... if you are using Lines array, then you should not be checking hotspots in RepExec. Or, if you check hotspots in RepExec, then you do not need Lines array at all.

There are 2 approaches:
1) Save Lines array in rep exec. Test both the line results and final results after button is pressed (in on_call).
2) Don't use Lines array at all. Test line results in rep exec and save booleans (VBaer and others) there. Then test these booleans in on_call.
#2908
Quote from: Amir on Fri 10/06/2022 12:19:19
Ok,

in room_RepExec (under the code of drawing)


What else is in room_RepExec? how do you fill Lines array?
#2909
Quote from: Amir on Fri 10/06/2022 11:39:42
It doesn't work  :-\ Maybe something else is missing?

I'm trying with just one line and bool. AnchorBoat = true;

Please post your current code?
#2910
I think you misunderstood my examples. The "room_RepExec" code you posted does nothing, it's just "if" condition with nothing inside. My code was a placeholder that should be filled with something. For instance, you could remember which items are connected, similar to the code you posted yesterday:
https://www.adventuregamestudio.co.uk/forums/index.php?topic=60037.msg636646898#msg636646898

The code "In Button" makes more sense, but I don't know where did you get "sx,sy" etc variables from. The idea was to use the stored variables from Lines instead.

So, the code called from the button press could look like:
Code: ags

  // test all lines to see what do they connect
  for (int i = 0; i < line_count; i++)
 {
     if ((Hotspot.GetAtScreenXY(Lines[i].sx, Lines[i].sy) == hotspot[1]) && (Hotspot.GetAtScreenXY(Lines[i].ex, Lines[i].ey) == hotspot[2]))
          AnchorBoat = true;
     else if ((Hotspot.GetAtScreenXY((Lines[i].sx, Lines[i].sy) == hotspot[3]) && (Hotspot.GetAtScreenXY(Lines[i].ex, Lines[i].ey) == hotspot[4]))
          ColaHotdog = true;
     // and so on -- other variants here
  }


afterwards, when you found and remembered which combinations are correct, you could display results, for example:
Code: ags

  if (AnchorBoat && ColaHotdog)
    cBerny.SayBubble("Bingo.");




In regards to the on_call problem, the on_call can take only 1 argument, as shown in the manual. You should compare that 1 argument with all possible values.
Code: ags

function on_call (int event) 
{
  
  if (event == 1) // lines reset
  {
     // do something for lines reset
  }
  else if (event == 2) // lines ok
  {
     // do something for lines check
  }
}


If you don't like using simple numbers, and prefer some text instead, you may create a enum. For example you may put this in the global header:
Code: ags

enum LinePuzzleEvents {
    LinePuzz_Reset,
    LinePuzz_Check
};


And then just do
Code: ags

function on_call (int event) 
{
  if (event == LinePuzz_Reset) // lines reset
  {
     // do something for lines reset
  }
  else if (event == LinePuzz_Check) // lines ok
  {
     // do something for lines check
  }
}


And similarly when doing CallRoomScript:
Code: ags

CallRoomScript(LinePuzz_Reset); // and so on
#2911
Have anything tried running latest 3.6.0 on linux in fullscreen mode? Trying this on a linux virtual machine results in a completely black window with no video or audio or reaction to input, regardless of the chosen renderer; so I am wondering if that's vm or engine's problem.
#2912
Quote from: Amir on Thu 09/06/2022 19:15:56
It occurred to me that this is for just one line, not multiple, am I right? how do I do this way for multiple lines? Does anyone have an idea.

There are two approaches, either:

1) Make a test when player finishes drawing line and save the test result.
2) Save final line coordinates (sx,sy,ex,ey) and test later (on button press?).

Since you have multiple lines you will have to make an array of final line coordinates or test results.

for a quick example:
Code: ags

struct Line {
    int sx,sy,ex,ey;
};

#define MAX_LINES 100
Line Lines[MAX_LINES];


Remember the line count in a integer variable, increase each time a line was finished, and reset to 0 when lines are cleared.

Then in the end, you may do a check:
Code: ags

    for (int i = 0; i < line_count; i++) {
        // test Lines[i] values:
        if (Hotspot.GetAtScreenXY(Lines[i].sx, Lines[i].sy) == ...) { // where line starts
        }
        if (Hotspot.GetAtScreenXY(Lines[i].ex, Lines[i].ey) == ...) { // where line ends
        }
    }
#2913
Quote from: Amir on Thu 09/06/2022 13:44:35
They get deleted but when you want to draw again, it gets drawed then disappears because we deleted spriteForAll.Delete(); . Something is probably missing in else if

Well, the solution is to not just delete spriteForAll when you click on button, but to clear it instead. Or delete it and recreate again.

Code: ags

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

     DrawingSurface *surface = spriteForAll.GetDrawingSurface();
     surface.Clear();
     surface.Release();
  }
}


This will preserve the main sprite, but clear it with transparent color
#2914
Quote from: Amir on Thu 09/06/2022 11:27:40But I can't make this on_call. what am I doing wrong?
this is the reset button. All lines should be deleted.

Your on_call code works for me.

I may only suggest begin with checking if the button script is called, on_call is called, and the conditions work correctly. This may be tested for instance with "Display" command, or placing breakpoints in the editor and running game with F5.

Also:
- is the button clickable;
- is the button covered by any clickable guis.
#2915
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
#2916
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();
  }
}
#2917
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.
#2918
Regarding color not working, I noticed that in the above script example DrawingColor is set after DrawLine. You need to swap these two commands.
#2919
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.
#2920
Quote from: Amir on Tue 07/06/2022 18:55:52
Yes slow and like a heavy stone. This is probably the default speed 1. The movement speed of my system cursor is almost 2.2.

As far as I recall, mouse speed is not applied by default in the windowed mode, only in fullscreen, and should not depend on mouse lock (it's a completely separate setting).
I also remember that by default the engine tries to make mouse speed in fullscreen close to the system cursor speed, but maybe this does not work well if the system cursor is sped up somehow (not sure).

IMHO the best is to not guess about other people by your system behavior, and leave the speed setting on default position, and let players adjust it only if really necessary.
SMF spam blocked by CleanTalk