cocos2d moving objects - iphone

Im trying to move an object around the screen like in the game geometry wars. I can rotate the object just fine, however I cant seem to get it to move based on the direction it is facing. I have this code here which i think is right for doing this but I keep getting syntax errors:
spriteObject.x = spriteObject.x + speed*cos(Angle)
spriteObject.y = spriteObject.y + speed*sin(Angle)
The errors are 'request for member x not in struct or union.' How do you do this in Objective-c/cocos2d syntax?

Looking at the documentation for the sprite class, you would need to do the following:
float angle = spriteObject.rotation
spriteObject.position.x = spriteObject.position.x + speed*cos(angle)
spriteObject.position.y = spriteObject.position.y + speed*sin(angle)
edit (in response to comment):
I see that you are programming for the iPhone, which means you need to be using the iphone cocos2d library, and not the one I linked to before.
The syntax will be different, as will the example code, since the iPhone version uses the Objective-C langugage, whereas the original cocos2d uses Python.
Google code has good documentation on the iPhone version of cocos2d, including sample code.
Based on that sample code, you will have to do the following:
float newX = spriteObject.position.x + speed * cos(angle);
float newY = spriteObject.position.y + speed * sin(angle);
spriteObject.position = ccp( newX, newY );

Related

Unity - Looking through the scope of a gun

Right now I have 2 Cameras: the main camera displays the gun at its normal state and a second camera is attached to the gun (the gun is a child of the main camera) and when toggled it looks through the scope of the gun and increases the field of view.
Heres a visual for a better understanding:
Now if I were to just toggle the second camera on and turn the main camera off, this would work splendid, but it's not very ideal. You should only have 1 camera per scene.
So I want to Lerp the position of the camera to look through the scope and manually decrease the fieldofview. So I have written the following script:
[RequireComponent(typeof(Camera))]
public class Zoom : MonoBehaviour {
private Transform CameraTransform = null;
public Transform ZoomedTransform;
private bool zoomed = false;
void Start () {
CameraTransform = Camera.main.transform;
}
// Update is called once per frame
void Update () {
if (Input.GetKey (KeyCode.LeftShift))
{
CameraTransform.position = Vector3.Lerp (
CameraTransform.position,
CameraTransform.position + ZoomedTransform.position,
5f * Time.deltaTime
);
CameraTransform.Rotate(ZoomedTransform.rotation.eulerAngles);
}
}
}
The problem with this is that it doesn't work: when I hit the zoom button, the camera speeds through the scene at the speed of light and it's hard to tell exactly what is going on.
Could anyone give me some insight as to what I'm doing wrong? I think it is something to do with the parent-child relationship, but even when I've tried using static values, I cannot seem to replicate the correct solution.
Hierarchy:
(This answer operates under the assumption that ZoomedTransform is a relative transformation, and not the absolute position of the camera as suspected by 31eee384's answer.)
I think there are a couple issues with your code. I'll tackle them individually so they're easier to understand, but they both relate to the following line:
CameraTransform.position = Vector3.Lerp (CameraTransform.position, CameraTransform.position + ZoomedTransform.position, 5f * Time.deltaTime);
First, let's look at how you're using Vector3.Lerp(). For the third argument of Vector3.Lerp(), you're supplying 5f * Time.deltaTime. What exactly does this value work out to? Well, the standard framerate is about 60 FPS, so Time.deltaTime = ~1/60. Hence, 5f * Time.deltaTime = 5/60 = ~0.0833.
What is Vector3.Lerp() expecting for the third argument, though? According to the documentation, that third argument should be between 0 and 1, and determines whether the returned Vector3 should be closer to the first or second given Vector3. So yes, 5f * Time.deltaTime falls within this range, but no interpolation will occur - because it will always be around ~0.0833, rather than progressing from 0 to 1 (or 1 to 0). Each frame, you're basically always getting back cameraPos + zoomTransform * 0.0833.
The other notable problem is how you're updating the value of CameraTransform.position every frame, but then using that new (increased) value as an argument for Vector3.Lerp() the next frame. (This is a bit like doing int i = i + 1; in a loop.) This is the reason why your camera is flying across the map so fast. Here is what is happening each frame, using the hypothetical result of your Vector3.Lerp() that I calculated earlier (pseudocode):
// Frame 1
cameraPosFrame_1 = cameraPosFrame_0 + zoomTransform * 0.0833;
// Frame 2
cameraPosFrame_2 = cameraPosFrame_1 + zoomTransform * 0.0833;
// Frame 3
cameraPosFrame_3 = cameraPosFrame_2 + zoomTransform * 0.0833;
// etc...
Every frame, zoomTransform * 0.0833 gets added to the camera's position. Which ends up being a really, really fast, and non-stop increase in value - so your camera flies across the map.
One way to address these problems is to have variables that stores your camera's initial local position, zoom progress, and speed of zoom. This way, we never lose the original position of the camera, and we can both keep track of how far the zoom has progressed and when to stop it.
[RequireComponent(typeof(Camera))]
public class Zoom : MonoBehaviour {
private Transform CameraTransform = null;
public Transform ZoomedTransform;
private Vector3 startLocalPos;
private float zoomProgress = 0;
private float zoomLength = 2; // Number of seconds zoom will take
private bool zoomed = false;
void Start () {
CameraTransform = Camera.main.transform;
startLocalPos = CameraTransform.localPosition;
}
// Update is called once per frame
void Update () {
if (Input.GetKey (KeyCode.LeftShift))
{
zoomProgress += Time.deltaTime;
CameraTransform.localPosition = Vector3.Lerp (startLocalPos, startLocalPos + ZoomedTransform.position, zoomProgress / zoomLength);
CameraTransform.Rotate(ZoomedTransform.rotation.eulerAngles);
}
}
}
Hope this helps! Let me know if you have any questions. This answer does ramble a little, so I hope you don't have any trouble getting the important points from it.
Your lerp target is relative to the camera's current position, so it's constantly moving. This is the target you have:
CameraTransform.position + ZoomedTransform.position
This means that as your camera moves to get closer to this position, the camera's new position causes the destination to change. So your camera keeps moving forever.
Your destination should be ZoomedTransform.position. No addition is necessary because position is in world coordinates. (And when you actually need to convert between spaces, check out TransformPoint and similar methods.)
It has been a while since I have done anything in Unity, but I think it is processing the Lerp function at frame time and not at actual time. You will need to call it in another function that is not being processed at frame time.

IK Angle Constraints Swift

I am trying to set angle constraints for body parts in Swift 2.0.
I have tried to automatically set them in the scene editor under IK Constraints and this failed.
I subsequently set them in the code:
lowerArmBack.reachConstraints?.lowerAngleLimit = 0
lowerArmBack.reachConstraints?.upperAngleLimit = CGFloat(10)
Neither has worked (with or without CGFloat). I am trying to follow this tutorial: http://www.raywenderlich.com/80917/sprite-kit-inverse-kinematics-swift but have stumbled in to issues since the Swift update.
Essentially I want to limit angles to prevent the arms moving in all 360 degrees but this isn't happening.
You need to set a zRotation constraint with a range for the body part you want:
let range = SKRange(lowerLimit: CGFloat(0).degreesToRadians(),
upperLimit: CGFloat(160).degreesToRadians())
let rotationConstraint = SKConstraint.zRotation(range)
lowerArmFront.constraints = [rotationConstraint]
Regarding the tutorial, I'm actually working on it's update fixing the issue.
You can also add a SKReachConstraint in the following way:
lowerLeg.reachConstraints = SKReachConstraints(lowerAngleLimit: CGFloat(-45).degreesToRadians(), upperAngleLimit: 0)
upperLeg.reachConstraints = SKReachConstraints(lowerAngleLimit: CGFloat(-45).degreesToRadians(), upperAngleLimit: CGFloat(160).degreesToRadians())
Hope it helps!

CLLocation - Find magnetic declination / deviation at another location

I know how to find the true heading/magnetic heading for the location my phone is currently at, but is it possible to find the magnetic deviation/declination for a remote location?
What I would like to do is be able to drop a pin at a place on the map and find both the true bearing and the bearing with magnetic variance from that point.
Thanks!
The code to calculate this must already exist in a framework somewhere since it's used by CLHeading when location services are available.
If anyone can find that code or has Objective C for the world magnetic model posting it would be appreciated.
UPDATE: I found a great open source iOS wrapper! Thanks Crookneck!
https://github.com/stephent/ObjectiveWMM
Simple installation as a git submodule
run this command:
$git submodule add https://github.com/stephent/ObjectiveWMM.git ObjectiveWMM
Add these files to your Xcode project:
CCMagneticDeclination.h
CCMagneticDeclination.m
CCMagneticModel.h
CCMagneticModel.m
NSDate+DecimalYear.h
NSDate+DecimalYear.m
WMM/EGM9615.h
WMM/GeomagnetismHeader.h
WMM/GeomagnetismLibrary.c
WMM/WMM.COF
Have you solved it? Otherwise you can calculate the azimuth angle of the remote location. Firstly with magnetic north heading and then with true north heading. Finally you subtract the two to get the magnetic deviation.
Here is how to calculate an azimuth angle for a remote location:
-(float)azimuthFromLocations:(CLLocationCoordinate2D)first toCoordinate:(CLLocationCoordinate2D)second{
float longitudeDifference = second.longitude - first.longitude;
float latitudeDifference = second.latitude - first.latitude;
float possibleAzimuth = (M_PI * .5f) - atan(latitudeDifference / longitudeDifference);
if (longitudeDifference > 0)
return possibleAzimuth;
else if (longitudeDifference < 0)
return possibleAzimuth + M_PI;
else if (latitudeDifference < 0)
return M_PI;
return 0.0f;
}
I needed the same solution in Swift, based on the World Magnetic Model.
Here is my implementation:
https://github.com/kanchudeep/Geomagnetism-Swift
It's a simple single class which can be dropped into any project and used.

Monsters/Enemies on Platforms(like on Doodlejump)Cocos2d

I'm new here so i hope you can help me.
I am following a tutorial on making simple cocos2d game
Ray Wenderlich's Tutorial
I implemented it on another game a jumping one like doodle jump.
in the said tutorial the monsters/targets are moving freely coming from the right to the left side of the screen. when i implement it on my app the monsters are like flying from left to right. What if i want the monsters to stand on the platforms just like the one on doodle jump? what particular things will i do?
PS:i tried some other things on google but none works
Here is the code of the monsters/targets:
- (void)initPlatforms {
// NSLog(#"initPlatforms");
currentPlatformTag = kPlatformsStartTag;
while(currentPlatformTag < kPlatformsStartTag + kNumPlatforms) {
[self initPlatform];
currentPlatformTag++;
}
[self resetPlatforms];
}
- (void)initPlatform {
CGRect rect;
switch(random()%2) {
case 0: rect = CGRectMake(608,64,102,36); break;
case 1: rect = CGRectMake(608,128,90,32); break;
}
AtlasSpriteManager *spriteManager = (AtlasSpriteManager*)[self getChildByTag:kSpriteManager];
AtlasSprite *platform = [AtlasSprite spriteWithRect:rect spriteManager:spriteManager];
[spriteManager addChild:platform z:3 tag:currentPlatformTag];
}
-(void)addTarget {
Sprite *target = [Sprite spriteWithFile:#"komodo.png"];
target.position = ccp(300,200);
[self addChild:target];
CGSize winSize = [[Director sharedDirector]winSize];
int minX = target.contentSize.height/2;
int maxX = winSize.height -target.contentSize.height/2;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX) +minX;
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minDuration;
int actualDuration = (arc4random() % rangeDuration) + minDuration;
id actionMove = [MoveTo actionWithDuration:actualDuration position:ccp(-target.contentSize.width,actualX)];
id actionMoveDone = [CallFuncN actionWithTarget:self selector:#selector(spriteMoveFinished:)];
[target runAction:[Sequence actions:actionMove, actionMoveDone,nil]];
target.tag = 1;
[_targets addObject:target];
}
Thanks to those who will help... you are so nice.
This is a pretty broad question unfortunately, which makes it difficult to answer in any definitive terms. If you are hoping to create actual platforms that can be bounced on (in a doodle jump manner) you are going to need to implement collision detection between the Monsters and the Platform ccNodes. There are numerous tutorials online for cocos2d collision detection, both simple implementation and the more advanced box 2d/chipmunk based solutions.
If you are looking to clone doodle jump fairly closely, there is an open source version of a clone available on github here - though I've not actually looked at the code.
Finally, if you mean that you simply want to restrict the movement of the monsters to a particular area of the screen (so they don't keep running off the edge) you just need to position the target to an area on the screen and alter theccAction so that the ccMoveTo uses the left most point of the 'platform' as the furthest point left it can move to and the right most point as the furthest right. (I'll confess I've not played Doodle Jump so have no idea what the enemies actually do).
If the enemies run back and forth across the platform you should look into using ccRepeatForever on your movement sequence and have two destination positions in the CCSequence : one that moves the monster to the left of the platform, the other to move it to the right.
Additional Info
Ok, I see what you are trying to do. This should get you started:
Platforms are created in initPlatforms. This calls initPlatform a number of times. This grabs an image from the AtlasSprite for the platform, creates a ccSprite for each platform and assigns it a unique tag.
Then, in - (void)step:(ccTime)dt it loops through all the platforms and moves them to their correct location based on how far the bird has moved:
for(t; t < kPlatformsStartTag + kNumPlatforms; t++) {
AtlasSprite *platform = (AtlasSprite*)[spriteManager getChildByTag:t];
//etc...
So, the bit you are waiting for:
If you want to add a monster to these platforms, you will have to follow a similar pattern. To get started try something like this (You will want to have a cleaner design than this though but it should put you on the right track)
in initPlatform add the following to the end of the function
// add a monster sprite
AtlasSprite *monster = [AtlasSprite spriteWithRect:CGRectMake(608,128,64,64) spriteManager:spriteManager];
[spriteManager addChild:monster z:3 tag:currentPlatformTag + 1000];
(I've just grabbed an image from the existing Atlas. You could replace the above with your actual 'Monster' sprite object. Notice I add 1000 to thecurrentPlatformTag. This is just for testing; you should have a monsterTag implementation eventually.
So now every platform has a 'monster' (Again, you will only want to target random platforms)
so we need to update the positions for the monsters.
In - (void)step:(ccTime)dt directly after you get the current platform
AtlasSprite *platform = (AtlasSprite*)[spriteManager getChildByTag:t];
You now also need to get the current monster (remembering to use the updated tag value we created for 'monsters':
AtlasSprite *monster = (AtlasSprite*)[spriteManager getChildByTag:t + 1000];
Then, a few lines below where we reposition the platform we will need to reposition the monster
platform.position = pos;
// We update the monster and set it a 32 pixels above the platform:
monster.position = ccp(pos.x, pos.y + 32);
So now each platform has a monster on it whose y position moves with the the platforms :-)
Hope this helps

determine if a sprite is on screen or not in cocos2d

i want to determine if the sprite is in the screen or not in cocos2d.
am using the code some thing like these.
CGSize winSize = [CCDirector sharedDirector].winSize;
if (_SmallBlueAlien1.position.x> 0 || _SmallBlueAlien1.position.x > winSize.width || _SmallBlueAlien1.position.y> 0 || _SmallBlueAlien1.position.y > winSize.height)
{
//Sprite is not in the screen)
}
but not working properly. were am mistaking.
correct me
Unless you changed the anchor point of the sprite this is only testing if half of the sprite is on the screen. To fix this you want to check if
_SmallBlueAlien1.position.x > [_SmallBlueAlien1 contentSize].texture.width / 2;
You can follow this process for all the other interactions.
//Edit
As phix23 noted this does not account for rotation or scale but should work if you are doing neither of those.
regardless of the semantics of 'position' in coco, your '>' should be '<' for both x and y, assuming your interpretation of the .position property holds. It is likely however that the 'sprite'.position is in reference to an enclosing object, thus even when your test is corrected, it may still not give you what you want to know ('visible on screen').

Categories