2424import org .destinationsol .assets .Assets ;
2525import org .destinationsol .common .SolMath ;
2626import org .destinationsol .game .Hero ;
27+ import org .destinationsol .game .SolCam ;
2728import org .destinationsol .game .SolGame ;
2829import org .destinationsol .game .input .Mover ;
2930import org .destinationsol .game .input .Shooter ;
3031import org .destinationsol .ui .SolInputManager ;
3132import org .destinationsol .ui .SolUiControl ;
33+ import org .slf4j .Logger ;
34+ import org .slf4j .LoggerFactory ;
3235
3336import java .util .List ;
3437
@@ -38,15 +41,16 @@ public class ShipMixedControl implements ShipUiControl {
3841 public final SolUiControl shoot2Ctrl ;
3942 public final SolUiControl abilityCtrl ;
4043 private final SolUiControl myDownCtrl ;
41- private final Vector2 myMouseWorldPos ;
44+ private final Vector2 mouseScreenPos ;
4245 private final TextureAtlas .AtlasRegion myCursor ;
43- private boolean myRight ;
44- private boolean myLeft ;
46+ private boolean turnRight ;
47+ private boolean turnLeft ;
48+ private Logger logger = LoggerFactory .getLogger (ShipMixedControl .class );
4549
4650 ShipMixedControl (SolApplication solApplication , List <SolUiControl > controls ) {
4751 GameOptions gameOptions = solApplication .getOptions ();
4852 myCursor = Assets .getAtlasRegion ("engine:uiCursorTarget" );
49- myMouseWorldPos = new Vector2 ();
53+ mouseScreenPos = new Vector2 ();
5054 upCtrl = new SolUiControl (null , false , gameOptions .getKeyUpMouse ());
5155 controls .add (upCtrl );
5256 myDownCtrl = new SolUiControl (null , false , gameOptions .getKeyDownMouse ());
@@ -63,22 +67,25 @@ public class ShipMixedControl implements ShipUiControl {
6367 public void update (SolApplication solApplication , boolean enabled ) {
6468 GameOptions gameOptions = solApplication .getOptions ();
6569 blur ();
66- if (!enabled ) {
70+ SolGame game = solApplication .getGame ();
71+ if (!enabled || problemWithProjections (game .getCam ())) {
6772 return ;
6873 }
6974 SolInputManager im = solApplication .getInputManager ();
70- SolGame game = solApplication .getGame ();
7175 Hero hero = game .getHero ();
7276 if (hero .isNonTranscendent ()) {
73- myMouseWorldPos .set (Gdx .input .getX (), Gdx .input .getY ());
74- game .getCam ().screenToWorld (myMouseWorldPos );
75- float desiredAngle = SolMath .angle (hero .getPosition (), myMouseWorldPos );
76- Boolean ntt = Mover .needsToTurn (hero .getAngle (), desiredAngle , hero .getRotationSpeed (), hero .getRotationAcceleration (), Shooter .MIN_SHOOT_AAD );
77- if (ntt != null ) {
78- if (ntt ) {
79- myRight = true ;
77+ mouseScreenPos .set (Gdx .input .getX (), Gdx .input .getY ());
78+ // project mouse coordinates [0;width] and [0;height] to screen coordinates [0,1], [0,1] by scaling down
79+ mouseScreenPos .scl (1.0f / Gdx .graphics .getWidth (), 1.0f / Gdx .graphics .getHeight ());
80+ Vector2 shipOnScreen = game .getCam ().worldToScreen (hero .getShip ()); // unproject hero to screen coordinates
81+ assertHeroAndMouseCoords (mouseScreenPos , shipOnScreen );
82+ float desiredAngle = SolMath .angle (shipOnScreen , mouseScreenPos );
83+ Boolean needsToTurn = Mover .needsToTurn (hero .getAngle (), desiredAngle , hero .getRotationSpeed (), hero .getRotationAcceleration (), Shooter .MIN_SHOOT_AAD );
84+ if (needsToTurn != null ) {
85+ if (needsToTurn ) {
86+ turnRight = true ;
8087 } else {
81- myLeft = true ;
88+ turnLeft = true ;
8289 }
8390 }
8491 if (!im .isMouseOnUi ()) {
@@ -95,14 +102,39 @@ public void update(SolApplication solApplication, boolean enabled) {
95102 }
96103 }
97104
105+ /**
106+ * When alt+tabbing in full screen mode, the client area can become 0 with/height, and when alt+tabbing back,
107+ * the camera matrix can contain NaN values for the first frame
108+ * @return true if projections should not be done this update
109+ */
110+ private boolean problemWithProjections (SolCam camera ) {
111+ return Gdx .graphics .getWidth () == 0 || Gdx .graphics .getHeight () == 0 ||
112+ camera .getViewWidth () <= 0.f || camera .getViewHeight () <= 0.f || !camera .isMatrixValid ();
113+ }
114+
115+ /**
116+ * Assert that the following vectors do not contain NaN or infinite values
117+ * @param mouseCoords mouse coordinates in [0;1] screen space
118+ * @param heroCoords hero coordinates projected to [0;1] screen space
119+ */
120+ private void assertHeroAndMouseCoords (Vector2 mouseCoords , Vector2 heroCoords ) {
121+ if (Double .isNaN (mouseCoords .x ) || Double .isNaN (mouseCoords .y )) {
122+ throw new RuntimeException ("Mouse coordinates are not valid: " + mouseCoords .x + " " + mouseCoords .y );
123+ }
124+
125+ if (Double .isNaN (heroCoords .x ) || Double .isNaN (heroCoords .y )) {
126+ throw new RuntimeException ("Hero coordinates are not valid: " + heroCoords .x + " " + heroCoords .y );
127+ }
128+ }
129+
98130 @ Override
99131 public boolean isLeft () {
100- return myLeft ;
132+ return turnLeft ;
101133 }
102134
103135 @ Override
104136 public boolean isRight () {
105- return myRight ;
137+ return turnRight ;
106138 }
107139
108140 @ Override
@@ -137,7 +169,7 @@ public TextureAtlas.AtlasRegion getInGameTex() {
137169
138170 @ Override
139171 public void blur () {
140- myLeft = false ;
141- myRight = false ;
172+ turnLeft = false ;
173+ turnRight = false ;
142174 }
143175}
0 commit comments