Cocos2dx v.3.0 Portrait Mode - c++

Hey I am developing a Cocos2dx application with XCode and iPhone 5c and I am looking to change the coordinate system to portrait.
I looked at these directions http://www.cocos2d-x.org/wiki/Device_Orientation. According to the direction, you need to change a couple of methods in the RootViewController so that before Cocos does its magic, iOS has already handled rotating the container.
Now the applicable methods of my RootViewController.mm look as follows. It builds and runs.
#ifdef __IPHONE_6_0
- (NSUInteger) supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
#endif
- (BOOL) shouldAutorotate {
return YES;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return UIInterfaceOrientationIsPortrait ( interfaceOrientation );
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
auto glview = cocos2d::Director::getInstance()->getOpenGLView();
if (glview)
{
CCEAGLView *eaglview = (__bridge CCEAGLView *)glview->getEAGLView();
if (eaglview)
{
CGSize s = CGSizeMake([eaglview getWidth], [eaglview getHeight]);
cocos2d::Application::getInstance()->applicationScreenSizeChanged((int) s.width, (int) s.height);
}
}
}
#end
The code for the init() method of my level looks like this
bool Level1::init()
{
//////////////////////////////
// 1. super init first
if ( !Scene::init() )
{
return false;
}
auto visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
for(int i= 0; i < MAX_TOUCHES; ++i) {
labelTouchLocations[i] = Label::createWithSystemFont("", "Arial", 42);
labelTouchLocations[i]->setVisible(false);
this->addChild(labelTouchLocations[i]);
}
auto eventListener = EventListenerTouchAllAtOnce::create();
// Create an eventListener to handle multiple touches, using a lambda, cause baby, it's C++11
eventListener->onTouchesBegan = [=](const std::vector<Touch*>&touches, Event* event){
// Clear all visible touches just in case there are less fingers touching than last time
std::for_each(labelTouchLocations,labelTouchLocations+MAX_TOUCHES,[](Label* touchLabel){
touchLabel->setVisible(false);
});
// For each touch in the touches vector, set a Label to display at it's location and make it visible
for(int i = 0; i < touches.size(); ++i){
labelTouchLocations[i]->setPosition(touches[i]->getLocation());
labelTouchLocations[i]->setVisible(true);
labelTouchLocations[i]->setString("Touched");
std::cout << "(" << touches[i]->getLocation().x << "," << touches[i]->getLocation().y << ")" << std::endl;
}
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(eventListener, this);
return true;
}
When I touch the point at the lowest left part of the iPhone, the x coordinate of the touch point I print out is about 150. The y coordinate is 0, as expected. Why is the x coordinate not zero? Is there something I am missing in the creation of the scene? I believe I made all the changes that the Cocos documentation requires. Are their docs out of date?

The coordinate system does not start at (0,0) at the bottom left as would be suggested by the documentation. However, there are simple methods that can be used to get the origin and size of the container that are included in the default scene.
auto visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();

Related

Cocos 2dx game increasing in memory every time a scene transition occurs

I am making a cocos 2dx game. But each time the memory increases with every level transition. For debugging purposes I am calling the same scene again and again on touch event. Each level is generated by changing the parameters for the folowing code. Initially I thought that the memory was increasing because there were more objects in the higher levels, but even when calling the same level, memory occupied is increasing.
#include "GameScene.h"
#include "MainMenuScene.h"
#include "GameOverScene.h"
#include "Levels.h"
#define COCOS2D_DEBUG 1
USING_NS_CC;
float theta=0;
int r=0;
int levelNo=0;
int controlable=0; // flag to check if user can controll the ball or not
int rMax=0; // max radius of circle
float objectTime; // stores the inverse of speed
int secondCount=0; // second han value in the timer
int minuteCount=0; //minute hand clock in the timer
float obstacleSpeed=0;
Label *timer;
GameScene::~GameScene()
{
rotationPoint->removeAllChildrenWithCleanup(true);
obstacleRotationPoint->removeAllChildrenWithCleanup(true);
this->removeAllChildrenWithCleanup(true);
}
Scene* GameScene::createScene(int level)
{
// 'scene' is an autorelease object
auto scene = Scene::create();
controlable=0;
r=0;
theta=0;
// 'layer' is an autorelease object
levelNo=level;
rMax=levels[levelNo].ringCount * 15; //setting various parameters
obstacleSpeed =levels[levelNo].obstacleSpeed;
objectTime=1.0/levels[levelNo].speed;
secondCount=0; minuteCount=0;
auto layer = GameScene::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool GameScene::init()
{
//////////////////////////////
// 1. super init first
if ( !Layer::init() )
{
return false;
}
controlable=0;
distance=rMax;
visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
#if COMPILE_FOR_MOBILE == 1
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(GameScene::onTouchBegan, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
#endif
goal = DrawNode::create();
goal->drawDot(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y), 5, Color4F(100,0,0,1));
this->addChild(goal,1); // drawing the goal
rotationPoint = Node::create();
rotationPoint->setPosition(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y);
this->addChild(rotationPoint, 2);
//Setting the exit button
auto exitLabel = Label::createWithTTF("Exit","fonts/Marker Felt.ttf",10);
exitButtonWidth=exitLabel->getContentSize().width;
exitButtonHeight=exitLabel->getContentSize().height;
exitLabel->setPosition(Point(visibleSize.width-exitButtonWidth,visibleSize.height-exitButtonHeight));
this->addChild(exitLabel);
//setting the clock
timer = Label::createWithTTF("00:00","fonts/Marker Felt.ttf",10);
timer->setPosition(Point(timer->getContentSize().width,visibleSize.height-timer->getContentSize().height));
this->schedule(schedule_selector(GameScene::updateClock),1.0f); //scedule to call upDateClock function every 1.0 sec
this->addChild(timer);
obstacleRotationPoint = Node::create();
obstacleRotationPoint->setPosition(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y);
this->addChild(obstacleRotationPoint, 3);
float theta=0;
snake[0] = DrawNode::create();
snake[0]->drawDot(Vec2(0,0),3,Color4F(100,110,0,1));
theta+=2*M_PI/150;
//this->addChild(snake[0],2);
rotationPoint->addChild(snake[0]);
// fixedPoint->addChild(snake[0]);
//loop to draw the concentric circles
for(r=15;r<=rMax;r+=15)
{
for(theta=0;theta<=2*M_PI;theta+=2*M_PI/r){
pathNode = DrawNode::create();
pathNode->drawDot(Vec2(r*cos(theta)+origin.x+visibleSize.width/2,r*sin(theta)+origin.y+visibleSize.height/2),1,Color4F(0,0,10,1));
//pathNode->autorelease();
this->addChild(pathNode,1);
//this->removeChild(pathNode);
}
}
controlable=0;
this->scheduleUpdate();
return true;
}
bool GameScene::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event)
{ // check if exit button region was clicked
_eventDispatcher->removeAllEventListeners();
auto scene = GameScene::createScene(levelNo);
Director::getInstance()->replaceScene(scene);
return true;
}
//function updates every frame
void GameScene::update(float dt){
}
The last part in the init function where I need to add pathNode is increasing my memory requirement everytime I transition a scene. I believe I am releasing everything in my destructor.
First of all, I don't recommend using global variables, which you have on top of your file (especially timer label). You should keep everything in class.
Second, you should check whether destructor is called in the first place.
Third, you can also try using some "Loading" screen between two levels and clean all unused textures like this:
setOnExitCallback([&](){
Director::getInstance()->getTextureCache()->removeUnusedTextures();
});
Fourth, I'd recommend to not recreate GameScene at all, but create function like restartLevel() and loadLevel() and just remove unnecessary stuff there and load new one.

Can not scroll when add 2 CCScrollLayer in a layer

I'm using CCScrollLayer files at here CCScrollLayer for my cocos2d-x project (version 2.2.2).
I adapted them to make it can scroll vertically. And I got a problem: when I add two CCScrollLayer in a layer, I just can only scroll the last CCScrollLayer that are added.
Here is my code:
I add a layer that contains the two CCScrollLayer to a Scene
void ChooseMapScene::addSlidingLayers()
{
mChooseCharacterLayer = createChooseCharaterLayer();
mChooseCharacterLayer->setPosition(CCPointZero);
mChooseCharacterLayer->setTouchEnabled(true);
this->addChild(mChooseCharacterLayer, GR_FOREGROUND);
}
I add SlideCharacter1 and SlideCharacter2 in a layer (chooseCharacterLayer) but just the SlideCharacter2 can scroll
CCLayer* ChooseMapScene::createChooseCharaterLayer()
{
CCLayer* chooseCharacterLayer = CCLayer::create();
CCArray* characterArr1 = createCharactersArray(CHARACTER_LEFT_LAYER_POS);
CCArray* characterArr2 = createCharactersArray(CHARACTER_RIGHT_LAYER_POS);
mSlideCharacter1 = CCScrollLayerVertical::nodeWithLayers(characterArr1, 0);
chooseCharacterLayer->addChild(mSlideCharacter1, GR_FOREGROUND);
mSlideCharacter2 = CCScrollLayerVertical::nodeWithLayers(characterArr2, 0);
chooseCharacterLayer->addChild(mSlideCharacter2, GR_FOREGROUND);
// I add SlideCharacter1 and SlideCharacter2 in a layer (chooseCharacterLayer) but just the SlideCharacter2 can scroll
return chooseCharacterLayer;
}
.
CCArray* ChooseMapScene::createCharactersArray(CCPoint pPos)
{
CCArray* characterArr = CCArray::createWithCapacity(NUMBER_CHARACTERS);
for (int i = 1; i <= NUMBER_CHARACTERS; ++i)
{
CCLayer* characterLayer = CCLayer::create();
CCSprite* character = CCSprite::create(CCString::createWithFormat("Images/Game/Object/c%i.png", i)->getCString());
character->setPosition(pPos);
characterLayer->addChild(character, GR_FOREGROUND, i);
characterArr->addObject(characterLayer);
}
return characterArr;
}
You can manually call SlideCharacter1's touch methods (began, cancelled, moved, ended) from SlideCharacter2's touch methods to simulate the touches

How do I set up an if statement to animate a sprite?

How can I set up an if statement so after every frame the sprite shows the next frame and then the next and then once it goes through all the frames it is over?
I tried using if statements and it has never worked for me, could anyone give an example?
Edit:
After demand for code I have decided to add a sample.
int frame4 = 1;
if(frame4 = 1)
{
WalkDownFrame1(); //Renders frame 4
}
else if(frame4 = 2)
{
WalkDownFrame2(); //Renders frame 2
}
else if(frame4 = 3)
{
WalkDownFrame3(); //Renders frame 3
}
else if(frame4 = 4)
{
WalkDownFrame4(); //Renders frame 4
}
else if(frame4 = 5)
{
frame4 = 1;
}
frame4++;
no matter what modifications I apply it stays stuck on one frame.
I'm assuming you mean if the conditions are true the animation occurs and if the conditions are false it stops, in which case it would look like
/*Rest of your model transformation code*/
if(shouldbeanimating){
/*animation code*/
}else{
/*default state or nothing if you want the model to
freeze at that point in the animation*/
}
Then whenever the program should stop the animation you just set shouldbeanimating to false
Well, you need to know how many frames your animation has. Then you proceed to draw frame after frame. If you hit the last frame you go back to the first or you stop.
Here's a link that will help you. It's doesnt matter if its SDL or any other lib, the approach is always the same.
http://lazyfoo.net/SDL_tutorials/lesson20/index.php
As an example
while(isAnimating)
{
framecounter++;
isAnimating = (framecounter < MAX_FRAMES);
}
They're many solutions. You can do a Sprite Class and add an attribute _tick, store your Texture into a container, like a std::vector. I'll give you a short hint. You put a method tick() to increment your tick number. You put an attribute nbFrames, that contains the number of frames for the current sprite.
int tick;
int nbFrames; //equivalent of textures.size()
std::vector<SDL_Texture*> textures;
SDL_Texture *idle_frame;
bool moving;
int x;
int y;
Sprite::Sprite()
{
_tick = 0;
//init your textures
moving = false;
x = 0;
y = 0;
}
int _tick;
void Sprite::tick(void)
{
// Consider that _tick can reach the Max Value of int32
_tick++;
}
void Sprite::render(void)
{
SDL_Texture *texture;
if(moving)
{
int fr_index = _tick % nbFrames;
texture = textures[fr_index];
}
else
{
texture = idle_frame;
}
//then you do your render code with SDL_RenderCopy, or OpenGL code
//.
//..
}
Still missing some other thing to handle, but that an hint for your solution.
Is it possible that you are just assigning in the if statement and not testing? Or did you just miss typed it here?
Because if your code is if(frame = 0) it should be (frame == 0).

Limit UIPanGestureRecognizer to a specific area

In my view I have in the right part 3 UISlider and in the left part the user can slide the menu with a UIPanGestureRecognizer. Sometimes, when the user uses the slider, it also drag the view. I don't want this to happen. I have this code in my panLayer method:
- (IBAction)panLayer:(UIPanGestureRecognizer *)pan {
if (pan.state == UIGestureRecognizerStateChanged) {
CGPoint point= [pan translationInView:self.topLayer];
CGRect frame = self.topLayer.frame;
frame.origin.x = MIN(258.0f, self.layerPosition + point.x);
if (frame.origin.x < 0) frame.origin.x = 0;
self.topLayer.frame = frame;
}
if (pan.state == UIGestureRecognizerStateEnded) {
if (self.topLayer.frame.origin.x <=160) {
[self animateLayerToPoint:0];
}
else {
[self animateLayerToPoint:VIEW_HIDDEN];
}
}
}
I want to create an if statement with the x position. Something like this:
if (firstTouch.x < 150 && firstTouch.x > 0) {
//Add my previous code
}
How can I access to the firstTouch in the view, and if it is in this area, run the UIPanGestureRecognizer?
Thanks
This can be easily achieved by adopting UIGestureRecognizerDelegate and implementing the following method:
-(BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldReceiveTouch:(UITouch*)touch
{
return touch.view != myUISlider;
}

Tilemap platform collision detection with Cocos2d

I'm getting my feet wet with game development by working on a platformer using Cocos2d for iPhone. I'm struggling a bit in getting collision detection running so that my character will have his jump action cancelled when he hits a platform.
I'm using a technique from this tutorial where I create a separate layer of "meta tiles". The problem is that collision detection does not occur until the character sprite is well within the collidable tile, not on top of it.
I'm using the code below to determine the tile coordinate based on my character sprite's current position:
- (CGPoint) tileCoordForPosition: (CGPoint) position {
int x = position.x / tileMap.tileSize.width;
int y = ((tileMap.mapSize.height * tileMap.tileSize.height) - position.y) / tileMap.tileSize.height;
return ccp(x, y);
}
I tried various techniques, even trying to figure out what tile was below my character using this code:
- (void) update: (ccTime) dt {
BOOL isCollision = NO;
if (firstRun) {
oldY = player.position.y;
firstRun = NO;
}
CGPoint oneTileDown = ccp(player.position.x, player.position.y / 2);
CGPoint tileCoord = [gameplayLayer tileCoordForPosition:oneTileDown];
int tileGid = [gameplayLayer.meta tileGIDAt:tileCoord];
if (tileGid) {
NSDictionary* tileProperties = [gameplayLayer.tileMap propertiesForGID:tileGid];
if (tileProperties) {
NSString* collision = [tileProperties valueForKey:#"Collidable"];
if (collision && [collision compare:#"True"] == NSOrderedSame) {
//CCLOG(#"Collision Below");
isCollision = YES;
if (player.characterState == kStateFalling) {
[player stopAllActions];
}
}
}
}
if (oldY < player.position.y) {
CCLOG(#"Character is jumping");
player.characterState = kStateJumping;
}
else if (oldY > player.position.y) {
CCLOG(#"Character is falling");
player.characterState = kStateFalling;
}
oldY = player.position.y;
}
But the same problem happens: my character jumps, lands inside of the collision tile and is stopped instead of landing on top of the tile.
Is there a better way of checking for collision in a tilemap?
I have the solution to this issue.
In the method (CGPoint) tileCoordForPosition: (CGPoint) position you have to write the following:
int x = position.x / tileMap.tileSize.width;
int y = ((tileMap.mapSize.height * tileMap.tileSize.height + player.contenSize().height / 2) - position.y) / tileMap.tileSize.height;
return ccp(x, y);
player is a sprite from which you have to add half its height.
What you need to do is use CGRectContainRect to check if the player sprite's bounding box is intersecting with and of the tiles where it shouldn't.