I've spent a lot of time today researching why my getters are returning null and cant seem to find a clean answer. I am looking to create a clean hierarchy using classes and pass the information from one to the other. I dont know if this is good practice im still new to game development and android studio in general. I would like to be able to pass the variables from the Game.java(which is my activity class) without adding it to my other classes in their constructors. I want to be able to access the getters like it is another class but cant seem to work out how. Full code will be included below: getXDirection and getyDirecion in the Game.java are returning 0 from the player class which implys they haven't been initialised
Game.java
package com.Frenchie.SpaceshipSammy;
import ...
public class Game extends Activity implements SensorEventListener{
private SensorManager senSensorManager;
private Sensor senAccelerometer;
//Directional constants
private static final int DIRECTION_STATIONARY = 0;
private static final int DIRECTION_LEFT = 1;
private static final int DIRECTION_RIGHT= 2;
private static final int DIRECTION_UP = 3;
private static final int DIRECTION_DOWN= 4;
//Direction variables
private int yDirection, xDirection;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Set view to GameView
setContentView(new GameView(this));
//Sensor stuff
senSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
senAccelerometer = senSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
senSensorManager.registerListener(this, senAccelerometer , SensorManager.SENSOR_DELAY_GAME);
}
#Override
public boolean onTouchEvent(MotionEvent motionEvent) {
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
//Finger down - Move up
yDirection = DIRECTION_UP;
break;
case MotionEvent.ACTION_UP:
//Finger lifted - Move down
yDirection = DIRECTION_DOWN;
break;
}
return true;
}
//Overriding Accelerometer to read data
#Override
public void onSensorChanged(SensorEvent sensorEvent) {
Sensor mySensor = sensorEvent.sensor;
if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) {
float x = sensorEvent.values[1];
if (x > -1 && x < 1) {
//Stationary
xDirection = DIRECTION_STATIONARY;
} else if (x >= 1) {
//Move right
xDirection = DIRECTION_RIGHT;
} else if (x <= -1) {
//Move left
xDirection = DIRECTION_LEFT;
} else {
Log.d("onSensorChanged", "Escaped");
}
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
//Getters for Player class to use
public int getyDirection() {
return yDirection;
}
public int getxDirection() {
return xDirection;
}
}
Player.java
package com.Frenchie.SpaceshipSammy;
import ...
public class Player {
//Directional constants
private static final int DIRECTION_STATIONARY = 0;
private static final int DIRECTION_LEFT = 1;
private static final int DIRECTION_RIGHT = 2;
private static final int DIRECTION_UP = 3;
private static final int DIRECTION_DOWN = 4;
//Location variables
private int x, y, speed;
//Sprite
private Bitmap sprite;
private Game userInput;
public Player(Context context){
speed = 10;
userInput = new Game();
sprite = BitmapFactory.decodeResource(context.getResources(), R.drawable.player);
}
//Called from Logic to move players location
public void PositionUpdate(){
xMove();
yMove();
}
private void xMove(){
if (userInput.getxDirection() == DIRECTION_STATIONARY){
//Stationary
}
else if (userInput.getxDirection() == DIRECTION_RIGHT){
//Move right
x += speed;
Log.d("xMove","Right");
}
else if (userInput.getxDirection() == DIRECTION_LEFT){
//Move left
x -= speed;
}
else {
Log.d("xMove", "xDirection unrecognised");
}
}
private void yMove(){
if (userInput.getyDirection() == DIRECTION_UP){
//Move up
y -= speed;
}
else if (userInput.getyDirection() == DIRECTION_DOWN){
//Move down
y += speed;
}
else{
//Log.d("yMove", "yDirection unrecognised");
}
}
//Get x and y for Logic
public int getX() {
return x;
}
public int getY() {
return y;
}
public Bitmap getSprite() {
return sprite;
}
}
Logic.java
package com.Frenchie.SpaceshipSammy;
import ...
public class Logic implements Runnable {
//Bring in required classes
private Player player;
//Player variables
private int yPlayer, xPlayer;
private Bitmap playerSprite;
public Logic(Context context){
player = new Player(context);
//Sprite currently wont change so this doesn't need to be updated with the location
playerSprite = player.getSprite();
//Creating and running thread
Thread thread = new Thread(this);
thread.start();
}
//Thread to tell the players position update method to run and update the players values in this class
#Override
public void run() {
while(true) {
player.PositionUpdate();
PlayerLocation();
}
}
//Updates the players location which can be passed onto GameView
public void PlayerLocation(){
xPlayer = player.getX();
yPlayer = player.getY();
}
//Getters for GameView to use
public int getyPlayer() {
return yPlayer;
}
public int getxPlayer() {
return xPlayer;
}
public Bitmap getPlayerSprite() {
return playerSprite;
}
}
GameView.java
package com.Frenchie.SpaceshipSammy;
import ...
public class GameView extends SurfaceView implements Runnable{
private SurfaceHolder surfaceHolder = getHolder();
private Canvas canvas;
//Link Logic class
private Logic logic;
public GameView(Context context) {
super(context);
//Creates logic as a new object
logic = new Logic(context);
//Creates and starts the thread
Thread thread = new Thread(this);
thread.start();
}
//Override thread method. This is called when the thread is started
#Override
public void run() {
while (true){
DrawFrame();
}
}
private void DrawFrame(){
canvas = surfaceHolder.lockCanvas();
if (surfaceHolder.getSurface().isValid()){
canvas.drawColor(Color.MAGENTA);
canvas.drawBitmap(logic.getPlayerSprite(), logic.getxPlayer(), logic.getyPlayer(), null);
surfaceHolder.unlockCanvasAndPost(canvas);
} else {
Log.d("DrawFrame", "Surface Invalid");
}
}
}
All help is appreciated!
This is your problem, in your GameView
userInput = new Game();
You are pointing to a new instance of your Activity, not the actual Activity that is displayed. You need to set this value after the Player is created with the activity instance 'this'.
I'm currently following this book to create my libgdx game..
So far, i have these classes to create my game :
AbstractGameScreen.java - that Implements libgdx's Screen
AbstractGameObject.java - that extends libgdx's Actor
GamePlay.java - which is my game screen
GameController.java - where i init my game objects
GameRenderer.java - when i render all my objects
Assets.java - a class that organizes my game assets
Ring.java - an object in my game
And here is my code..
AbstractGameScreen
public abstract class AbstractGameScreen implements Screen {
protected Game game;
public AbstractGameScreen(Game game){
this.game = game;
}
public abstract void render(float deltaTime);
public abstract void resize(int width, int height);
public abstract void show();
public abstract void hide();
public abstract void pause();
public void resume(String bg, String ring){
Assets.instance.init(new AssetManager(), bg, ring); // kosongin, jadinya default
}
public void dispose(){
Assets.instance.dispose();
}
}
AbstractGameObject
public abstract class AbstractGameObject extends Actor{ //implements EventListener{ //extends Sprite{
public Vector2 position;
public Vector2 dimension;
public Vector2 origin;
public Vector2 scale;
public float rotation;
public AbstractGameObject(){
position = new Vector2();
dimension = new Vector2(1, 1);
origin = new Vector2();
scale = new Vector2(1, 1);
rotation = 0;
}
public void update (float deltaTime){
}
public abstract void render(SpriteBatch batch);
}
GamePlay
public class GamePlay extends AbstractGameScreen implements InputProcessor{
private GameController gameController;
private GameRenderer gameRenderer;
private String dummyBg, dummyRing;
private boolean paused;
// for touch purposes
private static final int appWidth = Constants.VIEWPORT_GUI_WIDTH_INT;
private static final int appHeight = Constants.VIEWPORT_GUI_HEIGHT_INT;
public GamePlay(Game game) {
super(game);
// still dummy.. nantinya ngambil dari database nya
this.dummyBg = "bg-default";
this.dummyRing = "ring-default";
Gdx.input.setInputProcessor(this);
}
#Override
public void render(float deltaTime) {
if(!paused){
gameController.update(deltaTime);
}
//Gdx.gl.glClearColor(0x64 / 255.0f, 0x95 / 255.0f,0xed / 255.0f, 0xff / 255.0f);
//Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// render game nya
gameRenderer.render();
}
#Override
public void resize(int width, int height) {
gameRenderer.resize(width, height);
}
#Override
public void show() {
Assets.instance.init(new AssetManager(), "bg-default", "ring-default");
Gdx.app.log("GamePlay", "After show() method");
gameController = new GameController(game);
gameRenderer = new GameRenderer(gameController);
Gdx.input.setCatchBackKey(true);
}
#Override
public void hide() {
gameRenderer.dispose();
Gdx.input.setCatchBackKey(false);
}
#Override
public void dispose(){
gameRenderer.dispose();
Assets.instance.dispose();
}
#Override
public void pause() {
paused = true;
}
#Override
public void resume() {
super.resume(this.dummyBg, this.dummyRing);
//Assets.instance.init(new AssetManager(), this.dummyBg, this.dummyRing);
paused = false;
}
#Override
public boolean keyDown(int keycode) {
return false;
}
#Override
public boolean keyUp(int keycode) {
return false;
}
#Override
public boolean keyTyped(char character) {
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
return true;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
return true;
}
// for touch purposes
private float getCursorToModelX(int screenX, int cursorX) {
return (((float)cursorX) * appWidth) / ((float)screenX);
}
private float getCursorToModelY(int screenY, int cursorY) {
return ((float)(screenY - cursorY)) * appHeight / ((float)screenY) ;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(int amount) {
return false;
}
}
GameController
public class GameController extends InputAdapter{
// game objects
public Array<Tiang> tiangs;
public Array<Ring> rings;
//private Game game;
// game decorations
public Background background; public Sprite[] testSprite;
private Game game;
public GameController(Game game){
this.game = game;
init();
}
private void init(){
// preparing variables
rings = new Array<Ring>();
tiangs = new Array<Tiang>();
initObjects();
initDecorations();
initGui();
}
private void initObjects(){
AbstractGameObject obj = null;
obj = new Ring(1, "default");
obj.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
//super.clicked(event, x, y);
Gdx.app.log("tag", "test clisk");
}
});
rings.add((Ring)obj);
}
private void initDecorations(){
}
private void initGui(){
}
private void handleInput(float deltatime){
}
public void update(float deltaTime){
//if(Gdx.input.isTouched()){
// Gdx.app.log("update", "screen touched");
//}
}
}
GameRenderer
public class GameRenderer implements Disposable{
private OrthographicCamera camera;
private GameController controller;
private SpriteBatch batch;
public GameRenderer(GameController controller){
this.controller = controller;
init();
}
private void init(){
batch = new SpriteBatch();
camera = new OrthographicCamera(Constants.VIEWPORT_WIDTH, Constants.VIEWPORT_HEIGHT); //diambil dari class "Constants" (di package util)
camera.position.set(0, 0, 0);
camera.update();
}
public void resize(int width, int height){
camera.viewportWidth = (Constants.VIEWPORT_HEIGHT / height) * width;
camera.update();
}
public void render(){
renderGui();
renderDecorations();
renderObjects();
}
private void renderGui(){
}
private void renderDecorations(){
}
private void renderObjects(){
batch.setProjectionMatrix(camera.combined);
batch.begin();
for(Ring rings : controller.rings){
rings.render(batch);
}
batch.end();
}
#Override
public void dispose() {
}
}
Assets
public class Assets implements Disposable, AssetErrorListener{
public static final String TAG = Assets.class.getName();
public static final Assets instance = new Assets();
private AssetManager assetManager;
// inner class objects
public AssetTiang tiang;
public AssetBackgroud bg;
public AssetTombol tombol;
public AssetTombolBg tombolBg;
public AssetRing ring;
//singleton pattern, buat mencegah instansiasi dari class yang lain
private Assets(){}
//public void init(AssetManager assetManager){
public void init(AssetManager assetManager, String jenisBg, String jenisRing){
this.assetManager = assetManager;
assetManager.setErrorListener(this);
//load texture atlas yang udah dibikin pake TexturePacker nya (liat ebook page 167)
assetManager.load(Constants.TEXTURE_ATLAS_OBJECTS, TextureAtlas.class);
assetManager.load(Constants.TEXTURE_ATLAS_DECORATION, TextureAtlas.class);
assetManager.load(Constants.TEXTURE_ATLAS_GUI, TextureAtlas.class);
// inner class objects
tiang = new AssetTiang(atlasObject);
bg = new AssetBackgroud(atlasDecoration, jenisBg);
tombol = new AssetTombol(atlasGui);
tombolBg = new AssetTombolBg(atlasDecoration);
ring = new AssetRing(atlasObject, jenisRing);
}
#Override
public void error(AssetDescriptor asset, Throwable throwable) {
// TODO Auto-generated method stub
}
#Override
public void dispose(){
assetManager.dispose();
}
public class AssetRing{
public final AtlasRegion ring;
// jenis ring dimasukin disini, karena jenis ring bisa diganti-ganti sesuai yang dipilih
public AssetRing(TextureAtlas atlas, String jenisRing){
if(!jenisRing.equals("")){
ring = atlas.findRegion(jenisRing);
}
else{
ring = atlas.findRegion("ring-default");
}
}
}
}
And finally, Ring (Object)
public class Ring extends AbstractGameObject{
private TextureRegion ringOverLay;
private float length;
// jenis ring nya
public String jenis;
public Ring(float length, String jenis){
init();
setLength(length);
setJenis(jenis);
}
// getters
public float getLength(){
return this.length;
}
public String getJenis(){
return this.jenis;
}
public Vector2 getPosition(){
return position;
}
// setters
public void setLength(float length){
this.length = length;
dimension.set(5.0f, 1.0f);
}
public void setJenis(String jenis){
this.jenis = jenis;
}
public void setPosition(float x, float y){
position.set(x, y);
}
private void init(){
ringOverLay = Assets.instance.ring.ring; // Assets.instance.namaobjek.atlasregion
origin.x = dimension.x/2; // -dimension.x/2;
origin.y = dimension.y/2;
position.x = -5.0f;
position.y = -2.5f;
}
#Override
public void render(SpriteBatch batch) {
TextureRegion reg = null;
reg = ringOverLay;
batch.draw(reg.getTexture(), position.x, position.y, origin.x, origin.y, dimension.x, dimension.y, scale.x, scale.y, rotation, reg.getRegionX(), reg.getRegionY(), reg.getRegionWidth(), reg.getRegionHeight(), false, false);
}
}
So what's the problem? Okay, the problem is i cannot make the Ring (game object) become clickable.. the Ring is extending AbstractGameObject (which is Actor), and, in the GameController i've add a ClickListener to the Ring object, but the object still unclickable..
Please, anyone tell me what's my mistake?
You're using your Actor (in your case, the Ring) incorrectly: Actors are part of Scene2d, and as such must follow precise rules to work correctly.
To answer your question more specifically, Ring needs to be added to a Stage which itself is an InputProcessor. The Stage is responsible to distribute the input events (such as touch events) to the its Actors. Without defining a Stage your Actors will not respond to any input events.
Read up on Scene2d from the link above. This video tutorial is also helpful.
I am new to android graphics as far as custom views and such. I have the following program, but the SurfaceView for some reason will not draw a image from an object of another class. I continue to get a null pointer exception.
MAIN CLASS:
public class Main extends Activity {
MyView view;
TestObject test;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view = new MyView(this, this);
test = new TestObject(this);
setContentView(view);
}
public TestObject getTest() {
return test;
}
public void setTest(TestObject test) {
this.test = test;
}
}
VIEW CLASS:
public class MyView extends SurfaceView implements Runnable {
SurfaceHolder surfaceHolder;
Thread thread;
TestObject test;
public MyView(Context context, Main main) {
super(context);
this.test = main.getTest();
surfaceHolder = getHolder();
thread = new Thread(this);
thread.start();
}
#Override
public void run() {
while(true){
if(!surfaceHolder.getSurface().isValid())
continue;
Canvas canvas = surfaceHolder.lockCanvas();
canvas.drawBitmap(test.getImage(), test.getX(), test.getY(), null);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
OBJECT CLASS:
public class TestObject {
Main main;
Bitmap image;
int x,y;
DisplayMetrics dm;
public TestObject(Main main) {
this.main = main;
image = BitmapFactory.decodeResource(main.getResources(), R.drawable.ic_launcher);
dm = new DisplayMetrics();
x = dm.widthPixels / 2;
y = dm.heightPixels / 2;
}
public Bitmap getImage() {
return image;
}
public void setImage(Bitmap image) {
this.image = image;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
I get a null pointer exception at canvas.drawBitmap(test.getImage(), test.getX(), test.getY(), null); in the MyView class. Strangly, it will work if if was to say canvas.drawBitmap(BitmapFactory.decodeResource(main.getResources(), R.drawable.ic_launcher), 0, 0, null); (or any other x, y position).
Any help is appreciated!
You should override "onDraw" method of "MyView" instead of implementing Runnable.
I'm trying to create and extended class from the one bellow but I'm getting an error message from eclipse saying "Syntax error on token "{", { expected after this token"
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Vector2;
public class Ship {
protected int hull;
protected int shield;
protected Vector2 velocity;
protected int energy;
protected Texture shipTexture;
protected Vector2 position;
public Texture getShipTexture() {
return shipTexture;
}
public void setShipTexture(Texture shipTexture) {
this.shipTexture = shipTexture;
}
public Vector2 getPosition() {
return position;
}
public void setPosition(Vector2 position) {
this.position = position;
}
public int getHull() {
return hull;
}
public void setHull(int hull) {
this.hull = hull;
}
public int getShield() {
return shield;
}
public void setShield(int shield) {
this.shield = shield;
}
public Vector2 getVelocity() {
return velocity;
}
public void setVelocity(Vector2 velocity) {
this.velocity = velocity;
}
public int getEnergy() {
return energy;
}
public void setEnergy(int energy) {
this.energy = energy;
}
}
for this class after the first bracket:
public class Frigate extends Ship {
this.hull = 10;
this.shield = 10;
}
Is there a better way to set up "ships" with the same variables and actions but with different values?
It looks like you're attempting to initialize instance variables for your Frigate. Place that code inside a constructor.
public Frigate()
{
this.hull = 10;
this.shield = 10;
}
I would create a constructor fir Ship that accepts the two values:
protected Ship(int hull, int shield) {
this.hull = hull;
this.shield = shield;
}
Then call it from the subclass:
public class Frigate extends Ship {
public Frigate {
super(10, 10);
}
You should consider making Ship abstract as well, if it's just a "base" class.
How might I draw a graph of a function (for example, y = x^2 or y = (x +1)/(2*x +3)) on a Canvas in an Android app?
Here you have an example code ;D (plots the f(x)=x^3 function)
A sample thread that plots the function.
public class MainThread extends Thread {
private static final String TAG = MainThread.class.getSimpleName();
private SurfaceHolder surfaceHolder;
private MainGamePanel gamePanel;
private Paint paintRed;
private Paint paintBlue;
private boolean running;
public void setRunning(boolean running) {
this.running = running;
}
public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
super();
this.paintRed = new Paint();
this.paintRed.setColor(Color.RED);
this.paintRed.setStrokeWidth(1);
this.paintBlue = new Paint();
this.paintBlue.setColor(Color.BLUE);
this.paintBlue.setStrokeWidth(1);
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
class MeasuredAxis {
public static final int X_GAP = 1;
public static final int Y_GAP = 1;
int _realHeight;
int _realWidth;
public MeasuredAxis(int width, int height) {
_realWidth = width;
_realHeight = height;
}
public int getXAxisNegLimit() {
return (_realWidth / 2)*(-1);
}
public int getXAxisLimit() {
return (_realWidth / 2);
}
public float getXMeasured(int x) {
return ((_realWidth / 2) + x);
}
public float getYMeasured(float y) {
return ((_realHeight / 2) - y);
}
}
private float function(float x) {
return new Double(Math.pow(x, 3)).floatValue();
}
#Override
public void run() {
long fps = 0L;
Log.d(TAG, "Starting game loop");
Canvas canvas = surfaceHolder.lockCanvas();
MeasuredAxis measured = new MeasuredAxis(canvas.getWidth(), canvas.getHeight());
synchronized (canvas) {
int x = measured.getXAxisNegLimit();
//from -x to +x evaluate and plot the function
while (x++ < measured.getXAxisLimit()) {
canvas.drawLine(
measured.getXMeasured(x),
measured.getYMeasured(function(x)),
measured.getXMeasured(x+MeasuredAxis.X_GAP),
measured.getYMeasured(function(x+MeasuredAxis.Y_GAP)),
paintRed);
}
canvas.save();
canvas.translate(0, 0);
canvas.scale(canvas.getWidth(), canvas.getHeight());
canvas.restore();
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
A sample surface view where the function is drawn.
public class MainGamePanel extends SurfaceView implements
SurfaceHolder.Callback {
private MainThread thread;
public MainGamePanel(Context context) {
super(context);
getHolder().addCallback(this);
// create the game loop thread
thread = new MainThread(getHolder(), this);
setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas canvas) {
}
}
And an example activity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new MainGamePanel(this));
}
}
Hope this helps you!