Adventure Game Studio

AGS Support => Modules, Plugins & Tools => Topic started by: spook1 on Mon 15/03/2004 08:58:44

Title: drawing "elastic" lines
Post by: spook1 on Mon 15/03/2004 08:58:44
Hi there, again i have a question for dieas on my electricity game.

I try to preent the situation where I have an electric circuit board and plug in the componenets at obvious places. Instead I would prefer a workspace in which I can place my components at random places and connect them by flexible wires. Like the cords in "The incredible machine".
I would like to point out the starting point for a linem(click) and then draw the line to its end (click again). By checking the mouse.x and mouse.y at the clicks I can check if the wires is actually connected to a component. if not, the drawing will not take place.

I am thinking about the rawdraw functions, but I am not sure if it will work. I would have to draw the complete wiring at each cycle I am afraid.

can anyone refelct on this one?
I am not such a fast programmer that I have tried it already. If you tell me that it is not likely to succeed, i will look for other solutions..

Martijn
Title: Re:drawing "elastic" lines
Post by: RickJ on Wed 17/03/2004 16:37:57
Example 3-17-04
I debugged my first example and have listed the script below.  

//===================================================================
// AGS ROOM SCRIPT
//
// PROJECT: AGS Tutorials
//
// ROOM:    Drawing Wires
//              
// ABSTRACT:
// This is a basic wire drawing example. Operation is as follows:
//
//    Draw Wire - Press and hold left mouse button while moving
//                mouse.  Release mouse button to complete wire.
//
//    Select Wire - Position cursor over wire and left click.
//
//    Erase Wire - Position cursor over selected wire and left click.
//
// REVISION HISTORY:
// 03-17-03 RJJ   Original version
//
//===================================================================

//===================================================================
// Constant Definitions (i.e. #define)
//===================================================================
#define NONE -1
#define ALL  -2

//===================================================================
// WIRE LIST
//
// A wire list is needed to hold the coordniates of the wires/lines to
// be drawn.  The drawing of a wire requires four coordniates.  It
// would be convenient if  there were a variable type that could
// hold all four coodniates.  Since there is not such a variable type
// built-in to AGS we can make one of our own using "struct"
//
// This constant define the maximum number of wires that may be in
// the system.  The value below may be modified as needed.  The
// more wires the more work AGS has to do.  
      #define MAX_WIRES                 3
//  
// The following constant defines the normal wire color.  It is used
// to show  completed wire.
      #define  WIRE_NORMAL_COLOR        0
//  
// The following constant defines the normal wire color.  It is used
// to show a selected line.  
      #define  WIRE_SELECT_COLOR        63488
//
// The following constant defines the drawing wire color.  It is used
// to show a line that is the process of being drawn.
      #define  WIRE_DRAW_COLOR          65472
//
// The following constant defines the distance between the cursor and a
// wire when attempting to select.
      #define  WIRE_SELECT_RANGE        10
//
//===================================================================

// Create a "wire"  variable data type definition, WIRE_DEF can then
// be used as is "int", "string", "char", etc.
struct WIRE_DEF {
  int active;              // 0=don't draw, 1=draw this line
  int xcolor;              // line color
  int from_x;              // line coordinates
  int from_y;
  int to_x;
  int to_y;
  int dx;
  int dy;
  int m;
};

// Declare an array variable of type WIRE_DEF
WIRE_DEF wire[MAX_WIRES];

//===================================================================
// DrawWires
//
// Draw all the wires in the wire list, wire.  
//===================================================================
function DrawWires()
{
  int i;

  // Erase the wires first
  RawRestoreScreen();

  // Draw the wires
  i=0;
  while (i<MAX_WIRES) {
     if (wire.active) {
        RawSetColor(wire.xcolor);
        RawDrawLine(wire.from_x,
                    wire.from_y,
                    wire.to_x,
                    wire.to_y);
     }
     i++;
  }
}

//===================================================================
// EraseWire
//
// Erase the wire specified by id, the wire array index.  If
// an invalid id, such as -1, is specified then all wires are
// erased.
//===================================================================
function EraseWire(int id)
{
  int i;
  if ((id >= 0) && (id < MAX_WIRES)) {
     wire[id].active = 0;
  }
  else if (id==ALL) {
     i = 0;
     while (i<MAX_WIRES) {
        wire.active = 0;
        i++;  
     }
  }
}

//===================================================================
// WireIsSelected
//
// Return 1 if the specified wire is selected and 0 otherwise.
//
//===================================================================
function WireIsSelected(int id)
{
  int status;
 
  if ((id>=0)&&(id<MAX_WIRES)&&(wire[id].xcolor==WIRE_SELECT_COLOR)) status=1;
  else status = 0;
  return status;
}

//===================================================================
// NewWire
//
// Search the wire array for an empty slot and create a new wire
// in that slot.  The new line's start position will be set to the
// current mouse position.
//===================================================================
function NewWire()
{
  int i, id;

  // Find an empty slot
  id = NONE;
  i = 0;
  while (i<MAX_WIRES) {
     if (wire.active == 0) {
        id = i;
        i = MAX_WIRES;
     }
     i++;
  }

  // Set begin point of wire
  RefreshMouse();
  wire[id].active = 0;     //  don't make active until line length > 0
  wire[id].xcolor = WIRE_NORMAL_COLOR;
  wire[id].from_x = mouse.x;
  wire[id].from_y = mouse.y;
  wire[id].to_x   = mouse.x;
  wire[id].to_y   = mouse.y;

  // return id of new wire
  return id;
}

//===================================================================
// DragWire
//
// This function sets the specified wire's end point to the current
// mouse position.
//===================================================================
function DragWire(int id)
{
  RefreshMouse();
  if ((id >= 0) && (id < MAX_WIRES)) {
     wire[id].to_x   = mouse.x;
     wire[id].to_y   = mouse.y;
     wire[id].xcolor = WIRE_DRAW_COLOR;
     wire[id].active = 1;
  }
  else {
      Display("*** Error-DragWire, invalid id=%d specified",id);
  }
}

//===================================================================
// CompleteWire
//
// This function completes the drawing of a wire.  It sets
// the specified wire's color to normal and calculates it's
// slope.
//===================================================================
function CompleteWire(int id)
{

  if ((id >= 0) && (id < MAX_WIRES)) {
     // Calculate line's slope
     wire[id].dx = (wire[id].to_x - wire[id].from_x);
     wire[id].dy = (wire[id].to_y - wire[id].from_y);
     if (wire[id].dx!=0) wire[id].m = ((wire[id].dy * 1000) / (wire[id].dx));
     else wire[id].m = 999999;

     // Set normal color
     wire[id].xcolor = WIRE_NORMAL_COLOR;

     // Set wire active
     wire[id].active = 1;
  }
  else {
      Display("*** Error-CompleteWire, invalid id=%d specified",id);
  }
}

//===================================================================
// SelectWire
//
// This function selects the specified wire's end point to the current
// mouse position.
//===================================================================
function SelectWire(int sx, int sy)
{
  int i, id, nx, ny, y, range, valid;
  int ymax, ymin, xmax, xmin, symax, symin, sxmax, sxmin;
  string buf;
 
  // Deselect any previously selected wire, onl allow one selectionat a time
  i = 0;
  while (i<MAX_WIRES) {
     if (wire.xcolor==WIRE_SELECT_COLOR) wire.xcolor = WIRE_NORMAL_COLOR;
     i++;
  }

  // Test each of the wires to see if the point sx,sy
  // lies on or near the wire.
  id = NONE;
  i  = 0;
  while (i<MAX_WIRES) {

     // Validate selection coordinates
     valid = 1;
     if (wire.from_x > wire.to_x) {
        xmax = wire.from_x;
        xmin = wire.to_x;  
     }
     else {
        xmax = wire.to_x;
        xmin = wire.from_x;
     }
     if (wire.from_y > wire.to_y) {
        ymax = wire.from_y;
        ymin = wire.to_y;  
     }
     else {
        ymax = wire.to_y;
        ymin = wire.from_y;
     }
     sxmax = sx + WIRE_SELECT_RANGE;  
     sxmin = sx - WIRE_SELECT_RANGE;
     symax = sy + WIRE_SELECT_RANGE;
     symin = sy - WIRE_SELECT_RANGE;
 
     // Line segment fits within rectangular range of cursor
     if ((sxmax>xmax)&&(sxmin<xmin)&&(symax>ymax)&&(symin<ymin)) {
           wire.xcolor = WIRE_SELECT_COLOR;
           id = i;
           i = MAX_WIRES;
     }
     // Selection coordinates are within rectangular area
     // containing line segment
     else if ((sx<=xmax)&&(sx>=xmin)&&(sy<=ymax)&&(sy>=ymin)) {

        // Normalize selection coordinates to from_x,y
        nx = sx -  wire.from_x;
        ny = sy -  wire.from_y;

        // Calculate (y = mx+b)  for normalized coordniate system
        y = (nx * wire.m)/1000;

        // Is y within range of ny ?
        range = y-ny;
        if (range < 0) range = -range;
        if (range < WIRE_SELECT_RANGE) {
           wire.xcolor = WIRE_SELECT_COLOR;
           id = i;
           i = MAX_WIRES;
        }
     }
     i++;
  }
  return id;
}


continued ...
Title: Re:drawing "elastic" lines
Post by: RickJ on Wed 17/03/2004 16:38:34
Example (continued)

//===================================================================
// Event Handlers
//
// The following functions are to be called by AGS event handler
// routines.
//===================================================================
int new_wire, sel_wire, tmp_wire;      // Wire id
int debR, debL;                        // Mouse button debounce timers

function wire_start() {
  // Called when "Player Enters Room"
  int i;
 
  RawSaveScreen();
  new_wire=NONE;
  sel_wire=NONE;
  tmp_wire=NONE;

  i=0;
  while (i<MAX_WIRES) {
     wire.active = 0;
     i++;
  }
}

function wire_execute()
{
  int id;
  string buf;  

  // Use left button to draw a line, press left button and
  // drag mouse.  Lift button to complete line.  
  if ((IsButtonDown(LEFT)==1)&&(new_wire == -1)) {      // Mouse Down - Create a new wire
     new_wire = NewWire();
  }
  else if (IsButtonDown(LEFT)==1) {                     // Mouse Drag - Drag the wire
     DragWire(new_wire);
  }
  else if ((IsButtonDown(LEFT)==0)&&(new_wire != -1)) { // Mouse Up - Complete the wire
     CompleteWire(new_wire);
     new_wire = -1;
  }

  // Use right button to select and delete lines.  Right
  // click on a wire to selecte it.  Right click on a selected
  // wire to delete it.  Right click anywhere but the wire to
  // deselect it.
  if (IsButtonDown(RIGHT)) {  
     if ((WireIsSelected(sel_wire))&&(debR==0)) {
        EraseWire(sel_wire);
        sel_wire = NONE;
        tmp_wire = NONE;
     }
     else {
        sel_wire = SelectWire(mouse.x, mouse.y);
        debR = 10;
     }
  }
  else if (debR>0) debR--;

 
  // Update drawing changes
  DrawWires();

  // Debug messages
  StrFormat(buf,"Wire(%d) fx:%d fy:%d tx:%d ty:%d color:%d active:%d",
            id,
            wire[id].from_x,
            wire[id].from_y,
            wire[id].to_x,
            wire[id].to_y,
            wire[id].xcolor,
            wire[id].active);
  SetLabelText(0,0, buf);

  StrFormat(buf,"dx:%d dy:%d m:%d id:%d sw:%d tw:%d",
            wire[id].dx,
            wire[id].dy,
            wire[id].m, id, sel_wire, tmp_wire);
  SetLabelText(0,1, buf);
}

//===================================================================
// Event Handler Functions (i.e. function room_a())
//===================================================================
function room_a() {
 // script for room: Player enters screen (before fadein)
 GUIOff(MENU);
 wire_start();
 SetCursorMode(6);
 
}

function room_b() {
 // script for room: Repeatedly execute
 wire_execute();
}
Title: Re:drawing "elastic" lines
Post by: spook1 on Thu 18/03/2004 14:37:43
Works great!

I have it implemented in a test-game and drawing lines works just perfect.

perfect script!! And well written and easy to understand. Great job!