Dynamic firing arch Mesh

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.

9 Likes

Heh, nice. Now that you’ve had some experience with a custom meshes, hopefully the next one will take you a lot less time.

1 Like

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 :slight_smile:

2 Likes

I want to see your code :slight_smile:.
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 :stuck_out_tongue:

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);

	}

}
1 Like

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.

1 Like