I am trying to draw bullets on the screen when the player presses, but
after a few bullets I get the following error: FATAL EXCEPTION: Thread-2
Here is the classes of the bullet and of the gameView
public class Bullet {
private int x;
private int y;
private int speed;
private Bitmap bitmap;
public Bullet(Context context,int PositionX,int PositionY) {
Log.v("i am in bullet"," come on!!!");
speed = 10;
x = PositionX;
y = PositionY;
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.flash);
}
public void update() {
//Log.v("i am in update bullet"," come on!!!");
//animating the star horizontally right side
//by increasing x coordinate with player speed
x += 20;
}
public Bitmap getBitmap(){return bitmap;}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
returns
public class GameView extends SurfaceView implements Runnable {
private long fps;
private long timeThisFrame;
volatile boolean playing;
private Thread gameThread = null;
private Player player;
//a screenX holder
int screenX;
int i=0;
//context to be used in onTouchEvent to cause the activity transition from GameAvtivity to MainActivity.
Context context;
//the score holder
int score;
//the high Scores Holder
int highScore[] = new int[4];
//Shared Prefernces to store the High Scores
SharedPreferences sharedPreferences;
//to count the number of Misses
int countMisses;
//indicator that the enemy has just entered the game screen
boolean flag ;
//an indicator if the game is Over
private boolean isGameOver ;
private Paint paint;
private Canvas canvas;
private SurfaceHolder surfaceHolder;
private Enemy enemies;
//created a reference of the class Friend
private Friend friend;
//private Bullet bullet;
private ArrayList<Star> stars = new
ArrayList<Star>();
private ArrayList<Bullet> bullet = new
ArrayList<Bullet>();
//defining a boom object to display blast
private Boom boom;
//the mediaplayer objects to configure the background music
static MediaPlayer gameOnsound;
final MediaPlayer killedEnemysound;
final MediaPlayer gameOversound;
public GameView(Context context, int screenX, int screenY) {
super(context);
player = new Player(context, screenX, screenY);
surfaceHolder = getHolder();
paint = new Paint();
//initializing context
this.context = context;
int starNums = 20;
for (int i = 0; i < starNums; i++) {
Star s = new Star(context,screenX, screenY);
stars.add(s);
}
enemies = new Enemy(context,screenX,screenY);
//initializing boom object
boom = new Boom(context);
//initializing the Friend class object
friend = new Friend(context, screenX, screenY);
//setting the score to 0 initially
score = 0;
//setting the countMisses to 0 initially
countMisses = 0;
this.screenX = screenX;
isGameOver = false;
//initializing shared Preferences
sharedPreferences = context.getSharedPreferences("SHAR_PREF_NAME",Context.MODE_PRIVATE);
//initializing the array high scores with the previous values
highScore[0] = sharedPreferences.getInt("score1",0);
highScore[1] = sharedPreferences.getInt("score2",0);
highScore[2] = sharedPreferences.getInt("score3",0);
highScore[3] = sharedPreferences.getInt("score4",0);
//initializing the media players for the game sounds
gameOnsound = MediaPlayer.create(context,R.raw.gameon);
killedEnemysound = MediaPlayer.create(context,R.raw.killedenemy);
gameOversound = MediaPlayer.create(context,R.raw.gameover);
//starting the music to be played across the game
gameOnsound.start();
}
#Override
public void run() {
while (playing) {
long startFrameTime = System.currentTimeMillis();
synchronized (surfaceHolder) {
update();
draw();
control();
}
timeThisFrame = System.currentTimeMillis() - startFrameTime;
if (timeThisFrame >= 1) {
fps = 1000 / timeThisFrame;
}
}
}
private void update() {
//incrementing score as time passes
score++;
player.update();
//setting boom outside the screen
boom.setX(-250);
boom.setY(-250);
for (Star s : stars) {
s.update(player.getSpeed());
}
for (Bullet b : bullet) {
b.update();
}
//setting the flag true when the enemy just enters the screen
if(enemies.getX()==screenX){
flag = true;
}
enemies.update(player.getSpeed(),getFps());
}
private void draw() {
if (surfaceHolder.getSurface().isValid()) {
canvas = surfaceHolder.lockCanvas();
canvas.drawColor(Color.argb(500,135,206,250));
paint.setColor(Color.WHITE);
paint.setTextSize(20);
for (Star s : stars) {
canvas.drawBitmap(
s.getBitmap(),
s.getX(),
s.getY(),
paint);
}
for (Bullet b : bullet) {
canvas.drawBitmap(
b.getBitmap(),
b.getX(),
b.getY(),
paint);
}
canvas.drawBitmap(
player.getBitmap(),
player.getX(),
player.getY(),
paint);
canvas.drawBitmap( enemies.getBitmap(), enemies.getframeToDraw(), enemies.getwhereToDraw(), null);
//drawing the score on the game screen
paint.setTextSize(30);
canvas.drawText("Score:"+score,100,50,paint);
//drawing boom image
canvas.drawBitmap(
boom.getBitmap(),
boom.getX(),
boom.getY(),
paint
);
//draw game Over when the game is over
if(isGameOver){
paint.setTextSize(150);
paint.setTextAlign(Paint.Align.CENTER);
int yPos=(int) ((canvas.getHeight() / 2) - ((paint.descent() + paint.ascent()) / 2));
canvas.drawText("Game Over",canvas.getWidth()/2,yPos,paint);
}
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
private void control() {
try {
gameThread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void pause() {
playing = false;
try {
gameThread.join();
} catch (InterruptedException e) {
gameThread.interrupt();
}
}
public void resume() {
playing = true;
gameThread = new Thread(this);
gameThread.start();
}
//stop the music on exit
public static void stopMusic(){
gameOnsound.stop();
}
#Override
public boolean onTouchEvent(MotionEvent motionEvent) {
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP:
player.stopBoosting();
break;
case MotionEvent.ACTION_DOWN:
player.setBoosting();
break;
}
//if touch the player
if (player.getDetectCollision().contains((int)motionEvent.getX(), (int)motionEvent.getY())) {
Bullet b = new Bullet(context,player.getX()+player.getDetectCollision().width()
,player.getY()-(player.getDetectCollision().height()/2));
bullet.add(b);
Log.d("test", "touch not inside myEditText");
}
//if the game's over, tappin on game Over screen sends you to MainActivity
if(isGameOver){
if(motionEvent.getAction()==MotionEvent.ACTION_DOWN){
context.startActivity(new Intent(context,MainActivity.class));
}
}
return true;
}
public long getFps(){
return fps;
}
}
Related
I am running into an issue in my app. When my game ends (when life == 0) I am attempting to switch to a game over screen by using a different activity. When the game ends, the app simply crashes. I have included the XML for the activity I am trying to switch from as well as indicating where the app crashes. If anyone could help out, that would be great! Thanks.
activity_game.XML:
SurfaceView I am trying to switch from once game ends:
public class SVGameView extends SurfaceView implements Runnable {
private SurfaceHolder holder;
Thread thread = null;
volatile boolean running = false;
static final long FPS = 30;
private Sprite sprite;
private long lastClick;
private Bitmap ball, gameOver;
//private int x = 200, y = 200;
private int scorePosX = 100;
private int scorePosY = 100;
private int countScore = 0;
private int life = 1;
public SVGameView(Context context) {
super(context);
thread = new Thread(this);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
running = false;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
running = true;
thread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
ball = BitmapFactory.decodeResource(getResources(), R.drawable.ball2);
gameOver = BitmapFactory.decodeResource(getResources(),R.drawable.endscreen);
sprite = new Sprite(this, ball);
}
#Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = getHolder().lockCanvas();
synchronized (getHolder()) {
update();
draw(c);
}
} finally {
if (c != null) {
getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
thread.sleep(sleepTime);
else
thread.sleep(10);
} catch (Exception e) {}
}
}
private void update(){
sprite.update();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
canvas.drawPaint(paint);
paint.setColor(Color.WHITE);
paint.setTextSize(48);
canvas.drawText("Score: " + countScore, scorePosX, scorePosY, paint);
canvas.drawText("Lives: " + life, 500, 100, paint);
sprite.onDraw(canvas);
//Crashes here
if(life == 0) {
getContext().startActivity(new Intent(getContext(), SVGameOver.class));
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(System.currentTimeMillis()-lastClick > 300){
lastClick = System.currentTimeMillis();
}
synchronized (getHolder()){
if(sprite.isHit(event.getX(), event.getY())){
countScore += 1;
sprite.increase();
}else{
life --;
}
}
return super.onTouchEvent(event);
}
}
Activity I am trying to reach once the game ends:
public class SVGameOver extends Activity {
private Bitmap gameOverScreen;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
gameOverScreen = BitmapFactory.decodeResource(getResources(), R.drawable.endscreen);
}
protected void onDraw(Canvas canvas){
canvas.drawBitmap(gameOverScreen, 0,0,null);
}
}
I think logcat is asking you the right question: "have you declared this activity in your AndroidManifest.xml" ?
If you think you did it, It's highly probable you did it in a wrong way, most of the times that you think you added an Activity to the manifest but you are receiving this kind of crash, 99,9% of the time you declared it with a wrong namespace
Declare SVGameOver activity in your AndroidManifest.xml:
<activity
android:name="com.example.welcome.assignment2.SVGameOver">
...
</activity>
I am working on a small game with touch-motion, bluetooth, and menus. At the moment the code is implemented is in my custom View.
For example vectors of classes that store game-data, vectors for current data and later will there be some threads for animations and timers.
Yet there is no icons for "abilities", but I will implement them too.
Later will there be a process or a service with bluetooth which also calls methods which are at the moment in the custom view class.
I suppose this is a bad design - so I have no concrete idea how I can or should move my functions to for example the activity which holds the custom view and how to let the custom view and activity communicate with each other.
Maybe some of you have advice on what to do.
Here is the activity:
Gamecontroller_Activity:
public class Gamecontroller_Activity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("Enter Function","Enter onCreate Gamecontroler_Activity");
setContentView(R.layout.activity_gamecontroller);
}
}
activity_gamecontroller.xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.calma.Gamecontroller_View
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
And the big custom view class (shorted) Gamecontroller_View.java:
public class Gamecontroller_View extends View implements OnGestureListener{
//Touch
private PointF fingerpointer;
private int totalClickt;
private static final int SIZE = 60;
private Paint mPaint;
//Text Flashes
private Paint textPaint;
private Paint textPaintAction;
private String currentMsg;
private boolean currentMsgShow;
//Drawables (Pictures)
private int monsterscale;
private int monsterMinimumBorderX;
private int monsterMinimumBorderY;
private Bitmap bitmap1,bitmap2;
private HashMap<String, Bitmap> hashmapMonsterStandartBitmap;
Display Informations;
private DisplayMetrics displayMetrics;
private int xDisplayMaximum;
private int yDisplayMaximum;
//Monsters
private Vector<Monster> currentMonsters;
private int monsterCountGlobal;
//Player Stats
private Player playerMe;
//Enemy Player Stats
private Player playerEnemy;
public Gamecontroller_View(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public void initView(){
//display
displayMetrics = new DisplayMetrics();
((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(displayMetrics);
float displayPixelFactor = displayMetrics.widthPixels/displayMetrics.densityDpi;
xDisplayMaximum = displayMetrics.widthPixels ;
yDisplayMaximum = displayMetrics.heightPixels - (3*getStatusBarSizes());
Log.i("Display","displaywidthpixels/displayMetrics: "+xDisplayMaximum);
//yDisplayMaximum
//Enemy Player
playerEnemy = new Player();
//Monsters
monsterscale =10;
monsterMinimumBorderX= Math.min(xDisplayMaximum,yDisplayMaximum)/monsterscale;
monsterMinimumBorderY= Math.max(xDisplayMaximum,yDisplayMaximum)/monsterscale;
hashmapMonsterStandartBitmap = new HashMap<String,Bitmap>();
currentMonsters = new Vector<Monster>();
monsterCountGlobal = 0;
Log.i("display","Monsterscale: "+monsterscale + " minMonsterBorder: "+monsterMinimumBorderX);
//init Touch detection and draw
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
mPaint.setMaskFilter(new BlurMaskFilter(15, Blur.OUTER));
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
//init Text wich will be drawn
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(30);
textPaintAction = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaintAction.setTextSize(60);
currentMsg = "";
currentMsgShow = false;
//Futher init stuff
initPlayerMe();
initPlayerEnemy();
enemySpawn();
preloadImages();
showDebug();
}
public void initPlayerMe(){
//Player
playerMe = new Player();
playerMe.setlife(100);
playerMe.setMoney(0);
playerMe.setStrength(1);
}
public void initPlayerEnemy(){
//Player
playerEnemy = new Player();
playerEnemy.setlife(100);
playerEnemy.setMoney(0);
playerEnemy.setStrength(1);
}
public Vector<Dimension> findPlaceForMonsters(int n){
//First Collect allready existing Monster Coordinates
Vector <Dimension> currentPlaces = new Vector<Dimension>();
Vector <Dimension> newPlaces = new Vector<Dimension>();
for(int i = 0; i< currentMonsters.size();i++){
if (currentMonsters.elementAt(i) != null){
currentPlaces.add(currentMonsters.elementAt(i).getDimension());
}
}
for (int i=0; i < n ;i++){
newPlaces.add(new Dimension(getRandomNumberBetween(0, xDisplayMaximum-monsterMinimumBorderX),
getRandomNumberBetween(0, yDisplayMaximum-monsterMinimumBorderY)));
Log.i("randomPlaces","Point xy: " + newPlaces.lastElement().getX()+ " "+newPlaces.lastElement().getY());
}
Log.i("findPlfaceForMonsters",this.monsterMinimumBorderX+" "+this.monsterMinimumBorderY);
return newPlaces;
}
public void enemySpawn(){
int tempCount =0;
Vector<Dimension> newPlaces = findPlaceForMonsters(6);
for(int i=0; i < 2;i++){
currentMonsters.add(new MonsterMedium(monsterCountGlobal));
currentMonsters.lastElement().setDimension(new Dimension(newPlaces.elementAt(tempCount).getX(),newPlaces.elementAt(tempCount).getY(),monsterMinimumBorderX,monsterMinimumBorderY));
monsterCountGlobal++;
tempCount++;
}
for(int i=0; i < 2;i++){
currentMonsters.add(new MonsterSmall(monsterCountGlobal));
currentMonsters.lastElement().setDimension(new Dimension(newPlaces.elementAt(tempCount).getX(),newPlaces.elementAt(tempCount).getY(),monsterMinimumBorderX,monsterMinimumBorderY));
monsterCountGlobal++;
tempCount++;
}
for(int i=0; i < 2;i++){
currentMonsters.add(new MonsterHeavy(monsterCountGlobal));
currentMonsters.lastElement().setDimension(new Dimension(newPlaces.elementAt(tempCount).getX(),newPlaces.elementAt(tempCount).getY(),monsterMinimumBorderX,monsterMinimumBorderY));
monsterCountGlobal++;
tempCount++;
}
}
public void attackMonster(int id){
for (int i=currentMonsters.size()-1; i >= 0; i--){
if (currentMonsters.elementAt(i).getID() == id){
int restlife = currentMonsters.elementAt(i).setDamge(this.playerMe.getStrength());
lifeOfMonsterChanged(currentMonsters.elementAt(i).getID(),i,restlife);
break;
}
}
}
public void lifeOfMonsterChanged(int id,int index, int life){
if (life <= 0){
Log.i("MonsterTouchted", "Monster tot");
currentMonsters.removeElementAt(index);
}
else{
Log.i("MonsterTouchted", "Monster "+id+" restlife: "+life);
//effekte? (shake?) farbE?
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// get pointer index from the event object
int pointerIndex = event.getActionIndex();
// get pointer ID
int pointerId = event.getPointerId(pointerIndex);
Log.i("touch","event.getPointerID(): "+pointerId);
// get masked (not specific to a pointer) action
int maskedAction = event.getActionMasked();
switch (maskedAction) {
//Detection of a finger touch
case MotionEvent.ACTION_DOWN:
totalClickt = totalClickt+1;
//attackTheMonster(currentPlayer.attack());
fingerpointer = new PointF();
fingerpointer.x = event.getX(0);
fingerpointer.y = event.getY(0);
for (int i=currentMonsters.size()-1; i >= 0; i--){
if(currentMonsters.elementAt(i).getDimension().contains((int)fingerpointer.x, (int)fingerpointer.y)){
Log.i("MonsterTouchted","MonsterTouched: index: "+i);
attackMonster(currentMonsters.elementAt(i).getID());
break;
}
}
case MotionEvent.ACTION_POINTER_DOWN:
{
// Optional more than one finger
break;
}
case MotionEvent.ACTION_MOVE:
{ // a pointer was moved
if (fingerpointer != null) {
fingerpointer.x = event.getX(0);
fingerpointer.y = event.getY(0);
}
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL: {
fingerpointer = null;
break;
}
}
invalidate();
return true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw all pointers
if (fingerpointer != null){
mPaint.setColor(colors[0]);
canvas.drawCircle(fingerpointer.x, fingerpointer.y, SIZE, mPaint);
}
// draw mosnters
for(int i=0; i < currentMonsters.size();i++){
if( currentMonsters.elementAt(i) != null){
canvas.drawBitmap(hashmapMonsterStandartBitmap.get(currentMonsters.elementAt(i).getImagePath()), currentMonsters.elementAt(i).getDimension().getX(), currentMonsters.elementAt(i).getDimension().getY(), mPaint); //bitmap, abstand left, abstand top, paint
} else{
Log.i("Failure","Draw monster nullpointer bei index: "+i);
}
}
//draw extra texts
if(currentMsgShow){
Log.i("onDraw","enter currenMsgShow");
if(displayMetrics != null){
int textsize = (int) textPaintAction.measureText(currentMsg);
int sidespacing = (displayMetrics.widthPixels - textsize)/2;
canvas.drawText(currentMsg, sidespacing, displayMetrics.heightPixels/5 , textPaintAction);
}
}
//Draw extratext
canvas.drawText( "Total Clickt: " + totalClickt, 10, 40 , textPaint);
}
}
Project:
Make those changes:
1) in your activity_gamecontroller.xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.calma.Gamecontroller_View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/myGameController"/>
</RelativeLayout>
2) in your Gamecontroller_Activity:
public class Gamecontroller_Activity extends Activity {
Gamecontroller_View mGameControllerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("Enter Function","Enter onCreate Gamecontroler_Activity");
setContentView(R.layout.activity_gamecontroller);
mGameControllerView = (Gamecontroller_View) findViewById(R.id.myGameController);
}
}
3) now you can call for example mGameControllerView.initPlayerMe(); from any method in your Gamecontroller_Activity .
This is an example:
public class Gamecontroller_Activity extends Activity {
Gamecontroller_View mGameControllerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("Enter Function","Enter onCreate Gamecontroler_Activity");
setContentView(R.layout.activity_gamecontroller);
mGameControllerView = (Gamecontroller_View) findViewById(R.id.myGameController);
testMethod();
}
private void testMethod(){
mGameControllerView.enemySpawn();
}
}
good day... im a new programmer in android... and actually its my first time doing so...
but i have basic knowledge about java...
so here goes.. my game will have an icon that can be controlled by a joystick... and another icon that goes up and down the screen(non controllable) i want the speed to increase a little..... i have started the code but dont know where and how to start the collision.. another one is that the icon that is controllabe always passes the screen and pop out the opposite direction...
public class GameSurface1 extends SurfaceView implements SurfaceHolder.Callback {
private Context _context;
private GameThread1 _thread;
private GameControl _controls;
private GameJoystick1 _joystick;
private int y = 0;
private int xSpeed = 1;
private Bitmap _pointer, bmp;
public GameSurface1(Context context) {
super(context);
// TODO Auto-generated constructor stub
_context = context;
init();
}
private void init(){
//initialize our screen holder
SurfaceHolder holder = getHolder();
holder.addCallback( this);
//initialize our game engine
//initialize our Thread class. A call will be made to start it later
_thread = new GameThread1(holder, _context, new Handler(),this);
setFocusable(true);
_joystick = new GameJoystick1(getContext().getResources());
_pointer = (Bitmap)BitmapFactory.decodeResource(getResources(), R.drawable.icon1);
bmp = (Bitmap)BitmapFactory.decodeResource(getResources(), R.drawable.bad1);
//contols
_controls = new GameControl();
setOnTouchListener(_controls);
}
public void doDraw(Canvas canvas){
if (y == getHeight() - bmp.getHeight()) {
xSpeed = -1;
}
if (y == 0) {
xSpeed = 1;
}
y = y + xSpeed;
//update the pointer
_controls.update(null);
//draw the pointer
canvas.drawBitmap(_pointer, _controls._pointerPosition.x, _controls._pointerPosition.y, null);
//draw the joystick background
canvas.drawBitmap(_joystick.get_joystickBg(), 15,215, null);
//draw the dragable joystick
canvas.drawBitmap(_joystick.get_joystick(),_controls._touchingPoint.x - 26, _controls._touchingPoint.y - 26, null);
canvas.drawBitmap(bmp, 280, y, null);
}
//these methods are overridden from the SurfaceView super class. They are automatically called
//when a SurfaceView is created, resumed or suspended.
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {}
private boolean retry;
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
retry = true;
//code to end gameloop
_thread.state = GameThread1.STOPED;
while (retry) {
try {
//code to kill Thread
_thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
if(_thread.state==GameThread1.PAUSED){
//When game is opened again in the Android OS
_thread = new GameThread1(getHolder(), _context, new Handler(),this);
_thread.start();
}else{
//creating the game Thread for the first time
_thread.start();
}
}
ill appreciate all the help you can give...
thank you
I'm developing a simple game like BSD robots. This game contains a rather large board (over 40 cells) and it doesn't look nice even at 10 inch tablet. My decision was to scroll (move) surface view and not to scale each figure which size is like finger spot.
I've read tons articles about surface view but I cannot understand how to move it?
My activity code:
package ru.onyanov.robots;
public class MainActivity extends Activity {
public BoardView board;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
board = new BoardView(this);
setContentView(board);
}
}
Class Board:
package ru.onyanov.robots;
public class BoardView extends SurfaceView {
private GameThread mThread;
private boolean running = false;
public final int sizeX = 50;
public final int sizeY = 35;
public final int cellSize = 64;
private int robotCount = 4;
public ArrayList<Cell> cells = new ArrayList<Cell>();
private ArrayList<Robot> robots = new ArrayList<Robot>();
private Hero hero;
public Bitmap imageCell;
public Bitmap imageRobot;
public Bitmap imageHero;
public BoardView(Context context) {
super(context);
makeGraphic();
constructCells();
constructRobots();
hero = new Hero(this, 3, 2, imageHero);
mThread = new GameThread(this);
getHolder().addCallback(new SurfaceHolder.Callback() {
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
mThread.setRunning(false);
while (retry) {
try {
mThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
mThread.setRunning(true);
mThread.start();
}
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
private void makeGraphic() {
Bitmap cellImageSource = BitmapFactory.decodeResource(getResources(),
R.drawable.cell);
imageCell = Bitmap.createScaledBitmap(cellImageSource, cellSize,
cellSize, false);
imageRobot = BitmapFactory.decodeResource(getResources(),
R.drawable.robot);
imageHero = BitmapFactory.decodeResource(getResources(),
R.drawable.hero);
}
private void constructRobots() {
Robot robot;
Random rand = new Random();
for (int r = 0; r < robotCount; r++) {
int x = rand.nextInt(sizeX);
int y = rand.nextInt(sizeY);
robot = new Robot(this, x, y, imageRobot);
robots.add(robot);
}
return;
}
private void constructCells() {
Cell cell;
for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++) {
cell = new Cell(this, x, y, imageCell);
cells.add(cell);
}
}
return;
}
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
Cell cell;
for (int c = 0; c < cells.size(); c++) {
cell = cells.get(c);
cell.onDraw(canvas);
}
Robot robot;
for (int r = 0; r < robots.size(); r++) {
robot = robots.get(r);
robot.onDraw(canvas);
}
hero.onDraw(canvas);
}
public boolean onTouchEvent(MotionEvent e) {
int shotX = (int) e.getX();
int shotY = (int) e.getY();
if (e.getAction() == MotionEvent.ACTION_MOVE){
//TODO move board
showToast("move Board");
} else if (e.getAction() == MotionEvent.ACTION_UP) {
showToast("touchPoint: " + shotX + ", "+shotY);
hero.moveByDirection(shotX, shotY);
this.scrollTo(shotX, shotY);
}
return true;
}
public void showToast(String mes) {
Toast toast = Toast.makeText(getContext(), mes, Toast.LENGTH_LONG);
toast.show();
}
public class GameThread extends Thread {
private BoardView view;
public GameThread(BoardView view) {
this.view = view;
}
public void setRunning(boolean run) {
running = run;
}
public void run() {
while (running) {
Canvas canvas = null;
try {
canvas = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
onDraw(canvas);
}
canvas.scale(300, 300);
} catch (Exception e) {
} finally {
if (canvas != null) {
view.getHolder().unlockCanvasAndPost(canvas);
}
}
}
}
}
}
Some magic digits here are temporary. Now I just want to move BoardView;
The issue was to add x and y fields to SurfaceView, change them at onTouchEvent and draw all the elements in canvas with x- and y-offset. It's strange that I didn't recieved any answers...
Is it possible to pass arguments to an Android Handler?? I have two pieces of code.
new Thread(){
public void run(){
for(;;){
uiCallback.sendEmptyMessage(0);
Thread.sleep(2000); //sleep for 2 seconds
}
}
}.start();
private Handler uiCallback = new Handler(){
public void handleMessage(Message msg){
//add a new blossom to the blossom ArrayList!!
blossomArrayList.add(new Blossom(context, R.drawable.blossom));
}
};
I of course get an error because the Handler method cannot see my context. This is probably because of this piece of code
public BoardView(Context context){
super(context);
Context is not visible elsewhere, and I'm wondering if I can pass it as an argument to my Handler.
EDIT: I am posting the two main pieces of code to answer a question about why my Blossom object needs context. I myself am not 100% sure >.> Maybe you could have a look and see what's going on.
public class Blossom{
private Bitmap blossom;
private float blossomX = 0;
private float blossomY = 0;
private Random generator = new Random();
public Blossom(Context context, int drawable)
{
blossom = BitmapFactory.decodeResource(context.getResources(), drawable);
blossomX = generator.nextInt(300);
}
public Bitmap getBitmap()
{
return blossom;
}
public float getBlossomX()
{
return blossomX;
}
public float getBlossomY()
{
return blossomY;
}
public void Fall(Canvas canvas, float boxY)
{
//draws the flower falling
canvas.drawBitmap(blossom, blossomX,
blossomY = blossomY+3 , null);
//collision detection, currently not working after
//implementing random start location
//if(blossomY + 29 == boxY)
//{
//canvas.drawBitmap(blossom,0,0,null);
//}
}
}
public class BoardView extends SurfaceView implements SurfaceHolder.Callback{
Context mContext;
Bitmap box =
(BitmapFactory.decodeResource
(getResources(), R.drawable.box));
private BoardThread thread;
private float box_x = 140;
private float box_y = 378;
private float boxWidth = box.getWidth();
private float boxHeight = box.getHeight();
private ArrayList<Blossom> blossomArrayList = new ArrayList<Blossom>();;
boolean mode = false;
RectF boxRect = new RectF(box_x,box_y, box_x + boxWidth, box_y + boxHeight);
public BoardView(Context context){
super(context);
//surfaceHolder provides canvas that we draw on
getHolder().addCallback(this);
// controls drawings
thread = new BoardThread(getHolder(),this);
//pass variables to instance of Blossom
//for(int i = 0; i <= 3; i++)
//{
//blossomArrayList.add(new Blossom(context, R.drawable.blossom));
//}
new Thread(){
public void run(){
for(;;){
uiCallback.sendEmptyMessage(0);
Thread.sleep(2000); //sleep for 2 seconds
}
}
}.start();
//intercepts touch events
setFocusable(true);
}
#Override
public void onDraw(Canvas canvas){
canvas.drawColor(Color.WHITE);
//draw box and set start location
canvas.drawBitmap(box, box_x - (boxWidth/2),
box_y - (boxHeight/2), null);
for(int i = 0; i<= 3; i++)
{
blossomArrayList.get(i).Fall(canvas, box_y);
}
}
#Override
public boolean onTouchEvent(MotionEvent event){
if(event.getAction() == MotionEvent.ACTION_DOWN){
if(boxRect.contains(event.getX(),event.getY())){
mode = true;
}
}
if(event.getAction() == MotionEvent.ACTION_MOVE) {
if(boxRect.contains(event.getX(),event.getY())){
mode = true;
}
if(mode == true){
box_x = (int)event.getX();
boxRect.set(box_x,box_y, box_x + boxWidth, box_y + boxHeight);
}
}
if(event.getAction() == MotionEvent.ACTION_UP){
mode = false;
}
invalidate();
return true;
}
#Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height ){
}
#Override
public void surfaceCreated(SurfaceHolder holder){
thread.startRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder){
thread.startRunning(false);
thread.stop();
}
private Handler uiCallback = new Handler(){
public void handleMessage(Message msg){
//add a new blossom to the blossom ArrayList!!
blossomArrayList.add(new Blossom(context, R.drawable.blossom));
}
};
}
Create a class that extends Handler, and store a weak reference to the context. This will help prevent some memory issues.
public class SomeHandler extends Handler {
// A weak reference to the enclosing context
private WeakReference<Context> mContext;
public SomeHandler (Context context) {
mContext = new WeakReference<Context>(context);
}
public void handleMessage(Message msg) {
// Get an actual reference to the DownloadActivity
// from the WeakReference.
Context context=mContext.get();
...
}
}
What if you create a subclass which extends Handler? That way you could pass any parameters you want.
But just out of curiosity, why does the Blossom object require the context object? It's usually best to separate your logic from GUI dependencies.