Displaying part of the sprite - cocos2d-iphone

Here is my problem. The goal is to make a scale, that fills out while the char collects the food.
I got 2 sprites: the scale without the filling and the filling itself. So my question is simple: how to draw a part of the filling sprite depending on the number of "apples" eaten? =)

I solved a similar problem for a loading bar some time ago, using glScissor. Basically I extended CCSprite with a float indicating the filled portion, and overrode visit method like this.-
- (void) visit {
glEnable(GL_SCISSOR_TEST);
glScissor(0, 0, (loadingPercent / 100) * self.contentSize.width * CC_CONTENT_SCALE_FACTOR(), self.contentSize.height * 4);
[super visit];
glDisable(GL_SCISSOR_TEST);
}
Hope it helps.

Related

Change Cursor Image While Hovering Over An Object Drawn At OpenGL And Displaying Object's Variables

I am currently working on a project that I use C++, OpenGL, Qt 5.9.2 and Microsoft Visual Studio Professional 2015 on a 64 bit Operating System, Windows 10 Pro.
I have a user interface that I have created and in that user interface, there is a QGLWidget, that I am using for draw processes, with other widgets like push buttons and a dockWidget. I have a class Ball and it has variables(distance(double) and angle(int)) that determines where an instance of that Ball is going to be drawn inside the QGLWidget. Ball class has got 2 more variables that is, id(int), model(String) and year(int) Every other draw process draws lines except Ball drawings.
Drawings are 2 dimensional.
Every Ball has the same color(rgb)!
First problem: I want to left click to one of the Ball instances and I want to display it's id, model and year at The dockWidget.
Second Problem: While doing the stuff that I have mentioned at the First Problem section. I want the cursor image to change while hovering above any of the Ball instances, and change back to default Windows mouse cursor while not.
I have created a function that checks if the MouseEvent is LeftClick:
void DisplayManager::mousePressEvent(QMouseEvent* ev) {
if (ev->buttons() & Qt::LeftButton) { // Balls Are Green
if(// CHECK IF THERE IS A BALL AT THE CLICKED COORDINATES) {
// DISPLAY THE X and Y OF THE BALL AT THE DOCK WIDGET
}
}
}
This is my initializeGL function: (DisplayManager is the name of my QGLWidget)
void DisplayManager::initializeGL() {
glEnable(GL_COLOR_MATERIAL); // Enables the changing of the draw color with glColor() functions
glColor3f(0.0, 1.0, 0.0);
glEnable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 1); //sets a black background 1 0 0 1
}
On the basis this is a Picking problem and there are several information about it at the internet but I am not using GLUT and I am not using any shader. So in the light of all these I was unable to find any effective solution or clue about how can I accomplish all that I want.
I would be really glad if someone could help me with at least one of these problems.
I have currently finished working with the project. I thought that I should provide an answer to my question in case someone with a similar problem comes across with my question in the future.
void DisplayManager::mousePressEvent(QMouseEvent* ev) {
// The processes that are being executed after a left mouse button click on the DisplayManager.
if (ev->buttons() & Qt::LeftButton) {
double aspectRatio = openGLWidgetWidth / openGLWidgetHeight;
int xOfClicked = ev->x() - (openGLWidgetWidth / 2);
int yOfClicked = - (ev->y() - (openGLWidgetHeight / 2));
// The variable to be used for calculating fault tolerance of the click event.
int distanceBetweenPressAndDraw = 0;
// Executes the processes inside for every ball in vector.
for (int i = 0; i < ballVector.length(); i++) {
// Calculates the screen coordinates of the i'th ball.
int rangeOfBallInScreenDistance = rangeToScreenDistance(ballVector.at(i).range);
double screenXOfBall = rangeOfBallInScreenDistance * sin(ballVector.at(i).degree * DEGTORAD);
double screenYOfBall = rangeOfBallInScreenDistance * cos(ballVector.at(i).degree * DEGTORAD);
// Calculates the distance between pressed position and the i'th ball according to the screen coordinates.
distanceBetweenPressAndDraw = sqrt(pow((screenXOfBall - xOfClicked), 2) + pow((screenYOfBall - yOfClicked), 2));
// Decides if the clicked position is a ball (considering the fault tolerance).
if (distanceBetweenPressAndDraw < 10) {
emit printXY(QPointF(xOfClicked, yOfClicked)); // Prints the screen coordinates of the clicked positions (At the Dock Widget inside Main Window).
}
}
}
}
This was the solution for my First Problem. I would be glad though if someone could answer my Second problem in a comment or answer somehow.

Why does Cocos2d-x not show the sprite the first time?

What is the problem? It does not show the sprite the first time.
playerSprite = Sprite::create("ip.png");
playerSprite->setPosition(Vec2(visibleSize.width/2,visibleSize.height));
//this->addChild(playerSprite,1);
auto body = PhysicsBody::createCircle
(playerSprite->getContentSize().width / 2.5);
body->setContactTestBitmask(true);
body->setDynamic(true);
playerSprite->setPhysicsBody(body);
this->addChild(playerSprite,0);
Try Using Another Z-Order of your Sprite. this->addChild(playerSprite,TRY_WITH_SOME_LARGE_VALUE);`
AND see if the result are Same.
Since you questions is not much defined, answer might be incorrect.
First of all, make sure that image is placed correctly and there is no typos in image name.
playerSprite position is in the middle of the top. to center it:
->setPosition(Point(visibleSize.widht * 0.5, visibleSize.height * 0.5));
If this == Scene you can do it like this.
->setPosition(Point(this->getContentSize().width * 0.5, this->getContentSize().height * 0.5));
Also when adding Sprite make sure there is no other Sprite above by setting zOrder to a bigger number
this->addChild(playerSprite, 100);

Clip a CCSprite added to CCSpriteBatchNode

I'm clipping my sprite with this code:
//At my CCSprite subclass m.
-(void)visit
{
CGPoint worldOrg = [self convertToWorldSpace:ccp(0, 0)];
CGPoint dest = [self convertToWorldSpace:ccp(self.contentSize.width, self.contentSize.height)];
CGPoint dims = ccpSub(dest, worldOrg);
glEnable(GL_SCISSOR_TEST);
glScissor(worldOrg.x, worldOrg.y, dims.x, dims.y);
#define SHOW_CLIPPED_AREA 1
#if SHOW_CLIPPED_AREA
//Draws a red rectangle showing clipped area
ccDrawSolidRect(ccp(0, 0), ccp(1024, 1024), ccc4f(64, 0, 0, 128));
#endif
[super visit];
glDisable(GL_SCISSOR_TEST);
}
Then just create the sprite as usual, adjust the sprite.contentSize property to whatever I need:
CCSprite aSprite = [CCSprite spriteWith...];
aSprite.contentSize = CGSizeMake(20,20);
//Add it to my layer
[self addChild:aSprite];
And it works as expected!
Problem...
When adding it to a CCSpriteBatchNode, it wont clip the sprite... it shows the sprite but without clipping it.
Can someone please help me out with this, I've googled everywhere with no answer to this.
I've also used the ClippingNode class from Steffen Itterheim, but I'm also having issues adding it to a CCSpriteBatchNode.
Any help will be appreciated.
Clipping or any custom drawing won't work with sprite-batched sprites.
The CCSpriteBatchNode will not call visit (nor draw) methods on their children because the batch node takes over rendering of the children. Therefore any code you write in draw or visit methods of a CCSprite will have no effect when you sprite-batch the sprite.

How to draw line in topmost z-oder

I want to draw line connect two sprites, but i can not do that in this case:
//add Map Background
map = [CCTMXTiledMap tiledMapWithTMXFile:#"orthogonal-test-zorder.tmx"];
[self addChild:map z:1 tag:kTagTileMap];
//overite draw function
- (void)draw {
glColor4f(0.8, 1.0, 0.76, 1.0);
glEnable(GL_LINE_SMOOTH);
ccDrawLine( ccp(0, 0), ccp(150, 150) );
}
the line is not shown on screen, if i remove map background , it's shown.
I don't know Cocos2D so this is just wild guessing, but the z parameter of [self addChild:map z:1 tag:kTagTileMap]; seems to be a z offset. Since 1 would be in front of 0 (the likely default), your map would render in front of your line. Try [self addChild:map z:-1 tag:kTagTileMap];
I've encounted same problem 2 days ago.
My solution is to make a seperate MyLineLayer which only draw the line. Then you can set the z-index of the CCLayer to the top.
I think that using an enveloped MyLineLayer would be better than make the z-index of the tile map smaller.

Cocos2d iPhone - Sprite cliping/mask/frame

how can i clip/crop/mask or just set the frame of a CCSprite in Cocos2D?
Something similar to:
setting the frame for UIView, with clipping subviews = TRUE
My CCSprite Main Sprite have multiple Child Sprite added to it.
I only want Mask part of that Main Sprite Sprite visible.
Is there a way to clip or use a mask for CCSprite?
I could cut the background and layer that on top, leaving only that visible area, but is that the only way?!
here's a sample image demonstrating what I'm trying to achieve:
(source: dnamique.com)
I ended up using GL_SCISSOR.
in MainSprite I impemented:
- (void) visit
{
if (!self.visible) {
return;
}
glEnable(GL_SCISSOR_TEST);
glScissor(x, y, width, height);
[super visit];
glDisable(GL_SCISSOR_TEST);
}
This will clip or mask the specified area.
The only tricky bit is that in Landscape mode Cocos2D has 0,0 at the bottom-left side of the screen, while OpenGL has it at the bottom-right corner as it doesn't consider the orientation of the screen.
In other words, for OpenGL consider you have a rotated portrait Screen.
I wrote a ClippingNode class which does exactly that. You can add other nodes (sprites, labels, etc.) to the ClippingNode and they will only be drawn in the region specified by the ClippingNode. It also takes device rotation into account.
Internally it uses GL_SCISSOR_TEST like in Bach's answer.
http://www.learn-cocos2d.com/2011/01/cocos2d-gem-clippingnode/
I tried using Steffen Itterheim's ClippingNode, but was unable to get to work in a sufficiently robust
enough fashion for my needs.
Believe it or not, the below code works fairly well and should be code complete. It handles device orientation changes, anchorPoint, position, scale (scaleX, scaleY). For cocos2d v2, you may just need to
comment out the glPushMatrix and glPopMatrix calls..
To use, simply set the position and contentSize properties and add the child/children you want clipped to this ClippingNode instance. The contentSize property is used to define the dimensions of the clipping region.
example of usage:
ClippingNode *clipNode = [[ClippingNode alloc] init];
clipNode.anchorPoint = ccp(0.5f, 0);
clipNode.position = ccp(100, 25);
clipNode.contentSize = CGSizeMake(120, 120);
// add clipNode to your node hierarchy.
[parentNode addChild:clipNode];
// add one or more children to your clipNode:
[clipNode addChild:child1];
// ClippingNode.h
// CC0 - (public domain. Use in anyway you see fit.)
// No warranty of any kind is expressed or implied.
//
// by UChin Kim.
//
// the caller can simply set the regular cocos2d
// properties: position and contentSize to define the clipping region implicitly (i.e. the
// position and contentSize of the ClippingNode is the clipping region to be used).
// as an added bonus, position seems to work as expected (relative to parent node, instead of
// requiring absolute positioning).
//
// also, anchorPoint and scale properties seem to work as expected as well..
// no special code is neeed to handle device orientation changes correctly..
//
// To visually see exactly what is being clipped, set the following #define
// #define SHOW_CLIPPED_REGION_IN_LIGHT_RED 1
//
#import "cocos2d.h"
#interface ClippingNode : CCNode
#end
//
// ClippingNode.m
//
#import "ClippingNode.h"
#implementation ClippingNode
-(void) visit
{
CGPoint worldOrg = [self convertToWorldSpace:ccp(0, 0)];
CGPoint dest = [self convertToWorldSpace:ccp(self.contentSize.width, self.contentSize.height)];
CGPoint dims = ccpSub(dest, worldOrg);
glPushMatrix();
glEnable(GL_SCISSOR_TEST);
glScissor(worldOrg.x, worldOrg.y, dims.x, dims.y);
#if SHOW_CLIPPED_REGION_IN_LIGHT_RED
glColor4ub(64, 0, 0, 128);
ccDrawSolidRect(ccp(0, 0), ccp(1024, 1024));
#endif
[super visit];
glDisable(GL_SCISSOR_TEST);
glPopMatrix();
}
#end