Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (538)
Games in Android Showcase (132)
games submitted by our members
Games in WIP (600)
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  
  Fun Phys2D Hack  (Read 2197 times)
0 Members and 1 Guest are viewing this topic.
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Posted 2008-04-16 08:38:26 »

I wanted to have dynamic terrain in my game, so I created a hack for Phys2D that allows for destruction of small portions of Shapes. Basically if you've got a square and take a circle out of the edge, you get a polygonal Shape that looks like a "bite" out of a square.

The actual function I wrote appears to work, except actual implementation is very difficult, because doing this creates a huge number of artifacts. And rather than redo all the complicated geometry myself, I just convert the Shape to an Area (from java.awt.geom), then back to a Shape again after subtracting. This therefore allows you to do any and every of Area's modifications to Phys2D Shapes. But, once again, lots of artifacts when adding these shapes back into the world, especially if a shape splits into several. But it's a good experiment nonetheless, and I'll post implementation code when I actually have that working okay.

There are a few strange results here, like when cubes get turned into polygons, Phys2D treats them differently, and once you put any shape into this it comes out a polygon. So, certain shapes may act one way and then come out completely different, even though they look the same. I only want to use this on static bodies myself, so lots of these issues shouldn't matter too much for me.

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  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
package apk;

import net.phys2d.math.Vector2f;
import net.phys2d.math.ROVector2f;
import java.awt.geom.*;
import java.util.ArrayList;

/**
 * The ShapeSubtractor uses AWT's Area class to subtract pieces from Phys2D Shapes.
 * The subtracted Shape can then be manually set to match the affected Body.
 * The piece you subtract is also an AWT shape, because it would be silly to think
 * that two Phys2D Shapes could overlap. Also note that all resulting Shapes are
 * Polygons - spheres and the like are not factored. This completely ignores
 * Phys2D Line shapes, because Area doesn't work with lines.
 *
 * A potentially huge disadvantage: AWT has no float Polygons, they only
 * have integer ones. This means that point positions will be rounded slightly,
 * which graphically won't be noticeable, but can potentially cause issues.
 *
 * Also, AWT isn't the fastest thing ever as we all know. I would love if some
 * geometry wiz made their own operations for all these. I'm not said wiz. ;-)
 * @author Eli Delventhal
 */

public class ShapeSubtractor
{
   /**
    * Returns a list of Phys2D Shapes resulting from the subtract operation. The first Shape passed
    * will have the second Shape subtracted from it. It's possible this will result in a segmented
    * Shape, i.e. multiple Polygons, which is the reason for returning a list.
    * @param pos      The position of the Phys2D shape (necessary because otherwise absolutely everything is overlapping).
    * @param original   The original Phys2D Shape that is subtracted from.
    * @param subtract   The AWT Shape that is the subtractor.
    * @return         A list of all Phys2D shapes that may have resulted. These will always be Polygons.
    */

   public static ArrayList<net.phys2d.raw.shapes.Shape> subtract(ROVector2f pos, net.phys2d.raw.shapes.Shape original, java.awt.Shape subtract)
   {
      //Disallow Lines.
      if (original instanceof net.phys2d.raw.shapes.Line)
         return null;
     
      //First, convert the Phys2D Shape into an Area.
      Area o = new Area(phys2dToAwt(pos, original));
     
      //Now that we have the AWT Shape, we can use Area to do the work for us.
      o.subtract(new Area(subtract));
     
      //Now convert the AWT back to a Phys2D Shape and return it.
      return awtToPhys2d(pos, o);
   }
   
   /**
    * Returns the AWT version of the passed Phys2D Shape.
    * @param pos   The position of the Phys2D Shape.
    * @param s   The Phys2D Shape.
    * @return   The AWT Shape.
    */

   private static java.awt.Shape phys2dToAwt(ROVector2f pos, net.phys2d.raw.shapes.Shape s)
   {
      //Depending on the kind of Shape we're dealing with, return a matching result.
      if (s instanceof net.phys2d.raw.shapes.Circle)
      {
         net.phys2d.raw.shapes.Circle c = (net.phys2d.raw.shapes.Circle) s;
         return new Ellipse2D.Float(pos.getX(),pos.getY(),c.getRadius(),c.getRadius());
      }
      else if (s instanceof net.phys2d.raw.shapes.Box)
      {
         net.phys2d.raw.shapes.Box b = (net.phys2d.raw.shapes.Box) s;
         return new Rectangle2D.Float(pos.getX(),pos.getY(),b.getSize().getX(),b.getSize().getY());
      }
      else if (s instanceof net.phys2d.raw.shapes.Polygon)
      {
         net.phys2d.raw.shapes.Polygon p = (net.phys2d.raw.shapes.Polygon) s;
         ROVector2f[] verts = p.getVertices();
         int[] x = new int[verts.length];
         int[] y = new int[verts.length];
         for (int i = 0; i < verts.length; i++)
         {
            x[i] = Math.round(verts[i].getX() + pos.getX());
            y[i] = Math.round(verts[i].getY() + pos.getY());
         }
         return new java.awt.Polygon(x,y,verts.length);
      }
     
      return null;
   }
   
   /**
    * Returns the AWT version of the passed Phys2D Area.
    * @param a   The AWT Area.
    * @param pos The position of the original Shape, subtracted out this time.
    * @return   A list of the Phys2D Shape's. This will usually be one single Shape, but can be several.
    */

   private static ArrayList<net.phys2d.raw.shapes.Shape> awtToPhys2d(ROVector2f pos, Area a)
   {
      //This is significantly more complicated than the other conversion function.
      //Here, we need to scan through the path of the Area using a PathIterator.
      //Then, depending upon what we find, we can add all that to separate Polygons.
      //If the Area is multi-segmented, then more than one Shape results.
     
      //Note that this doesn't include SEG_QUADTO, etc., but that shouldn't be a problem.
      //Also note that Area's with "holes" (like a doughnut) are not properly converted. Holes are filled.
     
      ArrayList<net.phys2d.raw.shapes.Shape>polygons = new ArrayList<net.phys2d.raw.shapes.Shape>();
      ArrayList<Point2D.Float> current = new ArrayList<Point2D.Float>();
      PathIterator pi = a.getPathIterator(null);
      float [] pt = new float [6];
      while (! pi.isDone())
      {
         int code = pi.currentSegment(pt);
         
         //On a move, clear the current ArrayList and add that first point.
         if (code == PathIterator.SEG_MOVETO)
         {
            if (current.size() > 0)
               current.clear();
            current.add(new Point2D.Float(pt[0],pt[1]));
         }
         //On a close, finish off a polygon and create it.
         else if (code == PathIterator.SEG_CLOSE)
         {
            if (current.size() > 2)
            {
               //Copy the list of points over to an array, and during that time swap
               //the order so we have counter-clockwise instead of clockwise.
               Vector2f[] points = new Vector2f[current.size()];
               for (int i = current.size()-1; i >= 0; i--)
                  points[current.size()-i-1] = new Vector2f(current.get(i).x-pos.getX(),current.get(i).y-pos.getY());
               
               polygons.add(new net.phys2d.raw.shapes.Polygon(points));
            }
         }
         //On a line to, add the point to the current list.
         else if (code == PathIterator.SEG_LINETO)
         {
            current.add(new Point2D.Float(pt[0],pt[1]));
         }
         //else
         //   System.err.println("Error: Unallowed type of segment: " + code);

         pi.next ();
      }
     
      return polygons;
   }
}


Also, I would love if Kev or someone could come up with some more intelligent way of doing this and implemented it into Phys2D. I'm not good at all with Bezier curves and all that... I just already had made a function written for converting Area to Polygon, and putting destructible terrain into my current Phys2D game would be great. So I'm basically testing if it's possible.

[EDIT] Looks like maybe I've got a bug of some kind in here, although I need to test more to be sure. Some shape cuts are all hokey, while others are good. But I have a final in 13 hours I haven't studied for, so I think I'll take a more detailed look tomorrow.  Grin[/EDIT]

See my work:
OTC Software
Offline kevglass

« JGO Spiffy Duke »


Medals: 211
Projects: 24
Exp: 18 years


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #1 - Posted 2008-04-16 09:14:03 »

Yeah, it's been noted before that squares and polygon squares don't act the same, they're implemented different. Right now the solution is not to use boxes initially, always use polygons, they're pretty quick.

Kev

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.

rwatson462 (29 views)
2014-12-15 09:26:44

Mr.CodeIt (20 views)
2014-12-14 19:50:38

BurntPizza (40 views)
2014-12-09 22:41:13

BurntPizza (75 views)
2014-12-08 04:46:31

JscottyBieshaar (37 views)
2014-12-05 12:39:02

SHC (50 views)
2014-12-03 16:27:13

CopyableCougar4 (47 views)
2014-11-29 21:32:03

toopeicgaming1999 (114 views)
2014-11-26 15:22:04

toopeicgaming1999 (102 views)
2014-11-26 15:20:36

toopeicgaming1999 (30 views)
2014-11-26 15:20:08
Resources for WIP games
by kpars
2014-12-18 10:26:14

Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

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
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!