uiview resizing and manipulation problem for iphone 4G - uiview

I have written a code that I use for cropping purpose. The scenario is like, It has 4 uiviews
1) Top
2) Left
3) Right
4) Bottom
Each uiview is resized according to the desired change and the main uiview has a uiimageview which contains an image. when I run the code on iPhone 3, 3GS, iPad 2, iPad 4 it works fine but when i run it on iPhone 4G, it generates very undesired result. I know my code calculations are fine thats why they are working fine on every device except the iPhone 4G.
What will the issue be ? Any ideas ? Is uiview calculations are different for iPhone 4 or any other reason ?
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
// messageLabel.text = #"Drag Detected";
commonCropT = leftRect.frame.origin.y; // left.y or Right.y or Top.H is same thing
commonCropB = lowerRect.frame.origin.y;// left.H or Right.H or lower.y is same thing
commonCropL = leftRect.frame.size.width; //
commonCropR = rightRect.frame.origin.x;//
commonCropH = leftRect.frame.size.height;// left.width and right.width
leftYT = leftRect.frame.origin.y;
leftH = leftRect.frame.size.height;
leftYB = leftYT + leftH;
leftW = leftRect.frame.size.width; // leftXR
rightXL = rightRect.frame.origin.x;
rightW = rightRect.frame.size.width;
rightXR = rightXL + rightW;
rightYT = rightRect.frame.origin.y;
rightH = rightRect.frame.size.height;
rightYB = rightH + rightYT;
if (isTappedOnUpperLeftCorner)
{
if (commonCropR - movedPoint.x <= kWidthDifference)
return;
if (movedPoint.y < commonCropT )
{
commonCropH = commonCropH + (commonCropT - movedPoint.y);
}
else if (movedPoint.y > commonCropT )
{
if (commonCropB - movedPoint.y <= kHeightDifference ) {
return;
}
commonCropH = commonCropH - (movedPoint.y - commonCropT);
}
commonCropL = movedPoint.x;
commonCropT = movedPoint.y;
NSLog(#" cropW = %d ",cropW);
[upperRect setFrame:CGRectMake(upperRect.frame.origin.x, upperRect.frame.origin.y, upperRect.frame.size.width, commonCropT)];
[leftRect setFrame:CGRectMake(leftRect.frame.origin.x, commonCropT, commonCropL, commonCropH)];
[rightRect setFrame:CGRectMake(commonCropR, commonCropT, rightRect.frame.size.width, commonCropH)];
}
}

I believe the problem you're running into is similar to a problem I'm seeing. With the retina display the touch coordinates may be non-integral, e.g. 23.5. If you use non-integral value with the frame of a view you may run into this kind of behavior. It appears that UIView doesn't support non-integral values.
Use roundf() or a similar function at some point in your calculations to avoid this problem.

Related

Irregular iOS Touch Rate on iPhone

I posted this question three days ago, but I received the feedback that the question was not clear so I would like to ask again. Also, the scope of the problem has changed as I researched it further (no Unity issue!)
I'm making a game for iOS where you rotate an object left and right by touching the left or right side of the screen. The Object rotates as long as the display is touched and stops rotating when the touch ends. When I run the game on an actual iPad/iPhone for a while every few touches the Rotation of the Objects stutters for about 2 seconds. This happends in about 5% of the touches. All other touches work perfectly smooth.
All other Game Actions work fine at the set frame rate of 60 fps. The only thing that doesn't move smoothly is the rotated object, while the rest of the game is all running perfectly smooth. I tried to visualize the problem on the attached image. See here
It visually looks like the Touch Refresh Rate is freezed for two seconds.
What may be the cause for this and how do I fix this?
I created the game with the game engine Unity. I use these versions:
- Unity: 2019.3.15f1
- Xcode: 11
- Device: iPhone x
- iOS Version: 13.5.1
After a lot of research I found out, that this is not an issue related to Unity. Also, there is no issue when building the game on an Android device.
Steps to reproduce:
int rotation
private void FixedUpdate(){
for (int i = 0; i < Input.touchCount; i++)
{
Vector3 touchPos = Camera.main.ScreenToWorldPoint(Input.touches[i].position);
if (touchPos.x < 0)
{
rotation += 10;
}
else if (touchPos.x > 0)
{
rotation -= 10;
}
}
transform.Rotate(0, 0, rotation);
rotation = 0;
}
Coding the Touch Input via c# in Unity (see above)
Building the Project on iOS Platform (creating an xcodeproject)
Open the Project in XCode and running it on the iPhone
Does anybody have a solution for this?
Any "Input" class should be called in Update(), instead of FixedUpdate().
The Input data loss is expected if you are trying to get them in FixedUpdate().
Just for example, FixedUpdate can be execute twice in one frame, or skipped in one frame. That's how it causes data lost or inaccurate.
The proper solution will be sth like below.
int rotation
private void Update()
{
for (int i = 0; i < Input.touchCount; i++)
{
Vector3 touchPos = Camera.main.ScreenToWorldPoint(Input.touches[i].position);
if (touchPos.x < 0)
{
rotation += 10 * time.deltaTime;
}
else if (touchPos.x > 0)
{
rotation -= 10 * time.deltaTime;
}
}
transform.Rotate(0, 0, rotation);
rotation = 0;
}
and please be noted that your current rotation direction is determined by a ray casting from camera.
If you want to rotate left/right by screen space, this should work better.
private void Update()
{
int rotation = 0;
for (int i = 0; i < Input.touchCount; i++)
{
if (Input.touches[i].position.x < Screen.width/2)
{
rotation += 10 * time.deltaTime;
}
else
{
rotation -= 10 * time.deltaTime;
}
}
transform.Rotate(0, 0, rotation);
}
In general, I prefer a simple rotation script by checking last touch.
private void Update()
{
if(Input.touchCount > 0)
{
if (Input.touches[Input.touchCount-1].position.x < Screen.width/2)
{
transform.Rotate(0, 0, 10f * time.deltaTime);
}
else
{
transform.Rotate(0, 0, -10f * time.deltaTime);
}
}
}
Or, if you really want to sync the input with FixedUpdate(), you can do sth like below.
bool HasTouch = false;
float SpeedRot = 0;
private void Update()
{
if(Input.touchCount > 0)
{
HasTouch = true;
if (Input.touches[Input.touchCount-1].position.x < Screen.width/2)
{
SpeedRot = 10f;
}
else
{
SpeedRot = -10f;
}
}
else
{
HasTouch = false;
}
}
private void FixedUpdate()
{
if(HasTouch) transform.Rotate(0, 0, SpeedRot * Time.fixedDeltaTime);
}

Error in updating the score in a game

I have problem when i updating score in the game i make i dont know what is the problem but when i shoot something the score should increment by 1 but in my code sometimes it increment by 2 or 3 sometimes 1 it not constant i dont know why this happen here is the code i used
#interface GameScene () {
SKLabelNode* _scoreLabelNode;
NSInteger _score;
}
-(void)didMoveToView:(SKView *)view {
_score = 0;
_scoreLabelNode = [SKLabelNode labelNodeWithFontNamed:#"Silom Regular"];
_scoreLabelNode.fontSize = 50;
_scoreLabelNode.position = CGPointMake(self.size.width - 335 , self.size.height - 60);
_scoreLabelNode.zPosition = 100;
[self addChild:_scoreLabelNode];
_scoreLabelNode.text = [NSString stringWithFormat:#"%d",_score];
}
if (contact.bodyB.categoryBitMask == ObjectCategory) {
_score++;
_scoreLabelNode.text = [NSString stringWithFormat:#"%d",_score];
}
There are few similar issue with this delegate, see if this may fix your issue:
SpriteKit: didBeginContact being called non-stop on iPad
Why are didBeginContact called multiple times?
didBeginContact is being called multiple times for the same SKPhysicsBody
Even if it doesn't solve your problem, you can use a flag variable to handle this score update for once. e.g.,
bool hasScoreUpdated;
- (void)didBeginContact:(SKPhysicsContact * _Nonnull)contact
{
if(!hasScoreUpdated)
{
_score++;
hasScoreUpdated = true;
}
// your rest of the logic
}
- (void)didEndContact:(SKPhysicsContact * _Nonnull)contact
{
hasScoreUpdated = false;
}
EDIT:
Based on your comment above:
i put "NSLog (#"%d", _score )" after "_score++" it increment as should
like 10 11 12 .. etc but the score jumped from 10 to 12
It is possibly due to the very frequently calling the respective event and a very rapidly update of UI element.

Trying to find which Sprite was clicked in array of sprites onTouchEnded

I'm trying to detect which sprite was touched in an array of sprites and when it is touched to run an animation at the sprite which was touched. I have all the sprites placed in the map already but when the user touches any other sprite except for the first one the animation doesn't run. I'm using cocos2dx 3.5. Any help is appreciated thank you.
this is my onTouchesEnded
void BattleScreen::onTouchesEnded(const std::vector<cocos2d::Touch *> &touches, cocos2d::Event *event)
{
for (auto touch : touches)
{
auto tapped = touch->getLocationInView();
for (int i = 0; i < defenseSpots.size(); i++) {
if(defenseSpot[i]->getBoundingBox().containsPoint(tapped))
{
sealAnimationSprite = Sprite::create("sealanimation5.png");
sealAnimationSprite->setPosition(Point(defenseSpot[i]->getPosition().x, defenseSpot[i]->getPosition().y));
this->addChild(sealAnimationSprite,20);
// now lets create animation frames
Vector<SpriteFrame*> sealAnimationFrames;
sealAnimationFrames.reserve(5);
sealAnimationFrames.pushBack(SpriteFrame::create("sealanimation5.png", Rect(0,0,100,100)));
sealAnimationFrames.pushBack(SpriteFrame::create("sealanimation4.png", Rect(0,0,100,100)));
sealAnimationFrames.pushBack(SpriteFrame::create("sealanimation3.png", Rect(0,0,100,100)));
sealAnimationFrames.pushBack(SpriteFrame::create("sealanimation2.png", Rect(0,0,100,100)));
sealAnimationFrames.pushBack(SpriteFrame::create("sealanimation.png", Rect(0,0,100,100)));
// create the animation out of the frames
Animation* sealAnimation = Animation::createWithSpriteFrames(sealAnimationFrames, 0.01f);
animateSeal = Animate::create(sealAnimation);
// run it and repeat it forever
sealAnimationSprite->runAction((animateSeal));
}
}
}
}
and here is my method where i create the sprites and place them
void BattleScreen::createDefenseSpots()
{
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
for (int i = 0; i < 4;i++)
{
defenseSpot[i] = Sprite::create("placement.png");
if(i == 0)
defenseSpot[i]->setPosition(Point(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
if (i == 1)
defenseSpot[i]->setPosition(Point(visibleSize.width / 1.4 + origin.x, visibleSize.height / 3+ origin.y));
if (i == 2)
defenseSpot[i]->setPosition(Point(visibleSize.width / 3.5 + origin.x, visibleSize.height / 1.5 + origin.y));
if (i == 3)
defenseSpot[i]->setPosition(Point(visibleSize.width / 2.5 + origin.x, visibleSize.height / 4+ origin.y));
this->addChild(defenseSpot[i]);
defenseSpots.push_back(defenseSpot[i]);
}
}
Everything adds to the scene correctly but the only sprite the will run the animation is the first one. Im guessing the loop isn't executing correctly but I'm not sure how to fix it?
I've also tried looping through like this
for(int i = 0;i < 4; i++){
...
}
I figured it out , I was using
auto tapped = touch->getLocationInView();
when i should have been using
auto tapped = touch->getLocation();
Just in case anyone out there is making my same mistake.

Code for retina displays in iOS

We are coding in iOS 7.x and I came to the following code snippet:
if ( condition ) {
if (UIScreen.mainScreen.scale > 1) {
self.canvas.image = [myImage imageScaledToFitSize:CGSizeMake(30,30)];
} else {
self.canvas.image = [myImage imageScaledToFitSize:CGSizeMake(60,60)];
}
}
Is this the proper way to code? If this "retina" check is the way to go, then it should
be placed everywhere in the code.
If this UIScreen.mainScreen.scale is not correct, could you please point the correct way to go for retina/non-retina display handling?
Seems a bit hardcoded; better would be:
if ( condition ) {
CGFloat scale = UIScreen.mainScreen.scale;
self.canvas.image = [myImage imageScaledToFitSize:CGSizeMake(60.0 / scale, 60.0 / scale)];
}
However it's not clear to me what the 60 signifies...

Rectangle and Circle collision detection

I am trying to do collision detection between a rectangle and a circle. I came up with this method:
-(BOOL) isCollidingRect:(CCSprite *) spriteOne WithSphere:(CCSprite *) spriteTwo {
float diff = ccpDistance(spriteOne.position, spriteTwo.position);
float obj1Radii = [spriteOne boundingBox].size.width/2;
float obj2Radii = [spriteTwo boundingBox].size.width/2;
if (diff < obj1Radii + obj2Radii) {
return YES;
} else {
return NO;
}
}
and this is how I check it:
if ([self isCollidingRect:player WithSphere:blocker] == true) {
[self playerdeathstart];
}
This seems to work properly on the side of the rectangle but it doesn't above or below it. On the top and bottom, the collision occurs too early.
Is there a way I can get this collision to detected properly? Thank you for your help.
You can use CGRectIntersectsRect to achieve this.
-(BOOL) isCollidingRect:(CCSprite *) spriteOne WithSphere:(CCSprite *) spriteTwo {
return CGRectIntersectsRect([spriteOne boundingBox],[spriteTwo boundingBox]);
}
It is not pixel perfect but as i understand that is not necessary in this case.
This is not a solution for those who use Cocos2d-ObjC, but will help for Cocos2d-x devs (for instance, personally I found this topic because was searching for the same for my c++ game).
Cocos2d-x has method "intersectsCircle" for Rect class.
Here is how I solved in my c++ project almost the same problem as one described by you:
bool ObstacleEntity::hasCollisionAgainst(cocos2d::Sprite *spr)
{
cocos2d::Rect rect = cocos2d::Rect( spr->getPositionX(), spr->getPositionY(), spr->getBoundingBox().size.width, spr->getBoundingBox().size.height);
float rw = this->getBoundingBox().size.width / 2;
float rh = this->getBoundingBox().size.height / 2;
float radius = ( rw > rh ) ? rw : rh;
cocos2d::Vec2 center( this->getPositionX() + rw, this->getPositionY() + rh );
return rect.intersectsCircle( center, radius );
}
Passed Sprite here is rectangle, while ObstacleEntity always is almost ideally round.
Note that anchor points for all entities are set to lower left corner in my case.

Resources