Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 5 of 5

Thread: Getting moving rectangles to attach to each other

  1. #1
    Member
    Join Date
    Sep 2013
    Posts
    36
    Thanks
    13
    Thanked 0 Times in 0 Posts

    Default Getting moving rectangles to attach to each other

    So basically this is the snake game. We want the head to create another body part that attaches to it after it eats the piece of food. We are having troubles with this, we can get the the body part to show up on the screen but not attach and follow the head. Does anyone know how to go about doing this???? Here is our code.

    import java.awt.event.*;
    import javax.swing.*;
    import java.awt.*;
    import java.util.ArrayList; 
     
    SnakeFrame - JFrame
     
    public class snakeFrame2 extends JFrame
    {
       private static final int FRAME_WIDTH = 300;
       private static final int FRAME_HEIGHT = 300;
     
       private boolean right = false;
       private boolean left = false;
       private boolean up = false;
       private boolean down = false;
       private boolean wallCollision = true;
       private boolean onBoard = true; 
       private boolean newFood = true; 
     
       private int BOX_X = 100;
       private int BOX_Y = 100;
       private int BOX_WIDTH = 10;
       private int BOX_HEIGHT = 10;
       private int Food_X;
       private int Food_Y;
       private int xyCoordinate;
       private final int RandomPosition = 20;
       private int food_WIDTH = 7;
       private int food_HEIGHT =7;
     
     
     
     
       private Rectangle box;
       private Rectangle food;
       private Rectangle body; 
     
       // calls the other classes 
       private snakeBody2 head;
     
       private Timer t;
     
     
     
       //private ArrayList<headBody> head = new ArrayList<headBody>(); 
       class KeyStrokeListener implements KeyListener
       {
     
          public void keyPressed(KeyEvent event) 
          {
             String key = KeyStroke.getKeyStrokeForEvent(event).toString().replace("pressed ", ""); 
             if (key.equals("DOWN"))
             {
                down = true;
                right = false;
                left = false;
                up = false;          
             }
             else if ( key.equals("UP"))
             {
                up = true;
                right = false;
                down = false;
                left = false;          
             }
             else if ( key.equals("LEFT"))
             {
                left = true;
                right = false;
                down = false;
                up = false;
     
             }
             else if (key.equals("RIGHT"))
             {
     
                right = true;
                left = false;
                down = false;
                up = false;          
             }
     
          }
          public void keyTyped(KeyEvent event) {}
          public void keyReleased(KeyEvent event) {
     
          }
     
       }
     
       public snakeFrame2()
       { 
          head = new snakeBody2();
          add(head);
     
          head.addKeyListener(new KeyStrokeListener());
          head.makeNewFood(); 
          head.setFocusable(true);
     
     
        final ArrayList <snakeBody2> snake = new ArrayList<snakeBody2>();
     
        class TimerListener implements ActionListener
        {
     
          public void actionPerformed(ActionEvent event)
          {
            if (left == true)
                head.moveRectangleBy(-10, 0); 
            if (right == true)
                head.moveRectangleBy(10, 0);
            if (up == true)
                head.moveRectangleBy(0, -10);    
            if (down == true)
                head.moveRectangleBy(0, 10); 
     
          // checks collision for head and frame height
          if( head.getBox_X()> FRAME_HEIGHT)
             onBoard = false; 
     
          else if (head.getBox_X() < 0)
             onBoard = false; 
     
          else if(head.getBox_Y() > FRAME_WIDTH)
             onBoard = false;
     
          else if(head.getBox_Y() < 0)
             onBoard = false; 
     
          if(onBoard == false)
             System.out.println("Collision"); 
     
          else  if(onBoard == true)
          {
             //System.out.println("On Board"); 
          }
     
           Rectangle body = new Rectangle(head.getBox_X(), head.getBox_Y(), 10, 10);
           Rectangle foodRec = new Rectangle(head.getFood_X(), head.getFood_Y(), 7, 7);  
     
            if(body.intersects(foodRec))
            {
             newFood = false; 
            } 
     
           if (newFood == false)
           {
                head.makeNewFood();
                head.newBody(head.getBox_X(), head.getBox_Y(),head.getBoxWidth(), head.getBoxHeight());   
                //snake.add(new snakeBody2(head.getBox_X(), head.getBox_Y(), head.getBoxWidth(), head.getBoxHeight())); 
                repaint();  
                newFood = true;   
           }             
         }   
       }
     
          TimerListener listener2 = new TimerListener();
     
          final int DELAY = 249; 
          t = new Timer(DELAY, listener2);
          t.start(); 
     
     
          setSize(FRAME_WIDTH, FRAME_HEIGHT);
       }  
     
     
    }

    Snake Body - JComponent
    import java.awt.event.*;
    import javax.swing.*;
    import java.awt.*;
     
     
    public class snakeBody2 extends JComponent
    {
       private int Head_X = 100;
       private int Head_Y = 100;
       private int Head_X2;
       private int Head_Y2; 
       private int Head_WIDTH = 10;
       private int Head_HEIGHT = 10;
       private int Body_X;
       private int Body_Y;
       private int Food_X;
       private int Food_Y;
       private int xyCoordinate;
       private final int RandomPosition = 20;
       private int food_WIDTH = 7;
       private int food_HEIGHT =7;
     
       private int count = 0; 
     
     
     
     
       private Rectangle head;
       private Rectangle food;
     
       private Rectangle test; 
       private Rectangle[] body = new Rectangle[900]; 
     
       public snakeBody2()
       { 
          //Rectangle[] box = new Rectangle[900];  
          head = new Rectangle(Head_X, Head_Y, Head_WIDTH, Head_HEIGHT); 
          //repaint();         
       }
     
      /*
       public snakeBody2(int BOX_X, int BOX_Y, int BOX_WIDTH,int BOX_HEIGHT)
       {  
          //body = new Rectangle(BOX_X, BOX_Y, BOX_WIDTH, BOX_HEIGHT); 
          Rectangle[] boxTest = new Rectangle[900];  
     
          repaint(); 
       } */ 
     
     
     
       public void newBody(int Head_X,int Head_Y,int Head_WIDTH,int Head_HEIGHT)
       {
          findBody(); 
          body[count] = new Rectangle(Head_X2, Head_Y2, Head_WIDTH,Head_HEIGHT);
          count++; 
          repaint(); 
          //test = new Rectangle(BOX_X2, BOX_Y2, BOX_WIDTH, BOX_HEIGHT);
       } 
       public void makeNewFood()
       {  
          findFood(); 
          food = new Rectangle(Food_X, Food_Y, food_WIDTH, food_HEIGHT);
          repaint(); 
     
       }
     
       public void findFood()
       {
          xyCoordinate = (int) (Math.random() * RandomPosition); 
          Food_X = xyCoordinate *10 ;
          xyCoordinate = (int) (Math.random() * RandomPosition); 
          Food_Y = xyCoordinate * 10; 
       }
          public void findBody()
       {
          Head_X2 = Head_X;
          Head_Y2 = Head_Y + 10 ;
     
       }
     
     
       public void paintComponent(Graphics g)
       {  
     
          //super.paintComponent(g); 
          Graphics2D g2 = (Graphics2D) g;
          g2.draw(food);
          g2.setColor(Color.BLUE);
          g2.fill(food);  
          repaint(); 
     
          Graphics2D g3 = (Graphics2D) g;
          g3.draw(head);
          g3.setColor(Color.GREEN);
          g3.fill(head);
     
     
     
          Graphics2D g4 = (Graphics2D) g;
         // for statement to check the length of the array. If less than array draw box
          for ( int i = 0; i < count; i++) 
          {
          g4.draw(body[i]);
          g4.setColor(Color.GREEN);
          g4.fill(body[i]);
          }
     
     
       }
     
       // used to move the rectangle
       //Box x + dx allows us to recognize where the coordinates of the box have moved to after the translation
       public void moveRectangleBy(int dx, int dy)
       {
          Head_X = Head_X + dx;
          Head_Y = Head_Y + dy;
          head.translate(dx, dy);
         /* body[count].translate(dx, dy);
          for(int i = count; i < body.length; i--)
          {
          Body_X = Head_X + dx;
          Body_Y = Head_Y + dy;
          }*/
          repaint();      
       }
     
       public int getBox_Y()
       {
          return Head_Y;
     
       }
     
       public int getBox_X()
       {
          return Head_X; 
       }
     
       public int getBoxWidth()
       {
          return Head_WIDTH; 
       }
     
       public int getBoxHeight()
       {
          return Head_HEIGHT; 
       }
     
       public int getFood_X()
       {
          return Food_X;
       }
     
       public int getFood_Y()
       {
          return Food_Y;
       }
       public int getFoodWidth()
       {
          return food_WIDTH;
       }
       public int getFoodHeight()
       {
          return food_HEIGHT;
       }
       public int getBox_Y2()
       {
          return Head_Y2;
       }
       public int getBox_X2()
       {
          return Head_Y2;
       }

    SnakeViewer

    import java.awt.event.*;
    import javax.swing.*;
    import java.awt.*;
     
     
    public class snakeViewer2
    {  
       public static void main(String[] args)
       {   
          final JFrame frame = new snakeFrame2();
     
     
          JMenuBar menuBar = new JMenuBar();     
          frame.setJMenuBar(menuBar);
          //Make the menu
          JMenu menu = new JMenu("File");
          //create and add menuItems to menu
          final JMenuItem newItem = new JMenuItem("New Game");   
          final JMenuItem exitItem = new JMenuItem("Exit");      
          menu.add(newItem);
          menu.add(exitItem);
          menuBar.add(menu); //add menu to menuBar
     
          class MenuItemListener implements ActionListener
          {
             public void actionPerformed(ActionEvent event)
             {
                if(event.getSource() == newItem )
                   System.exit(0);
                else if(event.getSource() == exitItem )
                  System.exit(99);
     
             }
          }    
          //Make listener and register sources to listener
          ActionListener listener = new MenuItemListener();
          newItem.addActionListener(listener);      
          exitItem.addActionListener(listener);     
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setVisible(true);
       }
    }

    This is a tremendous amount of code to go through. Here is the part we believe we are messing up or don't know how to approach

       public void moveRectangleBy(int dx, int dy)
       {
          Head_X = Head_X + dx;
          Head_Y = Head_Y + dy;
          head.translate(dx, dy);
         /* body[count].translate(dx, dy);
          for(int i = count; i < body.length; i--)
          {
          Body_X = Head_X + dx;
          Body_Y = Head_Y + dy;
          }*/
          repaint();      
       }

    Again we are trying to get the body parts to follow along with the snake head. We go it to place by the coordinates where the food and snake intersect but cant get it to attach or follow the snake head. Thanks in advance


  2. #2
    Super Moderator Norm's Avatar
    Join Date
    May 2010
    Location
    Eastern Florida
    Posts
    22,265
    Thanks
    56
    Thanked 2,372 Times in 2,343 Posts

    Default Re: Getting moving rectangles to attach to each other

    What does "attach" mean in coding terms? How does the code define it? Specifically when the snake is moving in a direction, how are its sections kept together? What about when it turns a corner?

    The sad thing about all this code is that there are only 3 comments in it explaining the logic or reasons for the way it is coded.
    If you don't understand my answer, don't ignore it, ask a question.

  3. #3
    Member
    Join Date
    Sep 2013
    Posts
    36
    Thanks
    13
    Thanked 0 Times in 0 Posts

    Default Re: Getting moving rectangles to attach to each other

    That's what we're are trying to do in our code. As of right now there is no code that would attach these together except for what we are trying in the moveRectangle method which is obviously wrong because it doesn't work. So we don't know how to define this or code it up because we've never done anything like this. So if the snake is moving a directions we don't know how the sections will be kept together because we cant even get the sections to attach to each other where one rectangle would follow the other rectangle? If that makes sense I don't have a complete grasp on the concepts yet just started coding 2 months ago.

  4. #4
    Super Moderator Norm's Avatar
    Join Date
    May 2010
    Location
    Eastern Florida
    Posts
    22,265
    Thanks
    56
    Thanked 2,372 Times in 2,343 Posts

    Default Re: Getting moving rectangles to attach to each other

    Define a class that holds the info about the body parts of the snake and the direction it is moving. Give that class a draw method that will draw the parts of the snake as you want to see them. Start with a simple test scheme that just draws a snake with two parts. Have it move in one direction.
    Then work on the logic to have it move around a corner.
    Then work on having it respond to the keypresses.
    If you don't understand my answer, don't ignore it, ask a question.

  5. The Following User Says Thank You to Norm For This Useful Post:

    GoodbyeWorld (December 13th, 2013)

  6. #5
    Member GoodbyeWorld's Avatar
    Join Date
    Jul 2012
    Location
    Hidden command post deep within the bowels of a hidden bunker somewhere under a nondescrip building
    Posts
    383
    My Mood
    Angry
    Thanks
    46
    Thanked 63 Times in 63 Posts

    Default Re: Getting moving rectangles to attach to each other

    Quote Originally Posted by Edmacelroy View Post
    So basically this is the snake game. We want the head to create another body part that attaches to it after it eats the piece of food. We are having troubles with this, we can get the the body part to show up on the screen but not attach and follow the head. Does anyone know how to go about doing this???? Here is our code.

    import java.awt.event.*;
    import javax.swing.*;
    import java.awt.*;
    import java.util.ArrayList; 
     
    SnakeFrame - JFrame
     
    public class snakeFrame2 extends JFrame
    {
       private static final int FRAME_WIDTH = 300;
       private static final int FRAME_HEIGHT = 300;
     
       private boolean right = false;
       private boolean left = false;
       private boolean up = false;
       private boolean down = false;
       private boolean wallCollision = true;
       private boolean onBoard = true; 
       private boolean newFood = true; 
     
       private int BOX_X = 100;
       private int BOX_Y = 100;
       private int BOX_WIDTH = 10;
       private int BOX_HEIGHT = 10;
       private int Food_X;
       private int Food_Y;
       private int xyCoordinate;
       private final int RandomPosition = 20;
       private int food_WIDTH = 7;
       private int food_HEIGHT =7;
     
     
     
     
       private Rectangle box;
       private Rectangle food;
       private Rectangle body; 
     
       // calls the other classes 
       private snakeBody2 head;
     
       private Timer t;
     
     
     
       //private ArrayList<headBody> head = new ArrayList<headBody>(); 
       class KeyStrokeListener implements KeyListener
       {
     
          public void keyPressed(KeyEvent event) 
          {
             String key = KeyStroke.getKeyStrokeForEvent(event).toString().replace("pressed ", ""); 
             if (key.equals("DOWN"))
             {
                down = true;
                right = false;
                left = false;
                up = false;          
             }
             else if ( key.equals("UP"))
             {
                up = true;
                right = false;
                down = false;
                left = false;          
             }
             else if ( key.equals("LEFT"))
             {
                left = true;
                right = false;
                down = false;
                up = false;
     
             }
             else if (key.equals("RIGHT"))
             {
     
                right = true;
                left = false;
                down = false;
                up = false;          
             }
     
          }
          public void keyTyped(KeyEvent event) {}
          public void keyReleased(KeyEvent event) {
     
          }
     
       }
     
       public snakeFrame2()
       { 
          head = new snakeBody2();
          add(head);
     
          head.addKeyListener(new KeyStrokeListener());
          head.makeNewFood(); 
          head.setFocusable(true);
     
     
        final ArrayList <snakeBody2> snake = new ArrayList<snakeBody2>();
     
        class TimerListener implements ActionListener
        {
     
          public void actionPerformed(ActionEvent event)
          {
            if (left == true)
                head.moveRectangleBy(-10, 0); 
            if (right == true)
                head.moveRectangleBy(10, 0);
            if (up == true)
                head.moveRectangleBy(0, -10);    
            if (down == true)
                head.moveRectangleBy(0, 10); 
     
          // checks collision for head and frame height
          if( head.getBox_X()> FRAME_HEIGHT)
             onBoard = false; 
     
          else if (head.getBox_X() < 0)
             onBoard = false; 
     
          else if(head.getBox_Y() > FRAME_WIDTH)
             onBoard = false;
     
          else if(head.getBox_Y() < 0)
             onBoard = false; 
     
          if(onBoard == false)
             System.out.println("Collision"); 
     
          else  if(onBoard == true)
          {
             //System.out.println("On Board"); 
          }
     
           Rectangle body = new Rectangle(head.getBox_X(), head.getBox_Y(), 10, 10);
           Rectangle foodRec = new Rectangle(head.getFood_X(), head.getFood_Y(), 7, 7);  
     
            if(body.intersects(foodRec))
            {
             newFood = false; 
            } 
     
           if (newFood == false)
           {
                head.makeNewFood();
                head.newBody(head.getBox_X(), head.getBox_Y(),head.getBoxWidth(), head.getBoxHeight());   
                //snake.add(new snakeBody2(head.getBox_X(), head.getBox_Y(), head.getBoxWidth(), head.getBoxHeight())); 
                repaint();  
                newFood = true;   
           }             
         }   
       }
     
          TimerListener listener2 = new TimerListener();
     
          final int DELAY = 249; 
          t = new Timer(DELAY, listener2);
          t.start(); 
     
     
          setSize(FRAME_WIDTH, FRAME_HEIGHT);
       }  
     
     
    }

    Snake Body - JComponent
    import java.awt.event.*;
    import javax.swing.*;
    import java.awt.*;
     
     
    public class snakeBody2 extends JComponent
    {
       private int Head_X = 100;
       private int Head_Y = 100;
       private int Head_X2;
       private int Head_Y2; 
       private int Head_WIDTH = 10;
       private int Head_HEIGHT = 10;
       private int Body_X;
       private int Body_Y;
       private int Food_X;
       private int Food_Y;
       private int xyCoordinate;
       private final int RandomPosition = 20;
       private int food_WIDTH = 7;
       private int food_HEIGHT =7;
     
       private int count = 0; 
     
     
     
     
       private Rectangle head;
       private Rectangle food;
     
       private Rectangle test; 
       private Rectangle[] body = new Rectangle[900]; 
     
       public snakeBody2()
       { 
          //Rectangle[] box = new Rectangle[900];  
          head = new Rectangle(Head_X, Head_Y, Head_WIDTH, Head_HEIGHT); 
          //repaint();         
       }
     
      /*
       public snakeBody2(int BOX_X, int BOX_Y, int BOX_WIDTH,int BOX_HEIGHT)
       {  
          //body = new Rectangle(BOX_X, BOX_Y, BOX_WIDTH, BOX_HEIGHT); 
          Rectangle[] boxTest = new Rectangle[900];  
     
          repaint(); 
       } */ 
     
     
     
       public void newBody(int Head_X,int Head_Y,int Head_WIDTH,int Head_HEIGHT)
       {
          findBody(); 
          body[count] = new Rectangle(Head_X2, Head_Y2, Head_WIDTH,Head_HEIGHT);
          count++; 
          repaint(); 
          //test = new Rectangle(BOX_X2, BOX_Y2, BOX_WIDTH, BOX_HEIGHT);
       } 
       public void makeNewFood()
       {  
          findFood(); 
          food = new Rectangle(Food_X, Food_Y, food_WIDTH, food_HEIGHT);
          repaint(); 
     
       }
     
       public void findFood()
       {
          xyCoordinate = (int) (Math.random() * RandomPosition); 
          Food_X = xyCoordinate *10 ;
          xyCoordinate = (int) (Math.random() * RandomPosition); 
          Food_Y = xyCoordinate * 10; 
       }
          public void findBody()
       {
          Head_X2 = Head_X;
          Head_Y2 = Head_Y + 10 ;
     
       }
     
     
       public void paintComponent(Graphics g)
       {  
     
          //super.paintComponent(g); 
          Graphics2D g2 = (Graphics2D) g;
          g2.draw(food);
          g2.setColor(Color.BLUE);
          g2.fill(food);  
          repaint(); 
     
          Graphics2D g3 = (Graphics2D) g;
          g3.draw(head);
          g3.setColor(Color.GREEN);
          g3.fill(head);
     
     
     
          Graphics2D g4 = (Graphics2D) g;
         // for statement to check the length of the array. If less than array draw box
          for ( int i = 0; i < count; i++) 
          {
          g4.draw(body[i]);
          g4.setColor(Color.GREEN);
          g4.fill(body[i]);
          }
     
     
       }
     
       // used to move the rectangle
       //Box x + dx allows us to recognize where the coordinates of the box have moved to after the translation
       public void moveRectangleBy(int dx, int dy)
       {
          Head_X = Head_X + dx;
          Head_Y = Head_Y + dy;
          head.translate(dx, dy);
         /* body[count].translate(dx, dy);
          for(int i = count; i < body.length; i--)
          {
          Body_X = Head_X + dx;
          Body_Y = Head_Y + dy;
          }*/
          repaint();      
       }
     
       public int getBox_Y()
       {
          return Head_Y;
     
       }
     
       public int getBox_X()
       {
          return Head_X; 
       }
     
       public int getBoxWidth()
       {
          return Head_WIDTH; 
       }
     
       public int getBoxHeight()
       {
          return Head_HEIGHT; 
       }
     
       public int getFood_X()
       {
          return Food_X;
       }
     
       public int getFood_Y()
       {
          return Food_Y;
       }
       public int getFoodWidth()
       {
          return food_WIDTH;
       }
       public int getFoodHeight()
       {
          return food_HEIGHT;
       }
       public int getBox_Y2()
       {
          return Head_Y2;
       }
       public int getBox_X2()
       {
          return Head_Y2;
       }

    SnakeViewer

    import java.awt.event.*;
    import javax.swing.*;
    import java.awt.*;
     
     
    public class snakeViewer2
    {  
       public static void main(String[] args)
       {   
          final JFrame frame = new snakeFrame2();
     
     
          JMenuBar menuBar = new JMenuBar();     
          frame.setJMenuBar(menuBar);
          //Make the menu
          JMenu menu = new JMenu("File");
          //create and add menuItems to menu
          final JMenuItem newItem = new JMenuItem("New Game");   
          final JMenuItem exitItem = new JMenuItem("Exit");      
          menu.add(newItem);
          menu.add(exitItem);
          menuBar.add(menu); //add menu to menuBar
     
          class MenuItemListener implements ActionListener
          {
             public void actionPerformed(ActionEvent event)
             {
                if(event.getSource() == newItem )
                   System.exit(0);
                else if(event.getSource() == exitItem )
                  System.exit(99);
     
             }
          }    
          //Make listener and register sources to listener
          ActionListener listener = new MenuItemListener();
          newItem.addActionListener(listener);      
          exitItem.addActionListener(listener);     
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setVisible(true);
       }
    }

    This is a tremendous amount of code to go through. Here is the part we believe we are messing up or don't know how to approach

       public void moveRectangleBy(int dx, int dy)
       {
          Head_X = Head_X + dx;
          Head_Y = Head_Y + dy;
          head.translate(dx, dy);
         /* body[count].translate(dx, dy);
          for(int i = count; i < body.length; i--)
          {
          Body_X = Head_X + dx;
          Body_Y = Head_Y + dy;
          }*/
          repaint();      
       }

    Again we are trying to get the body parts to follow along with the snake head. We go it to place by the coordinates where the food and snake intersect but cant get it to attach or follow the snake head. Thanks in advance
    So, you got it to draw the food then? That was the issue in your other thread.

    Anyway, all your head would need to care about was the one after it. The same thing for the one after the head. And the same all the way down to the tail, which wouldn't care about anything.
    If you stored where a part ended, it would know where to latch onto when you added the next part. Now, does your snake only move four directions (Left, Right, Up, Down) or can it move sideways?
    JavaScript is NOT Java.

Similar Threads

  1. Rectangles
    By Skybear in forum What's Wrong With My Code?
    Replies: 3
    Last Post: May 27th, 2013, 07:46 PM
  2. Help With Moving A 2D Array Of Rectangles
    By billg118 in forum Collections and Generics
    Replies: 1
    Last Post: April 22nd, 2012, 03:23 PM
  3. Question on Rectangles
    By parkBENch in forum Java Theory & Questions
    Replies: 1
    Last Post: March 22nd, 2012, 12:13 AM
  4. Replies: 1
    Last Post: March 18th, 2012, 01:16 PM
  5. java GMAIL smtp with attach
    By Jhovarie in forum File I/O & Other I/O Streams
    Replies: 3
    Last Post: October 10th, 2011, 11:11 AM