Assuming that you are looking at your sprite from above (i.e. down the y-axis), this code may serve as a starting point (you just have to draw yourself an arrow-texture with the arrow pointing up to test it):
One last thing: Please use this code with the updated jPCT 1.02 from today. The version from yesterday had a bug in it that this code will suffer from).
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import com.threed.jpct.*;
import com.threed.jpct.util.*;
class TargetDemo {
private FrameBuffer buffer=null;
private World theWorld=null;
private TextureManager texMan=null;
private int width=640;
private int height=480;
private Frame frame=null;
private Graphics gFrame=null;
private int titleBarHeight=0;
private int leftBorderWidth=0;
private boolean exit=false;
private KeyMapper keyMapper=null;
private int mouseX;
private int mouseY;
private Object3D arrow=null;
public static void main(String[] args) {
new TargetDemo();
}
private TargetDemo() {
theWorld=new World();
texMan=TextureManager.getInstance();
Config.fadeoutLight=false;
theWorld.setAmbientLight(255, 255, 255);
texMan.addTexture("arrow", new Texture("textures"+File.separatorChar+"arrow.jpg"));
arrow=Primitives.getPlane(1,10);
arrow.setTexture("arrow");
arrow.setTransparency(1);
arrow.rotateX((float) (Math.PI/2d));
arrow.rotateMesh();
arrow.setRotationMatrix(new Matrix());
arrow.build();
theWorld.addObject(arrow);
theWorld.getCamera().setPosition(0,-100,0);
theWorld.getCamera().rotateCameraX((float) (Math.PI/2d));
Config.tuneForOutdoor();
initializeFrame();
gameLoop();
}
private void initializeFrame() {
frame=new Frame();
frame.setTitle("jPCT "+Config.getVersion());
frame.pack();
Insets insets=frame.getInsets();
titleBarHeight=insets.top;
leftBorderWidth=insets.left;
frame.setSize(width+leftBorderWidth+insets.right, height+titleBarHeight+insets.bottom);
frame.setResizable(false);
frame.show();
gFrame=frame.getGraphics();
keyMapper=new KeyMapper(frame);
frame.addMouseMotionListener(new MouseMotionAdapter(){
public void mouseMoved(MouseEvent e) {
mouseX=e.getX()-frame.getInsets().left;
mouseY=e.getY()-frame.getInsets().top;
}
});
}
private void display() {
buffer.display(gFrame, leftBorderWidth, titleBarHeight);
}
private void gameLoop() {
World.setDefaultThread(Thread.currentThread());
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
buffer=new FrameBuffer(width, height, FrameBuffer.SAMPLINGMODE_NORMAL);
buffer.enableRenderer(IRenderer.RENDERER_SOFTWARE);
buffer.setBoundingBoxMode(FrameBuffer.BOUNDINGBOX_USED);
while (!exit) {
poll();
buffer.clear();
theWorld.renderScene(buffer);
theWorld.draw(buffer);
buffer.update();
display();
// Rotation stuff
SimpleVector arrowCenter=Interact2D.projectCenter3D2D(buffer, arrow);
if (arrowCenter!=null) {
arrowCenter.z=0;
SimpleVector delta=arrowCenter.calcSub(new SimpleVector(mouseX, mouseY, 0));
delta.z=delta.y;
delta.x*=-1;
delta.y=0;
Matrix rotMat=delta.getRotationMatrix();
arrow.setRotationMatrix(rotMat);
if (delta.length()>5) {
// Move the arrow slowly...
SimpleVector t=arrow.getZAxis();
t.scalarMul(0.1f);
arrow.translate(t);
}
}
Thread.yield();
}
keyMapper.destroy();
System.exit(0);
}
private void poll() {
KeyState state=null;
do {
state=keyMapper.poll();
if (state!=KeyState.NONE) {
keyAffected(state);
}
} while (state!=KeyState.NONE);
}
private void keyAffected(KeyState state) {
int code=state.getKeyCode();
boolean event=state.getState();
switch (code) {
case (KeyEvent.VK_ESCAPE): {
exit=event;
break;
}
}
}
}