Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (498)
Games in Android Showcase (117)
games submitted by our members
Games in WIP (563)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Theoretical Solitaire Design Questions :)  (Read 782 times)
0 Members and 1 Guest are viewing this topic.
Offline Eyesackery

Junior Member


Medals: 1



« Posted 2013-03-01 02:30:21 »

Hi guys!

In my spare time I have been designing the classes for a Solitaire game I am hoping to program on the weekend. However I'm stuck on a particular problem.

Does anyone have any suggestions as to how to implement the 'drag-ability', of the solitaire cards, more how to distinguish between a card on the top of the stack, versus a card lower down the stack. Basically I'm stuck on how to deal with each card individually according to their position within the solitaire stack.

My initial solution was to have the Card class extend JComponent so I could determine when the mouse was within each component, or 'card', then handle them appropriately according to the mouse movement.

There must be a simpler way? If anyone has any suggestions I would be very very appreciative Smiley
Offline masteryoom

JGO Coder


Medals: 5
Projects: 2


If you look closely, you might see it turning...


« Reply #1 - Posted 2013-03-01 06:54:01 »

I think you could make a variable that is like numberOnStack where If 0 then if mouse touching reveal and a function that goes when dragged all the other cards have their variable decreased...

Smiley
Offline nerb
« Reply #2 - Posted 2013-03-01 08:52:04 »

I'd hold each card in a stack in an array. And for each card within the stack, calculate its 'visible/clickable extent', i.e. the top of the card poking out from within the stack, which could be stored as a Rectangle (this may be constant, or adjust dependant on the number of cards in the stack).

When you click on a stack, check which card's visible extent contains the click, by iterating through the cards in the stack array.

You could then use its array index to handle all cards above it. I.e. if a stack contains 13 cards, where stack.cards[0] is the card at the bottom of the stack, and stack.cards[12] is the topmost card, if your click detection determined you've clicked on stack.cards[8], then you apply the drag event to all cards from stack.cards[8] through to stack.cards[12].

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Eyesackery

Junior Member


Medals: 1



« Reply #3 - Posted 2013-03-01 08:58:10 »

I'd hold each card in a stack in an array. And for each card within the stack, calculate its 'visible/clickable extent', i.e. the top of the card poking out from within the stack, which could be stored as a Rectangle (this may be constant, or adjust dependant on the number of cards in the stack).

When you click on a stack, check which card's visible extent contains the click, by iterating through the cards in the stack array.

You could then use its array index to handle all cards above it. I.e. if a stack contains 13 cards, where stack[0] is the card at the bottom of the stack, and stack[12] is the topmost card, if your click detection determined you've clicked on stack[8], then you apply the drag event to all cards from stack[8] through to stack[12].



Yeah man, I was thinking that too (the clickable top rectangle), it seems like the most logical solution. You could handle the clickable areas sort of like tabs within the stack group, and like you said, they would lead the movement of the remainder of the stack.

I think I might go with this solution unless anyone else has a more efficient approach Smiley Plan to post the source code here when it's done (hopefully over the weekend).

Yay programming!  Grin
Offline Eyesackery

Junior Member


Medals: 1



« Reply #4 - Posted 2013-03-02 01:09:13 »

Not sure why my drag controller class is working Sad If someone could help me out that would be AWESOME!!!  Grin

(made a test project to play around with the drag controller class)

EDIT: Sorry for the double post!

MAIN SOLITAIRE CLASS:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Solitaire extends JPanel {

   private static final long serialVersionUID = 1L;
   
   private final static int GAME_WIDTH = 900;
   private final static int GAME_HEIGHT = GAME_WIDTH / 16 * 9;
   
   private JFrame frame;
   private Card card;
   
   private ArrayList<Card> cards = new ArrayList<Card>();
   
   public Solitaire() {
      this.setPreferredSize(new Dimension(GAME_WIDTH, GAME_HEIGHT));
      this.setFocusable(true);
      this.setVisible(true);
     
      frame = new JFrame();
     
      card = new Card();
   }
   
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2d = (Graphics2D)g;
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
     
      card.draw(g2d);
   }
   
   public static void main(String[] args) {
      Solitaire game = new Solitaire();

      game.frame.setResizable(false);
      game.frame.add(game);
      game.frame.pack();
      game.frame.setLocationRelativeTo(null);
      game.frame.setVisible(true);
      game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
     
   }

}


CARD CLASS:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
package com.eternalgames.javasolitaire;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;

import javax.swing.JComponent;

public class Card extends JComponent{
   
   private static final long serialVersionUID = 1L;

   private DragController dragController;
   
   private final int CARD_WIDTH = 100;
   private final int CARD_HEIGHT = 150;
   
   public int x = 0;
   public int y = 0;
   
   public Card() {
      dragController = new DragController(this);
   }
   
   public void draw(Graphics2D g2d) {
      g2d.setColor(Color.red);
      g2d.fillRect(x, y, CARD_WIDTH, CARD_HEIGHT);
   }

   public void setCardPos(int x, int y) {
      this.x = x;
      this.y = y;
   }
   
   @Override
   public Dimension getSize() {
      return new Dimension(CARD_WIDTH, CARD_HEIGHT);
   }
}


DRAG CONTROLLER CLASS:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
package com.eternalgames.javasolitaire;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;

import javax.swing.event.MouseInputAdapter;

public class DragController extends MouseInputAdapter {
   
   private Card card;
   
   private Point offset = new Point();
   private boolean dragging = false;
   
   public DragController(Card card) {
      this.card = card;
     
      card.addMouseListener(this);
      card.addMouseMotionListener(this);
   }

   public void mousePressed(MouseEvent e) {
      Point p = e.getPoint();
      Rectangle r = new Rectangle(card.getSize());
     
      if (r.contains(p)) {
         offset.x = p.x - r.x;
         offset.y = p.y - r.y;
         dragging = true;
      }
   }
   
   public void mouseReleased(MouseEvent e) {
      dragging = false;
   }
   
   public void mouseDragged(MouseEvent e) {
      if (dragging) {
         int x = e.getX() - offset.x;
         int y = e.getY() - offset.y;
         card.setCardPos(x, y);
      }
   }
}
Offline nerb
« Reply #5 - Posted 2013-03-02 05:41:45 »

Howdy,

It's not working because you treat the card as a JComponent, but you never actually add the card to a parent component. Hence even though you are drawing it, its not actually 'there' for click detection etc.

I'd also suggest that you don't do all that initialization within the main() method. That can all be moved to the Solitaire constructor.

Perhaps others would disagree with me, but I'm not too keen on your design here; using JComponents, having individual 'drag handlers' for each card etc. I'd use a single instance of a MouseInputListener, and handle everything from there.

Here's something I ripped up quickly, which is roughly how I would do the same thing:

Main Solitaire class:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
package solitaire;

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.util.*;

public class Solitaire implements MouseInputListener {
   
    ArrayList<Card> cards = new ArrayList<>();
   
    JFrame frame;
    SolitairePanel panel;
   
    int screenWidth = 800;
    int screenHeight = 600;
   
    //variables for card selection
   boolean cardSelected;
    Card selectedCard;
    Point lastPosition = new Point();
   
    Solitaire() {
       
        //Setting up the display
       frame = new JFrame();
        panel = new SolitairePanel(screenWidth, screenHeight, this);
        panel.addMouseListener(this);
        panel.addMouseMotionListener(this);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
       
        //Adding some cards
       cards.add(new Card(50,50));
        cards.add(new Card(200, 200));
       
    }
   
    /**
     * @param args the command line arguments
     */

    public static void main(String[] args) {
        Solitaire solitaire = new Solitaire();
        solitaire.go();
    }
   
    public void go(){
       
        //Bad loop just for demonstration.
       while(true){
            frame.repaint();
            try {
                Thread.sleep(16);
            } catch (Exception ex) {
               
            }
        }
    }

    @Override
    public void mousePressed(MouseEvent me) {
       
        for(int x = 0; x < cards.size(); x++) {
            if(cards.get(x).bounds.contains(me.getPoint())) {
                this.cardSelected = true;
                selectedCard = cards.get(x);
                lastPosition.setLocation(me.getPoint());
                break;
            }
        }    
    }

    @Override
    public void mouseDragged(MouseEvent me) {

        if(cardSelected){
            selectedCard.move((int)(me.getX() - lastPosition.getX()), (int)(me.getY() - lastPosition.getY()));
        }
       
        lastPosition.setLocation(me.getPoint());
    }
   
     @Override
    public void mouseReleased(MouseEvent me) {
       
         //NOTE: you would probably check if the card move is valid here. If so, update game, stacks, bounds etc. If not, return card to original position.
        if(cardSelected) {
            selectedCard.updateBounds();
            cardSelected = false;
         }      
    }  
   
     
     //Following methods aren't used.
   
    @Override
    public void mouseClicked(MouseEvent me) {}
   
    @Override
    public void mouseMoved(MouseEvent me) {}
   
    @Override
    public void mouseEntered(MouseEvent me) {}

    @Override
    public void mouseExited(MouseEvent me) {}
}


SolitairePanel - for drawing etc.:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
package solitaire;

import java.awt.*;
import javax.swing.*;

public class SolitairePanel extends JPanel {
   
    Solitaire game;
    int width;
    int height;
   
    SolitairePanel(int width, int height, Solitaire game) {
        this.game = game;  
        this.width = width;
        this.height = height;
        this.setPreferredSize(new Dimension(width, height));
    }
   
    @Override
    public void paint(Graphics g) {

        g.setColor(Color.black);
        g.fillRect(0, 0, width, height);
       
        for(int x = 0; x < game.cards.size(); x++) {
            game.cards.get(x).render(g);
        }
       
    }
}



Card class:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
package solitaire;

import java.awt.*;

public class Card {
   
    int width = 120;
    int height = 150;
   
    int xPos;
    int yPos;
   
    Rectangle bounds;
   
    Card(int xPos, int yPos) {
        this.xPos = xPos;
        this.yPos = yPos;
        bounds = new Rectangle(xPos, yPos, width, height);
    }
   
    //Move the card by setting the offset from its current position.
   public void move(int xOffset, int yOffset) {
       
        xPos += xOffset;
        yPos += yOffset;
       
    }
   
    //Update the bounds of the card, so that it can be selected.
   public void updateBounds() {
        bounds.setBounds(xPos, yPos, width, height);
    }
   
    public void render(Graphics g) {
        g.setColor(Color.red);
        g.fillRect(xPos, yPos, width, height);
        g.setColor(Color.blue);
        g.drawRect(xPos, yPos, width, height);
    }
}


Hope this helps!
Offline Eyesackery

Junior Member


Medals: 1



« Reply #6 - Posted 2013-03-03 09:25:32 »

Hey Nerb, thank you for taking the time to write me that detailed response, you are a legend! I actually learned a few things by your post, one of those 'click' moments, which is awesome!  Grin


Offline nerb
« Reply #7 - Posted 2013-03-04 05:53:28 »

No problemos! Good to hear.  Smiley
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Grunnt (18 views)
2014-09-23 14:38:19

radar3301 (14 views)
2014-09-21 23:33:17

BurntPizza (31 views)
2014-09-21 02:42:18

BurntPizza (22 views)
2014-09-21 01:30:30

moogie (20 views)
2014-09-21 00:26:15

UprightPath (29 views)
2014-09-20 20:14:06

BurntPizza (33 views)
2014-09-19 03:14:18

Dwinin (48 views)
2014-09-12 09:08:26

Norakomi (75 views)
2014-09-10 13:57:51

TehJavaDev (105 views)
2014-09-10 06:39:09
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!