How to pass a turn to AI in a game? - android

I am writing a simple game for 2 players, where they have to make turns after each other - select a few objects to remove from the board (removing is actually setting an ImageView invisible), then a player presses "End turn" at the end to pass the turn to another player.
The board is a GridLayout with the ImageViews, all ImageViews have onClickListener(), and they are all visible at the beginning of the game. A player clicks on several ImageViews (at these moments their IDs are placed in an array) and then clicks "End turn", this array of his move is analyzed, the corresponding ImageViews are set to invisible, and after that the turn should be passed to another player (the array is cleaned and the number of the current player changes).
All objects on the board have onClickListeners() attached. Upon clicking, their IDs are placed in an array, and a variable contains the number of the current player. The turns are switched in onClick() method on a onClickListener(), attached to the "End turn" button, and it's simply cleaning the array of the IDs and updating the number of the current player.
It works fine for the case of 2 humans playing (on the same device). But if a person plays with the computer, the AI calculates and makes its move in the same onClick() method. Since the user interface updates only after processing the onClick(), (ImageViews are set to invisible, and so on), AI's moves are not drawn on the screen and the player sees as if after his move (clicks on the objects), the board was redrawn immediately with the added changes made by the computer's move (objects removed).
So, I need to pass the turn to AI somehow differently, not in onClick() of the "End turn" button to be able to draw the AI's selection and hide selected views - before the player can make his next move. But how to do that and where?
onClick() method for the "End turn" button:
public void onClick(View v) {
hideSelectedImageViews();
if (currentGame.isWinningState()) {
//you won
} else {
changePlayer();
if (playWithAI) {
calculateAImove(currentGame);
showSelectedImageViewsByAI(); //doesn't work even with .invalidate()
hideSelectedImageViews();
if (currentGame.isWinningState()) {
//AI won
}
changePlayer();
}
}
}
In showSelectedImageViewsByAI(), a specific image resource is set for the ImageViews, so that they will look differently ("selected").

You can create a new Thread where it will run the AI's moves, when the AI makes their selections you can make the thread delay some seconds (so their selection can be shown) and then remove them. Your code has that problem, once the AI makes a selection, it's removed instantly (even if you did invalidate() twice)
If you are not familiar with Threads here is an example:
//I assume your code was inside an Activity
public class mainActivity extends Activity implements Runnable
{
Thread aiThread;
/*...*/
public void onClick(View v)
{
hideSelectedImageViews();
if (currentGame.isWinningState()) { /*you won*/ }
else
{
changePlayer();
if (playWithAI)
{
aiThread = new Thread(this);
aiThread.start();
}
}
}
public void run()
{
calculateAImove(currentGame);
showSelectedImageViewsByAI();
Thread.sleep(1000); //This will make thread wait for 1 second before removing selected (note the number is in milliseconds)
hideSelectedImageViews();
if (currentGame.isWinningState()) { /*AI won*/ }
changePlayer();
}
}
Please note that when using a thread to influence the UI you shouldn't affect views directly, you should instead call view.post() instead, if you are unfamiliar with either Threads or the view.post() method I recommend searching online for them.

Related

I can't handle this method: Thread.sleep()

I can't handle this method: Thread.sleep() in Android Studio.
I want to fill a 9x9 size TextView with a number every 0.1 seconds.
And, this is my codes.
public class MainActivity extends AppCompatActivity {
TextView[][] basicCell=new TextView[9][9];
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initVar();
int cnt=0;
for(int i=0; i<9; i++){
for(int j=0; j<9; j++){
basicCell[i][j].setText(j+"");
basicCell[i][j].setTextColor(Color.BLACK);
basicCell[i][j].setTextSize(20);
basicCell[i][j].setGravity(Gravity.CENTER);
try{
Thread.sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
Log.d("COUNT", ""+cnt++);
}
}
}
TextView[][] basicCell=new TextView[9][9]
All textviews are linked with basicCells.
And, The expected results screen is as follows.
In the middle of the code,
By inserting
try {Thread.sleep (100); }
catch (InterruptedException e) { e.printStackTrace();}
I tried to get the number one every 0.1 seconds ...
When you run the app, it stays on for a few seconds and the numbers come up at once.
I took a look at the log,
Log.d ("COUNT", "" + cnt ++);
In log chat, the logs are working hard,
The screen is in a state of jamming for a few seconds,
Since cnt is 80, the numbers are displayed on the screen at once.
I thought it was an emulator lag, so I ran it on my smartphone, and the result is the same.
I do not know what the problem is.
Is there a way to see the results as intended?
Please, take a look at the official guide for Processes and Threads. Your code is being executed on the main thread, but you can't just make it sleep, because it will freeze your UI. Also, onCreate is executed in order to create your activity, so you won't be able to update your UI just by sleeping the thread in onCreate, because Android will wait until onCreated is executed, then it will show your UI.
You need to create an AsyncTask. Please, read here:
https://developer.android.com/guide/components/processes-and-threads.html
setText(...), setTextColor(...), etc. don't change anything on the screen. They only change values recorded in the TextView objects to which you apply them. The framework will then ask the TextView objects to render themselves to the screen after your function has returned.
I don't know Android, so I don't know the proper names of things, but if you want things on the screen to change over time (i.e., if you want to animate your display), then you'll need to set up some kind of a timer task---a callback function that gets called periodically. Each time it gets called, it should change one thing (e.g., update one cell), and then it should return so that the cell will have a chance to render itself to the screen.

Measuring the load time of individual GUI elements

I am writing a program to measure the load time of every GUI element (like button, Text box etc.). Right now I am working on Windows Phone and I plan to expand it to Android and iOS (using swift probably, still undecided) and Java desktop.
I am using the click event of a button to generate a GUI element (a button in this case)
private void btnCreate_Click(object sender, RoutedEventArgs e)
{
CleanUp(); // to Garbage collect
watch.Start();
Button btn = new Button();
btn.Width = 110;
btn.Height = 56;
btn.Foreground = new SolidColorBrush(Windows.UI.Colors.White);
btn.Content = "Button";
btn.Click += btn_Click;
gridMain.Children.Add(btn);
watch.Stop();
}
I use a different button, with the following code in its event handler, to show the results
private void btnResults_Click(object sender, RoutedEventArgs e)
{
long ticks = watch.ElapsedTicks;
double ms = 1000.0 * (double)ticks / Stopwatch.Frequency;
// show results in a message box
}
I also have a button to remove the generated button and garbage collect so that I can remove and recreate and take several readings
private void btnRemove_Click(object sender, RoutedEventArgs e)
{
gridMain.Children.RemoveAt(3); //the dynamically generated button is at 3
watch.Reset();
}
The problem is that I am getting some what inconsistent results.
Here are few of my results (excluding the first run):
0.6028 ms
0.7217 ms
0.9596 ms
1.3834 ms
0.5626 ms
1.3814 ms
0.7343 ms
I don't understand the reason. Is this significantly inconsistent? if yes, then is my method flawed? is there a better way to do this? Thanks
Right now you're measuring constructing two objects (a Button and a SolidColorBrush), setting various properties, inserting a couple of things into vectors (the event handler and the children), etc. but I don't think the button is actually visible when you call Stop (there is probably a layout and render pass still to happen). So you're measuring some random things.
Off-hand (and I'm not a XAML perf guru by any stretch of the imagination) a variance of +/- 1ms wall-clock time for adding a Button to a Grid seems reasonable given the way you're measuring (eg, what else is your computer doing at the same time?). If you want to do perf analysis, use the performance analyzer tools.

Andengine swipe navigation

I am new to andengine and want to know that how I can switch between two BaseGameActivities. And also when switching from first activity to second, there is no black screen transition in between switching. Is there any possible way to do it.
Please help me out.
A BaseGameActivity can be used as any other Android Activity, too:
Intent intent = new Intent(this, MyOtherBaseGameActivity.class);
startActivity(intent);
So if you want to change from your program to another app (maybe by opening the browser…) you can do that as with any other Android App, too. However if both Activities are part of your own App, there is rarely a case where this is recommendable (It is like starting a second program). Although it is possible to exchange data between the activities as described in this post.
But maybe you are only looking for a way to switch between Views in AndEngine. If that's the case you can switch between Scenes without any transition necessary.
MyOtherScene secondScene = new MyOtherScene();
mEngine.setScene(secondScene);
That way you can switch between what is being displayed, without needing to load every image again.
EDIT:
Since you can't use AndEngine to switch between Activities, nor is a smooth switching between scenes possible. Here a quick example on how to switch between two screens (e.g. menus). In this example the screens are actually 2 different images (as big as the display … maybe some background images). Note: there is no such thing as 'screens' in AndEngine, it is simply a self made class that extends Entity.
Your Screen
public MyScreen extends Entity{
private float firstX;
public MyScreen(Sprite niceBackgroundImage1, Sprite niceBackgroundImage2){
this.attachChild(niceBackgroundImage1); // attach something to the screen, so you can see it (preferably an image that is as big as your camera)
this.attachChild(niceBackgroundImage2);
this.firstY=-1; // this is a variable to remember the first x coordinate touched
}
#Override
public boolean onAreaTouched(TouchEvent sceneTouchEvent, float touchAreaLocalX, float touchAreaLocalY) {
if(sceneTouchEvent.getAction()==TouchEvent.ACTION_DOWN){
this.firstY=touchAreaLocalX; // remember the x, on the first touch
}
if(sceneTouchEvent.getAction()==TouchEvent.ACTION_MOVE){
if(touchAreaLocalX>firstY+20){
// user swiped from left to right (at least 20 pixels)
niceBackgroundImage1.registerEntityModifier(new MoveModifier(3f, 0, niceBackgroundImage1.getWidth(), 0, 0, EaseBounceOut.getInstance()));
// the last line actualy moves the nice..image1 from left to right (in 3 seconds) and lets it bounce a little bit before it is completely out of the screen
return true;
}
}
return false;
}
...
}
Your Activity
private HUD hud; // create a HUD
...
#Override
protected void onCreateResources() {
this.hud = new HUD(); // init the HUD
this.myScreen = new MyScreen(image1, image2) // init the screen
this.hud.attachChild(myScreen); // attach the screen to the hud
mEngine.getCamera().setHud(hud); // attach your HUD to the camera
}
#Override
protected Scene onCreateScene() {
Scene myScene = new Scene();
myScene.registerTouchArea(myScreen); // you have to register the touch area of your Screen Class to the scene.
mEngine.setScene(myScene);
}
And this is how it works:
you create yourself a own screen class that extends Entity. An Entity can be everything visible in AndEngine (like a Sprite, Rectangle or even a whole scene). Put something in your screen class to make it look nice, preferably a big image that fills the whole display. That image will be responsible to register the touch afterwards. If the image is too small and the user misses the image, then no touch will be registered.
In this case I attach the instance of MyScreen to the cameras HUD. That way it will be at a fixed position on the display and it will have a fixed size (just in case you want to make the scene scrollable or zoomable).
Now when the app starts the HUD will be created and attached to the camera and with it your MyScreen class. Then the scene will be created and the screen's area will be registered as touch area to the scene. When a swipe movement on a horizontal axis gets noticed by the screen class, the first image will move outside the screen (in the same direction as the swipe).
But be careful, this is just an example. There is nothing defined on how the touch has to act when the first image was moved outside the screen or how big the screen actually is etc...
I know this is quite a long example, maybe it won't even work the first time and it is definitely not the only way on how switching between different screens can be done. But it shows you how to override the onAreaTouched() method and register the entity modifier to make the image move. Hopefully it will lead you in the right direction, to accomplish what you want to do.

android button animation with click

I'm trying to make flying balloons (up and down, infinitely) and by clicking on one of them, it will changes its direction. I tried to use Animation, but it don't support click on a view at a current position at a current time. I know, that there are two methods, for at least:
use an OpenGL
and use a Canvas.
I don't want to use OpenGL for so quit simple animation. And I don't understand how to do it, using Canvas(were read this, google docs and some google search links).
I don't need a code, all I need it's the way how to do it and the algorithm.
Alright, this is what I've set up for one of my projects that would work exactly as you need...
You need to create 4 main aspects:
- An Activity (extend Activity)
- A SurfaceView (extend SurfaceView implement SurfaceHolder.Callback)
- A Thread (Extend Thread)
- Objects that interact (extend Drawable)
The Activity starts and generates a SurfaceView that creates a Thread. The View or the Thread can contain the objects that you draw/interact with, its up to you how you want to store the data at this point but its easiest if you come up with a design that has the least coupling between classes.
Once started, the Thread runs constantly until stopped (setting isRunning to false):
/**
* Processing loop
*/
public void run() {
while (isRunning) {
try {
sleep(25);
} catch (InterruptedException e) {
Log.e("Thread","Thread Interruption");
e.printStackTrace();
}
update();
}
Log.d("Thread", "Game Loop Stopped");
}
/**
* Main processing of the game loop.
*/
private void update() {
handleInput();
updatePhysics();
updateUI();
updateState();
updateAI();
updateAnimations();
updateSound();
updateVideo();
}
In this class you see the update() method that does a bunch of actions each iteration of the thread.
The methods that will interest you mostly are the handleInput, updateUI and updatePhysics methods.
In the handleInput you'll do a callback to the SurfaceView to get the data that you need for processing information. My handleInput is fairly simple in that it just grabs the MotionEvent from the SurfaceView class's onTouchEvent (this gets implemented when you use the SurfaceHolder.OnCallBack interface).
The updateUI method calls the SurfaceView's update where it re-draws the Canvas with each object, or balloon
public void update(List<Actor> actors) {
Canvas canvas = null;
try {
canvas = surface.lockCanvas();
synchronized (surface) {
//Blank the Canvas
for (int i = 0; i < actors.size(); i++) {
actors.get(i).draw(canvas);
}
}
} catch (NullPointerException e) {
e.printStackTrace();
} finally {
if (canvas != null) {
surface.unlockCanvasAndPost(canvas);
}
}
}
Here we can see that it calls the draw method passing the canvas object to each one of your interactable objects. I've called mine "Actors" in the code above. How you choose to implement draw is up to you but it sounds like you'll be using a lot of canvas.drawBitmap() functions.
Going back to the Thread's updatePhysics method you'll want to use it to update the objects before or after they're drawn to the screen. For you you'll want to have them change their X and/or Y positions on the screen or change the direction its moving after the handleInput decides you've hit a balloon.
Its very hard to explain this well in a StackOverflow reply. If you really want I can try to put something more informative together this weekend and post it externally for you (I can provide my UML class diagrams among other information such as picture examples, structures and data flows.
Please let me know if I can help you further! Please note that this isn't all my work. I used a lot of tutorials online for basic Android Game structure but don't have the links available right now to provide references.

Android game scrolling background

I'm just trying to figure out the best approach for running a scolling background on an android device. The method I have so far.... its pretty laggy. I use threads, which I believe is not the best bet for android platforms
#Override
public void run() {
// Game Loop
while(runningThread){
//Scroll background down
bgY += 1;
try {
this.postInvalidate();
t.sleep(10);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
where postinvalidate in the onDraw function simply pushings the background image down
canvas.drawBitmap(backgroundImage, bgX, bgY, null);
Thanks in advance
UPDATE
I've identified the problem. And it is the fact that my player updates the same rate as the background scrolls (making it look choppy). from top to bottom. This is because both get drawn in the same function. I'm not really sure how to tackle this and would be grateful for any help. i.e so that player movement is handled separately from the map scrolling
Also how can I control the speed at which onDraw(canvas) get called?
Thanks in advance.
However, I have patched together a different run loop for anyone having the same problem. This is partially from the jetboy example on google.
Below is my inner class in my surfaceview
class MapThread extends Thread{
private Map map;
private SurfaceHolder holder;
private boolean run = false;
public MapThread(Map map, SurfaceHolder holder){
this.holder = holder;
this.map = map;
setRunning(true);
}
public void setRunning(boolean run){
this.run = run;
}
#Override
public void run(){
while(run){
try{
Canvas c = null;
try {
c = holder.lockCanvas(null);
synchronized (holder) {
map.onDraw(c);
}
} finally {
if (c != null) {
holder.unlockCanvasAndPost(c);
}
}
}
}
}
SOLUTION
https://gamedev.stackexchange.com/questions/8127/android-game-scrolling-background
Use the SurfaceView implementation draw on the screen. It allows you more control of what to draw and when.
The SurfaceView is a special subclass of View that offers a dedicated drawing surface within the View hierarchy. The aim is to offer this drawing surface to an application's secondary thread, so that the application isn't required to wait until the system's View hierarchy is ready to draw.
The basic design is to have a surfaceview that draws continuously in a while loop. Then add an if-statement whose condition is to be true if a timer thread tells you its time to draw. Say, every 30ms, draw the bitmap. This will give you about 33 fps.
Now you may also have another timer thread that tells you when to update the the bgX or bgY values. Say at every 60ms, it will set a boolean updateFlag = true; Then in your main thread, you have an if-statement check this flag, set it to false, and update your bgX and bgY values. By accurately controlling the timer and the bgX/bgY increments, you should be able to produce smooth animations.
It would be a good idea to look at the LunarLander source code provided by Google.
One thing to keep in mind is that sleep is very inaccurate. To work around this, you can keep track of exactly how much time passed during the sleep and update how much you move things accordingly.
Its not clear from you code, but you need to make sure that all of your UI updates happen in the UI thread.
You do need to do your timing outside of the UI thread, because otherwise the UI will never update. There are other methods of timing, like using a Handler that can be a little bit cleaner, but I think the overhead on them might be a bit much for what you are trying to do. I think a simple thread has the least amount of overhead.
I am using this method on the second level of my SpaceQuestAlpha game. This makes a seemless scroll.
I used the 2 lines below to set original position.
moony=0;
moon2y=-(heighty);
Then these lines increment both versions of the background image. One starts at 0 and one starts at negative screen height. Every time one of the images goes below the bottom of the screen it is moved up twice the height to move it back into position. I am using surface view with no latency issues.
moony+=5;
moon2y+=5;
if(moon2y>=heighty) {moon2y=moon2y-(heighty*2);}
canvas.drawBitmap(lavabackground, 0, moon2y, null);
if(moony>=heighty){moony=moony-(heighty*2);}
canvas.drawBitmap(lavabackground, 0, moony, null);

Categories

Resources