public class JoystickView extends SurfaceView implements SurfaceHolder.Callback, View.OnTouchListener { private float centerX; private float centerY; private float baseRadius; private float hatRadius; private RightJoystickListener rightJoystickListener; private LeftJoystickListener leftJoystickListener; private void setupDimensions() { centerX = getWidth() / 2; centerY = getHeight() / 2; baseRadius = Math.min(getWidth(), getHeight()) / 3; hatRadius = Math.min(getWidth(), getHeight()) / 6; } public JoystickView(Context context) { super(context); getHolder().addCallback(this); setOnTouchListener(this); if(context instanceof RightJoystickListener) { rightJoystickListener = (RightJoystickListener) context; } if(context instanceof LeftJoystickListener) { leftJoystickListener = (LeftJoystickListener) context; } getHolder().setFormat(PixelFormat.TRANSLUCENT); } public JoystickView(Context context, AttributeSet attrs) { super(context, attrs); getHolder().addCallback(this); setOnTouchListener(this); if(context instanceof RightJoystickListener) { rightJoystickListener = (RightJoystickListener) context; } if(context instanceof LeftJoystickListener) { leftJoystickListener = (LeftJoystickListener) context; } getHolder().setFormat(PixelFormat.TRANSLUCENT); } public JoystickView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); getHolder().addCallback(this); setOnTouchListener(this); if(context instanceof RightJoystickListener) { rightJoystickListener = (RightJoystickListener) context; } if(context instanceof LeftJoystickListener) { leftJoystickListener = (LeftJoystickListener) context; } } private void drawJoystick(float newX, float newY) { if (getHolder().getSurface().isValid()) { Canvas myCanvas = this.getHolder().lockCanvas(); Paint colors = new Paint(); myCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); colors.setARGB(100, 193, 193, 193); myCanvas.drawCircle(centerX, centerY, baseRadius, colors); colors.setARGB(255, 193, 193, 193); myCanvas.drawCircle(newX, newY, hatRadius, colors); getHolder().unlockCanvasAndPost(myCanvas); } } @Override public void surfaceCreated(SurfaceHolder holder) { setupDimensions(); drawJoystick(centerX, centerY); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } public boolean onTouch(View v, MotionEvent e) { if(v.equals(this)) { if(e.getAction() != e.ACTION_UP) { float displacement = (float)Math.sqrt((Math.pow(e.getX() - centerX, 2)) + Math.pow(e.getY() - centerY, 2)); if(displacement < baseRadius) { drawJoystick(e.getX(), e.getY()); } else { float ratio = baseRadius / displacement; float constrainedX = centerX + (e.getX() - centerX) * ratio; float constrainedY = centerY + (e.getY() - centerY) * ratio; drawJoystick(constrainedX, constrainedY); rightJoystickListener.onRightJoystickMoved( (constrainedX - centerX) / baseRadius, (constrainedY - centerY) / baseRadius , getId()); leftJoystickListener.onLeftJoystickMoved( (constrainedX - centerX) / baseRadius, (constrainedY - centerY) / baseRadius , getId()); } } else { drawJoystick(centerX, centerY); leftJoystickListener.onLeftJoystickMoved(0,0, getId()); rightJoystickListener.onRightJoystickMoved(0,0, getId()); } } return true; } public interface RightJoystickListener { void onRightJoystickMoved(float xPercent, float yPercent, int id); } public interface LeftJoystickListener { void onLeftJoystickMoved(float xPercent, float yPercent, int id); } }