My project is to create a flip card game in Android like http://partyhatmy.blogspot.kr/2012/08/angry-bird-matching-card-game.html. The differences are that there will be 3 x 4 total 12 cards on the screen, and the game will have a timer. So if the timer expires or if the user finds all pairs, the new stage begins.
My problem is that I do know how to implement this using SurfaceView, but since all cards are at fixed positions, I think it might be possible to implement the game using layouts in xml, but I don't know how. Is there any starting point resource available on the web?
Edition 1
My Code is like this: I just first want to print the remaining time to one TextView to the screen. The problem is that the screen is all black (without runOnUiThread() invocation, the activity draws the given layout activity_game flawlessly.
public class GameActivity extends Activity {
private TextView mTimerTextView;
private int mRemainingTime = 30;
#Override
protected void onCreate(Bundled savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_game);
mTimerTextView = (TextView)findViewById(R.id.remaining_time);
this.runOnUiThread(new Runnable() {
public void run() {
long lastSystemTime = 0;
mTimeTextView.setText(String.valueOf(mRemainingTime));
while (mRemainingTime > 0) {
if (lastSystemTime == 0) { // initial run
lastSystemTime = System.currentTimeMillis();
continue;
}
long currentTime = System.currentTimeMillis();
long elapsedTime = currentTime - lastSystemTime;
lastSystemTime = currentTime;
if (elapsedTime > 1000) {
mRemainingTime--;
mTimeTextView.setText(String.valueOf(mRemainingTime));
}
// To avoid excessive loop
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
}
see this link it will help you with flip animation
Displaying card flip animation on old android
or
http://www.techrepublic.com/blog/software-engineer/use-androids-scale-animation-to-simulate-a-3d-flip/
use this coode to do changes in ui thread
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
//do ui changes here
}
});
Related
I don't fully understand what is going on behind the scene, and therefore, what I can do to correctly code this issue. I'm looking for an explanation that will lead me to figure it out myself. This is just a fun home based project(I'm not a student), where I'm coding a turn based app. However, the battle scenes are randomly calculated durations, rather than turn based, so my desire is as follows:
Present initial battle count on screen for 2 seconds
Calculate first skirmish
Present updated battle count on screen for 2 seconds
Calculate 2nd skirmish
...
...
Present Victory or Defeat on screen
The problem I'm having is that the app is performing as follows currently:
Present initial battle count on screen
Calculate all skirmishes
Page displays null for the number, since it's apparently already returned?
Code looks like this:
void fightBattle(){
setContentView(R.layout.brigands);
boolean winnerDetermined = false;
while(!winnerDetermined) {
boolean brigandsWon = brigandsWon(player, brigandCount);
if(brigandsWon) {
player.removeWarriors(2);
}
displayWarriors(player);
if(brigandsWon){
if(player.getWarriors() < 2){
winnerDetermined = true;
}
}
if(!brigandsWon) {
brigandCount = brigandCount / 2;
}
displayBrigands();
if(brigandCount == 0){
winnerDetermined = true;
}
}
}
private void displayWarriors(Player player){
final Player currentPlayer = player;
new CountDownTimer(2000, 2000) {
public void onTick(long millisUntilFinished) { }
public void onFinish() {
setContentView(R.layout.warriors);
TextView warrior_count_tv = findViewById(R.id.warrior_count_tv);
warrior_count_tv.setText(currentPlayer.getWarriors());
}
}.start();
}
private void displayBrigands(Player player){
new CountDownTimer(2000, 2000) {
public void onTick(long millisUntilFinished) { }
public void onFinish() {
setContentView(R.layout.brigands);
TextView brigand_count_tv = findViewById(R.id.brigand_count_tv);
brigand_count_tv.setText(Integer.toString(brigandCount));
}
}.start();
}
Ultimately, what I want to see is something like the below sudo-code:
displayPage1For2Seconds;
while(somethingIsTrue){
calculateNumber;
displayPage2For2Seconds;
displayPage3for2Seconds;
}
displayPage4For2Seconds;
Calculate all skirmishes
Your current code does this because the while loop doesn't actually stops to wait. The flow will be like this:
enter while loop -> call displayWarriors() -> create CountDownTimer() to do something after 2 seconds -> return to while loop -> call displayBrigands() -> create CountDownTimer() to do something after 2 seconds -> return to while loop -> do the same until you exit while
With this code you'll end up with a bunch of CountDownTimers that are created and executed at the same(almost) time so after two seconds they all try to set a view to some value(with an indefinite behavior like you mention it happens).
There are several ways to do what you want. You could use a Thread for example:
void fightBattle(){
setContentView(R.layout.brigands);
new Thread(new Runnable() {
public void run() {
// I assume R.layout.brigands is the initial screen that you want to show for 2 seconds?!? In this case wait 2 seconds
TimeUnit.Seconds.sleep(2);
boolean winnerDetermined = false;
while(!winnerDetermined) {
// ...
// from your code it seems you want to show this for 2 seconds?
displayWarriors(player);
TimeUnit.Seconds.sleep(2);
//...
displayBrigands();
// also show this for 2 seconds
TimeUnit.Seconds.sleep(2);
// ...
}
}
}).start();
}
Then your display methods will be something like this:
private void displayWarriors(Player player){
// you need to wrap this code in a runOnUiThread() method(from the activity)
// because we are on a background thread and we are changing views!
final Player currentPlayer = player;
setContentView(R.layout.warriors);
TextView warrior_count_tv = findViewById(R.id.warrior_count_tv);
warrior_count_tv.setText(currentPlayer.getWarriors());
}
Another approach would be to use a Handler and break your code in Runnables that you then schedule at appropriate times.
I cant seem to figure out how to move my rects along with an imageview I am animating to use as a hit box. I have it detecting collisions with intersects but it just stays at the starting position of the image.
The first way I cracked at it was by using the getOnScreenLocation() and storing that in a variable to use .offsetTo() on the rect to move it with the image but that only moved the hitbox to the end of the animation and that was it. I have my hitbox movements and checking for collisions inside a seprate thread updating the UI frequently.
So my question is how can I get the rect hitbox to just stay attached to the imageview as it is animated across the screen? Any and all advice helps even if its just a method i should look into thank you.
Here is the latest version of my moveHitbox(), still it's not functioning correctly.
public void hitBox()
{
//declaration of rectangles around each image
getHits();
moveHitBox();
//see if rectangle around rocket intersects enemy ships rectangle
if (Rect.intersects(myViewRect, otherViewRect1)||Rect.intersects(myViewRect,
otherViewRect2) ||Rect.intersects(myViewRect, otherViewRect3)) {
check();
//immunity();
}
}
public void moveHitBox()
{
int YYY = (int)enemy_ship.getTranslationY();
int XXX = (int)enemy_ship.getTranslationX();
enemy_ship.setTranslationY(YYY);
enemy_ship.setTranslationX(XXX);
enemy_ship.getLocationOnScreen(thisLocation);
enemy_ship2.getLocationOnScreen(thisLocationA);
enemy_ship3.getLocationOnScreen(thisLocationB);
x.getLocationOnScreen(thisShipLocation);
otherViewRect1.union(thisLocation[0],thisLocation[1]);
otherViewRect2.union(thisLocationA[0], thisLocationA[1]);
otherViewRect3.union(thisLocationB[0],thisLocationB[1]);
}
// Separate thread that updates the ui thread
Runnable myRunnable = new Runnable() {
#Override
public void run() {
while (testByte == 0) {
try {
Thread.sleep(3); // Waits for 1 second (1000 milliseconds)
}catch(InterruptedException e)
{
finish();
}
enemy_ship.post(new Runnable() {
#Override
public void run() {
hitBox();
}
});
}
}
};
I am making an Android game modeled after the old Simon game. It is a little different in the layout as it is using a 3x3 layout of buttons. I am trying to get the buttons to light up one at a time inside the loop that randomly selects a button. The trouble I have is that all of the buttons light up at once and only the last (or first, not sure) changes back to the original color. I have tried very thoroughly to find an appropriate answer to my situation but have had no luck here or elsewhere. The button id(s) are in the butts[]. butts[0] is button 1, butts[2] ... Below is my attempt.
public void play()
{
for(int x = 0; x <= numButtons; ++x)
{
spot = randomGenerator.nextInt(9);
playMe[x] = spot;
//butts[spot].setBackgroundColor(Color.parseColor("#540115"));
handler.postDelayed(new Runna(spot), (x+1)*1000);
}
}
class Runna implements Runnable
{
public Runna(int j2)
{
butts[j2].setBackgroundColor(Color.parseColor("#540115"));
}
public void run()
{
butts[spot].setBackgroundColor(Color.LTGRAY);
}
}
I think it has to do with the value of spot. It is global to the functions and you change it every time. It runs, but at the end there is still only one spot and EVERY runnable is trying to change that same spot.
Perhaps save spot in your runnable?
class Runna implements Runnable
{
int s;
public Runna(int j2)
{
s = j2;
butts[s].setBackgroundColor(Color.parseColor("#540115"));
}
public void run()
{
butts[s].setBackgroundColor(Color.LTGRAY);
}
}
Have you tried to invalidate the button each time?
public Runna(int j2)
{
butts[j2].setBackgroundColor(Color.parseColor("#540115"));
butts[j2].invalidate();
}
To use a SurfaceView for drawing a 2D game in Android, I use this in the main activity's onCreate():
setContentView(new GameView(this));
Which is a reference to this class:
public class GameView extends SurfaceView implements SurfaceHolder.Callback
Additionally, I have a thread with its run() function:
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_panel.updatePhysics();
_panel.onDraw(c);
}
}
finally { // when exception is thrown above we may not leave the surface in an inconsistent state
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
In updatePhysics() I do some calculations. They are more complex than this simple example, of course, but work the same way:
public void updatePhysics() {
GraphicObject.Coordinates coord;
GraphicObject.Speed speed;
for (GraphicObject graphic : _allElements) {
coord = graphic.getCoordinates();
speed = graphic.getSpeed();
coord.setX(coord.getX() + speed.getX());
coord.setY(coord.getY() + speed.getY());
...
}
}
And in onDraw(), I draw everything to the canvas:
#Override
public void onDraw(Canvas canvas) {
canvas.drawBitmap(BITMAP, xPos, yPos, null);
...
}
This works fine - everything. And when I tested it on my device, it looked pretty good. But when I gave it to someone else and he did a test game, the objects were moving much faster! Why is this so? Because the thread calls updatePhysics() as often as possible which means that fast devices call this function more often?
How can I prevent this and make the game equally fast on all devices? Something like this?
private long lastRun = System.currentTimeMillis();
public void updatePhysics() {
long millisPassed = System.currentTimeMillis()-lastRun;
...
float newCoord = (coord.getX() + speed.getX()) * millisPassed / 33;
coord.setX(newCoord);
...
}
Thanks for your help!
If you can, use the time directly to calculate all your physics. That would usually work best.
If you have no way to calculate based on time because what you are doing that is just step based and you know that generating the next step does not take much time then you have another option.
You create two threads. The first one advances the state at a fixed rate (and you have to be sure that this works on slow devices at that rate too). The second one takes the current state is sees and draws that. Now the second thread can be as slow as it wants because it simply skips some states (or draws the same state several times if it is faster).
Small example below has one thread that advances some state object and replaces the reference each time so the consuming thread does not need to worry that it's state object gets modified
class GameState {
private int state = 0;
public GameState advanceState() {
GameState result = new GameState();
result.state = this.state + 1;
return result;
}
}
class SurfaceViewImplementation extends SurfaceView {
// the current state
volatile GameState mState = new GameState();
void somewhere() {
Thread fastProducer = new Thread(new Runnable() {
private static final long MAX_WAIT = 1000 / 60;
#Override
public void run() {
while (!Thread.interrupted()) {
long timeBefore = SystemClock.currentThreadTimeMillis();
GameState newState = mState.advanceState();
mState = newState;
long timeAfter = SystemClock.currentThreadTimeMillis();
long timeSpent = timeAfter - timeBefore;
SystemClock.sleep(Math.max(0, MAX_WAIT - timeSpent));
}
}
});
fastProducer.start();
Thread slowConsumer = new Thread(new Runnable() {
#Override
public void run() {
while (!Thread.interrupted()) {
GameState currentState = mState;
longRunningDraw(currentState);
}
}
});
slowConsumer.start();
}
}
That will still fail to give you a speed independant result if the producing thread can't run at the desired rate.
I would save the time when I start rendering the frame(in your case is updatePhysics()), and then next time I would got to this point, I know how much time pass, if it's to fast you can use Thread.Sleep();
I've got 30+ single bitmaps (320x240 pixels) that I would like to display one after another in full screen on Android devices resulting in an animation. Currently I implemented the animation using an ImageView and a Timer that sets the next frame and then sends a message that will apply the next frame. The resulting frame rate is very low: < 2 fps.
The timer:
animationTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
Drawable frame = getNextFrame();
if (frame != null) {
Message message = animationFrameHandler.obtainMessage(1, frame);
animationFrameHandler.sendMessage(message);
}
}
}, 0, (int) (1000.0d / fps));
The handler:
final Handler animationFrameHandler = new Handler() {
#Override
public void handleMessage(Message message) {
setImageDrawable((Drawable) message.obj);
}
};
Since I want to achieve frame rates up to 30 fps I have to make use of another mechanism and heard of Canvas.drawBitmapMesh() and OpenGL.
If possible I would like to avoid using OpenGL.
Thank you very sharing your experiences!
My now working approach is the following:
Before starting the animation, load every frame into a List<Bitmap>. Important: Call System.gc() if you're getting OutOfMemoryErrors – that really helps loading more bitmaps into the memory. Then have a thread running that posts the next frame to a View instance that then update it's canvas.
Loading the frames and starting the animation
// Loading the frames before starting the animation
List<Bitmap> frames = new ArrayList<Bitmap>();
for (int i = 0; i < 30; i++) {
// Load next frame (e. g. from drawable or assets folder)
frames.add(...);
// Do garbage collection every 3rd frame; really helps loading all frames into memory
if (i %% 3 == 0) {
System.gc();
}
}
// Start animation
frameIndex = 0;
animationThread.start();
Thread that applies the next frame
private final class AnimationThread extends Thread {
#Override
public void run() {
while (!isInterrupted()) {
// Post next frame to be displayed
animationView.postFrame(frames.get(frameIndex));
// Apply next frame (restart if last frame has reached)
frameIndex++;
if (frameIndex >= frames.size()) {
frameIndex = 0;
}
try {
sleep(33); // delay between frames in msec (33 msec mean 30 fps)
} catch (InterruptedException e) {
break;
}
}
}
}
The animation view
class AnimationView extends View {
Bitmap frame = null;
public void postFrame(Bitmap frame) {
Message message = frameHandler.obtainMessage(0, frame);
frameHandler.sendMessage(message);
}
protected final Handler frameHandler = new Handler() {
#Override
public void handleMessage(Message message) {
if (message.obj != null) {
frame = (Bitmap) message.obj;
} else {
frame = null;
}
invalidate();
}
}
#Override
protected void onDraw(Canvas canvas) {
if (frame == null) return;
canvas.drawARGB(0, 0, 0, 0);
canvas.drawBitmap(frame, null, null, null);
}
}
You should look at the FrameAnimation class; http://developer.android.com/guide/topics/graphics/2d-graphics.html#frame-animation to do frame animation with Androids animation.
Though that might still be too slow.
The other alternative if you don't want to use OpenGL ES is to draw to the Canvas as you've mentioned. But just use .drawBitmap, not the drawBitmapMesh. Create a SurfaceView, which has a thread, that thread should draw on your Canvas at whatever interval you want.
It's pretty straightforward, just read the Android docs, the information is all there.
I'll let someone else go into the best way of doing this but one thing that immediately jumps to mind from your post that isn't helping is using TimerTask is a terrible way to do this and is not meant for animation.
Probably won't help with performance, but if those bitmaps are resources you might want to consider using an AnimationDrawable. If not, try to extend Drawable and implement the Animatable interface. Views already have built-in support for animating drawables, no need to use a handler for that.
One way to improve performance might be to match the bit-depth of the drawables to those of your current window. Romain Guy did a keynote on this and animations in general once: http://www.youtube.com/watch?v=duefsFTJXzc