Jittering lines when scrolling a TMX map in cocos2d-x - cocos2d-x

I feel like I'm missing some fundamental concept as to why I am getting flickering when moving a tile map around.
I create a layer. In it, I add a TMXTiledMap.
_tileMap = TMXTiledMap::create("TMX/32Map.tmx");
_tileMap->setScale(1.f);
_floorLayer = _tileMap->getLayer("Floor");
this->addChild(_tileMap);
for(const auto& l : _tileMap->getChildren()) {
static_cast<SpriteBatchNode*>(l)->getTexture()->setAliasTexParameters();
}
this->scheduleUpdate();
In the update I move the layer.
Vec2 newPos = this->getPosition();
newPos.x = (newPos.x - 1);
newPos.y = (newPos.y - 1);
this->setPosition(newPos);
I realize I'm not moving it by dt. If I move it by dt I get an overall jumpiness to the whole layer. I understand this is due to how it renders partial pixels. But if I move it by one pixel like above, I get this # looking set of lines on the screen about 64 pixels or so on top and bottom and about 224 pixels from the left and right
That is when the window is 1024x768. If I make a 320x240 window, I don't see the lines and if I make it 640x480 I only see them on the left and right sides right near the edge of the screen.
Ultimately I'd just like to smoothly scroll a tile map around. Any help would be super appreciated, because I just can't seem to get started on this project.

For me working solution was to change CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL in ccConfig.h from 1 to 0. Find ccConfig.h in cocos/base/.

Related

How can I change GMSMapView padding without moving the map

I'd like to be able change the padding of a GMSMapView without changing the location of a map. Right now, Google Maps iOS SDK changes the map location so that the same point is in center after the padding has been applied. This is different than how the Android SDK works, which just leaves the map as it is.
I've found a slight workaround for this, but it doesn't work consistently. I can calculate what the new center location should be and update the map camera when I change the padding with the following...
UIEdgeInsets oldPadding = self.mapCtrl.map.padding;
UIEdgeInsets newPadding = UIEdgeInsetsMake(top, left, bottom, right);
float deltaX = ((newPadding.right - newPadding.left)/2 - (oldPadding.right-oldPadding.left)/2);
float deltaY = ((newPadding.top - newPadding.bottom)/2 - (oldPadding.top-oldPadding.bottom)/2);
GMSCameraUpdate *updatedCamera = [GMSCameraUpdate scrollByX:deltaX Y:deltaY];
[self.mapCtrl.map setPadding:newPadding];
[self.mapCtrl.map moveCamera:updatedCamera];
But I'd say it only works 50%. The other 50% the map moves to the new padding location and then back to where I want it to be.
I see two possible solutions for this... A) change the padding in a different way so that it doesn't move the map, or B) figure out a way to get the above code to work by somehow pausing or grouping map movements so that both calls only go through at once. But I can't figure out how to make either of those two things happen.
Make sure you have the same padding on top and bottom so everything keeps centered.
In case someone needs it in the future:
mapView.padding = newPadding
mapView.layer.removeAllAnimations()
That messes with the internals of GMSMapView though and the padding isn't applied to the map itself correctly, just to the UI.
I use the following code to re-apply the padding again after my animation so that the map behaves correctly again.
let newCenter = mapView.projection.coordinate(for: mapView.bounds.inset(by: newMapViewPadding).center)
mapView.padding = newMapViewPadding + UIEdgeInsets(all: 1)
mapView.padding = newMapViewPadding
mapView.moveCamera(GMSCameraUpdate.setTarget(newCenter))
It's correct that we need to set a padding with top AND bottom to keep things appearing correctly, but it's also important to do it AFTER attaching the view to it's parent.
I was doing it before and it did not work properly.

Why are there black lines between my sprites?

I have a single pixel sprite. To this sprite I add four sprites, each a quarter of a square. To offset the sprites, all i do is change their anchor points.
For example:
top right square is at anchor: (0,0);
bottom right : (0,1);
bottom left : (1,1);
top left : (1,0);
I expected the sprite edges to meet perfectly so that it looks like one big square. Instead there are black lines between the edges of each square so it looks like I have placed four squares close together.
I use texture packer to create a sprite sheet, containing the various squares.
Is there some setting in cocos2d-x or some code I must change to get the sprites to align perfectly ?
Edit: This is for cocos2d-x 3.1.1 and higher. Changing the anchor point is necessary and unavoidable.
EDIT: I use sprite frames from a sprite sheet created using TexturePacker. This was the problem. See my answer below.
The problem has something to do with using a sprite sheet (created using TexturePacker) to hold the pieces together. When you place the frames from the sprite sheet together to form a complete image the lines appear.
You can make the black lines disappear by setting the "Extrude" option in Texturepacker to at least 1.
EDIT: For those of you updating sprite positions based on a physics simulation, black lines can be caused by "sub pixel" positions. Try to either move your objects by complete pixels. Or search for answers with "sub pixel" for other solutions.
casting positions calculations to int type didn't help ?
Generally after certain float calculations like multiplying and divide and then complier auto demoting to to int may result in variation of 1px.
for example 26.500123 can be treated as pixel 26 or 27, depending to your casting methodology.
Test Case:
Are you saying you did this ?
auto testNode = Node::create();
auto s1 = Sprite::create("Images/1.png");
s1->cocos2d::Node::setAnchorPoint(Point(1,0));
auto s2 = Sprite::create("Images/2.png");
s2->cocos2d::Node::setAnchorPoint(Point(0,0));
auto s3 = Sprite::create("Images/3.png");
s3->cocos2d::Node::setAnchorPoint(Point(1,1));
auto s4 = Sprite::create("Images/4.png");
s4->cocos2d::Node::setAnchorPoint(Point(0,1));
testNode->addChild(s1);
testNode->addChild(s2);
testNode->addChild(s3);
testNode->addChild(s4);
testNode->setPosition(Point(screenSize.width/2,screenSize.height/2));
this->addChild(testNode);
and you got 1px gap ? i did that same with cocos2dx 3.1
i got this fine lady
Don't change anchorPoint, you'll regret it later. Calculate the correct position for each sprite.
Make sure the position x/y are on pixel boundaries. Casting to int will do the trick though Retina devices allow for 0.5 positions as well due to pixel density being 2x the point resolution.
Point #2 is also why you shouldn't use anchorPoint because you can't cast the position to integers when offsetting the texture with the anchorPoint.

cocos2d-x Actor does not move to touch location

I am trying to make an actor follow the player's finger (long touch). I'm positive I have the math right, but the actor fails to move exactly to where the player touched.
Here is an illustration of my problem:
When the touch is near the top, the actor goes beyond the visible scene at the top.
When the touch is near the bottom, the actor goes out of the visible scene at the bottom.
Same goes for the left and right.
When the touch is performed in the middle of the scene the actor moves perfectly to the touch. In short, the further the touch is away from the middle the more pronounced the distance between the actor and the touch is. In other words; the closer the touch is to the middle, the closer the actor moves towards the touch.
Please note that when the touch was near the bottom or the top the distance between the touch and the actor was more pronounced then when the touch was on the right or the left; as the top/bottom are further from the mid point.
Here is the code used to follow the actor towards the touch:
Lang: Lua
Lib: Cocosd2-x 3.1
local velocity = 1.4
local x, y = self.sprite:getPosition()
-- self.dest[X/Y] are cached coordinates to where the actor should move next.
local angle = math.atan2(touch.y - y, touch.x - x)
local deltaX = velocity * math.cos(angle)
local deltaY = velocity * math.sin(angle)
local newX = x + deltaX
local newY = y + deltaY
self.sprite:setPositionX(newX)
self.sprite:setPositionY(newY)
Things I've tried:
Changed the scale of background layer and sprites. No change
Changed the algorithm used to compute the angle. No change.
Created a red dot and set its position to the exact touch x/y to determine if there was some weird transformation issue when determining the actor's point. The red dot was always perfectly under the touch.
Discovered the issue. When I created the Actor sprite I set its z-index to 100. When I uncommented out the call that set the z-index, everything worked perfectly. In my situation, this particular sprite must always be above all other sprites. What I did to fix the issue is set the z-index much lower than what I had originally set it to; which ended up being 15.
sprite:setPositionZ(15)
From my observation it appears that the sprite is having some type of scale applied to its position the larger the z-index is of the sprite.
Update 1
Using :setPositionZ(int) will unnecessarily scale your sprite bigger in some cases. I now use :setGlobalZOrder(int) with much better success:
sprite:setGlobalZOrder(15)

scaling object to match field of view

I am overlaying some clickable hotspots on top of a proprietary panorama viewer application in flash (as3), and I need to make sure that the hotspots scale according to the changing field of view as the user zooms in / zooms out, but I'm not sure what formula to use.
I set a maximum and minimum field of view of 90 and 25, respectively. I've been given some suggestions of how to calculate the scale of the icons:
from the maker of the panorama software:
Scale => 1/tan(FoV)
This doesn't seem to work for me. And:
scalar += (ZOOM_SCALE_UPPER - ZOOM_SCALE_LOWER) * ( ZOOM_LIMIT_OUT - tempFOV )/( ZOOM_LIMIT_OUT-ZOOM_LIMIT_IN) ;
hotspot.scaleX = hotspot.scaleY = scalar;
Gets me close, but at some point the hotspot stops scaling even though the panorama continues to scale. I thought I could just do something like:
diffFOV = previousFOV - currentFOV.
hotspot.scale = currentScale*(1-diffFov)
But that's not quite right either. Everything gets way too big or too small.
Any ideas?
You may be over thinking it.
//assume we change the scale
var NEW_SCALE:Number = currentScale*(1-(previousFOV-currentFOV));
//1. change the scale of the parent containing both the view and the hotspots
viewSprite.scale = NEW_SCALE;
//this way the hotspot and the panorama will scale together
//2. if they are not in the same parent... then set them both to the same view
hotspot.scale = panorama.scale;
Only thing you may have to do after is reposition if they are not registered on their center point.

Why does this ActionScript Flip cause a blur on my website?

I'm using a flip mechanism to navigate through my site (flip file & demo). The problem is, once it's flipped the content been displayed good just like I want it, but there's some offset from the flipped (right) parts en the solid left part (visible when you look closely). Also the right part is now a little blurred (which is the disturbing part of my issue). This all caused by the flip (I think the rotationY is causing the problem).
When I click a button I do the following:
flip=new Flip(currentPage,nextPage,richting);
content.addChild(flip);
currentPage=nextPage;
nextPage = new MovieClip();
there is a fix for it, consider the following:
// store original matrix
var origMatrix:Matrix = box.transform.matrix;
// set initial position
box.rotationY = -180;
// start animation
TweenLite.to(box, 1, {rotationY:0, onComplete:cleanBlur})
// execute after animation complete
function cleanBlur():void {
box.transform.matrix = origMatrix;
}
maybe you can find better results using other 3d library.
EDIT: sorry the "box" object, I was testing in flash, but box would be any of your pages to flip. Just apply the same logic.
Matteo at Flash & Math has an excellent solution for this. He actually found that when you bring an object into native 3D space it expands the object by one pixel in both the width and height. This can be counteracted by scaling your object back and then setting it's z to 0 which will scale it back up. Now the object is ready to play with without the blur.
http://www.flashandmath.com/flashcs4/blursol/index.html
adding: This fixes the scale issue, but not the blurriness. You will still need to use the matrix transformation fix posted above.