I'm using Apple's UIImage+ImageEffects category from WWDC (2013?)
This method works just fine on iPhone 6, but creates a really strange unblurred, oversaturated image on iPhone 6 Plus:
[self applyBlurWithRadius:60 tintColor:[UIColor colorWithWhite:1.0 alpha:0.3] saturationDeltaFactor:2.4 maskImage:nil];
iPhone 6 (proper):
iPhone 6 Plus (weird):
Any idea what's going on?
Update: I've determined through trial and error that setting the blurRadius to anything less than or equal to 50 shows up OK, so it's related to the radius. I'd still like to know what exactly is causing it to goof on the larger screen.
I know this question is old and the OP has since moved on, but I would like to explain why it's different on each phone... for future generations.
The iPhone6 and the iPhone6+ have different screen resolutions. Mainly, the iPhone6 is has a scale of 2.0, while the iPhone6+ has a scale of 3.0.
Why does this matter?
In the source code for applyBlurWithRadius in the source file UIImage+ImageEffects.m, you will find these lines:
CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale];
uint32_t radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5);
if (radius % 2 != 1) {
radius += 1; // force radius to be odd so that the three box-blur methodology works.
}
You can see that the inputRadius will be different based on what the scale of the screen is. So, on the iPhone6, this value will be 60*2 (end result for radius will be: 227), and on the iPhone6+ the value will be 60*3 (end result for radius will be 339). This will obviously produce the different results since they are different values.
As for why the color difference? I am pretty sure the radius shouldn't exceed 255 otherwise undefined results may occur (probably integer overflow, causing color components to wrap back to zero). Since the iPhone6+'s screen scale value pushes it above this value, you see weird results, but not on the iPhone6 since it's below that threshold.
You should be able to see the same weirdness happen on an iPhone6 by using the value of 90 for the blurRadius parameter.
Side note: You shouldn't need values above 30 for parameter blurRadius anyway -- the results won't be much different beyond that point.
Hope this helps you.
Related
I am rather experiences libgdx developer but I struggle with one issue for some time so I decided to ask here.
I use FillViewport, TiledMap, Scene2d and OrtographicCamera. I want the camera to follow my player instance but there are bounds defined (equal to mapsize). It means that camera will never ever leave outside of map, so when player comes to an end of the map camera stops following and he goes to the edge of the screen itself. Maybe sounds complicated but it's simple and I am sure that you know what I mean, it's used in every game.
I calculated 4 values:
minCameraX = camera.viewportWidth / 2;
minCameraY = camera.viewportHeight / 2;
maxCameraX = mapSize.x camera.viewportWidth / 2;
maxCameraY = mapSize.y - camera.viewportHeight / 2;
I removed not necessary stuff like unit conversion, camera.zoom etc. Then I set the camera position like this:
camera.position.set(Math.min(maxCameraX, Math.max(posX, minCameraX)), Math.min(maxCameraY, Math.max(posY, minCameraY)), 0);
(posX, posY is player position) which is basically setting camera to player position but if it's to high or too low it sets it to max or min defined before in right axis. (I also tries MathUtils.clamp() and it works the same.
Everything is perfect until now. Problem occures when aspect ratio changes. By default I use 1280x768 but my phone has 1280x720. Because of that bottom and top edges of the screen are cut off because of the way how FillViewport works. Because of that part of my map is cut off.
I tried to modify maximums and minimums, calculate differences in ratio and adding them to calculations, changing camera size, different viewports and some other stuff but without success.
Can you guys help?
Thanks
I tried solution of noone and Tenfour04 from comments above. Both are not perfect but I am satisified enough i guess:
noone:
camera.position.x = MathUtils.clamp(camera.position.x, screenWidth/2 + leftGutter, UnitConverter.toBox2dUnits(mapSize.x) - screenWidth/2 + rightGutter);
camera.position.y = MathUtils.clamp(camera.position.y, screenHeight/2 + bottomGutter, UnitConverter.toBox2dUnits(mapSize.y) - screenHeight/2 - topGutter);
It worked however only for small spectrum of resolutions. For strange resolutions where aspect ratio is much different than default one I've seen white stripes after border. It means that whole border was printer and some part of the world outside of border. I don't know why
Tenfour04:
I changed viewport to ExtendViewport. Nothing is cut off but in different aspect ratios I also can see world outside of borders.
Solution for both is to clear screen with same color as the border is and background of level separatly which gave satisfying effect in both cases.
It stil has some limitations. As border is part of the world (tiled blocks) it's ok when it has same color. In case border has different colors, rendering one color outside of borders won't be a solution.
Thanks noone and Tenfour04 and I am still opened for suggestions:)
Here are some screenshots:
https://www.dropbox.com/sh/00h947wkzo73zxa/AAADHehAF4WI8aJ8bu4YzB9Va?dl=0
Why don't you use FitViewport instead of FullViewport? That way it won't cut off your screen, right?
It is a little bit late, but I have a solution for you without compromises!
Here width and height are world size in pixels. I use this code with FillViewport and everything works excellent!
float playerX = player.getBody().getPosition().x*PPM;
float playerY = player.getBody().getPosition().y*PPM;
float visibleW = viewport.getWorldWidth()/2 + (float)viewport.getScreenX()/(float)viewport.getScreenWidth()*viewport.getWorldWidth();//half of world visible
float visibleH = viewport.getWorldHeight()/2 + (float)viewport.getScreenY()/(float)viewport.getScreenHeight()*viewport.getWorldHeight();
float cameraPosx=0;
float cameraPosy=0;
if(playerX<visibleW){
cameraPosx = visibleW;
}
else if(playerX>width-visibleW){
cameraPosx = width-visibleW;
}
else{
cameraPosx = playerX;
}
if(playerY<visibleH){
cameraPosy = visibleH;
}
else if(playerY>height-visibleH){
cameraPosy = height-visibleH;
}
else{
cameraPosy = playerY;
}
camera.position.set(cameraPosx,cameraPosy,0);
camera.update();
how to make objects appear from (one side only), when I rotate them in iOS ?
What I want to happen, (as you can see i can add another face to my UITableview cell)
What is happening, i can't even add another face since the previous one is showing up again
The Code I'm using
func animate()
{
var id = CATransform3DIdentity
id.m34 = -1.0 / 1000
var transformAnim = CAKeyframeAnimation(keyPath:"transform")
transformAnim.values = [
NSValue(CATransform3D: CATransform3DRotate(id, 0 * CGFloat(-M_PI_2), 0, 1.0, 0)),
NSValue(CATransform3D: CATransform3DRotate(id, 1 * CGFloat(-M_PI_2), 0, 1.0, 0)),
NSValue(CATransform3D: CATransform3DRotate(id, 0 * CGFloat(-M_PI_2), 0, 1.0, 0))
]
transformAnim.keyTimes = [0, 0.5, 1.0]
transformAnim.duration = 0.7
self.imageViewLogo.layoutIfNeeded()
self.imageViewLogo.layer.addAnimation(transformAnim, forKey: "transform")
}
If you know a feature called [force 2 sided] in 3ds max for example, I want it turned of here, but it seems that iOS has no feature like this.
This is an advanced question, I wish an expert answers me.
Thanks.
EDIT
if you are still not sure what I'm asking, I mean this :
how to make an object to show only from one side when i rotate it ?
That is a standard flip transition. Take a look at the UIView method +transitionFromView:toView:duration:options:completion:, specifically the UIViewAnimationOptionTransitionFlipFromLeft and UIViewAnimationOptionTransitionFlipFromRight settings.
There is also a view controller transition if you want to do a flip transition to a different view controller.
If you want to build this animation yourself it's much more work.
What you have to do is create 2 separate animations, one for the front face and one for the back face:
First, you animate the front face rotating to 90 degrees, at which point it disappears because you are viewing it edge-on. At that point you add your back half view/layer, but facing the other way. Then in the second animation you rotate the new view 90 degrees, which leaves it flat and face-up. It's possible to get a seamless animation that gives you exactly the effect you want, but it's difficult, fussy code to write.
the solution was a simple statement that I never heard of before
imageViewLogo.layer.doubleSided = false
from apple's website :-
A Boolean indicating whether the layer displays its content when
facing away from the viewer. Animatable.
I have been having great difficulty creating a jumping system whereby the user can tap the jump button for a small jump and hold it down for a higher jump.
I stumbled upon this topic:
https://gamedev.stackexchange.com/questions/13277/variable-height-jumping-in-side-scrollers
Which greatly helped me develop the following code:
PlayerMovementTimer = [NSTimer scheduledTimerWithTimeInterval:0.005 target:self selector:#selector(movePlayer) userInfo:nil repeats:YES];
[JumpButton addTarget:self action:#selector(jumpPlayer:) forControlEvents:UIControlEventTouchDown];
[JumpButton addTarget:self action:#selector(stopJump:) forControlEvents:UIControlEventTouchCancel | UIControlEventTouchUpInside | UIControlEventTouchDragExit];
- (void)movePlayer
{
CGFloat playerY = Player.center.y + PlayerYV;
if(playerY > 264) {
PlayerYV = 0;
playerY = 264;
}
if(playerY < 264) {
PlayerYV += 0.048f - PlayerYD;
}
if(HoldingJump && PlayerYV < 0 && PlayerYD + 0.0018f < 0.048f) {
PlayerYD += 0.0018f;
}
Player.center = CGPointMake(Player.center.x + PlayerXV, playerY);
}
- (IBAction)jumpPlayer:(id)sender
{
if(Player.center.y == 264) {
PlayerYD = 0;
PlayerYV = -2.25;
HoldingJump = true;
}
}
- (IBAction)stopJump:(id)sender
{
HoldingJump = false;
}
The code seems to work (some of the values need a bit of fine tuning but I haven't gotten round to that yet). The only problem is that the movement appears to be slightly jerky (even on the real device) and that when the player is at the top of the jump they accelerate really slowly and no values I put seem to be able to get the jump to look smooth like on Mario games.
Please take a look at the code and see if I am missing something obvious, or if there is a more efficient method of controlling movement than an NSTimer calling a void function. Also, is setting a UIImageView's position to a float value bad?
Thanks.
So there are quite a few things wrong here. First, yes, you should never be setting the origin of an ImageView or any other UI element to a coordinate position that is a fractional pixel. This causes sub-pixelling which will blur your image. To avoid this, all CGFloats should be rounded to the nearest whole number using roundf() or other similar rounding functions.
Another issue I can see is that you're setting Player.center. I hope for your sake that Player is not an ImageView cause you're going to be making your life harder. As mentioned above, when the origin of a frame is not set to a CGFloat that is a round number, you'll get sub-pixelling. When you use the center property, you can easily cause yourself to get on a bad origin value. For example, if I have a 11 by 11 image and set it's center to (11,11), the origin will get set to (5.5,5.5) and will cause sub-pixelling. Easy ways to avoid this is just do the math to place the origin correctly and make sure to round the CGFloats that you feed into it (or use CGRectIntegral on the frame before you set it).
A third issue here is that the timer is being called 0.005 seconds. Let's assume you want this game to run with 60 FPS. 60 FPS translates to about 0.0167 seconds. The timer is calling the method three times more often then it would need to even if you wanted 60 FPS and additionally, calling this method so often could be causing some of your jerky motion.
Now in terms of getting a "Mario" like jump, what you really need to do is look at getting a dedicated physics engine since if you're using the code above, you don't appear to have one. What a physics engine would do is it would apply a constant "gravity" which will help make the player jumps look and act more realistically. You would, when a player presses a button, apply an impulse up on the player character. The use of impulses would also simplify your work as you could apply impulses in different ways depending on how long they hold the button, etc. The code above is simply trying to get around this problem instead of addressing the real issue of you not having a physics engine.
Go investigate cocos2D and Box2D as a possible physics engine you could use. There are a wealth of resources on cocos2D+Box2D and there is a developer who even has made a tutorial on using cocos2D to create a Super Mario clone that should give you some basic understanding of how physics engines work: http://www.raywenderlich.com/15230/how-to-make-a-platform-game-like-super-mario-brothers-part-1
I need some help (duh). I want to generate a random Y position for my game in cocos2d.
So the situation goes like this:
The game spawns a platform every 0.2 second. The iPhone / iPad is in landscape mode. Platform appear on the right of the screen (bigger x than width so that the platform appears outside the screen) and starts moving towards the left end of the screen using CCMoveTo.
I pick a random Y for every platform. The problem is that I do not want to spawn a platform on top of another. This means that I need to make a randY which is not "already taken".
The code I've tried so far is this:
//this is a part of code from my addPlatform function. This part in particular cares for the generation of my Y coordinate.
int randY = arc4random() % (int)(3 * (winSize.height/4)); //This prevents to spawn a Y larger than 3/4 of the screen
//here I would like to loop long enough to find a good Y
while (![self isGoodPlatformY:randY])
{
randY = arc4random() % (int)(3 * (winSize.height/4));
}
The next part is my isGoodPlatformY function
- (bool)isGoodPlatformY:(int)platY
{
CGSize winSize = [[CCDirector sharedDirector] winSize];
int padding = 100;
bool ok = true;
for (CCSprite *body in [self children])
{
if (body.tag > platformBody)
{
if (body.position.x < (winSize.width - padding))
{
if (abs(body.position.y - platY) < 20)
{
ok = false;
}
}
}
}
return ok;
}
I loop through all the bodies with larger tag than my platform. I have different types of platform which I separate by using tag. If the body is a platform I first check the X coordinate. If the platform is enough away (padding) I can spawn a new one at that exact point so I check the next one. If not I want to check the Y of that platform. If the Y coordinate is less than 20 pixels in this case I must find a new Y so thats why set the bool to false and return it after the for loop.
I know there is no need for those curly brackets but I was testing some other stuff, thats why I put them there.
This doesn't seem to work. Hope I made myself clear what I want to accomplish. Any help from your side would be much appreciated. Hope I didn't miss something too newbie style :)
I tagged the question in other languages to because this problem could occur "everywhere".
Assuming that all the spawned platforms have the same tag as you mentioned that you are using tags to separate different types of platforms.
All previous platforms will not return true for this line
if (body.tag > platformBody)
because they all have the same tag, you will compare (1 > 1) which is false.
Therefore your method will always return YES (which is your default value for ok) and will never check to see if the platforms collide with each other.
I recommend stepping through the method to see if this is the case.
Now I have discovered that I can answer my own questions :) (silly me). So yeah, the problem was fixed a long time ago but to anyone who might be reading this, the solution was to change the line:
if (body.position.x < (winSize.width - padding))
To:
if (body.position.x > (winSize.width - padding))
I am trying to make an app which uses both the GPS and the magnetometer for finding the way and direction for mecca (Mosque). It has some special features like date picker for upcoming prayers, prayer timings left calculated from current location time zone and weather on the current location and some more on. If anyone has sample code regarding to this, please reply.
Thanks in advance
The magnetometer can be told just to return the current device heading, via CLLocationManager. It can return in unfiltered 3d, but there's no reason to use it — from CLHeading just use the trueHeading property. That'll give you the same information shown in the Compass app.
To work out the heading to Mecca from where you are, you can use the formulas given here. Google Maps gives me a geolocation of about 21.436, 39.832 for Masjid al-Haram (I'm not sure it's terribly accurate, so I've rounded inappropriately low), so you could get the bearing from whatever location CLLocationManager tells you you're at something like:
#define toRadians(x) ((x)*M_PI / 180.0)
#define toDegrees(x) ((x)*180.0 / M_PI)
...
double y = sin(toRadians(39.832 - currentLocation.longitude)) * cos(toRadians(21.436));
double x = cos(toRadians(currentLocation.latitude)) * dsin(toRadians(21.436)) -
sin(toRadians(currentLocation.latitude)) * dcos(toRadians(21.436)) * dcos(toRadians(39.832 - currentLocation.longitude));
double bearing = toDegrees(atan2(y, x));
You can then rotate a pointer on screen by the difference between the device's heading and the one you've just calculated. Probably easiest to use a CGAffineTransform on a UIView's transform property.
That's all typed as I answer by the way, not tested. I'd check it against a reliable source before you depend on it.