Infinite x and y scroll of uiview - objective-c

I have a 1500x1500 uiview with a 1500x1500 uiimageview inside centered in the main view of my iPad project. The code below will infinitely scroll side to side when you tilt the iPad in either direction. What I have been trying to do is get it to also scroll up and down seamlessly like the side to side. Unfortunately it seems to jump around and not be correct. Any ideas?
- (void)accelerometer:(UIAccelerometer *)acel
didAccelerate:(UIAcceleration *)acceleration {
accelX = acceleration.x;
accelY = acceleration.y;
accelZ = acceleration.z;
int speed;
speed = 1;
imageView.center = CGPointMake(imageView.center.x+delta.x,imageView.center.y+delta.y);
// allows infinite side-to-side scrolling
if (imageView.center.x > 748){
imageView.center = CGPointMake(512,384);
NSLog(#"Greater than 780");
}
if (imageView.center.x < 284){
imageView.center = CGPointMake(519,384);
NSLog(#"Less than 284");
}
if (accelY > 0.01f) {delta.x = -speed;}
else if (accelY < -0.01f) {delta.x = speed;}
else if (0.01f < accelY > -0.01f){delta.x = 0;}
// should allow up/down infinite scrolling but does not - it is very jumpy when it resets
// if (imageView.center.y > 748){imageView.center = CGPointMake(512,384);}
// if (imageView.center.y < 284){imageView.center = CGPointMake(518,752);}
// this makes it run only with the angle of the iPad the way I want it
// if (accelZ > -0.5f) {delta.y = speed;}
// else if (accelZ < -0.1f) {delta.y = -speed;}
// else if (0.3f < accelZ > -0.3f){delta.y = 0;}
}

Related

Best way to do object collision?

I'm trying to do wall collision for objects and I've followed a tutorial that offers one method of doing collision.
This is the tutorial: https://www.youtube.com/watch?v=yZU1QJJdxgs
Currently, if the object detects a wall, instead of moving it's full distance, it moves pixel by pixel until it's against the wall. This worked well until I started trying to rotate the object with image_rotate, because it caused objects to get stuck in walls by either sliding against them or if they rotated into them.
I fixed this by using draw_sprite_ext instead and changing the rotation of the sprite itself and not the mask, which worked for about 20 minutes until it started causing more problems.
///obj_player Step
//Initialise Variables
hor_speed = 0;
ver_speed = 0;
accelerationspeed = 0.2;
decelerationspeed = 0.2;
maxspeed = 3;
pointdirection = 0;
//Get player's input
key_right = keyboard_check(ord("D"))
key_left = -keyboard_check(ord("A"))
key_up = -keyboard_check(ord("W"))
key_down = keyboard_check(ord("S"))
pointdirection = point_direction(x,y,mouse_x,mouse_y) + 270
hor_movement = key_left + key_right;
ver_movement = key_up + key_down;
//horizontal acceleration
if !(abs(hor_speed) >= maxspeed) {
hor_speed += hor_movement * accelerationspeed;
}
//horizontal deceleration
if (hor_movement = 0) {
if !(hor_speed = 0) {
hor_speed -= (sign(hor_speed) * decelerationspeed)
}
}
//vertical acceleration
if !(abs(ver_speed) >= maxspeed) {
ver_speed += ver_movement * accelerationspeed;
}
//vertical deceleration
if (ver_movement = 0) {
if !(ver_speed = 0) {
ver_speed -= (sign(ver_speed) * decelerationspeed)
}
}
//horizontal collision
if (place_meeting(x+hor_speed,y,obj_wall)) {
while(!place_meeting(x+sign(hor_speed),y,obj_wall)) {
x += sign(hor_speed);
}
hor_speed = 0;
}
//vertical collision
if (place_meeting(x,y+ver_speed,obj_wall)) {
while(!place_meeting(x,y+sign(ver_speed),obj_wall)) {
y += sign(ver_speed);
}
ver_speed = 0;
}
//move the player
x += hor_speed;
y += ver_speed;
///obj_player Draw
//rotate to look at cursor
draw_sprite_ext(spr_player, 0, x,y,image_xscale,image_yscale, pointdirection, image_blend, image_alpha);
I think the best way to rotate objects is through image_rotate, and I'd like to do it without getting stuff stuck in walls. Can my current method of collision be adapted to do this, or should I attempt to do it in a different way?
Your code looks fine, but if you're going to be rotating objects then you would also need to consider having a "knock back mechanic." Reason being is the player could be sitting next to this wall and if you rotate the object over them so they cant move, its not a fun time being stuck.
So you 'could' have the object that's rotating do a check before rotating and if objects are in the way then either stop it or push them back so they cant be within range.

Titanium: App locked to portrait, yet camera rotates, how to determine actual device orientation?

Appcelerator Titanium app, asking specifically about Android
Our app is locked to portrait mode:
android:screenOrientation="nosensor" is in the tiapp.xml
All windows have orientationModes: [Ti.UI.Portrait] set
Yet, when we show the camera (with an overlay), it is permitted to rotate. This means user photos can end up sideways or upside down. Unfortunately, because the app is locked to portrait mode, Ti.Gesture.orientation and myWindow.orientation always returns 1 (portrait) so we can't manually de-rotate the image.
How can I either a) lock the orientation of the camera, or b) find the actual device orientation so I can manually de-rotate the image?
The answer is to use the accelerometer.
function accelerometerCallback(e) {
var deviceOrientation;
// Get the current device angle
var xx = -e.x;
var yy = e.y;
var angle = Math.atan2(yy, xx);
if (angle >= -2.25 && angle <= -0.75) {
deviceOrientation = "portraitUpsideDown";
} else if (angle >= -0.75 && angle <= 0.75) {
deviceOrientation = "landscapeRight";
} else if (angle >= 0.75 && angle <= 2.25) {
deviceOrientation = "portrait";
} else if (angle <= -2.25 || angle >= 2.25) {
deviceOrientation = "landscapeLeft";
}
console.log('ACCELEROMETER: orientation = ' + deviceOrientation);
}
Ti.Accelerometer.addEventListener('update', accelerometerCallback);
myWin.addEventListener('close', function () {
Ti.Accelerometer.removeEventListener('update', accelerometerCallback);
});
Just keep in mind that the accelerometer listener fires like a bajillion times a second and is another drain on the battery. Make sure to remove the update listener as soon as you can.

SpriteKit make two force on a body with joint

The problem: I want balloons rise up in the air. They can collide with one another and they can rotate. With a gravitiy in upright direction that works fine.
But now I want to connect a basket to each balloon. Doing so will result in the basket "flying" up like the balloon. But in real life the basket should be "heavier" than the balloon, so it would always point downwards to earth.
How would I achieve that ?
One way to simulate a balloon with a basket is to set gravity to be in the downward direction to pull the basket toward the bottom of the scene and apply a buoyant force to the balloon to create lift. Here's an example of how to do that:
Define the constants
#define kRandMax 0x7fffffff
#define kNumBalloons 5
Create the balloons and baskets
self.physicsWorld.gravity = CGVectorMake(0, -3);
for (int i=0;i<kNumBalloons;i++) {
// Create a balloon near the bottom of the scene with a random x position
SKShapeNode *balloon = [SKShapeNode shapeNodeWithCircleOfRadius:16];
balloon.fillColor = [SKColor redColor];
balloon.name = #"balloon";
balloon.physicsBody.allowsRotation = NO;
CGFloat rand1 = arc4random_uniform(kRandMax) / (double)kRandMax;
// A value in (-view.frame.size.width/2, view.frame.size.width/2)
CGFloat xOffset = (rand1 - 0.5) * view.frame.size.width / 2;
balloon.position = CGPointMake (CGRectGetMidX(view.frame)+xOffset,
CGRectGetMinY(view.frame)+50);
balloon.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:16];
[self addChild:balloon];
// Create the basket
SKSpriteNode *basket = [SKSpriteNode spriteNodeWithColor:[SKColor brownColor] size:CGSizeMake(8, 8)];
basket.position = CGPointMake(balloon.position.x, balloon.position.y-24);
basket.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:basket.size.width/2];
[self addChild:basket];
// Connect the balloon and basket with an SKPhysicsJointPin
SKPhysicsJointPin *joint = [SKPhysicsJointPin jointWithBodyA:balloon.physicsBody
bodyB:basket.physicsBody anchor:balloon.position];
[self.physicsWorld addJoint:joint];
}
In the update method, apply a force to each balloon to create lift
-(void)update:(CFTimeInterval)currentTime {
// Apply buoyant force to all balloons in the scene
[self enumerateChildNodesWithName:#"//balloon" usingBlock:^(SKNode *node, BOOL *stop){
// Adjust force as needed
[node.physicsBody applyForce:CGVectorMake(0, 17.2)];
}];
}
Look into SKPhysicsBody documentations (can be found here).
Look into Defining a Body’s Physical Properties section.
Every physics body has properties (such as mass) that you want to play with, in order to get a more 'realistic' behaviour.
If you want a less general answer,
Post some code examples.
Good luck mate.
I have now a solution like this:
I create a forcefield going up
func createForceField(strength:Float) {
// add force field
for i in 1...9 {
let field = SKFieldNode.electricField()
field.physicsBody?.categoryBitMask = PhysikcsCategory.ForceField
field.position = CGPointMake(frame.size.width*0.1*CGFloat(i), -1000)
field.strength = strength
addChild(field)
}
}
Before starting the game I turn on gravity and forcefield
override init(size: CGSize) {
super.init(size: size)
// Set-Up forcefield
createForceField(0.1)
self.physicsWorld.gravity = CGVectorMake(0, -0.09)
startGame()
}
here I create the balloons with a rope and tag, the balloon is charged so it will react to the forcefield
func createBalloon(vokabel:Vokabel) {
let x = self.frame.width*0.2
let y = self.frame.height*0.2
// Balloon
var balloon = BalloonNode()
balloon.size = CGSizeMake(balloon.size.width*0.7, balloon.size.height*0.7)
balloon.position = CGPointMake(x-6,y)
balloon.name = "SPRITE"
balloon.vokabel = vokabel
balloon.score = 50
balloonLayer.addChild(balloon)
// Special Start
var specialStar = SKSpriteNode(imageNamed: "Star")
specialStar.size = CGSizeMake(balloon.size.width*0.7, balloon.size.height*0.7)
specialStar.hidden = true
specialStar.name = "STAR"
balloon.addChild(specialStar)
// Rope
let rope = SKSpriteNode(color: UIColor.blackColor(), size: CGSize(width: 2, height: 15))
rope.position = CGPointMake(x, y-balloon.size.height/2-rope.size.height/2)
rope.alpha = 0.2
balloonLayer.addChild(rope)
// Tag
var labelText = getLabelText(vokabel)
let tag = createTagWithText(labelText)
tag.position = CGPointMake(x, y-balloon.size.height/2-rope.size.height)
balloonLayer.addChild(tag)
self.physicsWorld.gravity=CGVectorMake(0.0, -0.3)
// physical bodies
balloon.physicsBody = SKPhysicsBody(rectangleOfSize: balloon.size)
rope.physicsBody = SKPhysicsBody(rectangleOfSize: rope.size)
tag.physicsBody = SKPhysicsBody(rectangleOfSize: tag.size)
// physical forces
balloon.physicsBody?.allowsRotation = false
balloon.physicsBody?.charge = 0.5
tag.physicsBody?.allowsRotation = false
tag.physicsBody?.linearDamping = 1.0
rope.physicsBody?.linearDamping = 1.0
// anchor Points
let anchorBalloonRope = CGPointMake(x, y-balloon.size.height/2)
let anchorRopeTag = CGPointMake(x, y-balloon.size.height/2-rope.size.height)
// create joints
let joint = SKPhysicsJointPin.jointWithBodyA(balloon.physicsBody, bodyB: rope.physicsBody, anchor: anchorBalloonRope)
let joint_rope_tag = SKPhysicsJointPin.jointWithBodyA(rope.physicsBody, bodyB: tag.physicsBody, anchor: anchorRopeTag)
// add joints to physic
self.physicsWorld.addJoint(joint)
self.physicsWorld.addJoint(joint_rope_tag)
// give it a horizontal push
balloon.physicsBody?.applyImpulse(CGVectorMake(10.0, 0.0))
// BalloonNode ( is just a layer, has no special position so it is the same coordinate system as the gamelayer)
let node = BalloonNode()
node.vokabel = vokabel
node.score = SCORE_STANDARD
node.name = "BALLOON"
node.rope = rope
node.tag = tag
}

Rendering painted lines as nodes in Cocos

I'm working on a drawing app for iPad using Cocos-iOS and I'm having performance issues with drawing lines as a type of CCNode. I understand that using draw in a node causes it to be called every time the canvas is repainted and the current code is very heavy if used every time:
for (LineNodePoint *point in self.points) {
start = end;
end = point;
if (start && end) {
float distance = ccpDistance(start.point, end.point);
if (distance > 1) {
int d = (int)distance;
float difx = end.point.x - start.point.x;
float dify = end.point.y - start.point.y;
for (int i = 0; i < d; i++) {
float delta = i / distance;
[[self.brush sprite] setPosition:ccp(start.point.x + (difx * delta), start.point.y + (dify * delta))];
[[self.brush sprite] visit];
}
}
}
}
Very heavy...
I either need a better way to draw the lines or to be able to cache the drawing as a raster.
Thanks in advance for any help.
How about ccDrawLine or CCMutableTexture? CCMutableTexture is for manipulating pixels using CCRenderTexture internally as you said.
ccDrawLine
cocos2d for iPhone 1.0.0 API reference
CCMutableTexture
Fast set/getPixel for an opengl texture?
[render texture] pixel manipulation (integrated CCMutableTexture functionality)

Pathfinding / Deciding on direction

i'm making a simple iPhone game using cocos2d-iphone. I have an array of fiends, the "fiendSet" which has to navigate around a field full of obstacles. I spent the last three nights trying to get my A* pathfinding to work. I found the actual A* implementation here on stackoverflow and it works brilliantly. However, once i try to move my fiends around i run into trouble.
Each of my fiends has a CGPoint called motionTarget which contains the x and y values for where the fiend has to go. If only set the positions x and y to absolute values once a second, it works, like so:
-(void) updateFiendPositions:(ccTime)dt {
for (MSWFiend *currFiend in fiendSet) {
currFiend.position = ccp(currFiend.motionTarget.x,currFiend.motionTarget.y);
}
}
However, this doesn't look very nice, the fiends just "jump" 20px each second instead of animating nicely. I only implemented this as a placeholder method to verify the pathfinding. Now i want smooth animation. This is what i did:
-(void) updatePositions:(ccTime) dt {
for (MSWFiend *currFiend in fiendSet) {
if (currFiend.motionTarget.x != -1 && currFiend.motionTarget.y != -1) {
float x,y;
if ((int)floor(currFiend.position.x) < (int)floor(currFiend.motionTarget.x)) {
x = currFiend.position.x+(currFiend.speed*dt);
}
if ((int)floor(currFiend.position.x) > (int)floor(currFiend.motionTarget.x)) {
x = currFiend.position.x-(currFiend.speed*dt);
}
if (abs((int)floor(currFiend.position.x)-(int)floor(currFiend.motionTarget.x)) < 2) {
x = currFiend.motionTarget.x;
}
if ((int)floor(currFiend.position.y) < (int)floor(currFiend.motionTarget.y)) {
y = currFiend.position.y+(currFiend.speed*dt);
}
if ((int)floor(currFiend.position.y) > (int)floor(currFiend.motionTarget.y)) {
y = currFiend.position.y-(currFiend.speed*dt);
}
if (abs((int)floor(currFiend.position.y)-(int)floor(currFiend.motionTarget.y)) < 2) {
y = currFiend.motionTarget.y;
}
currFiend.position = ccp(x,y);
}
}
}
This works great for fiends moving in one direction. As soon as a fiend is supposed to go around a bend, trouble starts. Instead of for example first going up, then right, then down; my fiends will combine the up/right motion into one, they are "cutting corners". I only want my fiends to move either north/south OR east/west for each position update, not both. In other words, i don't want to animate changes to x and y simultaneously. I hope this explanation is clear enough..
I'm pretty sure i have a logic error somewhere.. i just havn't been able to figure it out for the last three sleepless nights after work.. Help!
You have to keep track of each node in the path to the target. That way you only animate the motion to the next node. Also you can use a CCMoveTo action instead on doing the animation yourself.
#Aleph thanks for your suggestion. I found that it was the code which determines when to assign a new motionTarget, that was faulty, not the code i posted to begin with. When you mentioned keeping track of each nodes position, i thought of my motionTarget determination code and found the error after 2-3 hours. I ended up doing it like this:
-(void) updatePositions:(ccTime) dt {
for (MSWFiend *currFiend in fiendSet) {
int fiendGX,fiendGY,targetGX,targetGY,dGX,dGY;
float x,y,snappedX,snappedY;
BOOL snappedIntoPosition = FALSE;
fiendGX = (int)round(100.0f*(currFiend.position.x/20));
fiendGY = (int)round(100.0f*(currFiend.position.y/20));
targetGX = (int)round(100.0f*(currFiend.motionTarget.x/20));
targetGY = (int)round(100.0f*(currFiend.motionTarget.y/20));
snappedX = currFiend.position.x;
snappedY = currFiend.position.y;
dGX = abs(fiendGX-targetGX);
dGY = abs(fiendGY-targetGY);
float snappingThreshold; //1 = snap when 0.1 from motionTarget.
snappingThreshold = currFiend.speed/10;
if (dGX < snappingThreshold && dGY < snappingThreshold) {
snappingThreshold = currFiend.motionTarget.x;
snappingThreshold = currFiend.motionTarget.y;
int newPathStep;
newPathStep = currFiend.pathStep + 1;
currFiend.pathStep = newPathStep;
}
int gX,gY;
gX = [[currFiend.path objectAtIndex:currFiend.pathStep] nodeX];
gY = (tileMap.mapSize.height-[[currFiend.path objectAtIndex:currFiend.pathStep] nodeY])-1;
currFiend.motionTarget = ccp(gX*20,gY*20); //Assign motion target to the next A* node. This is later used by the position updater.
if (currFiend.motionTarget.x != -1 && currFiend.motionTarget.y != -1) {
x = currFiend.motionTarget.x;
y = currFiend.motionTarget.y;
if ((int)floor(currFiend.position.x) < (int)floor(currFiend.motionTarget.x)) {
//Move right
x = snappedX+(currFiend.speed*dt);
if (x > currFiend.motionTarget.x) {
x = currFiend.motionTarget.x;
}
y = snappedY;
}
if ((int)floor(currFiend.position.x) > (int)floor(currFiend.motionTarget.x)) {
//Move left
x = snappedX-(currFiend.speed*dt);
if (x < currFiend.motionTarget.x) {
x = currFiend.motionTarget.x;
}
y = snappedY;
}
if ((int)floor(currFiend.position.y) < (int)floor(currFiend.motionTarget.y)) {
//Move up
y = snappedY+(currFiend.speed*dt);
if (y > currFiend.motionTarget.y) {
y = currFiend.motionTarget.y;
}
x = snappedX;
}
if ((int)floor(currFiend.position.y) > (int)floor(currFiend.motionTarget.y)) {
//Move down
y = snappedY-(currFiend.speed*dt);
if (y < currFiend.motionTarget.y) {
y = currFiend.motionTarget.y;
}
x = snappedX;
}
}
currFiend.position = ccp(x,y);
}
}