I'm trying to drag a path around my canvas by re-plotting the coordinates, stored in an array of point, then re creating it. The path drags but flips horizontally and vertically, like a mirror image, over where the user clicks. I have no idea why.
private void drag(MotionEvent e) {
// TODO correct weird flip
if (clicked(e)) {
for (Point p : points) {
int modX = (int) (e.getX() + (e.getX() - p.x));
int modY = (int) (e.getY() + (e.getY() - p.y));
p.set(modX, modY);
}
updateOutline();
}
}
private void updateOutline() {
// update the outline
outline = new Path();
outline.moveTo(points.get(0).x, points.get(0).y);
for (Point coor : points)
outline.lineTo(coor.x, coor.y);
}
Any help will be appreciated, thanks
In my opinion there is a problem in these lines:
int modX = (int) (e.getX() + (e.getX() - p.x));
int modY = (int) (e.getY() + (e.getY() - p.y));
Consider two points A(1,5) and B(4,5). If user clicks in C(3,6), then point A will be translated to A'(5, 7) and point B to B'(2, 7). As you can see, points A and B will change places.
You might want to store start drag position and calculate distance and updated path position using this information.
Related
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;
}
}
i am developing an android app, about joining dots and making picture.
so far i can't find a way to extract exact x and y coordinates of black dots . so I've hard coded x and y locations to draw point on exact black dot of image. It worked wonderful on 1152*720 size ,but problem occurs when i tested it on 480*600 size , dots misplaced from there exact location , now
My Question is if I've written something like :
x = 100 ,
y = 200
(on screen 1152*720)
what will be x and y values in different screen sizes like 480*600 and how to calculate it ? i know it is silly question but i am new to this stuff.
Answering your question as you have asked it...
int oldScreenX // The current x coord
int newScreenX // The new x coord
...
float oldScreenSizeX = 1152.0f;
float newScreenSizeX = 600.0f;
newScreenX = (int)(oldScreenX / oldScreenSizeX) * newScreenSizeX; // Remember to cast the result back to an int
Do the same for y.
Additional:
Perhaps you should reconsider your approach.
The real problem is how do you put the dot in the same location on the Image, if the Image is being drawn at a different size. So forget about measuring the screen size. Measure the Image size instead.
For example, if you are showing your image in an ImageView, you could write a general scaling method like the following:
public int scaleCoordinate(int unscaledImageSize, int scaledImageSize, int unscaledCoordinate) {
scaledCoordinate = (int)(unscaledCoordinate / unscaledImageSize) * scaledImageSize; // Remember to cast the result back to an int
return scaledCoordinate;
}
Then you can use it in your code, something like:
ImageView imageView = (ImageView)findViewById(R.id.my_imageview);
Drawable drawable = image.getDrawable();
// Get the original size of the bitmap
int unscaledSizeX = drawable.getIntrinsicWidth();
// Get the current size it is being drawn at on the screen
int scaledSizeX = imageView.getWidth();
int scaledCoordinateX = scaleCoordinate(unscaledSizeX, scaledSizeX, unscaledCoordinateX);
NOTE:
The ImageView needs to be measured and laid out by the system before calling the above code. If you call it too early imageView.getWidth() will return 0.
It would be best to call the above code once the ImageView is actually displayed on the screen (from your onResume() or later).
I was done this, while studying java may be it will be helpful for you.
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
public class DrawLineOnGivenLocations extends Applet implements MouseListener, MouseMotionListener{
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
public void init() {
addMouseListener(this);
addMouseMotionListener(this);
}
public void mouseMoved(MouseEvent me) {
// show status
showStatus("Moving mouse at " + me.getX() + ", " + me.getY());
}
public void mouseClicked(MouseEvent me) {
// save coordinates
x1 = me.getX();
y1 = me.getY();
x2 = me.getX();
y2 = me.getY();
repaint();
}
public void paint(Graphics g){
g.drawLine(x1,y1 ,x2, y2);
}
public void mouseEntered(MouseEvent arg0) {}
public void mouseDragged(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}
public void mousePressed(MouseEvent arg0) {
//repaint();
}
public void mouseReleased(MouseEvent arg0) {}
}
I have drawn multiple circles of varying sizes and positions to a canvas, but I need to detect collisions between them.
public void run() {
while(Run){
if(!sHold.getSurface().isValid())
continue;
c[0][cnum].r++;
canvas = sHold.lockCanvas();
canvas.drawRGB(02, 02, 150);
Paint white = new Paint();
white.setColor(Color.WHITE);
if(c[0][cnum].x != 0 && c[0][cnum].y != 0)
canvas.drawCircle(c[0][cnum].x, c[0][cnum].y, c[0][cnum].r, white);
if(cnum!=0)
for(int i=0; i<cnum; i++)
canvas.drawCircle(c[1][i].x, c[1][i].y, c[1][i].r, white);
sHold.unlockCanvasAndPost(canvas);
if(((c[0][cnum].x - c[0][cnum].r)<0)||((c[0][cnum].y-c[0][cnum].r)<0)||((c[0][cnum].y+c[0][cnum].r)>height)||((c[0][cnum].x+c[0][cnum].r>width))){
c[1][cnum].x = c[0][cnum].x;
c[1][cnum].y = c[0][cnum].y;
c[1][cnum].r = c[0][cnum].r;
broken = true;
break;
}
}
}
You shouldn't do that on render phases.
When processing the logics you should check if circles intersects as described:
v1 = center of circle1
v2 = center of circle2
intersects = v1 - v2 < circle1radius + circle2radius
This Link is pretty useful!
Circle-Circle Collisions
It's very detailed and didatic
At the bottom of that page there are another links, to even more detailed stuff!
I used the Distance Between Centers method ---
Circles
By measuring the distance between each center you can say if they are colliding.
The distance should never be more then the sum of the 2 radius.
Here's what I did:
private boolean checkDrawContains(ShapeDrawable newHole)
{
long newCenterX = newHole.getBounds().left + (newHole.getBounds().width()/2); //Get the center of my shapes
long newCenterY = newHole.getBounds().top + (newHole.getBounds().height()/2);
for(ShapeDrawable hole: mHoles) // I was storing the circles in an ArrayList
{
long centerX = hole.getBounds().left + (hole.getBounds().width()/2); //Get the center of my shapes
long centerY = hole.getBounds().top + (hole.getBounds().height()/2);
long x = centerX - newCenterX;
long y = centerY - newCenterY;
long aux = (long) ((Math.pow(Math.abs(x),2)) + (Math.pow(Math.abs(y),2))); //Pythagoras the hard way :P
long distance = (long) Math.sqrt(aux);
long sRads = (newHole.getBounds().width()/2) + (hole.getBounds().width()/2);
if(distance <= sRads ) {
return true; //Is Colliding!
}
}
return false; // Is not Colliding!
}
I am in the process of learning cocos2d-android. I have been following a tutorial that ported some of Ray Wenderlich's iOS tutorials to Android. I have the first tutorials finished and wanted to continue on by converting the next Ray Wenderlich tutorial to Android by myself as an exercise in learning.
The original iOS tutorial can be found here http:// www raywenderlich com/1163/how-to-make-a-tile-based-game-with-cocos2d
I have converted the application to android but am having some trouble with the way its behaving.
My code is here:
public class GameLayer extends CCLayer{
private CGSize _winSize;
protected ArrayList<CCSprite> _targets;
protected ArrayList<CCSprite> _projectiles;
protected int _projectilesDestroyed;
protected CCSprite _player;
protected CCSprite _nextProjectile;
protected CCTMXTiledMap _map;
protected CCTMXLayer _background;
protected CCTMXObjectGroup _objects;
protected HashMap<String, String> _spawnPoint;
protected GameLayer() {
super();
_winSize = CCDirector.sharedDirector().displaySize();
_targets = new ArrayList<CCSprite>();
_projectiles = new ArrayList<CCSprite>();
_projectilesDestroyed = 0;
// Get TMX Map and associated layers/groups
_map = CCTMXTiledMap.tiledMap("TileMap.tmx");
_background = _map.layerNamed("Background");
_objects = _map.objectGroupNamed("Objects");
// Add my background layer
// TODO: Position layer in the correct spot.
addChild(_background);
_spawnPoint = _objects.objectNamed("SpawnPoint");
_player = CCSprite.sprite("Player3.png");
setPlayerPosition(CGPoint.ccp (100.0f, 100.0f));
addChild(_player);
setViewPointCentered(_player.getPosition());
Context context = CCDirector.sharedDirector().getActivity();
SoundEngine.sharedEngine().preloadEffect(context, R.raw.pew_pew_lei);
SoundEngine.sharedEngine().playSound(context, R.raw.background_music_aac, true);
this.setIsTouchEnabled(true);
this.schedule("update");
}
public void setViewPointCentered(CGPoint pos) {
float x = 0.0f;
float y = 0.0f;
x = Math.max(pos.x, _winSize.width / 2);
y = Math.max(pos.y, _winSize.height / 2);
x = Math.min(x, (_map.getMapSize().width * _map.getTileSize().width) - _winSize.width / 2 );
y = Math.min(y, (_map.getMapSize().height * _map.getTileSize().height) - _winSize.height / 2);
CGPoint actualPos = CGPoint.ccp(x, y);
CGPoint centerOfView = CGPoint.ccp(_winSize.width / 2, _winSize.height / 2);
CGPoint viewPoint = CGPoint.ccpSub(centerOfView, actualPos);
_background.setPosition(viewPoint);
}
public static CCScene scene() {
CCScene scene = CCScene.node();
CCLayer layer = new GameLayer();
scene.addChild(layer);
return scene;
}
#Override
public boolean ccTouchesBegan(MotionEvent event) {
return true;
}
void setPlayerPosition(CGPoint position) {
_player.setPosition(position);
}
#Override
public boolean ccTouchesEnded(MotionEvent event) {
// Choose one of the touches to work with
CGPoint touchLocation = CGPoint.ccp(event.getX(), event.getY());
touchLocation = CCDirector.sharedDirector().convertToGL(touchLocation);
touchLocation = this.convertToNodeSpace(touchLocation);
CGPoint playerPosition = _player.getPosition();
CGPoint diff = CGPoint.ccpSub(touchLocation, playerPosition);
if (Math.abs(diff.x) > Math.abs(diff.y)) {
if (diff.x > 0) {
playerPosition.x += _map.getTileSize().width;
} else {
playerPosition.x -= _map.getTileSize().width;
}
} else {
if (diff.y > 0) {
playerPosition.y += _map.getTileSize().height;
} else {
playerPosition.y -= _map.getTileSize().height;
}
}
if (playerPosition.x <= (_map.getMapSize().width * _map.getTileSize().width) &&
playerPosition.y <= (_map.getMapSize().height * _map.getTileSize().height) &&
playerPosition.y >= 0 &&
playerPosition.x >= 0 ) {
setPlayerPosition(playerPosition);
}
setViewPointCentered(_player.getPosition());
return true;
}
public void finishShoot() {
addChild(_nextProjectile);
_projectiles.add(_nextProjectile);
}
public void update(float dt) {
ArrayList<CCSprite> projectilesToDelete = new ArrayList<CCSprite>();
for (CCSprite projectile : _projectiles) {
CGRect projectileRect = CGRect.make(projectile.getPosition().x - (projectile.getContentSize().width / 2.0f),
projectile.getPosition().y - (projectile.getContentSize().height / 2.0f),
projectile.getContentSize().width,
projectile.getContentSize().height);
ArrayList<CCSprite> targetsToDelete = new ArrayList<CCSprite>();
for (CCSprite target : _targets) {
CGRect targetRect = CGRect.make(target.getPosition().x - (target.getContentSize().width),
target.getPosition().y - (target.getContentSize().height),
target.getContentSize().width,
target.getContentSize().height);
if (CGRect.intersects(projectileRect, targetRect)) {
targetsToDelete.add(target);
}
}
for (CCSprite target : targetsToDelete) {
_targets.remove(target);
removeChild(target, true);
}
if (targetsToDelete.size() > 0) {
projectilesToDelete.add(projectile);
}
}
for (CCSprite projectile : projectilesToDelete) {
_projectiles.remove(projectile);
removeChild(projectile, true);
if (++_projectilesDestroyed > 30) {
_projectilesDestroyed = 0;
CCDirector.sharedDirector().replaceScene(GameOverLayer.scene("You Win!"));
}
}
}
}
I first grab my display size and create my tiled map from my TMX file. I get my background layer and add it as a child. I then grab my objects layer and pull my spawn point object out of the map (I override this spawn point with 100, 100 for testing purposes). I grab my player sprite and set my player position to the 100, 100 coordinates. I then add the player as a child.
Next I call setViewPointCentered to move my map to an appropriate position based on my players position. This part works just fine and my map gets placed with the lower left corner (0,0) placed in the lower left corner (0,0) of my screen and my character is at 100,100 slightly left and down from the center of the screen.
The problem occurs when I begin moving up or right. Once I pass the center of the screen I would expect to have the player sprite stay centered on the screen and the background move the opposite direction as I continue moving. However both the player and the background move so eventually my player comes to the right or top edge of the screen and I can't move up or right any longer even though there is plenty of map left.
Notice the player in the upper left corner of the map.
Player reaching the top of screen and not staying centered as expected
Notice the player in the lower right corner of the map.
Player reaching the right of screen and not staying centered as expected
The "public boolean ccTouchesEnded(MotionEvent event)" method and the "public void setViewPointCentered(CGPoint pos)" method handle the player and view positioning but I don't think they're working correctly.
A friend of mine does iOS programming and created the app on his iPhone and it's working as expected so I'm wondering if there is a bug in the android port of cocos2d.
Does anyone have any ideas on why the character won't stay centered on the screen when I get to the middle and continue moving right or up on the map?
Thanks for any input you can provide. I've been beating my head against my desk for two days trying to figure this out.
OK I figured it out.
In this piece of code:
// Get TMX Map and associated layers/groups
_map = CCTMXTiledMap.tiledMap("TileMap.tmx");
_background = _map.layerNamed("Background");
_objects = _map.objectGroupNamed("Objects");
// Add my background layer
// TODO: Position layer in the correct spot.
addChild(_background);
I am adding my _background layer but what I really want to be doing is adding my _map instead:
// Get TMX Map and associated layers/groups
_map = CCTMXTiledMap.tiledMap("TileMap.tmx");
_background = _map.layerNamed("Background");
_objects = _map.objectGroupNamed("Objects");
// Add my background layer
// TODO: Position layer in the correct spot.
addChild(_map);
Now my player character remains in the center of my viewable screen while walking around unless I get to the edge of the map.
Each time when the touch ends, the player is moved by mapWidth or height. You should move the position with diff. Try
CGPoint diff = CGPoint.ccpSub(touchLocation, playerPosition);
if (Math.abs(diff.x) > Math.abs(diff.y)) {
if (diff.x > 0) {
playerPosition.x += diff.x;
} else {
playerPosition.x -= diff.x;
}
} else {
if (diff.y > 0) {
playerPosition.y += diff.y;
} else {
playerPosition.y -= diff.y;
}
}
I'm working on a painting application for Android and I'd like to use raw data from the device's touch screen to adjust the user's paint brush as they draw. I've seen other apps for Android (iSteam, for example) where the size of the brush is based on the size of your fingerprint on the screen. As far as painting apps go, that would be a huge feature.
Is there a way to get this data? I've googled for quite a while, but I haven't found any source demonstrating it. I know it's possible, because Dolphin Browser adds multi-touch support to the Hero without any changes beneath the application level. You must be able to get a 2D matrix of raw data or something...
I'd really appreciate any help I can get!
There are some properties in the Motion Event class. You can use the getSize() method to find the size of the object. The Motion Event class also gives access to pressure, coordinates etc...
If you check the APIDemos in the SDK there's a simple paitning app called TouchPaint
package com.example.android.apis.graphics;
It uses the following to draw on the canvas
#Override public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
mCurDown = action == MotionEvent.ACTION_DOWN
|| action == MotionEvent.ACTION_MOVE;
int N = event.getHistorySize();
for (int i=0; i<N; i++) {
//Log.i("TouchPaint", "Intermediate pointer #" + i);
drawPoint(event.getHistoricalX(i), event.getHistoricalY(i),
event.getHistoricalPressure(i),
event.getHistoricalSize(i));
}
drawPoint(event.getX(), event.getY(), event.getPressure(),
event.getSize());
return true;
}
private void drawPoint(float x, float y, float pressure, float size) {
//Log.i("TouchPaint", "Drawing: " + x + "x" + y + " p="
// + pressure + " s=" + size);
mCurX = (int)x;
mCurY = (int)y;
mCurPressure = pressure;
mCurSize = size;
mCurWidth = (int)(mCurSize*(getWidth()/3));
if (mCurWidth < 1) mCurWidth = 1;
if (mCurDown && mBitmap != null) {
int pressureLevel = (int)(mCurPressure*255);
mPaint.setARGB(pressureLevel, 255, 255, 255);
mCanvas.drawCircle(mCurX, mCurY, mCurWidth, mPaint);
mRect.set(mCurX-mCurWidth-2, mCurY-mCurWidth-2,
mCurX+mCurWidth+2, mCurY+mCurWidth+2);
invalidate(mRect);
}
mFadeSteps = 0;
}
Hope that helps :)
I'm working on something similar, and I'd suggest looking at the Canvas and Paint classes as well. Looking at getHistorySize() in Motion Event might also be helpful for figuring out how long a particular stroke has been in play.