Connecting gaming pieces ? - RFE:1611311

For some game systems (tabletops), it is important to move models in groups while maintaining the chance to move them alone when desired.

Is there a chance to connect game pieces temporarily so that you move more of them as “one piece” ?
I hope you understand what I mean.

You can select multiple units by dragging the selection rectangle or shift-clicking on any group of pieces. Dragging any selected piece will move all selected pieces as a group. This is the only way to group pieces together and it lasts only for that move by that player.

rk

Post generated using Mail2Forum (mail2forum.com)

I know about that feature but this is multi-selecting and not connecting.

For example I cannot pivot or rotate all models as one.

Some others ideas how to realize this ?

I remember trying to do this for Napoleon’s Triumph.

What ultimately needs to happen is when a group of pieces are selected, instead of pivoting them all around their own axes, they should pivot around the central axis of the selection area. Maybe it could be added as an option for the Pivot trait?

Similarily, this feature type is also brought up by the request 1611311. We discussed this last year but did not get far

sourceforge.net/tracker/index.ph … tid=594234

There are some obstacles involved, that Brent would have to comment on.
Counters/pieces would probably need some sort of unique internal ID that Vassal can use to ‘temporarily’ allow certain ID’s be joined together and act in conjunction with each other but still be able to act independent be it stacked/non-stacked

Thus spake “bsmith”:

If this gets implemented—call it a Group—I think it should be done
either similarly to, or as a subclass of Stack. A Group soulds like a
horizontal Stack to me.


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

Being able to ‘stack’ a group of pieces and then having them act as a single large piece, rotation being one of the big ones, would be a perfect solution.

Of course this sounds a lot simpler then it would be to code in.

Yoj

Umm? You can already do this.

Provided all your pieces are stacked together of course, there is no need to select (or drag a marquee window around) every single piece and rotate it.

Instead all pieces should have a proto to control this behavior with a GKC / Trigger / Rotate trait sequence - The command would be ‘Rotate Stack/Group’ whatever.
You would then also need a stand alone Rotate trait with a different key command to rotate pieces individually

He means have the pieces ‘stacked’ side by side, not on top of each other.

Be able to select a set of counters and ‘Group’ them, so that they now keep their positions relative to each other and move as one counter until ‘ungrouped’.

Brent.

*********** REPLY SEPARATOR ***********

On 31/12/2007 at 3:53 PM Tim M wrote:


Brent Easton
Analyst/Programmer
University of Western Sydney
Email: b.easton@uws.edu.au


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

Brent,

I was looking back at some of the old emails on this back from Aug/Sep.
You mentioned the idea of a special link trait. The problem you said was not the recording or handling, but your list regarding movement.

What if this special link trait causes one of the linked pieces to act as some sort of cross combination between a layer/stack.

So you would make this link trait tell one of the pieces even though your a piece with your own unique keys/commands/properties you are also now a layer that belongs to this other piece (sort of like a super layer?) and as a super layer you follows all the rules of a regular layer like movement, to the piece you are linked to. Its sort of like joining the two pieces into one ‘uber’ piece if you follow what I mean. And would work for grouping as well I imagine.

Thing is - in making this super layer/uber piece can you still access the individual commands of each individual piece still by doing that?

I had a look at the code and also thought that a stack subclass would do it, as stack already does most of the stuff…

I’d do the following to this special stack:

  • the stack displays always expanded (but is not) while no expanded clicking on it and moving it around you would move the whole stack right?
  • when double clicked it still displays expanded (but now is as a stack technically), so you can move pices in and out (for generals, joining, etc.) or shuffle pieces around in your special stack.
  • on right click a new option r&f: you would define the file # of game pieces, the ranks will be adjusted acordingly dependandt of how many game pieces are on the stack
  • any idea how to trigger the pivot? doing it with the stack based class should be easy, but how to trigger it so it can be done on a special corner of the rank & file stack ? 4 commands for each corner?

I’ll give it a try in the next weeks, and report back here.

Any ideas on how to implement this, or generalize it, or input to the pivot center problem would be appreciated…

A subclass of Stack makes sense. Sounds like your class needs to keep track of an angle in addition to the position. Then the code to draw the stack rotates all the pieces to the same angle but doesn’t actually rotate the individual pieces until you remove them from the stack. You’ll need some kind of visual border to distinguish between “expanded” and “unexpanded” stacks, but the selection highlighter will adapt easily.

You might actually put most of the logic into a subclass of StackMetrics. It includes a method for creating new Stacks, so that when a Map uses your new StackMetrics class, pieces will clump together into an instance of your new Stack class. The logic for drawing a Stack lives in the StackMetrics class anyway, so your Stack subclass may not need any extra code other than storing the angle.

rk

Post generated using Mail2Forum (mail2forum.com)

Thank you for the input. I already started to modify (for prototype) the stackmetrics class and it does at the moment create my rank & file layout. The clue I needed was to where the configuration which metric is used is configured in. I’ll take a close look at the map.

Perhaps I can go without an extra stack (where I had the same problem of configurability… which now I know how to solve, than again…).

For pivoting, I’d like to make a command for each corner. The way I intended it to work is: push the command or hotkey, now the cursor appears on the oposite corner. The user can move the cursor up an down, while he moves the arc will get shaded (something like the range underlay I saw in warhammer 40k). in addition the arc wil display the distance ‘arced’. When the user clicks again he finishes the arc move an the pivoting is finally executed. Has something like this already been done? if not which components could I use for this effect. What bothers me is the click once, click twice behavior, can this be done in vassal?

thanx for the input, have not realized so far that stackmetrics also works as the stack factory…

I’ll post some results as soon as I have the rank& file implementation running with multiple sized game pieces (which sometimes can be the case in warhammer…)

Should be possible using Map.pushMouseListener(), which replaces the default mouse listener with another implementation, which you can later pop off. See the Pivot or FreeRotator code for examples.

rk

Post generated using Mail2Forum (mail2forum.com)

Hi,

here are classes, which support grouping. To use them create a groupmap an add a groupcommand. Enjoy!
Next Step is a GroupRotator with the described effect above.

GroupStackMetrics .java

[code]package VASSAL.counters;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;

import VASSAL.build.module.map.StackMetrics;

/**

  • GroupStackMetrics just displays the pieces as they are as we are only
  • interrested in grouping them, and not doing anything fancy with them
  • @author tmi

/
public class GroupStackMetrics extends StackMetrics {
/
*
* Fill the argument arrays with the positions, selection bounds and bounding boxes of the pieces in the argument stack
* @param parent The parent Stack
* @param positions If non-null will contain a {@link Point} giving the position of each piece in parent
* @param shapes If non-null will contain a {@link Shape} giving the shape of for each piece in parent
* @param boundingBoxes If non-null will contain a {@link Rectangle} giving the bounding box for each piece in parent
* @param x the x-location of the parent
* @param y the y-location of the parent
* @return the number of pieces processed in the stack
*/
@Override
public int getContents(Stack parent, Point[] positions, Shape[] shapes, Rectangle[] boundingBoxes, int x, int y) {
int count = parent.getMaximumVisiblePieceCount();
Point orgPos = null;

    if (positions != null) {
      count = Math.min(count, positions.length);
    }
    if (boundingBoxes != null) {
      count = Math.min(count, boundingBoxes.length);
    }
    if (shapes != null) {
      count = Math.min(count,shapes.length);
    }

    for (int index = 0; index <count>= 0)
	return new Point(before[i]);
else
	return getPosition();

}

public void insertChild(GamePiece child, int index) {
if ( child.getParent() != null) {
child.getParent().remove(child);
child.setParent(null);
}
else if (child.getMap() != null) {
child.getMap().removePiece(child);
}
lastPos = child.getPosition();
child.setParent(this);
insertPieceAt(child, index);
lastPos = null;
}

protected void insertPieceAt(GamePiece p, int index) {
if (pieceCount >= contents.length) {
GamePiece[] newContents = new GamePiece[contents.length + INCR];
System.arraycopy(contents, 0, newContents, 0, pieceCount);
contents = newContents;

  Point[] newPoints = new Point[contents.length + INCR];
  System.arraycopy(before, 0, newPoints, 0, pieceCount);
  before = newPoints;
}
for (int i = pieceCount; i > index; --i) {
  contents[i] = contents[i - 1];
  before[i] = before[i - 1];
}
contents[index] = p;
before[index] = new Point(lastPos.x-pos.x,lastPos.y-pos.y);
lastPos =null;
pieceCount++;

}

protected void removePieceAt(int index) {
if (index >= 0 && index < pieceCount) {
//set pos relative to us otherwise the piece will drop to the center of teh group :frowning:
contents[index].setPosition(new Point(pos.x +before[index].x, pos.y +before[index].y));
pieceCount–;
for (int i = index; i 1);
}
}

public void insert(GamePiece p, int pos) {
if (p == null) {
return;
}
pos = Math.max(pos, 0);
pos = Math.min(pos, pieceCount);
int index = indexOf(p);
if (index >= 0) {
if (pos > index) {
insertPieceAt(p, pos + 1);
removePieceAt(index);
}
else {
removePieceAt(index);
insertPieceAt(p, pos);
}
}
else {
insertChild(p, pos);
}
}

}
[/code]

GroupCommand.java

[code]package VASSAL.counters;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Iterator;

import VASSAL.build.GameModule;
import VASSAL.build.module.Map;
import VASSAL.build.module.map.MassKeyCommand;

/**

  • Just create a stack out of the pieces the user has selected throwing away

  • any previous stack the pieces may have belonged to.
    */
    public class GroupCommand extends MassKeyCommand {

    public void apply(Map m) {

    if(m == null)
    return;

    GamePiece[] p = m.getAllPieces();

    if(p.length <= 1)
    return;

    ArrayList selected = new ArrayList();
    //collect all selected
    for(int i=0; i

    0) {
    //collect positions before
    Point before = null;
    Point summ = new Point(0,0);
    for (int i=0; i<selected.size(); i++) {
    GamePiece s = selected.get(i);
    before = s.getPosition();
    summ.translate(before.x, before.y);
    }
    //create new group
    Group grp = new Group();
    grp.setMap(selected.get(0).getMap());
    //position group on map
    summ.x /= selected.size();
    summ.y /= selected.size();
    grp.setPosition(summ);
    System.out.println(“grp x:”+summ.x+" y:"+summ.y);
    //add to new group
    for (int i=0; i<selected.size(); i++) {
    GamePiece s = selected.get(i);
    grp.add(s);
    }

     //add group to game
     grp.getMap().addPiece(grp);
     GameModule.getGameModule().getGameState().addPiece(grp);
     grp.getMap().repaint();
    

    }
    }

    private ArrayList getSelected(Group grp) {
    ArrayList l = new ArrayList();
    GamePiece p = null;
    for(Iterator it = grp.getPiecesIterator();it.hasNext():wink: {
    p=it.next();
    if(Boolean.TRUE.equals(p.getProperty(Properties.SELECTED))) {
    l.add(p);
    }
    }
    return l;
    }

}
[/code]

GroupingMap.java

[code]package VASSAL.build.module;

import java.awt.AlphaComposite;
import java.awt.Component;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;

import VASSAL.build.module.map.StackMetrics;
import VASSAL.counters.GamePiece;
import VASSAL.counters.GroupStackMetrics;
import VASSAL.counters.Properties;
import VASSAL.counters.Stack;

public class GroupingMap extends Map {

  public StackMetrics getStackMetrics() {
	    if (metrics == null) {
	      metrics = new GroupStackMetrics();
	      metrics.build(null);
	      add(metrics);
	      metrics.addTo(this);
	    }
	    return metrics;
	  }
  
  
  public void drawPiecesInRegion(Graphics g,
          Rectangle visibleRect,
          Component c) {

if (!hideCounters) {
Graphics2D g2d = (Graphics2D) g;
Composite oldComposite = g2d.getComposite();
g2d.setComposite(
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, pieceOpacity));
GamePiece[] stack = pieces.getPieces();
for (int i = 0; i < stack.length; ++i) {
Point pt = componentCoordinates(stack[i].getPosition());
if (stack[i] instanceof Stack) {
getStackMetrics().draw(
(Stack) stack[i], pt, g, this, getZoom(), visibleRect);
}
else {
stack[i].draw(g, pt.x, pt.y, c, getZoom());
if (Boolean.TRUE.equals(stack[i].getProperty(Properties.SELECTED))) {
highlighter.draw(stack[i], g, pt.x, pt.y, c, getZoom());
}
}
}
g2d.setComposite(oldComposite);
}
}

}
[/code]

I would be eager to try a beta with this out. If it works, I’ll restart modding the fantasy module. At the moment it’s not worth the work.

Just an update to let you know, Nearly finished the GroupRotator which allows rotation of all pieces of a group around arbitrary pivot points displaying an arc for degree visualization and the length of the rotation in board units.

Any further updates on this? I could definitely use this in the DBMM module I am working on.

I’ll post a link to the source and compiled binaries in the next days…

what bothers me at the moment is that the movement messages for the single pieces just dispolay offboard as a location and not the coordinates.

I’m checking if all works fine with load/save + logging at the moment before finishing the remaining tasks.

When this is finished, I’d love to integrate it into the core engine for v3.2.

rk

Post generated using Mail2Forum (mail2forum.com)