What do you think of my 3d collision idea?

For a sideview/top down game, Does it sound silly to hand draw simple 2d polygons for collision detection, to accompany my models? … Or preferably, is there some way to generate a cross section of a model or level, and use that sheet of 2d polygons for collision detection? … Since I am limiting the player to 2d movement, makes sense not to run detection in 3d.

Yea, I think that’s generally what folks do. If there’s no possibility of collision in the 3rd dimension, why bother checking?

Bounding rectangle or bounding circle collision is probably all you need. You can use something like a QuadTree to get the objects near you to see if you should even bother checking that :slight_smile:

The trick though is for terrain that meets the feet, which could be all sorts of advanced 3d geometry and gentle slopes and hills… It would just be sweet to be able to generate a 2d cross section at a specified depth. so I wouldn’t have to hand draw them :-)… I think I can actually DO that in blender using a plane, and just removing or cutting out the 3d stuff… hmmm… Those 2d sheets would be easy to trace if nothing else.

Or i could just color scan it for pixel collision instead of geometry… hmmmmm
advice?

Yea, in that case it might be easier to just make a simple editor (or extend any existing one you have) to edit a collision layer. Then draw rectangles to block off the places players shouldn’t be able to go. Lots of engines do this since it’s usually cheaper.

Automating it might be more of a challenge, but it depends on what your maps look like. It’s probably not that difficult to use the height of your terrain at intervals (or change in height) to determine what’s passable and what’s not, but then building out simple collision shapes from that becomes more complex.

Though as you said, if you just generate that as a black and white image, then draw your collision shapes on top of that as a guide, it might be easy.

Lots of options :slight_smile:

I had some old code that did that , see if you can make it work again. At the very least it will give you the general idea.


    struct TriangleIndices32
    {
        public Int32 A, B, C;
        public int VertexStride { get { return (sizeof(Int16)) * 3; } }

        public override string ToString()
        {
            return String.Format("A:{0,4} B:{1,4} C:{2,4}", A, B, C);
        }
    }

    struct TriangleIndices16
    {
        public Int16 A, B, C;
        public int VertexStride { get { return (sizeof(Int16)) * 3; } }

        public static TriangleIndices32 operator +(TriangleIndices16 left, int value)
        {
            TriangleIndices32 result;
            result.A = (Int32)(left.A + value);
            result.B = (Int32)(left.B + value);
            result.C = (Int32)(left.C + value);
            return result;
        }

        public override string ToString()
        {
            return String.Format("A:{0,4} B:{1,4} C:{2,4}", A, B, C);
        }
    }


    static class MeshHelper
    {
        public static Vector3[] GetVerticesPoints(ModelMeshPart modelMeshPart)
        {
            Vector3[] points = new Vector3[modelMeshPart.NumVertices];
            int startIndex = 0; // where to place data inside target array 'points'
            int elementCount = modelMeshPart.NumVertices;
            int vertexStride = modelMeshPart.VertexBuffer.VertexDeclaration.VertexStride;
            int offsetInBytes = modelMeshPart.VertexOffset * vertexStride;

            modelMeshPart.VertexBuffer.GetData<Vector3>(
                offsetInBytes,
                points, startIndex, elementCount,
                vertexStride);
            return points;
        }
    }


    public partial class IntersectionDialog //: Window
    {
        public Model Model { get; set; }
        public float Distance { get; set; }

        public IntersectionDialog()
        {
            InitializeComponent();
            Distance = 0.0135f;
        }


        private void btnCalculate_Click(/*object sender, RoutedEventArgs e*/)
        {
            StringBuilder strout = new StringBuilder();
            Plane plane = new Plane(Vector3.Up, -Distance);

            foreach(ModelMesh mesh in Model.Meshes)
            {
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    //get data
                    Vector3[] points = MeshHelper.GetVerticesPoints(part);
                    TriangleIndices16[] triangles = new TriangleIndices16[part.PrimitiveCount];
                    part.IndexBuffer.GetData<TriangleIndices16>(triangles);
                    List<TriangleIndices16> triangleList = new List<TriangleIndices16>(triangles);

                    while (triangleList.Count > 0)
                    {
                        TriangleIndices16 triangle = triangleList[0];
                        triangleList.RemoveAt(0);

                        Vector3 pointA = points[triangle.A];
                        Vector3 pointB = points[triangle.B];
                        Vector3 pointC = points[triangle.C];

                        Ray rayAB = new Ray(pointA, (pointB - pointA));
                        Ray rayBC = new Ray(pointB, (pointC - pointB));
                        Ray rayCA = new Ray(pointC, (pointA - pointC));
                        
                        float? iAB = rayAB.Intersects(plane);
                        float? iBC = rayBC.Intersects(plane);
                        float? iCA = rayCA.Intersects(plane);

                        bool found = false;
                        if (iAB != null && iAB.Value<1)
                        {
                                Vector3 dir = rayAB.Direction;
                                float len = dir.Length();
                                Vector3 ipos = rayAB.Position + dir * iAB.Value;
                                Vector2 proj = new Vector2(ipos.X, ipos.Z);
                                if (found) strout.Append(" , ");
                                strout.AppendFormat(System.Globalization.NumberFormatInfo.InvariantInfo,
                                    "({0:+0.000##f;-0.000##f} , {1:+0.000##f;-0.000##f})",
                                    Math.Round(proj.X, 5), Math.Round(proj.Y, 5));
                                found = true;
                            
                        }
                        if (iBC != null && iBC.Value<1)
                        {
                            Vector3 dir = rayBC.Direction;
                            float len = dir.Length();
                            Vector3 ipos = rayBC.Position + dir * iBC.Value;
                            Vector2 proj = new Vector2(ipos.X, ipos.Z);
                            if (found) strout.Append(" , ");
                            strout.AppendFormat(System.Globalization.NumberFormatInfo.InvariantInfo,
                                "({0:+0.000##f;-0.000##f} , {1:+0.000##f;-0.000##f})", 
                                Math.Round(proj.X, 5), Math.Round(proj.Y, 5));
                            found = true;
                        }
                        if (iCA != null && iCA.Value < 1)
                        {
                            Vector3 dir = rayCA.Direction;
                            float len = dir.Length();
                            Vector3 ipos = rayCA.Position + dir * iCA.Value;
                            Vector2 proj = new Vector2(ipos.X, ipos.Z);
                            if (found) strout.Append(" , ");
                            strout.AppendFormat(System.Globalization.NumberFormatInfo.InvariantInfo,
                                "({0:+0.000##f;-0.000##f} , {1:+0.000##f;-0.000##f})", 
                                Math.Round(proj.X, 5), Math.Round(proj.Y, 5));
                            found = true;
                        }

                        if (found) strout.AppendLine();
                    }
                    strout.AppendLine();
                }
                strout.AppendLine();
            }

            tbOut.Text = strout.ToString();

            return;            
        }
    }
1 Like

that’s cool of you to share, but there are no comments :wink: -Can you drop a few lines explaining what it does in low def?

I’m old enough to remember how we did things when we had 8bit processors running at just a couple of mega Hertz. @Trinith has a good idea about some code to generate data. If you place that data into a 2D array - think int[] collisionMap[x,y] where we tend to think of data as being grid references as opposed to pixels.

In those days, a character on screen was a bitmap of 8x8 pixels. So drawing background graphics was all about putting a byte in memory that happened to be an array of about 32x26. Can’t remember any more! It was the 80’s after all.

So all you’d need to do was take your 2D position on screen, and get its positition in your collision map. So if x = 123, then int mapX = 123 /8; where 8 being the x side of a grid cell / collision map entry. So the same with the y and you have your array access.

A word of warning though, back then, we only had 24x21 pixel sprites (on a C64) to play with, which is pretty close to 3x3 chars. So the middle of that being a char that was always under the ship. (mostly shooter games) and so a side effect of only checking that one position, was the sprite collision was considered “generous” and allowed you ship to scrape by certain things without colliding with it. If you did that today (assuming 8x8 still) it would likely be a bit too generous. So you can construct your grid to be 12x12 or 16x16, or just check more than one grid reference at a time if you keep it smaller. Your choice.

This is by far the quickest way of detecting collisions. For us back then, the background graphics were also our collision map! So we had no work to do in scrolling the collision map along with the screen. But in your case, you would need to.

When doing something like this for myself in the past, I actually rendered white boxes on screen for every character I could collide with - so I could test the movement, and collision detection as it worked with the scrolling (purely 2D game in my case).

This is the system I stick with even today, and I tend to stick with 8x8 as a nod to the 80’s and my beloved C64. But hey, its retro, right?

2 Likes

Completely unrelated to this thread topic, but if you haven’t heard of it, sounds like you might like this…

:slight_smile:

yea this is pretty much how I have done in modern times, only my resolution for was higher for my detection grid… Boy was I surprised when I found out a computer could handle grids with millions of entries… 1920*1080 for each screen of a sidescroller. Remarkable… Not even optimised or tiles, just 1:1 pixel for pixel collision maps! That’s what gigabytes of memory are for, right?

1 Like