i am creating custom view extending surfaceview. View is Used to Display Video thumbs horizontally and is used as timeline of video. i want to add smooth scrolling to this custom view. i have tried fling animation class from androidx
https://developer.android.com/guide/topics/graphics/fling-animation
but thisis used to scroll whole view. and using this fling view just graphically view is animating but its value remains the same. alternatively i have tried to use gesture listener but ufotunatilly. not worked can any one guide me in this matter.
what actually i want smooth scrolling
what actually working
public class TimelineView extends SurfaceView
touchmove Evvent method
f2 = ((float) this.timeFullWidth) / ((float) this.viewWidth);
j2 = this.startTouchTime - ((long) (f2 * (f - this.startTouch.x)));
this.currentTime = j2;
if (j2 < mediaList.get(0).getStartTrim()) {
this.currentTime = glitchCamEditorMediaList.get(0).getStartTrim();
}
if (j2 > mediaList.get(0).getEndTrim()) {
this.currentTime = glitchCamEditorMediaList.get(0).getEndTrim();
}
============================================================================
public void onDraw(Canvas canvas) {
int i = 0;
for (Media media: this.mediaList) {
long j = this.currentTime;
int i2 = this.timeFullWidth;
long j2 = j - ((long) (i2 / 2));
if (media.getStartTimeLine() < j + ((long) (i2 / 2)) && media.getEndTrim() > j2) {
drawCard(canvas, media);
}
i++;
}
}
Related
I am trying to build a card based game in which a card is added to player after every round. To win the match player has to remove all cards from his deck.However i have also drawn some additional button for some other purposes. The issue is that when the number of cards got high, they hide behind the buttons like below image.
Is there any way through which i can draw the bitmaps in a fixed area? Something like below image(Highlighted rectangle behind the card images).
Following is my code to draw Bitmaps for one player
private void setMainPlayer() {
// Log.d(TAG, "Inside Set Main Player Method");
Card localcard = null;
Bitmap localimage = null;
int currentiteration = 0;
int Card_Gap = Screen_Width / 10;
int Down_Card_Gap = 0;
int Down_Card_Gap_positive = 0;
int Down_Card_Gap_negative = 0;
playerList.get(0).sortBySuit();
// Log.d(TAG,"Main Player Deck size"+MainPlayer.Count());
while (currentiteration < playerList.get(0).decksize()) {
localcard = playerList.get(0).getCard(currentiteration);
localcard.setCurrent_Y(Screen_Height - localcard.getImage(context, Card_Width, Card_Height).getHeight());
playerList.get(0).setCurrentCard(localcard, currentiteration);
currentiteration++;
if (Down_Card_Gap >= 0) {
Down_Card_Gap_positive = Down_Card_Gap;
localcard.setCurrent_X(Screen_Center_X + Down_Card_Gap_positive);
Down_Card_Gap += Card_Gap;
} else {
Down_Card_Gap_negative = Down_Card_Gap;
localcard.setCurrent_X(Screen_Center_X + Down_Card_Gap_negative);
}
Down_Card_Gap *= -1;
}
}
private void DrawMainPlayerDeck(Canvas canvas) {
// Log.d(TAG, " Inside Draw Main Player Deck");
Card localcard;
int currentiteration = 0;
while (currentiteration < playerList.get(0).decksize()) {
localcard = playerList.get(0).getCard(currentiteration);
canvas.drawBitmap(localcard.getImage(context, Card_Width, Card_Height), localcard.getCurrent_X(), localcard.getCurrent_Y(), null);
currentiteration++;
}
}
I am drawing bitmaps on surfaceview.
Any suggestion would be really helpful.
Thanks in advance.
I have written a custom view that shows a simulated oscilloscope, it essentially holds a series of points to plot, and periodically places a pulse (a separate set of points) into the main series. The only problem is that I'd like to update the points at the correct rate of 25mm/sec on one plot and 4mm/sec on another.
setRate() is called before the view is drawn. updateData() is called from a thread that runs a loop at 60fps with SystemClock.elapsedRealtime(). The problem is that pxToDraw is not the right value to keep it at the rate I'd like.
Here is my code
static class FakePlot extends OscView.Plot {
public void setRate(int width, DisplayMetrics dm) {
float xdpi = dm.xdpi;
mWidthMm = width/ xdpi * 25.4f;
pxPerSec =TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, mScanRateMM, dm);
pxPerTick = ((float)width) / mData.length;
lastPulse = SystemClock.elapsedRealtime();
Log.e(TAG,String.format("setRate() %s: pxPerSec=%f pxPerTick=%f",mTitle,pxPerSec,pxPerTick));
}
/**
* Copy the next set of points along
* #param realTime
*/
public void updateData(long realTime) {
long diff = realTime - lastUpdate;
lastUpdate = realTime;
float pxToDraw = ((diff/1000f)/pxPerSec);
float ticksToDraw = pxToDraw/(1f/pxPerTick);
for (int j = 0; j < ticksToDraw; j++){
// update mData with the next ticksToDrawPoints
}
setChanged();
notifyObservers();
}
}
A full working example (without the correct scan rate is here: http://pastebin.com/nHBxumhV)
The correct code is:
float extraToDraw;
public void updateData(long realTime) {
float mmPerTick = mWidthMm/mData.length;
float mmToDraw = (mScanRateMM*diffSec)+extraToDraw;
if(mmToDraw < 1) {extraToDraw = mmToDraw;return;}
extraToDraw = 0;
float drawn = 0;
while(drawn < mmToDraw) {
drawn+= mmPerTick;
// draw the next tick
}
}
I have programmed a basic gaming App that consists of blocks which can be exchanged by a swipe (similar to CandyCrush). I succeeded in recognizing the swipe gesture but my code that changes the positions of the Views (blocks) within a GridLayout does only work in the emulator but not on a real device (Samsung Galaxy S3).
Also I couldn't find a way of animating the interchange of the two views. I've added android:animateLayoutChanges="true" to the GridLayout XML but it didn't change anything.
Here's my exchanging code:
// change to blocks positions in grid layout
GridLayout.LayoutParams sourceParams = (GridLayout.LayoutParams)this.imageView.getLayoutParams();
GridLayout.LayoutParams targetParams = (GridLayout.LayoutParams)otherBlock.imageView.getLayoutParams();
GridLayout.Spec sourceRowSpec = sourceParams.rowSpec;
GridLayout.Spec sourceColumnSpec = sourceParams.columnSpec;
sourceParams.rowSpec = targetParams.rowSpec;
sourceParams.columnSpec = targetParams.columnSpec;
targetParams.rowSpec = sourceRowSpec;
targetParams.columnSpec = sourceColumnSpec;
this.imageView.setLayoutParams(sourceParams);
otherBlock.imageView.setLayoutParams(targetParams);
gameGridLayout.requestLayout();
And here's a screenshot of the App:
You should have an index table of your layout, and in your drawing method you run through this index to draw each block.
Like that:
private int [][] index;
void onDraw(Canvas canvas) {
for (int i = 0; i < MAX_BLOCK_HEIGHT; i++) {
for (int j = 0; j < MAX_BLOCK_WIDTH; j++) {
// Draw block index[i][j]
}
}
}
void swapBlock(int blockX, int blockY, int relativePos) {
int tmpBlock = index[blockY][blockX];
if (relativePos == AT_LEFT) {
index[blockY][blockX] = index[blockY][blockX - 1];
index[blockY][blockX - 1] = tmpBlock;
}
// And so on...
}
And this index can be helpful all the time, not only for blit.
The below code is my attempt to send mMyView to the front or the back of the set of children of mPivotParent so it will be rendered on top or behind the others. Hiding the view will not suffice in my case.
mPivotParent is a FrameLayout.
Looking at mPivotParent.mChildren shows that my code below "works" in that the ordering is being set correctly. Yet it has no impact on the z order. Not only this, but the framerate gets cumulatively slower and slower the more times the repositioning code gets called. There are 4 children total and mPivotParent.mChildrenCount remains at 4 throughout as expected.
I'm targeting API Level 7.
#Override
public boolean onTouchEvent(MotionEvent event) {
Display display = getWindowManager().getDefaultDisplay();
float x = event.getRawX();
float sWidth = (int)display.getWidth();
float xLerpFromCenter = ((x / sWidth) - .5f) * 2.f; // [-1, 1]
mRotateAnimation.mfLerp = xLerpFromCenter;
if(xLerpFromCenter < -0.2f && mPivotParent.getChildAt(0) != mMyView)
{
mPivotParent.removeView(mMyView);
mPivotParent.addView(mMyView, 0);
refreshEverything();
}
else if(xLerpFromCenter > 0.2f && mPivotParent.getChildAt(0) == mMyView)
{
mPivotParent.removeView(mMyView);
mPivotParent.addView(mMyView, mPivotParent.getChildCount() - 1);
refreshEverything();
}
return super.onTouchEvent(event);
}
private void refreshEverything()
{
for(int i = 0; i < mPivotParent.getChildCount(); ++i)
{
mPivotParent.getChildAt(i).invalidate();
mPivotParent.getChildAt(i).requestLayout();
}
mPivotParent.invalidate();
mPivotParent.requestLayout();
}
Partial Solution
Here's a somewhat inefficient hack but it works for my purpose, which is to take the top item and send it to the back, keeping all other items in their same order.
private void putFrontAtBack()
{
for(int i = 0; i < mPivotParent.getChildCount() - 1; ++i)
{
mPivotParent.getChildAt(0).bringToFront();
}
refreshEverything();
}
Note: This doesn't work in the general case of arbitrary re-ordering.
Try this.
private void reorder(int[] order)
{
if(order == null || order.length != mPivotParent.getChildCount()) return;
for(int i = order.length - 1; i >= 0; i--)
{
mPivotParent.getChildAt(order[i]).bringToFront();
}
refreshEverything();
}
This code provides arbitrary reordering. The integer array "order" is used to indicate the new order of each view, where order[n]=x means the new order of childAt(x) is n.
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;
}
}