So I decided it’s time for me to learn how to code my own meshes. I needed a way to create a dynamic firing arc for my game so it was the perfect opportunity to learn. I mean how hard could it be … lol … Well after a 48 hour session I succeeded. It’s a custom mesh that has the texture cords set up so that it stretches a square texture over the surface. You can specify a min/max range, a field of view in degrees, and a gun angle in degrees. If people are interested, I can clean up the code and release it.
Heh, nice. Now that you’ve had some experience with a custom meshes, hopefully the next one will take you a lot less time.
Once you figure out how all the buffers work it’s really very easy. Now that I know how to create meshes the next step will be to create a generic deformation algorithm so that my ships can have visible damage when hit … Basically I can use the normals around the impact site and randomly move the points in the position buffer in the opposite direction slightly and … tada! … simulated real damage
I want to see your code .
can I ?
OK here is the code. I removed the gun angle piece because you can just easily rotate the arc on your model. Enjoy. I can picture @pspeed cringing because I did not use tmpVars everywhere but hey … it was an all nighter
import java.nio.FloatBuffer;
import com.jme3.bullet.debug.BulletRigidBodyDebugControl;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Mesh.Mode;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.util.BufferUtils;
public class FiringArc extends Mesh
{
private float fovAngle, minDistance, maxDistance;
private Vector3f center;
private int samples;
private ColorRGBA color = ColorRGBA.Blue;
public FiringArc(float fovAngle, float minDistance, float maxDistance, int samples, ColorRGBA color)
{
this(Vector3f.ZERO, fovAngle, minDistance, maxDistance, samples, color);
}
public FiringArc(Vector3f center, float fovAngle, float minDistance, float maxDistance, int samples, ColorRGBA color)
{
super();
this.fovAngle = fovAngle;
this.minDistance = minDistance;
this.maxDistance = maxDistance;
this.center = center;
this.samples = samples;
if(color != null)
this.color = color;
setMode(Mode.Triangles);
updateGeometry();
}
protected void updateGeometry()
{
FloatBuffer positions = BufferUtils.createFloatBuffer(samples * 4 * 3);
FloatBuffer normals = BufferUtils.createFloatBuffer(samples * 4 * 3);
FloatBuffer colors = BufferUtils.createFloatBuffer(samples * 4 * 3 * 4);
FloatBuffer textCords = BufferUtils.createFloatBuffer(samples * 4 * 2);
short[] indices = new short[samples * 3 * 2];
float angleDelta = fovAngle / samples;
float angleStart = 360f - (fovAngle / 2);
float angleEnd = fovAngle / 2;
float angleCurrent = angleStart;
float angleNext = angleStart + angleDelta;
float textCordXMin = 0;
float textCordXOffset = (float) (1f / (float) samples);
float textCordXMax = textCordXMin + textCordXOffset;
Vector3f posCurrMin = Vector3f.ZERO;
Vector3f posCurrMax = Vector3f.ZERO;
Vector3f posNextMin = Vector3f.ZERO;
Vector3f posNextMax = Vector3f.ZERO;
Vector3f sphereCurrent = new Vector3f();
Vector3f sphereNext = new Vector3f();
for(int i = 0; i < samples; i++)
{
sphereCurrent.set(FastMath.sin(FastMath.DEG_TO_RAD * angleCurrent), center.y, FastMath.cos(FastMath.DEG_TO_RAD * angleCurrent));
sphereNext.set(FastMath.sin(FastMath.DEG_TO_RAD * angleNext), center.y, FastMath.cos(FastMath.DEG_TO_RAD * angleNext));
posCurrMin = center.add(sphereCurrent).mult(minDistance);
posCurrMax = center.add(sphereCurrent).mult(maxDistance);
posNextMin = center.add(sphereNext).mult(minDistance);
posNextMax = center.add(sphereNext).mult(maxDistance);
int a = 4 * i;
int b = 4 * i + 1;
int c = 4 * i + 2;
int d = 4 * i + 3;
positions.put(posCurrMin.toArray(null)); // Position a
colors.put(new float[]
{ color.getRed() * 0.2f, color.getGreen() * 0.2f, color.getBlue(), 0.2f });
textCords.put(textCordXMin).put(0);
normals.put(new float[]
{ 0, 1, 0 });
positions.put(posNextMin.toArray(null)); // Position b
colors.put(new float[]
{ color.getRed() * 0.2f, color.getGreen() * 0.2f, color.getBlue(), 0.2f });
textCords.put(textCordXMax).put(0);
normals.put(new float[]
{ 0, 1, 0 });
positions.put(posCurrMax.toArray(null)); // Position c
colors.put(new float[]
{ color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha() });
textCords.put(textCordXMin).put(1);
normals.put(new float[]
{ 0, 1, 0 });
positions.put(posNextMax.toArray(null)); // Position d
colors.put(new float[]
{ color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha() });
textCords.put(textCordXMax).put(1);
normals.put(new float[]
{ 0, 1, 0 });
// Indices should be clockwise so the triangles do not get culled
// from the top view
indices[6 * i] = (short) b; // Triangle1: bac
indices[6 * i + 1] = (short) a;
indices[6 * i + 2] = (short) c;
indices[6 * i + 3] = (short) c; // Triangle2: cdb
indices[6 * i + 4] = (short) d;
indices[6 * i + 5] = (short) b;
angleCurrent += angleDelta;
angleNext += angleDelta;
textCordXMin = textCordXMax;
if(i == samples - 1)
textCordXMax = 1;
else
textCordXMax += textCordXOffset;
}
setBuffer(Type.Position, 3, positions);
setBuffer(Type.Normal, 3, normals);
setBuffer(Type.Index, 3, indices);
setBuffer(Type.Color, 4, colors);
setBuffer(Type.TexCoord, 2, textCords);
updateBound();
updateCounts();
}
public static void main(String[] args)
{
FiringArc firingArc = new FiringArc(45, 2, 20, 45, null);
}
}
Generally, tempVars is unnecessary. I personally never use it and I recommend end users also never use it.
The engine has some specific constraints and deployment targets that make it a necessary evil. In user code, there is almost always a better way.