Related
I have this screen with two bird animatons using Bitmap. I want the bitmaps to be clickable but I am unable to figure out how. I can easily make the entire screen clickable by setting view.OnClickListener but that is not what I want, I want separate things to happen depending on which bird the user clicks on.
Also, how and where would I create a local variable for my bitmaps, for now I can only access them inside of the draw() method.
The run() method is for the animation and works fine.
I am new to all of this and appreciate any help!
Code
public class PlayActivity extends AppCompatActivity {
surfaceView view;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view = new surfaceView(this);
setContentView(view);
}
public class surfaceView extends SurfaceView {
public surfaceView(Context context) {
super(context);
new Anim().start();
}
private class Anim extends Thread {
int counter = 0;
int counter2 = 0;
#Override
public void run() {
long last_updated_time = 0;
long delay = 150;
int[] purple_bird = {
R.drawable.bird1,
R.drawable.bird2
};
int[] red_bird = {
R.drawable.red1,
R.drawable.red2,
R.drawable.red3,
R.drawable.red4,
R.drawable.red5,
R.drawable.red6,
R.drawable.red7,
R.drawable.red8,
R.drawable.red9,
R.drawable.red10
};
while (true) {
boolean playing = true;
if (playing) {
long current_time = System.currentTimeMillis();
if (current_time > last_updated_time + delay) {
if (counter >= 2) {
counter = 0;
}
if (counter2 >= 4) {
counter2 = 0;
}
draw(purple_bird[counter], red_bird[counter2]);
last_updated_time = current_time;
counter++;
counter2++;
}
}
}
}
private void draw(int red_bird, int purple_bird) {
SurfaceHolder holder = getHolder();
Canvas canvas = holder.lockCanvas();
if (canvas != null) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
Bitmap purpleBird = BitmapFactory.decodeResource(getContext().getResources(), purple_bird);
Bitmap redBird = BitmapFactory.decodeResource(getContext().getResources(), red_bird);
Bitmap resizedRedBird = Bitmap.createScaledBitmap(redBird, (int) (redBird.getWidth() * 0.1), (int) (redBird.getHeight() * 0.1), true);
Bitmap resizedPurpleBird = Bitmap.createScaledBitmap(purpleBird, (int) (purpleBird.getWidth() * 0.8), (int) (purpleBird.getHeight() * 0.8), true);
canvas.drawBitmap(resizedRedBird, 100, 100, paint);
canvas.drawBitmap(resizedPurpleBird, 100, 600, paint);
holder.unlockCanvasAndPost(canvas);
}
}
}
}
}
Can you guys help me with my problem? My program is running with no problems on Android Studio Emulator (Pixel 2 API 28), but after I install it on my phone (Samsung Galaxy S8+ API 28), it just keep on crashing every time i tap the play button :(. I also tried it on some phones and I still have the same problem
Actually it isnt my program but i found it on youtube but the one who make the code in youtube gave me the green light to use it on my term project.
Link of the video on how to make that program in the youtube:
https://www.youtube.com/watch?v=5W3rVBDYFjE
This is the link of the source code you can run it:
https://github.com/heyletscode/2D-Game-In-Android-Studio
All I want is to run this code on a physical device especially on my phone Samsung Galaxy S8+. I can't seem to solve the issue I'm kind of desperate. I am very new to java programming i'm very sorry.
Code for com.heyletscode.ihavetofly.Flight class as requested by #Marc
int toShoot = 0;
boolean isGoingUp = false;
int x, y, width, height, wingCounter = 0, shootCounter = 1;
Bitmap flight1, flight2, shoot1, shoot2, shoot3, shoot4, shoot5, dead;
private GameView gameView;
Flight(GameView gameView, int screenY, Resources res) {
this.gameView = gameView;
flight1 = BitmapFactory.decodeResource(res, R.drawable.fly1);
flight2 = BitmapFactory.decodeResource(res, R.drawable.fly2);
width = flight1.getWidth();
height = flight1.getHeight();
width /= 4;
height /= 4;
width *= (int) screenRatioX;
height *= (int) screenRatioY;
flight1 = Bitmap.createScaledBitmap(flight1, width, height, false);
flight2 = Bitmap.createScaledBitmap(flight2, width, height, false);
shoot1 = BitmapFactory.decodeResource(res, R.drawable.shoot1);
shoot2 = BitmapFactory.decodeResource(res, R.drawable.shoot2);
shoot3 = BitmapFactory.decodeResource(res, R.drawable.shoot3);
shoot4 = BitmapFactory.decodeResource(res, R.drawable.shoot4);
shoot5 = BitmapFactory.decodeResource(res, R.drawable.shoot5);
shoot1 = Bitmap.createScaledBitmap(shoot1, width, height, false);
shoot2 = Bitmap.createScaledBitmap(shoot2, width, height, false);
shoot3 = Bitmap.createScaledBitmap(shoot3, width, height, false);
shoot4 = Bitmap.createScaledBitmap(shoot4, width, height, false);
shoot5 = Bitmap.createScaledBitmap(shoot5, width, height, false);
dead = BitmapFactory.decodeResource(res, R.drawable.dead);
dead = Bitmap.createScaledBitmap(dead, width, height, false);
y = screenY / 2;
x = (int) (64 * screenRatioX);
}
Bitmap getFlight() {
if (toShoot != 0) {
if (shootCounter == 1) {
shootCounter++;
return shoot1;
}
if (shootCounter == 2) {
shootCounter++;
return shoot2;
}
if (shootCounter == 3) {
shootCounter++;
return shoot3;
}
if (shootCounter == 4) {
shootCounter++;
return shoot4;
}
shootCounter = 1;
toShoot--;
gameView.newBullet();
return shoot5;
}
if (wingCounter == 0) {
wingCounter++;
return flight1;
}
wingCounter--;
return flight2;
}
Rect getCollisionShape() {
return new Rect(x, y, x + width, y + height);
}
Bitmap getDead() {
return dead;
}
}
-----------EDITED------------
CODE FOR GameView.java
private Thread thread;
private boolean isPlaying, isGameOver = false;
private int screenX, screenY, score = 0;
public static float screenRatioX, screenRatioY;
private Paint paint;
private Bird[] birds;
private SharedPreferences prefs;
private Random random;
private SoundPool soundPool;
private List<Bullet> bullets;
private int sound;
private Flight flight;
private GameActivity activity;
private Background background1, background2;
public GameView(GameActivity activity, int screenX, int screenY) {
super(activity);
this.activity = activity;
prefs = activity.getSharedPreferences("game", Context.MODE_PRIVATE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_GAME)
.build();
soundPool = new SoundPool.Builder()
.setAudioAttributes(audioAttributes)
.build();
} else
soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
sound = soundPool.load(activity, R.raw.shoot, 1);
this.screenX = screenX;
this.screenY = screenY;
screenRatioX = 1920f / screenX;
screenRatioY = 1080f / screenY;
background1 = new Background(screenX, screenY, getResources());
background2 = new Background(screenX, screenY, getResources());
flight = new Flight(this, screenY, getResources());
bullets = new ArrayList<>();
background2.x = screenX;
paint = new Paint();
paint.setTextSize(128);
paint.setColor(Color.WHITE);
birds = new Bird[4];
for (int i = 0;i < 4;i++) {
Bird bird = new Bird(getResources());
birds[i] = bird;
}
random = new Random();
}
#Override
public void run() {
while (isPlaying) {
update ();
draw ();
sleep ();
}
}
private void update () {
background1.x -= 10 * screenRatioX;
background2.x -= 10 * screenRatioX;
if (background1.x + background1.background.getWidth() < 0) {
background1.x = screenX;
}
if (background2.x + background2.background.getWidth() < 0) {
background2.x = screenX;
}
if (flight.isGoingUp)
flight.y -= 30 * screenRatioY;
else
flight.y += 30 * screenRatioY;
if (flight.y < 0)
flight.y = 0;
if (flight.y >= screenY - flight.height)
flight.y = screenY - flight.height;
List<Bullet> trash = new ArrayList<>();
for (Bullet bullet : bullets) {
if (bullet.x > screenX)
trash.add(bullet);
bullet.x += 50 * screenRatioX;
for (Bird bird : birds) {
if (Rect.intersects(bird.getCollisionShape(),
bullet.getCollisionShape())) {
score++;
bird.x = -500;
bullet.x = screenX + 500;
bird.wasShot = true;
}
}
}
for (Bullet bullet : trash)
bullets.remove(bullet);
for (Bird bird : birds) {
bird.x -= bird.speed;
if (bird.x + bird.width < 0) {
if (!bird.wasShot) {
isGameOver = true;
return;
}
int bound = (int) (30 * screenRatioX);
bird.speed = random.nextInt(bound);
if (bird.speed < 10 * screenRatioX)
bird.speed = (int) (10 * screenRatioX);
bird.x = screenX;
bird.y = random.nextInt(screenY - bird.height);
bird.wasShot = false;
}
if (Rect.intersects(bird.getCollisionShape(), flight.getCollisionShape())) {
isGameOver = true;
return;
}
}
}
private void draw () {
if (getHolder().getSurface().isValid()) {
Canvas canvas = getHolder().lockCanvas();
canvas.drawBitmap(background1.background, background1.x, background1.y, paint);
canvas.drawBitmap(background2.background, background2.x, background2.y, paint);
for (Bird bird : birds)
canvas.drawBitmap(bird.getBird(), bird.x, bird.y, paint);
canvas.drawText(score + "", screenX / 2f, 164, paint);
if (isGameOver) {
isPlaying = false;
canvas.drawBitmap(flight.getDead(), flight.x, flight.y, paint);
getHolder().unlockCanvasAndPost(canvas);
saveIfHighScore();
waitBeforeExiting ();
return;
}
canvas.drawBitmap(flight.getFlight(), flight.x, flight.y, paint);
for (Bullet bullet : bullets)
canvas.drawBitmap(bullet.bullet, bullet.x, bullet.y, paint);
getHolder().unlockCanvasAndPost(canvas);
}
}
private void waitBeforeExiting() {
try {
Thread.sleep(3000);
activity.startActivity(new Intent(activity, MainActivity.class));
activity.finish();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void saveIfHighScore() {
if (prefs.getInt("highscore", 0) < score) {
SharedPreferences.Editor editor = prefs.edit();
editor.putInt("highscore", score);
editor.apply();
}
}
private void sleep () {
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void resume () {
isPlaying = true;
thread = new Thread(this);
thread.start();
}
public void pause () {
try {
isPlaying = false;
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (event.getX() < screenX / 2) {
flight.isGoingUp = true;
}
break;
case MotionEvent.ACTION_UP:
flight.isGoingUp = false;
if (event.getX() > screenX / 2)
flight.toShoot++;
break;
}
return true;
}
public void newBullet() {
if (!prefs.getBoolean("isMute", false))
soundPool.play(sound, 1, 1, 0, 0, 1);
Bullet bullet = new Bullet(getResources());
bullet.x = flight.x + flight.width;
bullet.y = flight.y + (flight.height / 2);
bullets.add(bullet);
}
}
This is the Logcat on Error tab after installing and tapping the play button on the program on my Samsung Galaxy S8+
2019-10-07 16:59:12.317 11879-11879/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2019-10-07 16:59:12.322 11879-11879/? E/Zygote: accessInfo : 1
2019-10-07 16:59:21.447 11879-11879/com.heyletscode.ihavetofly E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.heyletscode.ihavetofly, PID: 11879
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.heyletscode.ihavetofly/com.heyletscode.ihavetofly.GameActivity}: java.lang.IllegalArgumentException: width and height must be > 0
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3114)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7050)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Caused by: java.lang.IllegalArgumentException: width and height must be > 0
at android.graphics.Bitmap.createBitmap(Bitmap.java:1074)
at android.graphics.Bitmap.createBitmap(Bitmap.java:1041)
at android.graphics.Bitmap.createBitmap(Bitmap.java:991)
at android.graphics.Bitmap.createBitmap(Bitmap.java:912)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:782)
at com.heyletscode.ihavetofly.Flight.<init>(Flight.java:35)
at com.heyletscode.ihavetofly.GameView.<init>(GameView.java:70)
at com.heyletscode.ihavetofly.GameActivity.onCreate(GameActivity.java:22)
at android.app.Activity.performCreate(Activity.java:7327)
at android.app.Activity.performCreate(Activity.java:7318)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3094)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7050)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
The actual problem is in GameView.java:64, where fixed screen height and width used instead of dynamic. This code runs smoothly on device with screen below or equal 1920x1080 px.
Will Cause problem when screen size goes more than that as the screenRatioX and screenRatioY comes < 1 which turn to o in Flight.java:32 by cast, which caused the exception as
width and height must be > 0
To Use Dynamic screen size, you can use this:
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
Use size.x and size.y instead of 1920f and 1080f respectively. Thanks
Trying to make a motion detection app based on this project. The intention is to make the app take pictures when motion is detected by comparing two images. Up to this part, the app is working fine.
Requirement:
To specify area of detection by a custom view. So that, the pictures will be captured only if a motion is detected inside the defined area by calculating the detection area.
What I have done so far:
Created a movable custom view, like a crop view of which the dimensions (Rect) are saved in the preference each time when the view is moved.
What is not working:
The motion detection from inside the custom view is not working. I believe that the bitmaps must be cropped according to the size of the custom view to do the comparison.
In the detection thread I tried setting the width and height from the preference like :
private int width = Prefe.DetectionArea.width();
private int height = Prefe.DetectionArea.height();
But it didn't work. Please help me by explaining how this could be achieved so that the motion detection will happen according to the size of the custom view. Any help is appreciated.
Project Source Code: https://drive.google.com/drive/folders/0B7-oKqt7w49mbTR6VWZYVURmVms
MotionDetectionActivity.java
public class MotionDetectionActivity extends SensorsActivity {
private static final String TAG = "MotionDetectionActivity";
private static long mReferenceTime = 0;
private static IMotionDetection detector = null;
public static MediaPlayer song;
public static Vibrator mVibrator;
private static SurfaceView preview = null;
private static SurfaceHolder previewHolder = null;
private static Camera camera = null;
private static boolean inPreview = false;
private static AreaDetectorView mDetector;
private static FrameLayout layoutDetectorArea;
static FrameLayout layoutMain;
static View mView;
private static volatile AtomicBoolean processing = new AtomicBoolean(false);
/**
* {#inheritDoc}
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.main);
mVibrator = (Vibrator)this.getSystemService(VIBRATOR_SERVICE);
layoutMain=(FrameLayout)findViewById(R.id.layoutMain);
preview = (SurfaceView) findViewById(R.id.preview);
previewHolder = preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mView=layoutMain;
mDetector= (AreaDetectorView) findViewById(R.id.viewDetector);
layoutDetectorArea=(FrameLayout) findViewById(R.id.layoutDetectArea);
ToggleButton toggle = (ToggleButton) findViewById(R.id.simpleToggleButton);
toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// The toggle is enabled
} else {
// The toggle is disabled
}
}
});
if (Preferences.USE_RGB) {
detector = new RgbMotionDetection();
} else if (Preferences.USE_LUMA) {
detector = new LumaMotionDetection();
} else {
// Using State based (aggregate map)
detector = new AggregateLumaMotionDetection();
}
}
/**
* {#inheritDoc}
*/
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
/**dd:
* Song play # 1
* Camera callback
*
* {#inheritDoc}
*/
#Override
public void onPause() {
super.onPause();
if(song!=null && song.isPlaying())
{
song.stop();}
camera.setPreviewCallback(null);
if (inPreview) camera.stopPreview();
inPreview = false;
camera.release();
camera = null;
}
/**
* {#inheritDoc}
*/
#Override
public void onResume() {
super.onResume();
camera = Camera.open();
}
private PreviewCallback previewCallback = new PreviewCallback() {
/**
* {#inheritDoc}
*/
#Override
public void onPreviewFrame(byte[] data, Camera cam) {
if (data == null) return;
Camera.Size size = cam.getParameters().getPreviewSize();
if (size == null) return;
if (!GlobalData.isPhoneInMotion()) {
DetectionThread thread = new DetectionThread(data, size.width, size.height);
thread.start();
}
}
};
private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
/**
* {#inheritDoc}
*/
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(previewHolder);
camera.setPreviewCallback(previewCallback);
} catch (Throwable t) {
Log.e("Prek", "Exception in setPreviewDisplay()", t);
}
}
/**
* {#inheritDoc}
*/
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if(camera != null) {
Camera.Parameters parameters = camera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
Log.d(TAG, "Using width=" + size.width + " height=" + size.height);
}
camera.setParameters(parameters);
camera.startPreview();
inPreview = true;
}
//AreaDetectorView.InitDetectionArea();
}
/**
* {#inheritDoc}
*/
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Ignore
}
};
private static Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) result = size;
}
}
}
return result;
}
//***************Detection Class******************//
private final class DetectionThread extends Thread {
private byte[] data;
private int width;
private int height;
public DetectionThread(byte[] data, int width, int height) {
this.data = data;
this.width = width;
this.height = height;
}
/**
* {#inheritDoc}
*/
#Override
public void run() {
if (!processing.compareAndSet(false, true)) return;
// Log.d(TAG, "BEGIN PROCESSING...");
try {
// Previous frame
int[] pre = null;
if (Preferences.SAVE_PREVIOUS) pre = detector.getPrevious();
// Current frame (with changes)
// long bConversion = System.currentTimeMillis();
int[] img = null;
if (Preferences.USE_RGB) {
img = ImageProcessing.decodeYUV420SPtoRGB(data, width, height);
} else {
img = ImageProcessing.decodeYUV420SPtoLuma(data, width, height);
}
// Current frame (without changes)
int[] org = null;
if (Preferences.SAVE_ORIGINAL && img != null) org = img.clone();
if (img != null && detector.detect(img, width, height)) {
// The delay is necessary to avoid taking a picture while in
// the
// middle of taking another. This problem can causes some
// phones
// to reboot.
long now = System.currentTimeMillis();
if (now > (mReferenceTime + Preferences.PICTURE_DELAY)) {
mReferenceTime = now;
//mVibrator.vibrate(10);
Bitmap previous = null;
if (Preferences.SAVE_PREVIOUS && pre != null) {
if (Preferences.USE_RGB) previous = ImageProcessing.rgbToBitmap(pre, width, height);
else previous = ImageProcessing.lumaToGreyscale(pre, width, height);
}
Bitmap original = null;
if (Preferences.SAVE_ORIGINAL && org != null) {
if (Preferences.USE_RGB) original = ImageProcessing.rgbToBitmap(org, width, height);
else original = ImageProcessing.lumaToGreyscale(org, width, height);
}
Bitmap bitmap = null;
if (Preferences.SAVE_CHANGES) {
if (Preferences.USE_RGB) bitmap = ImageProcessing.rgbToBitmap(img, width, height);
else bitmap = ImageProcessing.lumaToGreyscale(img, width, height);
}
Log.i(TAG, "Saving.. previous=" + previous + " original=" + original + " bitmap=" + bitmap);
Looper.prepare();
new SavePhotoTask().execute(previous, original, bitmap);
} else {
Log.i(TAG, "Not taking picture because not enough time has passed since the creation of the Surface");
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
processing.set(false);
}
// Log.d(TAG, "END PROCESSING...");
processing.set(false);
}
};
private static final class SavePhotoTask extends AsyncTask<Bitmap, Integer, Integer> {
/**
* {#inheritDoc}
*/
#Override
protected Integer doInBackground(Bitmap... data) {
for (int i = 0; i < data.length; i++) {
Bitmap bitmap = data[i];
String name = String.valueOf(System.currentTimeMillis());
if (bitmap != null) save(name, bitmap);
}
return 1;
}
private void save(String name, Bitmap bitmap) {
File photo = new File(Environment.getExternalStorageDirectory(), name + ".jpg");
if (photo.exists()) photo.delete();
try {
FileOutputStream fos = new FileOutputStream(photo.getPath());
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (java.io.IOException e) {
Log.e("PictureDemo", "Exception in photoCallback", e);
}
}
}
}
AreaDetectorView.java
public class AreaDetectorView extends LinearLayout {
public static int Width;
public static int Height;
private static Paint BoxPaint = null;
private static Paint TextPaint = null;
private static Paint ArrowPaint = null;
private static Path mPath = null;
private static Rect mRect = null;
private static int lastX, lastY = 0;
private static boolean mBoxTouched = false;
private static boolean mArrowTouched = false;
private static Context mContext;
private static int ArrowWidth = 0;
private static Paint BoxPaint2 = null;
public AreaDetectorView(Context context) {
super(context);
mContext = context;
}
//attrs was not there
public AreaDetectorView(Context context, AttributeSet attrs) {
super(context,attrs);
mContext = context;
// TODO Auto-generated constructor stub
if (!this.getRootView().isInEditMode()) {
ArrowWidth =GetDisplayPixel(context, 30);
}
//InitDetectionArea();
InitMemberVariables();
setWillNotDraw(false);
}
public static int GetDisplayPixel(Context paramContext, int paramInt)
{
return (int)(paramInt * paramContext.getResources().getDisplayMetrics().density + 0.5F);
}
public static void InitMemberVariables() {
if (BoxPaint == null) {
BoxPaint = new Paint();
BoxPaint.setAntiAlias(true);
BoxPaint.setStrokeWidth(2.0f);
//BoxPaint.setStyle(Style.STROKE);
BoxPaint.setStyle(Style.FILL_AND_STROKE);
BoxPaint.setColor(ContextCompat.getColor(mContext, R.color.bwff_60));
}
if (ArrowPaint == null) {
ArrowPaint = new Paint();
ArrowPaint.setAntiAlias(true);
ArrowPaint.setColor(ContextCompat.getColor(mContext,R.color.redDD));
ArrowPaint.setStyle(Style.FILL_AND_STROKE);
}
if (TextPaint == null) {
TextPaint = new Paint();
TextPaint.setColor(ContextCompat.getColor(mContext,R.color.yellowL));
TextPaint.setTextSize(16);
//txtPaint.setTypeface(lcd);
TextPaint.setStyle(Style.FILL_AND_STROKE);
}
if (mPath == null) {
mPath = new Path();
} else {
mPath.reset();
}
if (mRect == null) {
mRect = new Rect();
}
if (BoxPaint2 == null) {
BoxPaint2 = new Paint();
BoxPaint2.setAntiAlias(true);
BoxPaint2.setStrokeWidth(2.0f);
//BoxPaint.setStyle(Style.STROKE);
BoxPaint2.setStyle(Style.STROKE);
BoxPaint2.setColor(ContextCompat.getColor(mContext,R.color.bwff_9e));
}
}
public static void InitDetectionArea() {
try {
int w = Prefe.DetectionArea.width();
int h = Prefe.DetectionArea.height();
int x = Prefe.DetectionArea.left;
int y = Prefe.DetectionArea.top;
// ver 2.6.0
if (Prefe.DetectionArea.left == 1
&& Prefe.DetectionArea.top == 1
&& Prefe.DetectionArea.right == 1
&& Prefe.DetectionArea.bottom == 1) {
w = Prefe.DisplayWidth / 4;
h = Prefe.DisplayHeight / 3;
// ver 2.5.9
w = Width / 4;
h = Height / 3;
Prefe.DetectorWidth = w; //UtilGeneralHelper.GetDisplayPixel(this, 100);
Prefe.DetectorHeight = h; //UtilGeneralHelper.GetDisplayPixel(this, 100);
x = (Prefe.DisplayWidth / 2) - (w / 2);
y = (Prefe.DisplayHeight / 2) - (h / 2);
// ver 2.5.9
x = (Width / 2) - (w / 2);
y = (Height / 2) - (h / 2);
}
//Prefe.DetectionArea = new Rect(x, x, x + Prefe.DetectorWidth, x + Prefe.DetectorHeight);
Prefe.DetectionArea = new Rect(x, y, x + w, y + h);
Prefe.gDetectionBitmapInt = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()];
Prefe.gDetectionBitmapIntPrev = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()];
} catch (Exception e) {
e.printStackTrace();
}
}
public static void SetDetectionArea(int x, int y, int w, int h) {
try {
Prefe.DetectionArea = new Rect(x, y, w, h);
} catch (Exception e) {
e.printStackTrace();
}
}
private void DrawAreaBox(Canvas canvas) {
try {
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void dispatchDraw(Canvas canvas) {
try {
if (this.getRootView().isInEditMode()) {
super.dispatchDraw(canvas);
return;
}
//canvas.save(Canvas.MATRIX_SAVE_FLAG);
//Prefe.DetectionAreaOrient = UtilGeneralHelper.GetDetectRectByOrientation();
canvas.drawColor(0);
mPath.reset();
canvas.drawRect(Prefe.DetectionArea, BoxPaint);
mPath.moveTo(Prefe.DetectionArea.right - ArrowWidth, Prefe.DetectionArea.bottom);
mPath.lineTo(Prefe.DetectionArea.right, Prefe.DetectionArea.bottom - ArrowWidth);
mPath.lineTo(Prefe.DetectionArea.right, Prefe.DetectionArea.bottom);
mPath.lineTo(Prefe.DetectionArea.right - ArrowWidth, Prefe.DetectionArea.bottom);
mPath.close();
canvas.drawPath(mPath, ArrowPaint);
mPath.reset();
//canvas.drawRect(Prefe.DetectionAreaOrient, BoxPaint2);
//canvas.drawRect(Prefe.DetectionAreaOrientPort, BoxPaint2);
TextPaint.setTextSize(16);
//TextPaint.setLetterSpacing(2);
TextPaint.setColor(ContextCompat.getColor(mContext,R.color.bwff));
TextPaint.getTextBounds(getResources().getString(R.string.str_detectarea), 0, 1, mRect);
canvas.drawText(getResources().getString(R.string.str_detectarea),
Prefe.DetectionArea.left + 4,
Prefe.DetectionArea.top + 4 + mRect.height(),
TextPaint);
int recH = mRect.height();
TextPaint.setStrokeWidth(1.2f);
TextPaint.setTextSize(18);
TextPaint.setColor(ContextCompat.getColor(mContext,R.color.redD_9e));
TextPaint.getTextBounds(getResources().getString(R.string.str_dragandmove), 0, 1, mRect);
canvas.drawText(getResources().getString(R.string.str_dragandmove),
Prefe.DetectionArea.left + 4,
Prefe.DetectionArea.top + 20 + mRect.height()*2,
TextPaint);
TextPaint.getTextBounds(getResources().getString(R.string.str_scalearea), 0, 1, mRect);
canvas.drawText(getResources().getString(R.string.str_scalearea),
Prefe.DetectionArea.left + 4,
Prefe.DetectionArea.top + 36 + mRect.height()*3,
TextPaint);
super.dispatchDraw(canvas);
//canvas.restore();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onDraw(Canvas canvas) {
try {
super.onDraw(canvas);
invalidate();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
boolean retValue = true;
int X = (int)event.getX();
int Y = (int)event.getY();
//AppMain.txtLoc.setText(String.valueOf(X) + ", " + String.valueOf(Y));
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mBoxTouched = TouchedInBoxArea(X, Y);
//AppMain.txtLoc.setText("BoxTouched: " + String.valueOf(mBoxTouched));
if (!mBoxTouched) break;
lastX = X;
lastY = Y;
BoxPaint.setStyle(Style.FILL_AND_STROKE);
BoxPaint.setColor(ContextCompat.getColor(mContext,R.color.redD_9e));
mArrowTouched = TouchedInArrow(X, Y);
//AppMain.txtLoc.setText("ArrowTouched: " + String.valueOf(mBoxTouched));
if (mArrowTouched) {
ArrowPaint.setColor(ContextCompat.getColor(mContext,R.color.bwff_9e));
}
break;
case MotionEvent.ACTION_MOVE:
if (!mBoxTouched) break;
int moveX = X - lastX;
int moveY = Y - lastY;
//AppMain.txtLoc.setText("Move X, Y: " + String.valueOf(moveX) + "," + String.valueOf(moveY));
if (!mArrowTouched) {
if (Prefe.DetectionArea.left + moveX < 0) {
break;
}
// if (Prefe.DetectionArea.right + moveX > Prefe.gDisplay.getWidth()) {
// break;
// }
// ver 2.5.9
if (Prefe.DetectionArea.right + moveX > Width) {
break;
}
if (Prefe.DetectionArea.top + moveY < 0) {
break;
}
// if (Prefe.DetectionArea.bottom + moveY > Prefe.gDisplay.getHeight()) {
// break;
// }
// ver 2.5.9
if (Prefe.DetectionArea.bottom + moveY > Height) {
break;
}
}
if (mArrowTouched) {
if ((Prefe.DetectionArea.width() + moveX) < ArrowWidth * 2){
break;
}
if ((Prefe.DetectionArea.height() + moveY) < ArrowWidth * 2) {
break;
}
Prefe.DetectionArea.right += moveX;
Prefe.DetectionArea.bottom += moveY;
//Log.i("DBG", "W,H: " + String.valueOf(Prefe.DetectionArea.width()) + "," + String.valueOf(Prefe.DetectionArea.height()));
} else {
Prefe.DetectionArea.left += moveX;
Prefe.DetectionArea.right += moveX;
Prefe.DetectionArea.top += moveY;
Prefe.DetectionArea.bottom += moveY;
}
lastX = X;
lastY = Y;
//AppMain.txtLoc.setText(String.valueOf(Prefe.DetectionArea.left) + ", " + String.valueOf(Prefe.DetectionArea.top));
break;
case MotionEvent.ACTION_UP:
mBoxTouched = false;
mArrowTouched = false;
//BoxPaint.setStyle(Style.STROKE);
BoxPaint.setStyle(Style.FILL_AND_STROKE);
BoxPaint.setColor(ContextCompat.getColor(mContext,R.color.bwff_60));
ArrowPaint.setColor(ContextCompat.getColor(mContext,R.color.redDD));
//AppMain.txtLoc.setText(String.valueOf(Prefe.DetectionArea.left) + ", " + String.valueOf(Prefe.DetectionArea.top));
if (Prefe.DetectionArea.left < 0) {
Prefe.DetectionArea.left = 0;
}
// if (Prefe.DetectionArea.right > Prefe.gDisplay.getWidth()) {
// Prefe.DetectionArea.right = Prefe.gDisplay.getWidth();
// }
// ver 2.5.9
if (Prefe.DetectionArea.right > Width) {
Prefe.DetectionArea.right = Width;
}
if (Prefe.DetectionArea.top < 0) {
Prefe.DetectionArea.top = 0;
}
// if (Prefe.DetectionArea.bottom > Prefe.gDisplay.getHeight()) {
// Prefe.DetectionArea.bottom = Prefe.gDisplay.getHeight();
// }
if (Prefe.DetectionArea.bottom > Height) {
Prefe.DetectionArea.bottom = Height;
}
Prefe.gDetectionBitmapInt = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()];
Prefe.gDetectionBitmapIntPrev = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()];
//Prefe.gDetectionBitmapInt = null;
//Prefe.gDetectionBitmapIntPrev = null;
String area = String.valueOf(Prefe.DetectionArea.left)
+ "," + String.valueOf(Prefe.DetectionArea.top)
+ "," + String.valueOf(Prefe.DetectionArea.right)
+ "," + String.valueOf(Prefe.DetectionArea.bottom);
// UtilGeneralHelper.SavePreferenceSetting(Prefe.gContext, Prefe.PREF_DETECTION_AREA_KEY, area);
//Saving the value
SharedPrefsUtils.setStringPreference(mContext.getApplicationContext(), Prefe.PREF_DETECTION_AREA_KEY, area);
Log.v("TAG", SharedPrefsUtils.getStringPreference(mContext.getApplicationContext(),Prefe.PREF_DETECTION_AREA_KEY));
break;
}
invalidate();
return retValue;
}
private boolean TouchedInBoxArea(int x, int y) {
boolean retValue = false;
try {
if (x > Prefe.DetectionArea.left && x < Prefe.DetectionArea.right) {
if (y > Prefe.DetectionArea.top && y < Prefe.DetectionArea.bottom) {
retValue = true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return retValue;
}
private boolean TouchedInArrow(int x, int y) {
boolean retValue = false;
try {
if (x > Prefe.DetectionArea.right - ArrowWidth && x < Prefe.DetectionArea.right) {
if (y > Prefe.DetectionArea.bottom - ArrowWidth && y < Prefe.DetectionArea.bottom) {
retValue = true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return retValue;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
Width = width;
Height = height;
InitDetectionArea();
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
for (int i = 0; i < this.getChildCount()-1; i++){
(this.getChildAt(i)).layout(l, t, r, b);
}
if (changed) {
// check width height
if (r != Width || b != Height) {
// size does not match
}
}
}
}
Prefe.java
public class Prefe extends Application{
...
public static final String PREF_DETECTION_AREA_KEY = "pref_detection_area_key";
}
static{
...
DetectionArea = new Rect(1, 1, 1, 1);
}
}
I have written the code for movement of two balls within a rectangle(canvas). The balls deflect in opposite direction when they hit the top, bottom, left or right of the rectangle. But,I've tried in vain to make the balls collide with each other and deflect in opposite direction. I have searched many sites and articles but in vain. Can someone please help.
This is MainActivity.java
package com.example.movements;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MovementView(this));
}
}
This is MovementView.java
package com.example.movements;
public class MovementView extends SurfaceView implements SurfaceHolder.Callback{
private int xPos,xPos1;
private int yPos,yPos1;
private int xVel,xVel1;
private int yVel,yVel1;
private int width;
private int height;
private int circleRadius,circleRadius1;
private Paint circlePaint,circlePaint1;
UpdateThread updateThread;
public MovementView(Context context) {
super(context);
getHolder().addCallback(this);
circleRadius = 10;
circlePaint = new Paint();
circlePaint.setColor(Color.BLUE);
xVel = 10;
yVel = 10;
circleRadius1 = 10;
circlePaint1 = new Paint();
circlePaint1.setColor(Color.MAGENTA);
xVel1 = 11;
yVel1 = 11;
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
canvas.drawCircle(xPos, yPos, circleRadius, circlePaint);
canvas.drawCircle(xPos1, yPos1, circleRadius1, circlePaint1);
}
public void updatePhysics() {
xPos += xVel;
yPos += yVel;
if (yPos - circleRadius < 0 || yPos + circleRadius > height) {
if (yPos - circleRadius < 0) {
yPos = circleRadius;
}else{
yPos = height - circleRadius;
}
yVel *= -1;
}
if (xPos - circleRadius < 0 || xPos + circleRadius > width) {
if (xPos - circleRadius < 0) {
xPos = circleRadius;
} else {
xPos = width - circleRadius;
}
xVel *= -1;
}
xPos1 += xVel1;
yPos1 += yVel1;
if (yPos1 - circleRadius1 < 0 || yPos1 + circleRadius1 > height) {
if (yPos1 - circleRadius1 < 0) {
yPos1 = circleRadius1;
}else{
yPos1 = height - circleRadius1;
}
yVel1 *= -1;
}
if (xPos1 - circleRadius1 < 0 || xPos1 + circleRadius1 > width) {
if (xPos1 - circleRadius1 < 0) {
xPos1 = circleRadius1;
} else {
xPos1 = width - circleRadius1;
}
xVel1 *= -1;
}
}
public void surfaceCreated(SurfaceHolder holder) {
Rect surfaceFrame = holder.getSurfaceFrame();
width = surfaceFrame.width();
height = surfaceFrame.height();
xPos = width / 2;
yPos = circleRadius;
xPos1 = width / 2;
yPos1 = circleRadius1;
updateThread = new UpdateThread(this);
updateThread.setRunning(true);
updateThread.start();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
updateThread.setRunning(false);
while (retry) {
try {
updateThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}
This is UpdateThread.java
package com.example.movements;
import android.view.SurfaceHolder;
public class UpdateThread extends Thread {
private long time;
private final int fps = 20;
private boolean toRun = false;
private MovementView movementView;
private SurfaceHolder surfaceHolder;
public UpdateThread(MovementView rMovementView) {
movementView = rMovementView;
surfaceHolder = movementView.getHolder();
}
public void setRunning(boolean run) {
toRun = run;
}
#Override
public void run() {
Canvas c;
while (toRun) {
long cTime = System.currentTimeMillis();
if ((cTime - time) <= (1000 / fps)) {
c = null;
try {
c = surfaceHolder.lockCanvas(null);
movementView.updatePhysics();
movementView.onDraw(c);
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
time = cTime;
}
}
}
To check wether they are hitting each other, you can just check if the distance between their centers is smaller than (radius*2). To make a nice deflection, you'll have to do some math that's beyond me. Here is another answer on that.
I've googled it a bit and apparantly the term used in physics for this problem is called elastic collision. I've found a nice tutorial on the subject here (especially the dynamic circle-circle collision bit). Also, here is an applet which demonstrates this. The source code for this can be found [here]
I keep getting a NPE when I run this very basic 2D game. It has something to do with the Key Events but I am not sure how to fix this. Can someone help me? It says the NPE is on this line if (_input.up.isPressed()) {
Here is the InputHandler Class
public class InputHandler implements KeyListener {
public InputHandler(Game game) {
game.addKeyListener(this);
}
public class Key {
private boolean pressed = false;
public void toggle(boolean isPressed) {
pressed = isPressed;
}
public boolean isPressed() {
return pressed;
}
}
// public List<Key> keys = new ArrayList<Key>();
public Key up = new Key();
public Key down = new Key();
public Key left = new Key();
public Key right = new Key();
public void keyPressed(KeyEvent e) {
toggleKey(e.getKeyCode(), true);
}
public void keyReleased(KeyEvent e) {
toggleKey(e.getKeyCode(), false);
}
public void keyTyped(KeyEvent e) {
}
public void toggleKey(int keyCode, boolean isPressed) {
if (keyCode == KeyEvent.VK_W) {
up.toggle(isPressed);
} else if (keyCode == KeyEvent.VK_S) {
down.toggle(isPressed);
} else if (keyCode == KeyEvent.VK_A) {
left.toggle(isPressed);
} else if (keyCode == KeyEvent.VK_D) {
right.toggle(isPressed);
}
}
}
here is the Player Class
public class Player extends Mob {
private InputHandler _input;
private int _speed;
private int _r = 10;
private int _x, _y;
public Player(int x, int y, int speed, InputHandler input) {
super("Player", x, y, 1);
_input = input;
_speed = speed;
_x = x;
_y = y;
}
public boolean hasCollided(int dx, int dy) {
return false;
}
public void update() {
int dx = 0;
int dy = 0;
if (_input.up.isPressed()) {
dy--;
} else if (_input.down.isPressed()) {
dy++;
} else if (_input.left.isPressed()) {
dx--;
} else if (_input.right.isPressed()) {
dx++;
}
if (dx != 0 || dy != 0) {
move(dx, dy);
isMoving = true;
} else {
isMoving = false;
}
if (_x < _r)
_x = _r;
if (_y < _r)
_y = _r;
if (_x > Game.WIDTH - _r)
_x = Game.WIDTH - _r;
if (_y > Game.HEIGHT - _r)
_y = Game.HEIGHT - _r;
}
public void render(Graphics2D g) {
g.setColor(Color.BLACK);
g.fillOval(x - _r, y - _r, 2 * _r, 2 * _r);
g.setStroke(new BasicStroke(3));
g.setColor(Color.GRAY);
g.drawOval(x - _r, y - _r, 2 * _r, 2 * _r);
g.setStroke(new BasicStroke(1));
}
}
here is the game class which creates the player
public class Game extends Canvas implements Runnable {
private static Game _instance;
private static final String TITLE = "ProjectG";
public static final int WIDTH = 960;
public static final int HEIGHT = WIDTH * 3 / 4;
private static final int SCALE = 1;
// to make it have a higher resolution double the width and height but half
// the scale. You are doubling the width and height but keeping the same
// window size by reducing the scale
public static final Dimension SIZE = new Dimension(WIDTH * SCALE, HEIGHT * SCALE);
private static final int UPDATE_RATE = 60;
private static final int RENDER_RATE = 60;
private JFrame _frame;
private Thread _thread;
private boolean _running = false;
private int _tps = 0;
private int _fps = 0;
private int _totalTicks = 0;
private BufferedImage image;
private Graphics2D g;
public InputHandler input;
private Player player;
public Game() {
_instance = this;
setPreferredSize(SIZE);
setMinimumSize(SIZE);
setMaximumSize(SIZE);
_frame = new JFrame(TITLE);
_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
_frame.setLayout(new BorderLayout());
_frame.add(_instance, BorderLayout.CENTER);
_frame.pack();
_frame.setResizable(false);
_frame.setLocationRelativeTo(null);
_frame.setVisible(true);
player = new Player(Game.WIDTH / 2, Game.HEIGHT / 2, 1, input);
}
public synchronized void start() {
_running = true;
_thread = new Thread(this, TITLE + "_main");
_thread.start();
}
public synchronized void stop() {
_running = false;
if (_thread != null) {
try {
_thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run() {
double lastUpdateTime = System.nanoTime();
double lastRenderTime = System.nanoTime();
final int ns = 1000000000;
final double nsPerUpdate = (double) ns / UPDATE_RATE;
final double nsPerRender = (double) ns / RENDER_RATE;
final int maxUpdatesBeforeRender = 1;
int lastSecond = (int) lastUpdateTime / ns;
int tickCount = 0;
int renderCount = 0;
image = new BufferedImage(WIDTH * SCALE, HEIGHT * SCALE, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
while (_running) {
long currTime = System.nanoTime();
int tps = 0;
while ((currTime - lastUpdateTime) > nsPerUpdate && tps < maxUpdatesBeforeRender) {
update();
tickCount++;
_totalTicks++;
tps++;
lastUpdateTime += nsPerUpdate;
}
if (currTime - lastUpdateTime > nsPerUpdate) {
lastUpdateTime = currTime - nsPerUpdate;
}
float interpolation = Math.min(1.0F, (float) ((currTime - lastUpdateTime) / nsPerUpdate));
render(interpolation);
draw();
renderCount++;
lastRenderTime = currTime;
int currSecond = (int) (lastUpdateTime / ns);
if (currSecond > lastSecond) {
_tps = tickCount;
_fps = renderCount;
tickCount = 0;
renderCount = 0;
lastSecond = currSecond;
System.out.println(_tps + " TPS " + _fps + " FPS");
}
while (currTime - lastRenderTime < nsPerRender && currTime - lastUpdateTime < nsPerUpdate) {
Thread.yield();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
currTime = System.nanoTime();
}
}
}
public void update() {
player.update();
}
public void render(float interpolation) {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
}
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH * SCALE, HEIGHT * SCALE);
g.setColor(Color.BLACK);
g.drawString("TPS: " + _fps + " FPS: " + _fps, 10, 20);
player.render(g);
}
public void draw() {
Graphics g2 = this.getGraphics();
g2.drawImage(image, 0, 0, null);
g2.dispose();
}
public Game getGame() {
return this;
}
}
You haven't initialized input, so what you pass to
player = new Player(Game.WIDTH / 2, Game.HEIGHT / 2, 1, input);
is null. You need to initialize it before
input = new InputHandler(this);