Well trying to program a simple game in Android, I cam across the problem of saving data. I went the route of using simple Key Value pairs using Shared Preferences, mostly because I'm only saving 10 - 15 simple Integers. But I cant save it in the main Activity. because I cant seem to call it on Surface Created (In the Game Panel). Also I tried having the function of saving data in the Game Panel but it cant be created in a static method. Which the Game Panel is. So it seems I don't know where to put it.
Here is the GamePanel code:
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback {
private MainThread thread;
private UserObject player = new UserObject();
private MainActivity activity = new MainActivity();
private loadImage background;
private loadImage house;
private loadImage constructionWorker;
private loadImage houseUpgrade;
private loadImage bob;
private loadImage workGroup;
private loadImage bank;
private loadImage factory;
private loadImage superTapping;
private loadImage unlockStore;
private loadImage store;
int screenWidth = this.getResources().getDisplayMetrics().widthPixels;
int screenHeight = this.getResources().getDisplayMetrics().heightPixels;
Bitmap buttonVars = BitmapFactory.decodeResource(getResources(), R.drawable.house_upgrade);
int buttonWidth = buttonVars.getWidth();
int buttonHeight = buttonVars.getHeight();
Bitmap houseVars = BitmapFactory.decodeResource(getResources(), R.drawable.house_upgrade);
int houseWidth = houseVars.getWidth();
int houseHeight = houseVars.getHeight();
public GamePanel(Context context) {
super(context);
//add the callback to the surface holder to intercept events
getHolder().addCallback(this);
//make gamePanel focusable so it can handle events
setFocusable(true);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
activity.saveData();
boolean retry = true;
while (retry) {
try {
thread.setRunning(false);
thread.join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
//we can safely start the game loop
activity.getData()
thread = new MainThread(getHolder(), this);
thread.setRunning(true);
thread.start();
//Create Bitmaps
background = new loadImage(BitmapFactory.decodeResource(getResources(), R.drawable.blue_background), 0, 0);
house = new loadImage(BitmapFactory.decodeResource(getResources(), R.drawable.crap_shack), ((screenWidth / 2) - houseWidth), (houseHeight * 2));
houseUpgrade = new loadImage(BitmapFactory.decodeResource(getResources(), R.drawable.house_upgrade), 0, (screenHeight - buttonHeight));
constructionWorker = new loadImage(BitmapFactory.decodeResource(getResources(), R.drawable.construction_worker), ((screenWidth / 2) - (buttonWidth / 2)), (screenHeight - buttonHeight));
bob = new loadImage(BitmapFactory.decodeResource(getResources(), R.drawable.bob), (screenWidth - buttonWidth), (screenHeight - buttonHeight));
workGroup = new loadImage(BitmapFactory.decodeResource(getResources(), R.drawable.work_group), 0, (screenHeight - (buttonHeight * 3)));
bank = new loadImage(BitmapFactory.decodeResource(getResources(), R.drawable.bank), ((screenWidth / 2) - (buttonWidth / 2)), (screenHeight - (buttonHeight * 3)));
factory = new loadImage(BitmapFactory.decodeResource(getResources(), R.drawable.factory), (screenWidth - buttonWidth), (screenHeight - (buttonHeight * 3)));
superTapping = new loadImage(BitmapFactory.decodeResource(getResources(), R.drawable.super_tapping), 0, (screenHeight - (buttonHeight * 5)));
unlockStore = new loadImage(BitmapFactory.decodeResource(getResources(), R.drawable.unlock_store), ((screenWidth / 2) - (buttonWidth / 2)), (screenHeight - (buttonHeight * 5)));
store = new loadImage(BitmapFactory.decodeResource(getResources(), R.drawable.store), (screenWidth - buttonWidth), (screenHeight - (buttonHeight * 5)));
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//handle house
house.handleActionDown((int) event.getX(), (int) event.getY());
if (house.touched) {
player.money += player.MPC;
house.setTouched(false);
}
//handle houseUpgrade
houseUpgrade.handleActionDown((int) event.getX(), (int) event.getY());
if (houseUpgrade.touched && player.money >= player.houseUpgradeCost) {
player.money -= player.houseUpgradeCost;
player.MPC += 1;
player.houseUpgradeCost += 250;
houseUpgrade.setTouched(false);
}
//handle ConstructionWorker
constructionWorker.handleActionDown((int) event.getX(), (int) event.getY());
if (constructionWorker.touched && player.money >= player.constructionWorkerCost) {
player.money -= player.constructionWorkerCost;
player.MPS += 1;
player.constructionWorkerCost += 25;
constructionWorker.setTouched(false);
}
//handle bob
bob.handleActionDown((int) event.getX(), (int) event.getY());
if (bob.touched && player.money >= player.bobCost) {
player.money -= player.bobCost;
player.MPS += 5;
player.bobCost += 200;
bob.setTouched(false);
}
//handle workGroup
workGroup.handleActionDown((int) event.getX(), (int) event.getY());
if (workGroup.touched && player.money >= player.workGroupCost) {
player.money -= player.workGroupCost;
player.MPS += 50;
player.workGroupCost += 1250;
workGroup.setTouched(false);
}
//handle bank
bank.handleActionDown((int) event.getX(), (int) event.getY());
if (bank.touched && player.money >= player.bankCost) {
player.money -= player.bankCost;
player.MPS += 250;
player.bankCost += 5000;
bank.setTouched(false);
}
//handle Factory
factory.handleActionDown((int) event.getX(), (int) event.getY());
if (factory.touched && player.money >= player.factoryCost) {
player.money -= player.factoryCost;
player.MPS += 1000;
player.factoryCost += 25000;
factory.setTouched(false);
}
//handle superTapping
superTapping.handleActionDown((int) event.getX(), (int) event.getY());
if (superTapping.touched && player.money >= player.superTappingCost) {
player.money -= player.superTappingCost;
player.MPC += 25;
player.superTappingCost += 7500;
superTapping.setTouched(false);
}
//handle unlockStore
unlockStore.handleActionDown((int) event.getX(), (int) event.getY());
if (unlockStore.touched && player.money >= player.unlockStoreCost && !player.storeUnlocked) {
player.money -= player.unlockStoreCost;
player.storeUnlocked = true;
unlockStore.setTouched(false);
}
//handle store
store.handleActionDown((int) event.getX(), (int) event.getY());
if (store.touched && player.storeUnlocked) {
}
}
if (event.getAction() == MotionEvent.ACTION_UP) {
house.setTouched(false);
houseUpgrade.setTouched(false);
constructionWorker.setTouched(false);
bob.setTouched(false);
workGroup.setTouched(false);
bank.setTouched(false);
factory.setTouched(false);
superTapping.setTouched(false);
unlockStore.setTouched(false);
}
return super.onTouchEvent(event);
}
public void draw(Canvas canvas) {
//Draws to canvas
background.draw(canvas);
house.draw(canvas);
houseUpgrade.draw(canvas);
constructionWorker.draw(canvas);
bob.draw(canvas);
workGroup.draw(canvas);
bank.draw(canvas);
factory.draw(canvas);
superTapping.draw(canvas);
unlockStore.draw(canvas);
if (player.storeUnlocked) {
store.draw(canvas);
}
writeText(canvas, "Money: $" + player.money, Paint.Align.CENTER, Color.BLACK, 25, (screenWidth / 2), 50);
writeText(canvas, "MPS: " + player.MPS, Paint.Align.CENTER, Color.BLACK, 25, (screenWidth / 2), 75);
writeText(canvas, "MPC: " + player.MPC, Paint.Align.CENTER, Color.BLACK, 25, (screenWidth / 2), 100);
writeText(canvas, "Cost: $" + player.houseUpgradeCost, null, Color.BLACK, 15, 0, (screenHeight - buttonHeight));
writeText(canvas, "Cost: $" + player.constructionWorkerCost, Paint.Align.CENTER, Color.BLACK, 15, (screenWidth / 2), (screenHeight - buttonHeight));
writeText(canvas, "Cost: $" + player.bobCost, Paint.Align.LEFT, Color.BLACK, 15, screenWidth, (screenHeight - buttonHeight));
writeText(canvas, "Cost: $" + player.workGroupCost, null, Color.BLACK, 15, 0, ((screenHeight - (buttonHeight * 3))));
writeText(canvas, "Cost: $" + player.bankCost, Paint.Align.CENTER, Color.BLACK, 15, (screenWidth / 2), ((screenHeight - (buttonHeight * 3))));
writeText(canvas, "Cost: $" + player.factoryCost, Paint.Align.LEFT, Color.BLACK, 15, (screenWidth), ((screenHeight - (buttonHeight * 3))));
writeText(canvas, "Cost: $" + player.superTappingCost, null, Color.BLACK, 15, 0, ((screenHeight - (buttonHeight * 5))));
writeText(canvas, "Cost: $" + player.unlockStoreCost, Paint.Align.CENTER, Color.BLACK, 15, (screenWidth / 2), ((screenHeight - (buttonHeight * 5))));
}
private void writeText(Canvas canvas, String text, Paint.Align align, int color, int textSize, int x, int y) {
//Sets default align if null
if (align == null) {
align = Paint.Align.RIGHT;
}
//Sets paint using values
Paint paint = new Paint();
paint.setTextAlign(align);
paint.setColor(color);
paint.setTextSize(textSize);
canvas.drawText(text, x, y, paint);
}
}
Here is the actual Main Activity where I'm trying to save the Data.
public class MainActivity extends Activity {
private UserObject player = new UserObject();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Sets window settings FULLSCREEN, NO TITLE, NO ACTION BAR.
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new GamePanel(this));
}
public void saveData() {
SharedPreferences sharedPreferences = getSharedPreferences("houseTapper_dataSaveFile", MODE_PRIVATE);
SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit();
sharedPreferencesEditor.putInt("money", player.money);
sharedPreferencesEditor.putInt("MPS", player.MPS);
sharedPreferencesEditor.putInt("MPC", player.MPC);
sharedPreferencesEditor.putInt("houseUpgradeCost", player.houseUpgradeCost);
sharedPreferencesEditor.putInt("constructionWorkerCost", player.constructionWorkerCost);
sharedPreferencesEditor.putInt("bobCost", player.bobCost);
sharedPreferencesEditor.putInt("workGroupCost", player.workGroupCost);
sharedPreferencesEditor.putInt("bankCost", player.bankCost);
sharedPreferencesEditor.putInt("factoryCost", player.factoryCost);
sharedPreferencesEditor.putInt("superTappingCost", player.superTappingCost);
sharedPreferencesEditor.putBoolean("storeUnlocked", player.storeUnlocked);
sharedPreferencesEditor.apply();
}
public void getData() {
SharedPreferences sharedPreferences = getSharedPreferences("houseTapper_dataSaveFile", MODE_PRIVATE);
player.money = sharedPreferences.getInt("money", 0);
player.MPS = sharedPreferences.getInt("MPS", 0);
player.MPC = sharedPreferences.getInt("MPC", 0);
player.houseUpgradeCost = sharedPreferences.getInt("houseUpgradeCost", 0);
player.constructionWorkerCost = sharedPreferences.getInt("constructionWorkerCost", 0);
player.bobCost = sharedPreferences.getInt("bobCost", 0);
player.workGroupCost = sharedPreferences.getInt("workGroupCost", 0);
player.bankCost = sharedPreferences.getInt("bankCost", 0);
player.factoryCost = sharedPreferences.getInt("factoryCost", 0);
player.superTappingCost = sharedPreferences.getInt("superTappingCost", 0);
player.storeUnlocked = sharedPreferences.getBoolean("storeUnlocked", false);
}
}
Finnaly here is the mainThread
public class MainThread extends Thread {
private UserObject player = new UserObject();
private int FPS = 30;
private SurfaceHolder surfaceHolder;
private GamePanel gamePanel;
private boolean running;
public static Canvas canvas;
//Game variables
public MainThread(SurfaceHolder surfaceHolder, GamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
@Override
public void run() {
long startTime;
long timeMillis;
long waitTime;
long targetTime = 1000/FPS;
int frames = 0;
while(running) {
startTime = System.nanoTime();
canvas = null;
if (frames == 30) {
frames = 0;
player.money += player.MPS;
}
//try locking the canvas for pixel editing
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
this.gamePanel.draw(canvas);
}
} catch (Exception e) {
}
finally{
if(canvas!=null)
{
try {
surfaceHolder.unlockCanvasAndPost(canvas);
}
catch(Exception e){e.printStackTrace();}
}
}
timeMillis = (System.nanoTime() - startTime) / 1000000;
waitTime = targetTime-timeMillis;
frames++;
try {
this.sleep(waitTime);
} catch(Exception e) {}
}
}
public void setRunning(boolean b)
{
running=b;
}
}
I left out the LoadImage and UserObject classes. Because they are unimportant.
What has saving/loading got to do with an activity? Nothing, you probably just started with it there, but it has no reason to stay there.
So separate Persistence out to own class, then you can call anywhere you have a Context
:
public final class Persistence {
private final SharedPreferences sharedPreferences;
public Persistence(Context context) {
sharedPreferences = context.getSharedPreferences("houseTapper_dataSaveFile", MODE_PRIVATE);
}
public void saveData(Player player) {
SharedPreferences.Editor sharedPreferencesEditor = sharedPreferences.edit();
sharedPreferencesEditor.putInt("money", player.money);
sharedPreferencesEditor.putInt("MPS", player.MPS);
sharedPreferencesEditor.putInt("MPC", player.MPC);
// etc...
sharedPreferencesEditor.apply();
}
public void getData(Player player) {
player.money = sharedPreferences.getInt("money", 0);
player.MPS = sharedPreferences.getInt("MPS", 0);
player.MPC = sharedPreferences.getInt("MPC", 0);
// etc...
}
}
Usage:
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback {
private final Persistence persistence = new Persistence(getContext());
@Override
public void surfaceCreated(SurfaceHolder holder) {
//we can safely start the game loop
persistence.getData(player);
}