Well, a couple of days ago I decided to code a first person shooter-like game, in order to expand my knowledge some more. I tried to keep it clean, and flexible. (The opposite of my other opengl projects).
1PX790I1Dz0
The things that I was more interested about were the networking part and the shaders part. Sadly, I found time for first one only. I tried to give the feeling that there is light using glColor, but it caused a huge fps drop, and I removed it.
EDIT: Forgot to mention that currently I am using a really inefficient way to see at what object the player is looking/targeting at. I would really appreciate some help with the ray-casting.
Here is a list of some things I want to add but I haven’t yet, due to limited time, boredom or due to lack of knowledge at some spots. (Lighting, ray-casting)
TO-DO List: Add the networking part.
Add a chat. Load maps from .txt file.
Actually kill other players.
Ray-casting.
Lighting.
I am just using the built in Sockets and ServerSockets. I didn’t really read any tutorials. I was looking at other sources to have a taste until I get the whole idea. I had made a 2d rpg game using swing some years ago and I had done some networking back then, so it wasn’t a completely new world to explore.
Now after I load the file, I go through each character. If, for example, the character is a ‘.’, then it adds a grass box and at some distance above it adds a box which is part of the roof. If it is a ‘#’, then it adds a wall at that point.
To make it easier, you can use image-based loading.
You scan an image for every pixels’ location and color, and if the color = X, then it will return a certain object at the location corresponding to the pixel’s.
You don’t control the height via the text file. You just say that if the character is a ‘#’ create at y = 20, or whatever, a new object. It is something that you can preconfigured in your code.
Once again I am stuck and I cannot move the project on, because I fail at implementing an actual ray-casting script. Even though, I have pretty much understood the whole concept I keep failling at actually making it work. Right now, I am just generating points until a specified distance and I check if there is any kind of intersection between them and the objects. It turns out it is completely inaccurate and inefficient.
I could give you a (kind-of fast and) simple raytracing code for your game.
(Raytracing is somehow the same thing as raycasting for me…)
(I really need to pimp up my knowledge of 3D math.)
Well at least my raytracing code can raytrace a image at 400x300px with 40 FPS,
even the fact that the scene consits only of 5 triangles, its still fast enough for most things.
EDIT:
I am just going to put this here, so you can use it.
The entire class is completely mathematically correct, so if the code fails to detect a hit for some odd reason, its your fault, not the fault of this code.
(Btw: I just copied this without changes from my utility library)
// Copyright @Longor1996
package de.L19.math2;
// All methods in this class are not fully optimized.
// Optimize where needed (Both Memory and CPU wise).
/**Defines a 3D ray with an Origin and a Direction.**/
public class Ray {
/**The Origin of this Ray Object.**/
public Vector4D Origin;
/**The Direction of this Ray Object.**/
public Vector4D Direction;
/**
* Constructs a new Ray instance pointing forward (Positive Z).
**/
public Ray(){
this.Origin = new Vector4D(0,0,0,1);
this.Direction = new Vector4D(0,0,1,1);
}
/**
* Returns the Point at the given Distance from this ray's PointOfView.
*
* Use this to get the intersection-point from the intersection-distance returned by the methods in this class.
**/
public Vector4D getPoint(double t) {
return this.Origin._doAdd(this.Direction._doMultiplyBy(t));
}
/**
* Fastest possible Ray/Plane intersection method.
* This method calculates the intersection-distance between a ray and a infinite plane (/hyperplane).
*
* @return The intersection-distance between the ray and the plane.
**/
public double RayIntersectionPlane(Ray ray,Vector4D Position,Vector4D Normal){
return -((Normal.doDotProduct(ray.Origin) + (-Normal.doDotProduct(Position))) / Normal.doDotProduct(ray.Direction));
}
/**
* Fastest possible Ray/Plane intersection method.
* This method calculates the intersection-distance between a ray and a infinite plane (/hyperplane).
*
* @return The intersection-point between the ray and the plane.
**/
public Vector4D RayIntersectionPlane(Vector4D Position,Vector4D Normal){
return this.getPoint(this.RayIntersectionPlane(this,Position, Normal));
}
/**
* Untested, probably buggy, method.
**/
public double RayIntersectionPlaneInAABB(Vector4D Position,Vector4D Normal,double ax,double ay,double az,double bx,double by,double bz,boolean invertPlane){
// Inverts the plane if told so. Creates a negated copy of the normal vector. (Waste of Memory, don't do that too often)
if(invertPlane)
Normal = Normal._doNegate();
// Calculates the intersection between this ray and the given AABB side-plane.
final double d = this.RayIntersectionPlane(this, Position, Normal) + 0.0001D;
final Vector4D v = this.getPoint(d);
// check if the intersection-point is inside the AABB...
if(v.x < ax)return Double.POSITIVE_INFINITY;
if(v.y < ay)return Double.POSITIVE_INFINITY;
if(v.z < az)return Double.POSITIVE_INFINITY;
if(v.x > bx)return Double.POSITIVE_INFINITY;
if(v.y > by)return Double.POSITIVE_INFINITY;
if(v.z > bz)return Double.POSITIVE_INFINITY;
// Point is inside the AABB from the view of the given Box-Side, done calculating.
return d;
}
/**
* This method calculates the intersection-distance between a ray and a sphere (with the given radius and position).
*
* @return The intersection-point between the ray and the sphere.
*
**/
public double RayIntersectionSphere(final Ray ray,final Vector4D position,final double radius){
final Vector4D s = position._doSubtract(ray.Origin); //s=Sphere Center Translated into Coordinate Frame of Ray Origin
//Intersection of Sphere and Line = Quadratic Function of Distance
final double A = ray.Direction.doDotProduct(ray.Direction);// Remember This From High School? :
final double B = -2.0F * s.doDotProduct(ray.Direction); // A x^2 + B x + C = 0
final double C = s.doDotProduct(s) - (radius*radius); // (r'r)x^2 - (2s'r)x + (s's - radius^2) = 0
final double D = (B*B) - (4F*A*C); // Precompute Discriminant
//Solution Exists only if sqrt(D) is Real (not Imaginary)
if (D > 0.0){
final double sign = (C < -0.00001) ? 1 : -1; //Ray Originates Inside Sphere If C < 0
final double lDist = (-B + (sign * Math.sqrt(D))) / (2 * A); //Solve Quadratic Equation for Distance to Intersection
return lDist;
} else
return Float.POSITIVE_INFINITY;
}
/**
* Calculates the intersection-distance between a ray and a triangle.
* This method is REALLY slow, but you can still call it 2.700 times per second without problems.
*
* @return The intersection-distance between the given ray and the given triangle.
**/
public double RayIntersectionTriangle(Ray ray,Vector4D point1,Vector4D point2,Vector4D point3){
Vector4D edge1 = point2._doSubtract(point1);
Vector4D edge2 = point3._doSubtract(point1);
// Find the cross product of edge2 and the ray direction
Vector4D s1 = ray.Direction._getCrossProduct(edge2);
// Find the divisor, if its zero, return false as the triangle is
// degenerated
final double divisor = s1.doDotProduct(edge1);
if (divisor == 0.0)
return Double.POSITIVE_INFINITY;
// A inverted divisor, as multiplying is faster then division
final double invDivisor = 1 / divisor;
// Calculate the first barycentic coordinate. Barycentic coordinates
// are between 0.0 and 1.0
final Vector4D distance = ray.Origin._doSubtract(point1);
final double barycCoord_1 = distance.doDotProduct(s1) * invDivisor;
if ((barycCoord_1 < 0.0) || (barycCoord_1 > 1.0))
return Double.POSITIVE_INFINITY;
// Calculate the second barycentic coordinate
final Vector4D s2 = distance._getCrossProduct(edge1);
final double barycCoord_2 = ray.Direction.doDotProduct(s2) * invDivisor;
if ((barycCoord_2 < 0.0) || ((barycCoord_1 + barycCoord_2) > 1.0))
return Double.POSITIVE_INFINITY;
// After doing the barycentic coordinate test we know if the ray hits or
// not. If we got this far the ray hits.
// Calculate the distance to the intersection point
final double intersectionDistance = edge2.doDotProduct(s2) * invDivisor;
return intersectionDistance >= 0 ? intersectionDistance : Double.POSITIVE_INFINITY;
}
/**
* Calculates the intersection-distance between this ray and the given AABB.
* Probably buggy, may fail in some cases.
**/
public double RayIntersectionAABB(double ax,double ay,double az,double bx,double by,double bz){
final double plane_top = this.RayIntersectionPlaneInAABB(new Vector4D(0,by,0),new Vector4D(0,+1,0), ax, ay, az, bx, by, bz, false);
final double plane_bottom= this.RayIntersectionPlaneInAABB(new Vector4D(0,ay,0),new Vector4D(0,-1,0), ax, ay, az, bx, by, bz, false);
final double plane_left = this.RayIntersectionPlaneInAABB(new Vector4D(ax,0,0),new Vector4D(-1,0,0), ax, ay, az, bx, by, bz, false);
final double plane_right = this.RayIntersectionPlaneInAABB(new Vector4D(bx,0,0),new Vector4D(+1,0,0), ax, ay, az, bx, by, bz, false);
final double plane_front = this.RayIntersectionPlaneInAABB(new Vector4D(0,0,az),new Vector4D(0,0,+1), ax, ay, az, bx, by, bz, false);
final double plane_back = this.RayIntersectionPlaneInAABB(new Vector4D(0,0,bz),new Vector4D(0,0,-1), ax, ay, az, bx, by, bz, false);
double t = Double.POSITIVE_INFINITY;
t = Math.min(t, plane_top);
t = Math.min(t, plane_bottom);
t = Math.min(t, plane_left);
t = Math.min(t, plane_right);
t = Math.min(t, plane_front);
t = Math.min(t, plane_back);
return t;
}
}
Example Usage:
Ray yourRay = ...;
SomeObjectType someObject = null;
double lastClosestDistance = Double.POSITIVE_INFINITY;
// go trough each of the object to check...
for(SomeObjectType objectToCheck)
{
double dist = RayIntersectionXXXX(yourRay, ...);
// check if the intersection is closer
if(dist < lastClosestDistance){
someObject = objectToCheck;
lastClosestDistance = dist;
}
}
// result is in the 'lastClosestDistance' and 'someObject' variables!
I apologise for bringing up this topic after a couple of months of inactivity, but now that I found time to code again, I decided to work on the ray picking part that it used to hold me back and it’s still does. I thought of an no-so-efficient way to do the ray-picking but I decided to give it a try anyway. The engine kinda generates many points in a fixed distance direction he is looking at and checks each time if the points intersects to a rectangle. If it does it removes the rectangle. The problem is that when the camera starts to have a big angle, sometimes it starts removing wrong rectangles. I re-wrote the code in a different way but I keep getting the same malfunction.
sZUqfNx-fJU
The following function returns the nearest object that players looks.
public Rectangle getTargetedObject() {
double cameraPitchInRadians = Math.toRadians(Game.getCamera().pitch);
double cameraYawInRadians = Math.toRadians(Game.getCamera().yaw);
for (float x = 1; x < 15; x++) {
for (float y = 1; y < 15; y++) {
for (float z = 1; z < 15; z++) {
float newX = (x * (float)Math.sin(cameraYawInRadians));
float newZ = (z * (float)Math.cos(cameraYawInRadians));
float newY = (y * (float)Math.sin(cameraPitchInRadians));
float pointX = 0, pointY = 0, pointZ = 0;
pointX = getX() + newX;
pointY = getY() - newY;
pointZ = getZ() - newZ;
for (Rectangle rect:MapManager.getCurrentMap().getObjects()) {
if (rect.isCollidingWithPoint(pointX, pointY, pointZ)) {
return rect;
}
}
}
}
}
return null;
}
This one actually checks if the point that is generated using the function above is actually interesting with a rectangle.
public boolean isCollidingWithPoint(float x, float y, float z) {
if (width == 0) width++;
if (height == 0) height++;
if (length == 0) length++;
if(Math.abs((getX() + width / 2) - x) < width / 2)
{
if(Math.abs((getY() + height / 2) - y) < height / 2)
{
if (Math.abs((getZ() + length / 2) - z) < length / 2) {
if (width == 1) width--;
if (height == 1) height--;
if (length == 1) length--;
return true;
}
}
}
if (width == 1) width--;
if (height == 1) height--;
if (length == 1) length--;
return false;
}
If anyone can see anything, that I cannot, please let me know.