v0.4.3: implemented a new 'Power Saver' mode

As a bonus, this allows shattered to run on small screen devices, by forcing power saver, which downsamples in this specific case allowing for the minimum 2x game scale.
This commit is contained in:
Evan Debenham 2016-09-30 04:30:24 -04:00
parent 8591a0b3dc
commit debbb57066
9 changed files with 138 additions and 27 deletions

View File

@ -24,6 +24,7 @@ package com.watabou.input;
import java.util.ArrayList;
import java.util.HashMap;
import com.watabou.noosa.Game;
import com.watabou.utils.PointF;
import com.watabou.utils.Signal;
@ -96,6 +97,9 @@ public class Touchscreen {
float x = e.getX( index );
float y = e.getY( index );
x /= (Game.dispWidth / (float)Game.width);
y /= (Game.dispHeight / (float)Game.height);
start = new PointF( x, y );
current = new PointF( x, y );
@ -104,7 +108,13 @@ public class Touchscreen {
}
public void update( MotionEvent e, int index ) {
current.set( e.getX( index ), e.getY( index ) );
float x = e.getX( index );
float y = e.getY( index );
x /= (Game.dispWidth / (float)Game.width);
y /= (Game.dispHeight / (float)Game.height);
current.set( x, y );
}
public Touch up() {

View File

@ -53,8 +53,12 @@ import android.view.View;
public class Game extends Activity implements GLSurfaceView.Renderer, View.OnTouchListener {
public static Game instance;
//actual size of the display
public static int dispWidth;
public static int dispHeight;
// Actual size of the screen
// Size of the EGL surface view
public static int width;
public static int height;
@ -107,6 +111,8 @@ public class Game extends Activity implements GLSurfaceView.Renderer, View.OnTou
DisplayMetrics m = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics( m );
density = m.density;
dispHeight = m.heightPixels;
dispWidth = m.widthPixels;
try {
version = getPackageManager().getPackageInfo( getPackageName(), 0 ).versionName;

View File

@ -13,12 +13,14 @@
<uses-feature
android:glEsVersion="0x00020000"/>
<!-- Note that the game doesn't truly support small screen resolutions,
it instead forces downscaling to work on these displays.-->
<supports-screens
android:smallScreens="false"
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"/>
<!--android:xlargeScreens="true"-->
android:largeScreens="true"
android:xlargeScreens="true"/>
<application
android:icon="@drawable/ic_launcher"

View File

@ -30,6 +30,7 @@ enum Preferences {
public static final String KEY_LANDSCAPE = "landscape";
public static final String KEY_IMMERSIVE = "immersive";
public static final String KEY_POWER_SAVER = "power_saver";
public static final String KEY_SCALE = "scale";
public static final String KEY_MUSIC = "music";
public static final String KEY_MUSIC_VOL = "music_vol";

View File

@ -20,8 +20,8 @@
*/
package com.shatteredpixel.shatteredpixeldungeon;
import android.annotation.SuppressLint;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
@ -34,6 +34,7 @@ import com.watabou.noosa.Game;
import com.watabou.noosa.RenderedText;
import com.watabou.noosa.audio.Music;
import com.watabou.noosa.audio.Sample;
import com.watabou.utils.GameMath;
import javax.microedition.khronos.opengles.GL10;
import java.util.Locale;
@ -172,7 +173,10 @@ public class ShatteredPixelDungeon extends Game {
updateImmersiveMode();
DisplayMetrics metrics = new DisplayMetrics();
instance.getWindowManager().getDefaultDisplay().getMetrics( metrics );
if (immersed() && Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1)
getWindowManager().getDefaultDisplay().getRealMetrics( metrics );
else
getWindowManager().getDefaultDisplay().getMetrics( metrics );
boolean landscape = metrics.widthPixels > metrics.heightPixels;
if (Preferences.INSTANCE.getBoolean( Preferences.KEY_LANDSCAPE, false ) != landscape) {
@ -274,6 +278,7 @@ public class ShatteredPixelDungeon extends Game {
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
Preferences.INSTANCE.put( Preferences.KEY_LANDSCAPE, value );
((ShatteredPixelDungeon)instance).updateDisplaySize();
}
public static boolean landscape() {
@ -284,11 +289,8 @@ public class ShatteredPixelDungeon extends Game {
Preferences.INSTANCE.put( Preferences.KEY_SCALE, value );
}
// *** IMMERSIVE MODE ****
private static boolean immersiveModeChanged = false;
@SuppressLint("NewApi")
public static void immerse( boolean value ) {
Preferences.INSTANCE.put( Preferences.KEY_IMMERSIVE, value );
@ -297,21 +299,78 @@ public class ShatteredPixelDungeon extends Game {
public void run() {
updateImmersiveMode();
immersiveModeChanged = true;
//ensures surfacechanged is called if the view was previously set to be fixed.
((ShatteredPixelDungeon)instance).view.getHolder().setSizeFromLayout();
}
} );
}
@Override
public void onSurfaceChanged( GL10 gl, int width, int height ) {
super.onSurfaceChanged( gl, width, height );
updateDisplaySize();
if (immersiveModeChanged) {
requestedReset = true;
immersiveModeChanged = false;
}
}
@SuppressLint("NewApi")
private void updateDisplaySize(){
DisplayMetrics m = new DisplayMetrics();
if (immersed() && Build.VERSION.SDK_INT >= 19)
getWindowManager().getDefaultDisplay().getRealMetrics( m );
else
getWindowManager().getDefaultDisplay().getMetrics( m );
dispHeight = m.heightPixels;
dispWidth = m.widthPixels;
float dispRatio = dispWidth / (float)dispHeight;
float renderWidth = dispRatio > 1 ? PixelScene.MIN_WIDTH_L : PixelScene.MIN_WIDTH_P;
float renderHeight = dispRatio > 1 ? PixelScene.MIN_HEIGHT_L : PixelScene.MIN_HEIGHT_P;
//force power saver in this case as all devices must run at at least 2x scale.
if (dispWidth < renderWidth*2 || dispHeight < renderHeight*2)
Preferences.INSTANCE.put( Preferences.KEY_POWER_SAVER, true );
if (powerSaver()){
int maxZoom = (int)Math.min(dispWidth/renderWidth, dispHeight/renderHeight);
renderWidth *= GameMath.gate( 2, (float)Math.ceil(maxZoom/2f), 4);
renderHeight *= GameMath.gate( 2, (float)Math.ceil(maxZoom/2f), 4);
if (dispRatio > renderWidth / renderHeight){
renderWidth = renderHeight * dispRatio;
} else {
renderHeight = renderWidth / dispRatio;
}
final int finalW = Math.round(renderWidth);
final int finalH = Math.round(renderHeight);
if (finalW != width || finalH != height){
runOnUiThread(new Runnable() {
@Override
public void run() {
view.getHolder().setFixedSize(finalW, finalH);
}
});
}
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
view.getHolder().setSizeFromLayout();
}
});
}
}
public static void updateImmersiveMode() {
if (android.os.Build.VERSION.SDK_INT >= 19) {
try {
@ -336,7 +395,14 @@ public class ShatteredPixelDungeon extends Game {
return Preferences.INSTANCE.getBoolean( Preferences.KEY_IMMERSIVE, false );
}
// *****************************
public static boolean powerSaver(){
return Preferences.INSTANCE.getBoolean( Preferences.KEY_POWER_SAVER, false );
}
public static void powerSaver( boolean value ){
Preferences.INSTANCE.put( Preferences.KEY_POWER_SAVER, value );
((ShatteredPixelDungeon)instance).updateDisplaySize();
}
public static int scale() {
return Preferences.INSTANCE.getInt( Preferences.KEY_SCALE, 0 );

View File

@ -54,6 +54,7 @@ public class PixelScene extends Scene {
public static int defaultZoom = 0;
public static int maxDefaultZoom = 0;
public static int maxScreenZoom = 0;
public static float minZoom;
public static float maxZoom;
@ -82,6 +83,7 @@ public class PixelScene extends Scene {
}
maxDefaultZoom = (int)Math.min(Game.width/minWidth, Game.height/minHeight);
maxScreenZoom = (int)Math.min(Game.dispWidth/minWidth, Game.dispHeight/minHeight);
defaultZoom = ShatteredPixelDungeon.scale();
if (defaultZoom < Math.ceil( Game.density * 2 ) || defaultZoom > maxDefaultZoom){

View File

@ -54,6 +54,12 @@ public abstract class OptionSlider extends Component {
public OptionSlider(String title, String minTxt, String maxTxt, int minVal, int maxVal){
super();
//shouldn't function if this happens.
if (minVal > maxVal){
minVal = maxVal;
active = false;
}
this.title.text(title);
this.minTxt.text(minTxt);
this.maxTxt.text(maxTxt);
@ -61,12 +67,6 @@ public abstract class OptionSlider extends Component {
this.minVal = minVal;
this.maxVal = maxVal;
//really shouldn't display the slider if this happens.
if (minVal > maxVal){
active = false;
visible = false;
}
sliderTicks = new ColorBlock[(maxVal - minVal) + 1];
for (int i = 0; i < sliderTicks.length; i++){
add(sliderTicks[i] = new ColorBlock(1, 11, 0xFF222222));

View File

@ -127,12 +127,9 @@ public class WndSettings extends WndTabbed {
}
};
scale.setSelectedValue(PixelScene.defaultZoom);
if ((int)Math.ceil(2* Game.density) < PixelScene.maxDefaultZoom) {
scale.setRect(0, 0, WIDTH, SLIDER_HEIGHT);
scale.setRect(0, 0, WIDTH, SLIDER_HEIGHT);
if ((int)Math.ceil(2* Game.density) < PixelScene.maxDefaultZoom)
add(scale);
} else {
scale.setRect(0, 0, 0, 0);
}
OptionSlider brightness = new OptionSlider(Messages.get(this, "brightness"),
Messages.get(this, "dark"), Messages.get(this, "bright"), -2, 2) {
@ -142,7 +139,7 @@ public class WndSettings extends WndTabbed {
}
};
brightness.setSelectedValue(ShatteredPixelDungeon.brightness());
brightness.setRect(0, scale.bottom() + GAP_SML, WIDTH, SLIDER_HEIGHT);
brightness.setRect(0, scale.bottom() + GAP_TINY, WIDTH, SLIDER_HEIGHT);
add(brightness);
CheckBox chkImmersive = new CheckBox( Messages.get(this, "soft_keys") ) {
@ -152,11 +149,34 @@ public class WndSettings extends WndTabbed {
ShatteredPixelDungeon.immerse(checked());
}
};
chkImmersive.setRect( 0, brightness.bottom() + GAP_LRG, WIDTH, BTN_HEIGHT );
chkImmersive.setRect( 0, brightness.bottom() + GAP_SML, WIDTH, BTN_HEIGHT );
chkImmersive.checked(ShatteredPixelDungeon.immersed());
chkImmersive.enable(android.os.Build.VERSION.SDK_INT >= 19);
add(chkImmersive);
CheckBox chkSaver = new CheckBox( Messages.get(this, "saver") ) {
@Override
protected void onClick() {
super.onClick();
checked( !checked() );
ShatteredPixelDungeon.scene().add(new WndOptions(
Messages.get(ScreenTab.class, "saver"),
Messages.get(ScreenTab.class, "saver_desc"),
Messages.get(ScreenTab.class, "okay"),
Messages.get(ScreenTab.class, "cancel")){
@Override
protected void onSelect(int index) {
if (index == 0){
checked( !checked() );
ShatteredPixelDungeon.powerSaver(checked());
}
}
});
}
};
chkSaver.setRect( 0, chkImmersive.bottom() + GAP_TINY, WIDTH, BTN_HEIGHT );
chkSaver.checked(ShatteredPixelDungeon.powerSaver());
if (PixelScene.maxScreenZoom >= 2) add(chkSaver);
RedButton btnOrientation = new RedButton( ShatteredPixelDungeon.landscape() ?
Messages.get(this, "portrait")
@ -166,7 +186,7 @@ public class WndSettings extends WndTabbed {
ShatteredPixelDungeon.landscape(!ShatteredPixelDungeon.landscape());
}
};
btnOrientation.setRect(0, chkImmersive.bottom() + GAP_LRG, WIDTH, BTN_HEIGHT);
btnOrientation.setRect(0, chkSaver.bottom() + GAP_SML, WIDTH, BTN_HEIGHT);
add( btnOrientation );
}
}

View File

@ -88,6 +88,10 @@ windows.wndsettings$screentab.brightness=Brightness
windows.wndsettings$screentab.dark=Dark
windows.wndsettings$screentab.bright=Bright
windows.wndsettings$screentab.soft_keys=Hide Software Keys
windows.wndsettings$screentab.saver=Power Saver Mode
windows.wndsettings$screentab.saver_desc=Power saver mode draws the game at a reduced size and scales it up to fit your screen.\n\nThis will make the graphics less crisp, but will improve performance and battery life.\n\nYou may need to restart the game for changes to take effect.
windows.wndsettings$screentab.okay=Okay
windows.wndsettings$screentab.cancel=Cancel
windows.wndsettings$screentab.portrait=Switch to portrait
windows.wndsettings$screentab.landscape=Switch to landscape
windows.wndsettings$uitab.mode=Toolbar Mode: