Я работаю в игре с видом на корабль первого лица. У меня есть джойстик, и когда я перемещаю джойстик, я могу перемещать все объекты (астероиды) экрана, имитируя, что космический корабль перемещается с помощью джойстика.Проблема с моей игрой Джойстик
Игра работает отлично, но теперь у меня есть проблема. Если вы нажимаете джойстик в макс левом положении, а затем вы снова активируете ACTION_UP, а затем мгновенно ACTION_DOWN в джойстике, но в максимальном правильном положении, космический корабль начинает двигаться вправо с максимальной скоростью. Трудно это объяснить. Например, если вы нажмете джойстик в макс левом положении, космический корабль движется -20px за кадр влево, и если вы нажмете джойстик в макс. Правильном положении, космический корабль движется вправо + 20 пикселей на кадр.
Итак, теперь, если я сделать быстрый максимум левый и правый максимум касания на джойстике, космический корабль делает это движение: -20 .... + 20
Это не reallistic движение.
Я хочу получить это движение: -20 -17 -14 -9 -5 0 +5 +9 +14 +17 +20 .... Я имею в виду более реалистичное движение космического корабля. Но проблема в том, что я не специалист по математике или физике, и я не знаю, как получить такую функциональность в этом джойстике ... любая помощь будет очень благодарна.
Здесь вы можете найти демонстрационный проект с помощью джойстика:https://mega.co.nz/#!cp5FhYIT!dM88qx_xQdyhED9fX_4xeJ9ciQYJirUlNzEi-KOzU2k
Это код джойстик, я нашел его в Google и работает очень хорошо для не реалистического движения, которое я описал раньше, за исключением:
public class Joystick extends View {
public static final int INVALID_POINTER = -1;
private JoystickMovedListener moveListener;
//# of pixels movement required between reporting to the listener
private float moveResolution;
//Max range of movement in user coordinate system
private float movementRange;
//Last touch point in view coordinates
private int pointerId = INVALID_POINTER;
private float touchX;
private float touchY;
private float touchXDelayedMovement;
private float touchYDelayedMovement;
//Handle center in view coordinates
private float handleX;
private float handleY;
//Last reported position in view coordinates (allows different reporting sensitivities)
private float reportX;
private float reportY;
//Center of the view in view coordinates
private int cX;
private int cY;
//Size of the view in view coordinates
private int dimX;
private int dimY;
private int innerPadding;
private int bgRadius;
private int handleRadius;
private int movementRadius;
private int handleInnerBoundaries;
//Cartesian coordinates of last touch point - joystick center is (0,0)
private int cartX;
private int cartY;
//User coordinates of last touch point
private int userX;
private int userY;
//Offset co-ordinates (used when touch events are received from parent's coordinate origin)
private int offsetX;
private int offsetY;
private Paint bgPaint;
private Paint handlePaint;
boolean disabled;
Handler handler;
Handler handlerDelayedMovement;
public Joystick(Context context) {
super(context);
initJoystickView();
}
private void initJoystickView() {
setFocusable(true);
handlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
handlePaint.setColor(Color.RED);
handlePaint.setStrokeWidth(1);
handlePaint.setStyle(Paint.Style.FILL_AND_STROKE);
bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bgPaint.setColor(Color.DKGRAY);
bgPaint.setStrokeWidth(1);
bgPaint.setStyle(Paint.Style.FILL_AND_STROKE);
this.moveResolution = 1.0f;
handler = new Handler();
handlerDelayedMovement = new Handler();
}
public void setMovementRange(float movementRange) {
this.movementRange = movementRange;
}
public void setOnJostickMovedListener(JoystickMovedListener listener) {
this.moveListener = listener;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int d = Math.min(getMeasuredWidth(), getMeasuredHeight());
dimX = d;
dimY = d;
cX = d/2;
cY = d/2;
bgRadius = dimX/2 - innerPadding;
handleRadius = (int)(d * 0.2);
handleInnerBoundaries = handleRadius;
movementRadius = Math.min(cX, cY) - handleInnerBoundaries;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Here we make sure that we have a perfect circle
int measuredWidth = measure(widthMeasureSpec);
int measuredHeight = measure(heightMeasureSpec);
setMeasuredDimension(measuredWidth, measuredHeight);
}
private int measure(int measureSpec) {
int result = 0;
// Decode the measurement specifications.
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.UNSPECIFIED) {
result = 200; // Return a default size of 200 if no bounds are specified.
} else {
result = specSize; // As you want to fill the available space always return the full available bounds.
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.save();
// Draw the background
canvas.drawCircle(cX, cY, bgRadius, bgPaint);
// Draw the handle
handleX = touchX + cX;
handleY = touchY + cY;
canvas.drawCircle(handleX, handleY, handleRadius, handlePaint);
canvas.restore();
}
public void setPointerId(int id) {
this.pointerId = id;
}
public int getPointerId() {
return pointerId;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_MOVE: {
if (disabled==true)
break;
return processMoveEvent(ev);
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
if (pointerId != INVALID_POINTER) {
returnHandleToCenter();
returnHandleToCenterDelayedMovement();
setPointerId(INVALID_POINTER);
}
break;
}
case MotionEvent.ACTION_POINTER_UP: {
if (pointerId != INVALID_POINTER) {
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == this.pointerId) {
returnHandleToCenter();
returnHandleToCenterDelayedMovement();
setPointerId(INVALID_POINTER);
return true;
}
}
break;
}
case MotionEvent.ACTION_DOWN: {
handlerDelayedMovement.removeCallbacksAndMessages(null);
if (pointerId == INVALID_POINTER) {
int x = (int) ev.getX();
if (x >= offsetX && x < offsetX + dimX) {
setPointerId(ev.getPointerId(0));
if (disabled==true){
return true;
}
return processMoveEvent(ev);
}
}
break;
}
case MotionEvent.ACTION_POINTER_DOWN: {
if (pointerId == INVALID_POINTER) {
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
int x = (int) ev.getX(pointerId);
if (x >= offsetX && x < offsetX + dimX) {
setPointerId(pointerId);
return true;
}
}
break;
}
}
return false;
}
private boolean processMoveEvent(MotionEvent ev) {
if (pointerId != INVALID_POINTER) {
final int pointerIndex = ev.findPointerIndex(pointerId);
// Translate touch position to center of view
float x = ev.getX(pointerIndex);
touchX = x - cX - offsetX;
float y = ev.getY(pointerIndex);
touchY = y - cY - offsetY;
reportOnMoved();
invalidate();
return true;
}
return false;
}
private void reportOnMoved() {
//constraint circle
float diffX = touchX;
float diffY = touchY;
double radial = Math.sqrt((diffX*diffX) + (diffY*diffY));
if (radial > movementRadius) {
touchX = (int)((diffX/radial) * movementRadius);
touchY = (int)((diffY/radial) * movementRadius);
}
//We calc user coordinates
//First convert to cartesian coordinates
cartX = (int)(touchX/movementRadius * movementRange);
cartY = (int)(touchY/movementRadius * movementRange);
//Cartesian Coordinates
userX = cartX;
userY = cartY;
if (moveListener != null) {
boolean rx = Math.abs(touchX - reportX) >= moveResolution;
boolean ry = Math.abs(touchY - reportY) >= moveResolution;
if (rx || ry) {
this.reportX = touchX;
this.reportY = touchY;
moveListener.OnMoved(userX, userY);
}
}
}
private void reportOnMovedDelayedMovement() {
//constraint circle
float diffX = touchXDelayedMovement;
float diffY = touchYDelayedMovement;
double radial = Math.sqrt((diffX*diffX) + (diffY*diffY));
if (radial > movementRadius) {
touchXDelayedMovement = (int)((diffX/radial) * movementRadius);
touchYDelayedMovement = (int)((diffY/radial) * movementRadius);
}
//We calc user coordinates
//First convert to cartesian coordinates
cartX = (int)(touchXDelayedMovement/movementRadius * movementRange);
cartY = (int)(touchYDelayedMovement/movementRadius * movementRange);
//Cartesian Coordinates
userX = cartX;
userY = cartY;
if (moveListener != null) {
boolean rx = Math.abs(touchXDelayedMovement - reportX) >= moveResolution;
boolean ry = Math.abs(touchYDelayedMovement - reportY) >= moveResolution;
if (rx || ry) {
this.reportX = touchXDelayedMovement;
this.reportY = touchYDelayedMovement;
moveListener.OnMoved(userX, userY);
}
}
}
private void returnHandleToCenter() {
final int numberOfFrames = 5;
final double intervalsX = (0 - touchX)/numberOfFrames;
final double intervalsY = (0 - touchY)/numberOfFrames;
handler.removeCallbacksAndMessages(null);
for (int i = 0; i < numberOfFrames; i++) {
final int j = i;
handler.postDelayed(new Runnable() {
@Override
public void run() {
touchX += intervalsX;
touchY += intervalsY;
//reportOnMoved();
invalidate();
if (moveListener != null && j == numberOfFrames - 1) {
moveListener.OnReturnedToCenter();
}
}
}, i * 10);
}
if (moveListener != null) {
moveListener.OnReleased();
}
}
private void returnHandleToCenterDelayedMovement() {
final int numberOfFrames = 25;
touchXDelayedMovement=touchX;
touchYDelayedMovement=touchY;
final double intervalsX = (0 - touchXDelayedMovement)/numberOfFrames;
final double intervalsY = (0 - touchYDelayedMovement)/numberOfFrames;
handlerDelayedMovement.removeCallbacksAndMessages(null);
for (int i = 0; i < numberOfFrames; i++) {
handlerDelayedMovement.postDelayed(new Runnable() {
@Override
public void run() {
touchXDelayedMovement += intervalsX;
touchYDelayedMovement += intervalsY;
reportOnMovedDelayedMovement();
}
}, i * 50);
}
}
public void setInnerPadding(int innerPadding){
this.innerPadding=innerPadding;
}
public void disable(){
disabled=true;
}
public void enable(){
disabled=false;
}
public interface JoystickMovedListener {
public void OnMoved(int pan, int tilt);
public void OnReleased();
public void OnReturnedToCenter();
}
}
Вы должны сделать это в классе, который будет использовать джойстик:
private JoystickMovedListener joystickListener = new JoystickMovedListener() {
@Override
public void OnMoved(int pan, int tilt) {
//here i move the objects in the game
}
}
@Override
public void OnReleased() {}
public void OnReturnedToCenter() {};
};
joystickOnScreen = new Joystick(this);
joystickOnScreen.setMovementRange(screenHeight/50);
joystickOnScreen.setInnerPadding(screenHeight/30);
joystickOnScreen.setOnJostickMovedListener(joystickListener);
RelativeLayout.LayoutParams joystickParams = new RelativeLayout.LayoutParams(sh/3, sh/3);
joystickParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
joystickParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
joystickParams.setMargins(sh/100, 0, 0, sh/100);
joystickOnScreen.setLayoutParams(joystickParams);
joystickOnScreen.setAlpha(0.3f);
Возможный дубликат [Проблема с моей игрой Джойстик] (http://stackoverflow.com/questions/28792914/issue-with-my-game-joystick) – Clive
, что сообщение не существует, оно удалено – NullPointerException
Нет необходимости задайте один и тот же вопрос снова и снова, если он существует. Дубликаты будут удалены или закрыты. Просто подождите, пока у кого-нибудь есть ответ/сделайте какое-нибудь исследование/откройте щедрость существующего вопроса (желательно все три). – fge