简体   繁体   English

Java 3D LWJGL冲突

[英]Java 3D LWJGL collision

I am making a 3D Java game with the LWJGL library, and I was wondering how to add collision detection, so that the player does not go through models. 我正在使用LWJGL库制作3D Java游戏,我想知道如何添加碰撞检测,以使玩家不会浏览模型。

I am using OBJ models. 我正在使用OBJ模型。 Here is the OBJLoader class, which loads the models: 这是OBJLoader类,用于加载模型:

package renderEngine;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;

import models.RawModel;

import org.lwjgl.util.vector.Vector2f;
import org.lwjgl.util.vector.Vector3f;

public class OBJLoader {


    public static RawModel loadObjModel(String fileName, Loader loader){
        FileReader fr = null;
        try {
            fr = new FileReader(new File("res/"+fileName+".obj"));
        } catch (FileNotFoundException e) {
            System.err.println("Couldn't load file!");
            e.printStackTrace();
        }
        BufferedReader reader = new BufferedReader(fr);
        String line;
        List<Vector3f> vertices = new ArrayList<Vector3f>();
        List<Vector2f> textures = new ArrayList<Vector2f>();
        List<Vector3f> normals = new ArrayList<Vector3f>();
        List<Integer> indices = new ArrayList<Integer>();
        float[] verticesArray = null;
        float[] normalsArray = null;
        float[] textureArray = null;
        int[] indicesArray = null;
        try{
            while(true){
                line = reader.readLine();
                String[] currentLine = line.split(" ");
                if(line.startsWith("v ")){
                    Vector3f vertex = new Vector3f(Float.parseFloat(currentLine[1]), 
                            Float.parseFloat(currentLine[2]), Float.parseFloat(currentLine[3]));
                    vertices.add(vertex);
                }else if(line.startsWith("vt ")){
                    Vector2f texture = new Vector2f(Float.parseFloat(currentLine[1]), 
                            Float.parseFloat(currentLine[2]));
                    textures.add(texture);
                }else if(line.startsWith("vn ")){
                    Vector3f normal = new Vector3f(Float.parseFloat(currentLine[1]), 
                            Float.parseFloat(currentLine[2]), Float.parseFloat(currentLine[3]));
                    normals.add(normal);
                }else if(line.startsWith("f ")){
                    textureArray = new float[vertices.size() * 2];
                    normalsArray = new float[vertices.size() * 3];
                    break;
                }
            }

            while(line != null){
                if(!line.startsWith("f ")){
                    line = reader.readLine();
                    continue;
                }
                String[] currentLine = line.split(" ");
                String[] vertex1 = currentLine[1].split("/");
                String[] vertex2 = currentLine[2].split("/");
                String[] vertex3 = currentLine[3].split("/");

                processVertex(vertex1, indices, textures, normals, textureArray, normalsArray);
                processVertex(vertex2, indices, textures, normals, textureArray, normalsArray);
                processVertex(vertex3, indices, textures, normals, textureArray, normalsArray);
                line = reader.readLine();
            }

            reader.close();
        }catch(Exception e){
            e.printStackTrace();
        }
        verticesArray = new float[vertices.size()*3];
        indicesArray = new int[indices.size()];


        int vertexPointer = 0;
        for(Vector3f vertex:vertices){
            verticesArray[vertexPointer++] = vertex.x;
            verticesArray[vertexPointer++] = vertex.y;
            verticesArray[vertexPointer++] = vertex.z;
        }
        for(int i=0;i<indices.size(); i++){
            indicesArray[i] = indices.get(i);
        }
        return loader.loadToVAO(verticesArray, textureArray, normalsArray, indicesArray);
    }

    private static void processVertex(String[] vertexData, List<Integer> indices, 
            List<Vector2f> textures, 
            List<Vector3f> normals, float[] textureArray, float[] normalsArray){

        int currentVertexPointer = Integer.parseInt(vertexData[0]) - 1;
        indices.add(currentVertexPointer);
        Vector2f currentTex = textures.get(Integer.parseInt(vertexData[1]) - 1);
        textureArray[currentVertexPointer*2] = currentTex.x;
        textureArray[currentVertexPointer*2+1] = 1 - currentTex.y;
        Vector3f currentNorm = normals.get(Integer.parseInt(vertexData[2])-1);
        normalsArray[currentVertexPointer*3] = currentNorm.x;
        normalsArray[currentVertexPointer*3+1] = currentNorm.y;
        normalsArray[currentVertexPointer*3+2] = currentNorm.z;
    }

}

Thanks! 谢谢!

You have a few options here. 您在这里有一些选择。 The easiest is to simply create an axis-aligned bounding box (AABB) around the object; 最简单的方法是简单地围绕对象创建一个与轴对齐的边界框(AABB)。 this can be done algorithmically by simply finding the minimum and maximum values for each axis. 通过简单地找到每个轴的最小值和最大值,可以通过算法实现这一点。 For some applications this will work fine, but this obviously isn't very precise. 对于某些应用程序,它可以很好地工作,但这显然不是很精确。 It's worth noting, though, that if two AABBs do not intersect, then the objects themselves definitely don't intersect either; 但是,值得注意的是,如果两个AABB不相交,则对象本身也绝对不会相交。 you can use this fact as an early-exit for your collision-checking algorithm. 您可以将此事实用作冲突检查算法的提前退出。

In addition to bounding boxes, some game engines employ other basic types of bounding volumes, such as bounding spheres. 除边界框外,某些游戏引擎还使用其他基本类型的边界体积,例如边界球。 Detecting if a point is in a sphere is as simple as checking if the distance between the center of the sphere and the point is less than or equal to the radius of the sphere. 检测点是否在球体中就像检查球体中心与该点之间的距离是否小于或等于球体半径一样简单。 Investigate the bounding volume Wikipedia page for other types . 研究其他类型边界量Wikipedia页面 You can often approximate the true boundaries of your object by creating compound bounding volumes -- that is, bounding volumes composed of several simpler volumes, like spheres, boxes, cylinders, etc. This is how the Unity game engine handles collision detection. 您通常可以通过创建复合边界体积(即,由多个简单体积组成的边界体积,例如球体,盒子,圆柱体等)来近似对象的真实边界。这就是Unity游戏引擎处理碰撞检测的方式。

You might also want to investigate 2D collision detection algorithms, like the separating axis theorem example (see further reading section). 您可能还需要研究2D碰撞检测算法,例如分离轴定理示例(请参阅其他阅读部分)。 These algorithms can almost always be scaled to higher dimensions. 这些算法几乎总是可以扩展到更高的维度。

If all this seems too complicated, I'd recommend picking up a prebaked solution, such as Bullet ( Java port ). 如果这一切看起来太复杂,我建议您选择一个预先烘焙的解决方案,例如BulletJava port )。 Google around a bit; 谷歌有点; you'll probably find something that fits your use case. 您可能会找到适合您的用例的东西。 Don't feel bad if you feel overwhelmed; 如果不知所措,不要感到难过; collision detection is a complicated subject backed by decades of research. 碰撞检测是数十年来研究支持的一个复杂主题。

Further reading: 进一步阅读:

I am also in the process of making a game via LWJGL. 我也在通过LWJGL制作游戏。 I use a fairly simple process for determining collisions. 我使用一个相当简单的过程来确定冲突。 First, I find all entities within a certain distance of the focal entity. 首先,我找到所有在焦点实体一定距离内的实体。 I use a method like this: 我使用这样的方法:

public static float getDistance(Vector3f pointOne, Vector3f pointTwo) {
    float distance = 0;

    float x1 = pointOne.x;
    float y1 = pointOne.y;
    float z1 = pointOne.z;

    float x2 = pointTwo.x;
    float y2 = pointTwo.y;
    float z2 = pointTwo.z;

    distance = (float) Math.pow((Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) + Math.pow(z1 - z2, 2)), .5f);

    return distance;
}

Next, I call the method and determine which entities are within a certain radii of the focal entity, and add them to a list. 接下来,我调用该方法并确定哪些实体在焦点实体的某个半径内,并将它们添加到列表中。

List<Entity> possibleCollision;
if(distance < radius) {
    possibleCollision.add(entity);
}

Finally, I determine the coordinates of each of the vertices in two different lists. 最后,我确定两个不同列表中每个顶点的坐标。 One list is used to store coordinates of the focal entity and the other is to store coordinates of all other entities in the range of possible collision. 一个列表用于存储焦点实体的坐标,另一个列表用于存储可能发生碰撞的所有其他实体的坐标。

List<Vector3f> focal_vertices = new ArrayList<Vector3f>();
//Get Vertices for Focal Entity
focal_verticies.add(vertex);

List<Vector3f> entity_vertices = new ArrayList<Vector3f>();
//Get Vertices for Focal Entity
entity_vertices.add(vertex);

Finally, I run a loop to check the lists contain duplicate entries. 最后,我运行一个循环来检查列表中是否包含重复的条目。 This is the most simple part of the system. 这是系统中最简单的部分。

for(int i = 0; i < entity_vertices.size() - 1; i++) {

    if(player_vertices.contains(entity_vertices.get(i))) {

        //Collision Detected

    }

}

This works for every OBJ file I have ever tested it with. 这适用于我测试过的每个OBJ文件。 Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM