I'm trying to make an Android puzzle game out of a picture.
What i've done 'till now is:
-i've cut the picture in how many parts i get from the EditText field;
-i've put the cut pictures in a gridview and got a puzzle table;
-i've also used the Collection.suffle(list) to suffle the images in the gridview;
Now, i am trying to implement the sliding effect on two images from gridview. So what i want to achieve is a sliding effect similar to CandyCrush app or this one http://www.youtube.com/watch?v=qUoP87fNB8w . I mean, i want to hold an image and drag it top so it should slide top. If i click the picture and slide bottom, it should change with the picture below it and so on...
Here is my code:
Reset = (Button) findViewById(R.id.BReset);
SplitNo = (EditText) findViewById(R.id.edSplitBy);
SplitBy = Integer.parseInt(SplitNo.getText().toString());
ImgNo = SplitBy * SplitBy;
puzzle = (GridView) findViewById(R.id.puzzle);
rootImg = (ImageView) findViewById(R.id.source_image);
splitImage(rootImg);
formPuzzle(smallimages);
Reset.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Reset.setText("Reset");
SplitNo.getEditableText().toString();
SplitBy = Integer.parseInt(SplitNo.getText().toString());
ImgNo = SplitBy * SplitBy;
Collections.shuffle(smallimages);
formPuzzle(smallimages);
}
});
And here is how i form the puzzle:
private void formPuzzle(ArrayList<PuzzleItem> smallimages) {
SMI = new SmallImageAdapter(this, smallimages);
puzzle.setAdapter(SMI);
puzzle.setNumColumns(SplitBy);
puzzle.setHorizontalSpacing(0);
puzzle.setVerticalSpacing(0); }
PuzzleItem.class:
public class PuzzleItem {
Bitmap puzzlepartImage;
int correctPosition;
public PuzzleItem(Bitmap d, int index) {
puzzlepartImage = d;
correctPosition = index;
}
I used this class just to remember the position of the pieces so i can check if the puzzle is finished...
So i'm only interested in how to implement the sliding motion by draging an item from gridview...
Thanks :)
EDIT: Should i use an OnTouchListener ?
Ok, I've managed to find the solution by myself :
private void formPuzzle(final ArrayList<PuzzleItem> smallimages) {
SMI = new SmallImageAdapter(this, smallimages);
puzzle.setAdapter(SMI);
puzzle.setNumColumns(SplitBy);
puzzle.setHorizontalSpacing(0);
puzzle.setVerticalSpacing(0);
puzzle.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
startX = event.getX();
startY = event.getY();
smallimage_Position = puzzle.pointToPosition((int) startX,
(int) startY);
return true;
}
case MotionEvent.ACTION_MOVE: {
endX = event.getX();
endY = event.getY();
Log.d("X", "..." +endX);
Log.d("Y", "..." +endY);
if(endX > startX + smallimage_Width/2 && (endY < startY - smallimage_Height/2 || endY < startY + smallimage_Height/2) ){
PuzzleItem p1 = SMI.smallimages.get(smallimage_Position);
PuzzleItem p2 = SMI.smallimages.get(smallimage_Position +1);
SMI.smallimages.set(smallimage_Position, p2);
SMI.smallimages.set(smallimage_Position +1, p1);
SMI.notifyDataSetChanged();
startX = endX*200;
startY = endY*200;
}
return true;
}
}
return true;
}
});
The slide is given by the MotionEvent.Action_MOVE and by calculating the pixels you can find out in what direction is the finger moving ... For example .. the if from my Action_Move case is recognising a swipe to the right ...
I hope this will help some of you guys ...
Another way to go about achieving slides in a slider puzzle game is to use a game engine. I recommend Cocos2D for Android, and theres a detailed tutorial on that here ...
http://denvycom.com/blog/step-by-step-guide-on-how-to-build-your-first-slider-puzzle-game-in-cocos2d-for-android-part-1/
Related
What I want to do is to click a space on the screen, get the coordinates and paint the image here. I did this using paintIcon and mouseListener in eclipse but how to do the same thing in android studio? Thanks!
public static Game game = new Game();
public Control(){
this.setLayout(null);
this.setBounds(0, 0, 780, 780);
addMouseListener(this);
}
public void paint(Graphics g){
setBackground(Color.GREEN);
board.paintIcon(this, g, 0, 0);
for(int i = 0; i < 19; i++){
for(int j = 0; j < 19; j++){
if(game.gameBoard.board[i][j] != 'E'){
if(game.gameBoard.board[i][j] == 'B'){
black.paintIcon(this, g, j * 40, i * 40);
}
if(game.gameBoard.board[i][j] == 'W'){
white.paintIcon(this, g, j * 40, i * 40);
}
}
}
}
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
mouseX = e.getX();
mouseY = e.getY();
int targetX = mouseX / 40;
int targetY = mouseY / 40;
game.move(targetX, targetY);
repaint();
}
In Android you use a different system than in "Java"(you know Android is Java), for instance as is clear from your code you do not have a Mouse but a Touch event.
The first thing you should do is to study this official link that explains the concept of Canvas. Then you will learn how to integrate the "tap" into your app that is instead this official link
This is an excellent post to learn ho to do it.
You begin extending the View and overriding the method onDraw(Canvas canvas) then you need to override a listener that say you when the user clicked the screen onTouchEvent(MotionEvent event) usually there are three motion events you want to cover MotionEvent ACTION_DOWN(you tap and the screen recognizes the X,Y coordinates, that is the one you need),ACTION_MOVE(if you drag your finger maintaining pressure on the screen) and ACTION_UP(when you release your finger)
Just remember you need to call invalidate() if you have an animation or something changes on the screen. Basically is a "forced" call to the "onDraw" method. On the basis of the three links I sent you can cover all thebasis of the 2d graphics in Android that is a bit different by Java because of the different features but also the Android dependency on the specific SDK classes
what I want to do is to click a space on the screen, get the coordinates and paint the image here
Here is an example of how you can obtain that in Android instead of "just" Java, please see the notes comments I did below with the double slashes //
public class YourBoard extends View {//EXTENDS VIEW this is important because you override methods
Drawable editIcon = getResources().getDrawable(R.drawable.icon);
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.background);
float xPos = 0;
float yPos = 0;
public YourBoard (Context context) {//HERE THE CONSTRUCTOR YOU CAN INITIALIZE THINGS HERE
super (context);
}
#Override
protected void onDraw (Canvas canvas) {//This was your paint(Graphics g)
super.onDraw(canvas);
canvas.save();
canvas.drawBitmap(mBitmap, 0, 0, null);
canvas.translate(xPos, yPos);
editIcon.draw(canvas);
canvas.restore();
}
#Override
public boolean onTouchEvent (MotionEvent event) {//THIS WAS YOUR MOUSE LISTENER
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN :
xPos = event.getX();
yPos = event.getY();
invalidate();//NOTICE THE INVALIDATE I MENTIONED
break;
}
return true;
}
}
}
I am developing an android application where I am creating dynamic Images arrow on relative layout. The images are created on a x,y coordinated of the click area of relative layout. Below is the code the I am using for it.
presciptionScreenArrowImg.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (canSelectMedianStatus == 2) {
if (event == simulationEvent)
return false;
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
Log.e("onTouchListener", "User touch at X:" + x + " Y:" + y);
pointerArrow = new ImageView(getApplication());
pointerArrow.setImageResource(R.drawable.pointer);
pointerArrow.setId(imageArrayTag);
imageArrayTag++;
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(40, 40);
params.topMargin = y;
params.leftMargin = x;
pointerArrow.setLayoutParams(params);
presciptionScreenArrowImg.addView(pointerArrow);
long length = 0;
if (action == MotionEvent.ACTION_DOWN) {
// click(v, x, y);
}
}
return false;
}
});
Now, I need is there on button click the last Image drawn should remove first. Basically I need an undo functionality to remove Images as LIFO structure.
let consider presciptionScreenArrowImg is your main layout which contains your all views so for removing
int index=presciptionScreenArrowImg.getChildCount();
if(index>0)
presciptionScreenArrowImg.removeViewAt(index-1);
from above get count of child and remove last view if you have any problem let me know
Store the views in a Queue, and when you add a new view check if the queue is full. If it is, pop a view from the queue, and call presciptionScreenArrowImg.remove(poppedView);
I have a drag and drop list implementation in Xamarin. The problem is that I want to be able to drag and drop element only when the drag and drop button is touched not the whole element.
I was trying to detect for the ImageView being pressed but I am unable to get the correct hit ImageView.
public bool OnDown (MotionEvent e) {
int x = (int) e.GetX();
int y = (int) e.GetY();
int itemnum = PointToPosition(x, y);
if (itemnum == AdapterView.InvalidPosition) {
return false;
}
if (m_dragging != null) {
m_dragging.Stop();
m_dragging = null;
}
View item = GetChildAt(itemnum - FirstVisiblePosition);
item.Pressed = false;
var dragImage = item.FindViewById<ImageView> (Resource.Id.drag_image);
Rect bounds = new Rect();
dragImage.GetDrawingRect (bounds);
if (!bounds.Contains (x, y)) {
return false;
}
The following code works only for the first element in the list and does not apply to any other. I am suspecting that the detection of hit is incorrect.
Solved followingly. I realized that I actually do not need to care about the Y axis and it's enough to take just X axis in account.
// Detect if the user is actually pressing the drag and drop image or not.
var dragImage = item.FindViewById<ImageView> (Resource.Id.drag_image);
if (dragImage != null) {
var dragImageHitRect = new Rect ();
dragImage.GetDrawingRect (dragImageHitRect);
// In this case we do not care about the Y axis. Just compare the x axis.
if (!dragImageHitRect.Contains (x, (int)dragImage.GetY ())) {
return false;
}
}
Many of us must have come across apps like Tinder and Dripper where you can pull down on the view containing an image and the image zooms in. And then when you let it go, the image zooms out to go back to its origin state.
Let's take an example from Tinder :
Original State: and Zoomed-in state when pulled:
In iOS it is done by
- (void)viewDidLoad {
[super viewDidLoad];
self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"church-welcome.png"]];
self.imageView.contentMode = UIViewContentModeScaleAspectFill;
self.cachedImageViewSize = self.imageView.frame;
[self.tableView addSubview:self.imageView];
[self.tableView sendSubviewToBack:self.imageView];
self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 170)];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat y = -scrollView.contentOffset.y;
if (y > 0) {
self.imageView.frame = CGRectMake(0, scrollView.contentOffset.y, self.cachedImageViewSize.size.width+y, self.cachedImageViewSize.size.height+y);
self.imageView.center = CGPointMake(self.view.center.x, self.imageView.center.y);
}
}
Since my expertise in Objective C and iOS is very limited, I am not being able to implement it in Android.
Here is what I think should be done :
catch the pull-down gesture
increase the height of the view by the pull amount
do some sort of scale animation on the Image to fit it in the expanded view
Does anyone have any idea if there is any library that could be used for this purpose?
Check out this project:
https://github.com/Gnod/ParallaxListView
If you combine it with the ViewPagerIndicator library, you pretty much get Tinder's profile page feature set
https://github.com/JakeWharton/Android-ViewPagerIndicator
I think the easiest way is to override the onTouchEvent method of View.
Something like this:
boolean inZoom = false;
float prevY = 0;
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventY = event.getY();
float eventX = event.getX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(touchedTheImage(eventX, eventY)){
setZoomCenter(eventX, eventY);
prevY = eventY;
inZoom = true;
return true;
}
break;
case MotionEvent.ACTION_MOVE:
if(inZoom){
changeZoomLevel(prevY, eventY);
return true;
}
break;
case MotionEvent.ACTION_UP:
if(inZoom){
resetZoomLevel();
inZoom = false;
return true;
}
break;
}
return false;
}
EDIT:
for the animation part consider this post:
https://stackoverflow.com/a/6650473/3568892
I have displayed images from resource in my application as rows and columns randomly.
From those rows and columns i would like to swap the two images when user click on beside of images only.The following code will display the images in rows and columns as randomly.
private void rand(int imagesList[][])
{
Random generator = new Random();
int temp;
for (int i = 0; i < MAX_ROWS; i++)
for(int j = 0; j < MAX_COLS; j++)
{
int randRowPos = generator.nextInt(MAX_ROWS);
int randColPos = generator.nextInt(MAX_COLS);
temp = imagesList[i][j];
imagesList[i][j] = imagesList[randRowPos][randColPos];
imagesList[randRowPos][randColPos]= temp;
}
}
by using the above code i have displayed images as rows and columns.
Here how can i swap the two beside images from rows and columns?
please any body help me.....
I don't have privilege to add comment, so I am posting this as answer.
What do you mean by beside images ?
Is it when user will click on one image , it should get swapped with the image next to it ?
Can you also share the code where you have binned these images to view or any adapterview ?
EDIT :
I too had similar situation at the times when absolute layouts were alive.
What I had done is as follows:
Class:
public class PlayScreen extends Activity implements OnTouchListener
private Panel mainPanel; // Panel for out display
boolean firstClick = false;
OnCreate :
main = new Panel(this);
// Display the panel (calls the ondraw and updates the display)
setContentView(main,new ViewGroup.LayoutParams(screenwidth,screenheight));
// Listen for touchevents on the panel
main.setOnTouchListener(this);
Panel :
class Panel extends View
{
/*
* Init a Panel to draw on and a paint to paint with
*/
Paint mBitmapPaint;
public Panel(Context context)
{
super(context);
mBitmapPaint = new Paint();
}
#Override
protected void onDraw(Canvas canvas)
{
drawImages(canvas);
}
}
drawImages :
private void drawImages(Canvas canvas)
{
for(int i = 0; i<MAX_ROWS; i++){
for(int j=0; j<MAX_COLS; j++)
{
int xpos = j*bmp.getWidth()+j*2;
int ypos = i*bmp.getHeight()+i*2;
bmp = BitmapFactory.decodeResource(mContext.getResources(), items[i][j],opts);
canvas.drawBitmap(bmp,xpos,ypos,mBitmapPaint);
clickzonex.add(xpos);
clickzoney.add(ypos);
clickzonei.add(i);
clickZonej.add(j);
}
}
}
OnTouch:
onTouch(View v, MotionEvent event) :
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
// imply logic
x = (int) event.getX();
y = (int) event.getY();
for(int i = 0; i < clickzonex.size();i++)
{
if((x>clickzonex[i]) && (x<(clickzonex[i]+ bmp.getwidth())) && (y>(clickzoney[i])) && (y<(clickzoney[i]+bmp.getHeight())))
{
// we have a click in a zone so we get the card-number in that zone
if(firstClick == false)
{
itemAti=clickzonei[i];
itemAtj = clickzonej[i];
firstclick = false;
}
else
{
FirstItemToSwap = items[clickzonei[i]][clickzonej[i]];
SecondItemToSwap = items[itemAti][itemAtj];
// Now do the swaping using any algo you like.
main.postInvalidate();
firstclick = true;
}
break;
}
}
return true;
}
else
{
return false;
}
I have just tried to show you the logic using my own example and mixing it with your code. The main point is that in ondraw method just call drawcanvas and on touch just swap the items[][] and call postinvalidate method of Panel class.
I had to do something like this once. I just swapped the image references in the array and did a redraw(invalidate()) on the whole thing.
void swap(int x1, int y1, int x2, int y2) {
// swap items[x1][y1] and items[x2][y2]
........
invalidate();
}
Not quite sure what you are actually asking here, so please try to clarify the question.
One approach could be to use a ViewAnimator as a parent for each of the drawable ImageViews.
<ViewAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/slideshow_animator"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
Then once you capture the event that should trigger the swap, you can use the ViewAnimator to swap the View (in your case ImageView) it uses. You can even easily add an animation effect
http://developer.android.com/reference/android/widget/ViewAnimator.html