I'm developing an app that when a user opens there will be an image, controlled by CMMotionManager, which moves according to the direction the user tilts the device.
....
This is my code to start the device motion.
motionManager = [[CMMotionManager alloc] init];
motionManager.showsDeviceMovementDisplay = YES;
motionManager.deviceMotionUpdateInterval = 1.0 / 60.0;
[motionManager startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryCorrectedZVertical];
The is the code I use to control my image in reference to the motion of the device.
- (void)drawRect:(CGRect)rect
{
if (placesOfInterestCoordinates == nil) {
return;
}
mat4f_t projectionCameraTransform;
multiplyMatrixAndMatrix(projectionCameraTransform, projectionTransform, cameraTransform);
int i = 0;
for (MovingImage *poi in [placesOfInterest objectEnumerator]) {
vec4f_t v;
multiplyMatrixAndVector(v, projectionCameraTransform, placesOfInterestCoordinates[i]);
float x = (v[0] / v[3] + 1.0f) * 0.5f;
float y = (v[1] / v[3] + 1.0f) * 0.5f;
if (v[2] < 0.0f) {
CGPoint movingTo = CGPointMake(x*self.bounds.size.width, self.bounds.size.height-y*self.bounds.size.height);
if (movingTo.x < -118) {
movingTo.x = -118;
}
if (movingTo.x > 542) {
movingTo.x = 542;
}
if (movingTo.y < 215) {
movingTo.y = 215;
}
if (movingTo.y > 390) {
movingTo.y = 390;
}
poi.view.center = movingTo;
poi.view.hidden = NO;
} else {
poi.view.hidden = YES;
}
i++;
}
}
The image is in the middle of the screen rarely when the user opens the app, the image is usually to the right or left 90 degrees of the starting position, or exactly in the middle consistently.
I assume that CMAttitudeReferenceFrameXArbitraryCorrectedZVertical is the issue, but I have also tried CMAttitudeReferenceFrameXArbitraryZVertical which doesn't work either.
If useful, my project is here, for anyone interested. I used Apple pARk sample code as well.
- (void)drawRect:(CGRect)rect
{
if (placesOfInterestCoordinates == nil) {
return;
}
mat4f_t projectionCameraTransform;
multiplyMatrixAndMatrix(projectionCameraTransform, projectionTransform, cameraTransform);
int i = 0;
for (MovingImage *poi in [placesOfInterest objectEnumerator]) {
vec4f_t v;
multiplyMatrixAndVector(v, projectionCameraTransform, placesOfInterestCoordinates[i]);
float x = (v[0] / v[3] + 1.0f) * 0.5f;
float y = (v[1] / v[3] + 1.0f) * 0.5f;
if (v[2] < 1.0f) { // change here
CGPoint movingTo = CGPointMake(x*self.bounds.size.width, self.bounds.size.height-y*self.bounds.size.height);
if (movingTo.x < -118) {
movingTo.x = -118;
}
if (movingTo.x > 542) {
movingTo.x = 542;
}
if (movingTo.y < 215) {
movingTo.y = 215;
}
if (movingTo.y > 390) {
movingTo.y = 390;
}
poi.view.center = movingTo;
poi.view.hidden = NO;
} else {
poi.view.hidden = YES;
}
i++;
}
}
try changing (v[2] < 0.0f) to (v[2] < 1.0f)
The viewing angle is different because it is looking for when the image comes into view, other than your device's perspective angle.
Related
Library : https://github.com/SocialObjects-Software/AMSlideMenu
Problem : When you are in closed menu state and receives a call(Simply simulate in iOS simulator) after ending call or while in the call if you try to open slide menu, Menu will appear as little bit smaller.
Any better workarounds for this?
Quick workaround,
Go to AMSlideMenuMainViewController.m
Replace below methods in the file,
- (void)openRightMenu
{
CGRect frame = self.rightMenu.view.frame;
frame.origin.x = [UIScreen mainScreen].bounds.size.width - [self rightMenuWidth];
frame.origin.y = 0;
frame.size = [UIScreen mainScreen].bounds.size;
frame.size.width = [self rightMenuWidth];
self.rightMenu.view.frame = frame;
[self openRightMenuAnimated:YES];
}
- (void)openLeftMenu
{
CGRect frame = self.leftMenu.view.frame;
frame.origin.x = 0;
frame.origin.y = 0;
frame.size = [UIScreen mainScreen].bounds.size;
self.leftMenu.view.frame = frame;
[self openLeftMenuAnimated:YES];
}
And this,
- (void)configure3DTransformForMenu:(AMSlideMenu)menu panningView:(UIView *)panningView
{
float cx = 0;
float cy = 0;
float cz = 0;
float opacity = 0;
/********************************************* DEEPNESS EFFECT *******************************************************/
if (menu == AMSlideMenuLeft && panningView.frame.origin.x != 0 && [self deepnessForLeftMenu])
{
//Workaround for in-call status bar
CGRect frame = self.leftMenu.view.frame;
frame.origin.x = 0;
frame.origin.y = 0;
frame.size = [UIScreen mainScreen].bounds.size;
self.leftMenu.view.frame = frame;
//end workaround for in-call status bar
cx = kMenuTransformScale.m11 + (panningView.frame.origin.x / [self leftMenuWidth]) * (1.0 - kMenuTransformScale.m11);
cy = kMenuTransformScale.m22 + (panningView.frame.origin.x / [self leftMenuWidth]) * (1.0 - kMenuTransformScale.m22);
cz = kMenuTransformScale.m33 + (panningView.frame.origin.x / [self leftMenuWidth]) * (1.0 - kMenuTransformScale.m33);
opacity = kMenuLayerInitialOpacity + (panningView.frame.origin.x / [self leftMenuWidth]) * (1.0 - kMenuLayerInitialOpacity);
self.leftMenu.view.layer.transform = CATransform3DMakeScale(cx, cy, cz);
self.leftMenu.view.layer.opacity = opacity;
}
else if (menu == AMSlideMenuRight && panningView.frame.origin.x != 0 && [self deepnessForRightMenu])
{
//Workaround for in-call status bar
CGRect frame = self.rightMenu.view.frame;
frame.origin.x = [UIScreen mainScreen].bounds.size.width - [self rightMenuWidth];
frame.origin.y = 0;
frame.size = [UIScreen mainScreen].bounds.size;
frame.size.width = [self rightMenuWidth];
self.rightMenu.view.frame = frame;
//end workaround for in-call status bar
cx = kMenuTransformScale.m11 + (-panningView.frame.origin.x / [self rightMenuWidth]) * (1.0 - kMenuTransformScale.m11);
cy = kMenuTransformScale.m22 + (-panningView.frame.origin.x / [self rightMenuWidth]) * (1.0 - kMenuTransformScale.m22);
cz = kMenuTransformScale.m33 + (-panningView.frame.origin.x / [self rightMenuWidth]) * (1.0 - kMenuTransformScale.m33);
opacity = kMenuLayerInitialOpacity + (-panningView.frame.origin.x / [self rightMenuWidth]) * (1.0 - kMenuLayerInitialOpacity);
self.rightMenu.view.layer.transform = CATransform3DMakeScale(cx, cy, cz);
self.rightMenu.view.layer.opacity = opacity;
}
/********************************************* DEEPNESS EFFECT *******************************************************/
/********************************************* STATUS BAR FIX *******************************************************/
if (menu == AMSlideMenuLeft && panningView.frame.origin.x != 0)
{
if (self.statusBarView)
{
self.statusBarView.layer.opacity = 1 - panningView.frame.origin.x / [self leftMenuWidth];
}
}
else if (menu == AMSlideMenuRight && panningView.frame.origin.x != 0)
{
if (self.statusBarView)
{
self.statusBarView.layer.opacity = 1 - abs(panningView.frame.origin.x) / [self rightMenuWidth];
}
}
/********************************************* STATUS BAR FIX *******************************************************/
/********************************************* DARKNESS EFFECT *******************************************************/
if (menu == AMSlideMenuLeft)
{
CGFloat alpha = [self maxDarknessWhileLeftMenu] * (panningView.frame.origin.x / [self leftMenuWidth]);
self.darknessView.alpha = alpha;
}
else if(menu == AMSlideMenuRight)
{
CGFloat alpha = [self maxDarknessWhileRightMenu] * (abs(panningView.frame.origin.x) / [self rightMenuWidth]);
self.darknessView.alpha = alpha;
}
/********************************************* DARKNESS EFFECT *******************************************************/
}
I am using UIAccelerometer in my game and it is working fine in portrait mode but not working properly in landscape mode.
Can some one fix the issue in my code
I am putting my code as below:
#import "GameLayer.h"
#implementation GameLayer
+(id)scene
{
CCScene *scene = [CCScene node];
CCLayer *layer = [GameLayer node];
[scene addChild:layer];
return scene;
}
- (id)init
{
if ((self = [super init]))
{
self.isAccelerometerEnabled = YES;
player = [CCSprite spriteWithFile:#"spaceship.png"];
[self addChild:player];
CGSize screenSize = [CCDirector sharedDirector].winSize;
player.position = CGPointMake(screenSize.width / 2, screenSize.height / 2);
[self scheduleUpdate];
}
return self;
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
float deceleration = 1.0f;
float maxVelocity = 50;
playerVelocity.x = playerVelocity.x * deceleration + acceleration.x;
playerVelocity.y = playerVelocity.y * deceleration + acceleration.y;
if (playerVelocity.x > maxVelocity)
{
playerVelocity.x = maxVelocity;
}
else if (playerVelocity.x < -maxVelocity)
{
playerVelocity.x = -maxVelocity;
}
if (playerVelocity.y > maxVelocity)
{
playerVelocity.y = maxVelocity;
}
else if (playerVelocity.y < -maxVelocity)
{
playerVelocity.y = -maxVelocity;
}
}
- (void)update:(ccTime)delta
{
CGPoint pos = player.position; pos.x += playerVelocity.x;
pos.y += playerVelocity.y;
CGSize screenSize = [CCDirector sharedDirector].winSize;
float imageWidthHalved = player.texture.contentSize.width * 0.5f;
float imageHeightHalved = player.texture.contentSize.height * 0.5f;
float leftBorderLimit = imageWidthHalved;
float rightBorderLimit = screenSize.width - imageWidthHalved;
float topBorderLimit = imageHeightHalved;
float bottomBorderLimit = screenSize.height - imageHeightHalved;
if (pos.x < leftBorderLimit)
{
pos.x = leftBorderLimit;
playerVelocity.x = 0;
}
else if (pos.x > rightBorderLimit)
{
pos.x = rightBorderLimit;
playerVelocity.x = 0;
}
if (pos.y < topBorderLimit)
{
pos.y = topBorderLimit;
playerVelocity.y = 0; }
else if (pos.y > bottomBorderLimit)
{
pos.y = bottomBorderLimit;
playerVelocity.y = 0;
}
player.position = pos;
}
#end
The accelerometer axes do not change with change in orientation. You will have to handle the different orientation cases in your - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration method by detecting the current device orientation.
How to get all X,Y coordinates between two points.
I want to move a UIButton in a diagonal pattern in objective C.
Example. To move UIButton from position 'Point A' towards position 'Point B'.
.Point B
. Point A
Thanks in advance.
you can use Bresenham's line algorithm
Here is a slightly simplified version, I have used a bunch of times
+(NSArray*)getAllPointsFromPoint:(CGPoint)fPoint toPoint:(CGPoint)tPoint
{
/*Simplified implementation of Bresenham's line algoritme */
NSMutableArray *ret = [NSMutableArray array];
float deltaX = fabsf(tPoint.x - fPoint.x);
float deltaY = fabsf(tPoint.y - fPoint.y);
float x = fPoint.x;
float y = fPoint.y;
float err = deltaX-deltaY;
float sx = -0.5;
float sy = -0.5;
if(fPoint.x<tPoint.x)
sx = 0.5;
if(fPoint.y<tPoint.y)
sy = 0.5;
do {
[ret addObject:[NSValue valueWithCGPoint:CGPointMake(x, y)]];
float e = 2*err;
if(e > -deltaY)
{
err -=deltaY;
x +=sx;
}
if(e < deltaX)
{
err +=deltaX;
y+=sy;
}
} while (round(x) != round(tPoint.x) && round(y) != round(tPoint.y));
[ret addObject:[NSValue valueWithCGPoint:tPoint]];//add final point
return ret;
}
If you simply want to animate a UIControl from one location to another, you might want to use UIAnimation:
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^{
btn.center = CGPointMake(<NEW_X>, <NEW_Y>)
} completion:^(BOOL finished) {
}];
You should really use Core Animation for this. You just need to specify the new origin for your UIButton and Core Animation does the rest:
[UIView animateWithDuration:0.3 animations:^{
CGRect frame = myButton.frame;
frame.origin = CGPointMake(..new X.., ..new Y..);
myButton.frame = frame;
}];
For Swift 3.0,
func findAllPointsBetweenTwoPoints(startPoint : CGPoint, endPoint : CGPoint) {
var allPoints :[CGPoint] = [CGPoint]()
let deltaX = fabs(endPoint.x - startPoint.x)
let deltaY = fabs(endPoint.y - startPoint.y)
var x = startPoint.x
var y = startPoint.y
var err = deltaX-deltaY
var sx = -0.5
var sy = -0.5
if(startPoint.x<endPoint.x){
sx = 0.5
}
if(startPoint.y<endPoint.y){
sy = 0.5;
}
repeat {
let pointObj = CGPoint(x: x, y: y)
allPoints.append(pointObj)
let e = 2*err
if(e > -deltaY)
{
err -= deltaY
x += CGFloat(sx)
}
if(e < deltaX)
{
err += deltaX
y += CGFloat(sy)
}
} while (round(x) != round(endPoint.x) && round(y) != round(endPoint.y));
allPoints.append(endPoint)
}
This version of Bresenham's line algorithm works well with horizontal line:
+ (NSArray*)getAllPointsFromPoint:(CGPoint)fPoint toPoint:(CGPoint)tPoint {
/* Bresenham's line algorithm */
NSMutableArray *ret = [NSMutableArray array];
int x1 = fPoint.x;
int y1 = fPoint.y;
int x2 = tPoint.x;
int y2 = tPoint.y;
int dy = y2 - y1;
int dx = x2 - x1;
int stepx, stepy;
if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
dy <<= 1; // dy is now 2*dy
dx <<= 1; // dx is now 2*dx
[ret addObject:[NSValue valueWithCGPoint:CGPointMake(x1, y1)]];
if (dx > dy)
{
int fraction = dy - (dx >> 1); // same as 2*dy - dx
while (x1 != x2)
{
if (fraction >= 0)
{
y1 += stepy;
fraction -= dx; // same as fraction -= 2*dx
}
x1 += stepx;
fraction += dy; // same as fraction -= 2*dy
[ret addObject:[NSValue valueWithCGPoint:CGPointMake(x1, y1)]];
}
} else {
int fraction = dx - (dy >> 1);
while (y1 != y2) {
if (fraction >= 0) {
x1 += stepx;
fraction -= dy;
}
y1 += stepy;
fraction += dx;
[ret addObject:[NSValue valueWithCGPoint:CGPointMake(x1, y1)]];
}
}
return ret;
}
UPDATE: this is actually simple math find the point on the line made out of two points, here is my algo:
+ (NSArray*)getNumberOfPoints:(int)num fromPoint:(CGPoint)p toPoint:(CGPoint)q {
NSMutableArray *ret = [NSMutableArray arrayWithCapacity:num];
float epsilon = 1.0f / (float)num;
int count = 1;
for (float t=0; t < 1+epsilon && count <= num ; t += epsilon) {
float x = (1-t)*p.x + t*q.x;
float y = (1-t)*p.y + t*q.y;
[ret addObject:[NSValue valueWithCGPoint:CGPointMake(x, y)]];
count++;
}
// DDLogInfo(#"Vector: points made: %d",(int)[ret count]);
// DDLogInfo(#"Vector: epsilon: %f",epsilon);
// DDLogInfo(#"Vector: points: %#",ret);
return [ret copy];
}
I have create simple game. How can I increase the speed of ball. Please help!
-(void)BallMovement{
[self ComputerMovement];
[self Collision];
football.center = CGPointMake(football.center.x + X, football.center.y + Y);
if (football.center.x < 15) {
X = 0 - X;
}
if (football.center.x > 305) {
X = 0 - X;
}
if (football.center.y < 0) {
PlayerScoreNumber = PlayerScoreNumber + 1;
PlayerScore.text = [NSString stringWithFormat:#"%i", PlayerScoreNumber];
[timer invalidate];
StartButton.hidden = NO;
button.hidden = NO;
football.center = CGPointMake(147, 250);
clearly based on your code variable X is your velocity.
so just increase it. (example X +=0.1) based on some condition.
-(void)BallMovement{
X=X+1
[self ComputerMovement];
[self Collision];
football.center = CGPointMake(football.center.x + X, football.center.y + Y);
if (football.center.x < 15) {
X = 0 - X;
}
if (football.center.x > 305) {
X = 0 - X;
}
if (football.center.y < 0) {
I am making an application just for testing some codes. There is a ship that is shooting enemies. These enemies comes down from the top of the screen and they are added with this code (The reason why its 4 different enemies is that they all have different behaviors)
-(void) addEnemy {
int randomX = arc4random() % screenWidth;
Enemy* anEnemy;
int diceRoll = arc4random() % 4;
if (diceRoll == 0) {
anEnemy = [Enemy createEnemy:#"enemy1" framesToAnimate:24];
} else if (diceRoll == 1) {
anEnemy = [Enemy createEnemy:#"enemy2" framesToAnimate:17];
} else if (diceRoll == 2) {
anEnemy = [Enemy createEnemy:#"enemy3" framesToAnimate:14];
} else if (diceRoll == 3) {
anEnemy = [Enemy createEnemy:#"enemy4" framesToAnimate:24];
}
[self addChild:anEnemy z:depthLevelBelowBullet];
anEnemy.position = ccp ( randomX , screenHeight + 200);
numberOfEnemiesOnstage ++;
}
The enemies are being added with a random x-value which means enemies sometimes is half outside the screen. Like this:
How do limit the x-value from both sides of the screen so this won't happen?
You're not considering the image width when you're calculating the random x position. You have to move the randomX declaration and initialization after you've created the enemy objects so the textureRect property will be properly set.
int offset = (int)[Enemy textureRect].size.width / 2;
int randomX = (arc4random() % (screenWidth - (2 * offset))) + offset;
The above answer is correct but if you are using CCSprite it will be a little different. Try the following code:
-(void) addEnemy {
int randomX = arc4random() % screenWidth;
Enemy* anEnemy;
int diceRoll = arc4random() % 4;
int halfWidth;
if (diceRoll == 0) {
anEnemy = [Enemy createEnemy:#"enemy1" framesToAnimate:24];
halfWidth = anEnemy.contentSize.width/2;
} else if (diceRoll == 1) {
anEnemy = [Enemy createEnemy:#"enemy2" framesToAnimate:17];
halfWidth = anEnemy.contentSize.width/2;
} else if (diceRoll == 2) {
anEnemy = [Enemy createEnemy:#"enemy3" framesToAnimate:14];
halfWidth = anEnemy.contentSize.width/2;
} else if (diceRoll == 3) {
anEnemy = [Enemy createEnemy:#"enemy4" framesToAnimate:24];
halfWidth = anEnemy.contentSize.width/2;
}
if(randomX < halfWidth) {
randomX = halfWidth;
} else {
randomX = randomX-halfWidth;
}
[self addChild:anEnemy z:depthLevelBelowBullet];
anEnemy.position = ccp ( randomX , screenHeight + 200);
numberOfEnemiesOnstage ++;
}