Player drawing lines on screen [Solved]

Started by AnasAbdin, Thu 29/06/2017 00:03:02

Previous topic - Next topic

AnasAbdin

I tried so hard to do a task, and when I got desperate I honestly searched a little :-[

What I'm trying to achieve is to give the player the ability to draw lines on a specific area on the screen. I'm using a GUI as the area. And a hHotspot1_Interact() as a trigger. The effect I'm looking for is the same idea when drawing lines using normal paint programs. That is, when the left mouse button is pressed over a point and the mouse moves while the button is still down, a line is drawn between the clicked point and the current mouse location no matter where it moves.

I managed to do that part well.

Then, when you finally decide that the line is perfect for you, you release the mouse and the line is drawn permanently. I managed to make the final line gets drawn but not permanently. It stays until you try to draw another line then it disappears :-\

I'm sure I have missed something simple, or misplaced a lines.. and that I would be embarrassed later :-[
Could someone please help?

Here's my code:

Code: ags
// room script file
int prev_mx, prev_my;
DrawingSurface *surface;
 
function hHotspot1_Interact()
{
  DynamicSprite* Field_Spr = DynamicSprite.Create(640, 300, false); //drawing area is top 3/4 of the room..
  
  surface = Field_Spr.GetDrawingSurface();

  //The desired GUI to be drawing into
  gCSTiles.Visible = true;
  gCSTiles.Clickable = false;
  
  //saving the previous mouse xy
  prev_mx = 0;
  prev_my = 0;
 
  //saving the first point of the line
  int mx = mouse.x;
  int my = mouse.y;

  //The lines is drawn here and moves smoothly with the mouse movement
  while ( mouse.IsButtonDown(eMouseLeft) )
  {
    surface.DrawingColor=65535;
    surface.DrawLine(mx, my, mouse.x, mouse.y);
    Wait(1);
    //clearing the old line until the player is satisfied with another line
    if ( mouse.x != prev_mx || mouse.y != prev_my )
    {
      surface.Clear();
      surface.DrawLine(mx, my, mouse.x, mouse.y);
    }
  }

  surface = Field_Spr.GetDrawingSurface();
  //draw the 'permanent' line
  surface.DrawLine(mx, my, mouse.x, mouse.y);
  
  gCSTiles.BackgroundGraphic = Field_Spr.Graphic;
  surface.Release();
}

Gilbert

Declare and initialise the dynamic sprite elsewhere.
The sprite is (re)created every time the hotspot is interacted with, so after you release the mouse button to settle for a line, and you click the hotspot again to draw another line, the sprite will be cleared.
Also, since you need to wipe the line (by clearing the sprite) repeatedly while the mouse button is kept pressed, you actually need 2 dynamic sprites, one for the temporal line and another for the "permanent" picture, so to elaborate:

Dynamic sprite 1: Holds the "permanent" picture. Should be declared in the script (global script if this feature is gamewise , or room script if this only applies to a certain room) outside of functions and be created only once.

Dynamic sprite 2: Hold the temporal line. Could be just what you are doing already and it will be destroyed after the event ends.

Crimson Wizard

I would like to add that having DrawingSurface as a global variable does not make any sense, because surface must be released as soon as you finished drawing anyway, after which it cannot be used until assigned with GetDrawingSurface again.

Gilbert

To some degree, yes, but there are cases that this could be useful, like the demo to my module here for example. In the global script, only one drawing surface is declared script-wise, saving it from creating one every time a function is called. It doesn't make any difference though. I just thought having only one single declaration and reusing it to death would be more manageable.

There may also be cases that the surface is not supposed to be released immediately every time. For example (just some quickly made-up scenario), you may have a dynamic sprite that's to be drawn onto step by step according to the player's action, maybe taking more than 1 single game loop and that sprite is not supposed to be shown until later. Then you may just get the drawing surface from the sprite, draw and draw and draw on it, and release it only before it is ready to be displayed. Of course you can alternately do the get-release surface cycle in each single drawing action, but IMO that's more like the programmer's own preference.

AnasAbdin

I will try your tips when I get access to my pc and update you.

AnasAbdin

#5
Thanks guys it's solved :-*

I created a second dynamic sprite and another GUI for the permanent line. It works as a charm.
I also moved the dynamic sprites initialization to the room_Load() function.

Code: ags
function room_Load()
{
  Field_Spr =  DynamicSprite.Create(640, 300, false);
  Field_Spr2 = DynamicSprite.Create(640, 300, false);

  // Non relevant lines..
  // ...
}


Code: ags
function hHotspot1_Interact()
{
  surface2 = Field_Spr.GetDrawingSurface();
  surface  = Field_Spr2.GetDrawingSurface();

  gCSTiles.Visible = true;
  gCSTiles.Clickable = false;
  gCSTiles2.Visible = true;
  gCSTiles2.Clickable = false;
 
  // Rest of the code is the same as first post
  // ...

  surface2.DrawingColor=65504;
  surface2.DrawLine(mx, my, mouse.x, mouse.y, 2);
  
  gCSTiles.BackgroundGraphic  = Field_Spr.Graphic;
  gCSTiles2.BackgroundGraphic = Field_Spr2.Graphic;

  surface.Release(); 
  surface2.Release();
}

SMF spam blocked by CleanTalk