Is it possible to clip a Layer with a clipping box using cocos2d-x 3.2? - cocos2d-x

I need to clip the drawing area of a custom layer so that it will only draw inside a box instead of drawing into the whole window.
I've come up with this solution, but it is not working:
void GameLayer::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags) {
auto director = Director::getInstance();
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
glEnable(GL_SCISSOR_TEST);
static Rect clippingRegion = {0,0,200,200};
director->getOpenGLView()->setScissorInPoints(
clippingRegion.origin.x + origin.x, clippingRegion.origin.y + origin.y,
clippingRegion.size.width, clippingRegion.size.height);
Layer::visit(renderer, parentTransform, parentFlags);
glDisable(GL_SCISSOR_TEST);
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}
The layer will draw as if this code wasn't there. But if I remove the glDisable(GL_SCISSOR_TEST) the whole window will be clipped to the {0,0,200,200} rect.
Is it possible to clip a Layer using this approach?

I've found a solution to this problem looking at how the Layout class in cocos2d-x implements the clipping rect. All you have to do is add these two variables to the class:
CustomCommand _beforeVisitCmdScissor;
CustomCommand _afterVisitCmdScissor;
and then you can modify the visit(...) method like this:
void GameLayer::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags) {
_beforeVisitCmdScissor.init(_globalZOrder);
_beforeVisitCmdScissor.func = CC_CALLBACK_0(GameLayer::onBeforeVisitScissor, this);
renderer->addCommand(&_beforeVisitCmdScissor);
Layer::visit(renderer, parentTransform, parentFlags);
_afterVisitCmdScissor.init(_globalZOrder);
_afterVisitCmdScissor.func = CC_CALLBACK_0(GameLayer::onAfterVisitScissor, this);
renderer->addCommand(&_afterVisitCmdScissor);
}
void GameLayer::onBeforeVisitScissor()
{
static float size = Tile::size;
static Rect clippingRegion = {0,0,200,200};
glEnable(GL_SCISSOR_TEST);
Director::getInstance()->getOpenGLView()->setScissorInPoints(
clippingRegion.origin.x + origin.x, clippingRegion.origin.y + origin.y,
clippingRegion.size.width, clippingRegion.size.height);
}
void GameLayer::onAfterVisitScissor()
{
glDisable(GL_SCISSOR_TEST);
}

Related

Libgdx , When to use camera.position.set?

I am really confused with two examples related to viewport and orthagraphic. Although i understand that Viewport is the size of the dimensions we set to view on the screen and camera projects that. I am learning libgdx and cannot finish through orthographic camera and viewport examples which have left me completely confused. the code runs fine for both examples and with proper result on screen.
here's one example in which camera.position.set is used to position the camera.
public class AnimatedSpriteSample extends GdxSample {
private static final float WORLD_TO_SCREEN = 1.0f / 100.0f;
private static final float SCENE_WIDTH = 12.80f;
private static final float SCENE_HEIGHT = 7.20f;
private static final float FRAME_DURATION = 1.0f / 30.0f;
private OrthographicCamera camera;
private Viewport viewport;
private SpriteBatch batch;
private TextureAtlas cavemanAtlas;
private TextureAtlas dinosaurAtlas;
private Texture background;
private Animation dinosaurWalk;
private Animation cavemanWalk;
private float animationTime;
#Override
public void create() {
camera = new OrthographicCamera();
viewport = new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, camera);
batch = new SpriteBatch();
animationTime = 0.0f;
...
...
..
camera.position.set(SCENE_WIDTH * 0.5f, SCENE_HEIGHT * 0.5f, 0.0f);
Here's another example which does not use camera.position.set and still the result is the same.
#Override
public void create() {
camera = new OrthographicCamera();
viewport = new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, camera);
batch = new SpriteBatch();
oldColor = new Color();
cavemanTexture = new Texture(Gdx.files.internal("data/caveman.png"));
cavemanTexture.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
}
#Override
public void dispose() {
batch.dispose();
cavemanTexture.dispose();
}
#Override
public void render() {
Gdx.gl.glClearColor(BACKGROUND_COLOR.r,
BACKGROUND_COLOR.g,
BACKGROUND_COLOR.b,
BACKGROUND_COLOR.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
int width = cavemanTexture.getWidth();
int height = cavemanTexture.getHeight();
float originX = width * 0.5f;
float originY = height * 0.5f;
// flipX, flipY
// Render caveman centered on the screen
batch.draw(cavemanTexture, // Texture itselft
-originX, -originY, // pass in the world space coordinates where we to draw, Considering the camera is centered at (0,0). by default we need to position
// out cavement at -originX, -originY.
originX, originY, // coordinates in pixels of our texture that we consider to be the origin starting from the bottom-left corner.
// in our case, we want the origin to be the center of the texture. then we pass the dimensions of the texture and the scale
// and the scale along both axes (x and Y).
width, height, // width, height
WORLD_TO_SCREEN, WORLD_TO_SCREEN, // scaleX, scaleY
0.0f, // rotation
0, 0, // srcX, srcY
width, height, // srcWidth, srcHeight
false, false); // flipX, flipY
What is really confusing me is why does it not use camera.position.set on the second example to adjust the camera's view and why is it important to use this on the first example.
I really hope this question is legit and makes sense. I have searched the forum here and couldnt find any clues. Hope someone can guide in the right direction.
Many Thanks.
In the first example a 2 dimensional vector has been initialized for the position of the camera the x direction and the y direction. This for the specifically the camera.
camera = new OrthographicCamera();
So, this code creates a camera object from the OrthographicCamera class created by libgdx creators. Check out the documentation for the class here from that class you can see when that it is constructed it accepts both the viewport_height and viewport_width. (in your example you've left it blank, so these are 0 for the time being.)
viewport = new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, camera);
This line of code defines the width, height and which camera should be used for the viewport. check out the documentation for FitViewport class here
So when camera.position.set is called, it sets for the x and y direction based on the viewport's width and height. This whole example defines the viewport dimensions for the overall viewport.
The difference between this and the second example is that the camera is set around the texture that has been loaded onto the screen. So the viewport's x and y direction has been positioned and the width, height, originX, originY of the texture/camera has been defined also:
int width = cavemanTexture.getWidth();
int height = cavemanTexture.getHeight();
float originX = width * 0.5f;
float originY = height * 0.5f;
Libgdx then allows you to draw the texture using the spritebatch class to draw both the texture and the viewport surrounding that texture.
Summary
Example one allows you to define a viewport on it's own, without any textures being drawn. This will allow you to draw multiple textures with the same viewport being set (a normal process of game creation)
But in Example two if you wanted the viewport to say, follow the main character around on the screen. you can define the viewport surrounding the texture to thus follow that texture.
Personally, i'd always pursue the first example as you can define a viewport for any game width or height and then i'd create a second viewport ontop to follow any textures i've drawn on the screen. They both work, just for different reasons.
Hope this helps you clear things up.
Happy coding,
Bradley.

How do I extend the ViewPort and use it to paint a "window" of 3D graphics on the screen

I need to create a 3D perspective camera viewport of 480x480 and display it on the bottom right corner of the screen. The rest of the screen is filled with 2D graphics.
I tried extending Viewport and using viewportX, and viewportY as well as viewportHeight and viewportWidth, but the test 3D object does not draw.
I followed this tutorial to get the basic prototype going.
https://code.google.com/p/libgdx-users/wiki/Decals
How do I properly extend the ViewPort and use it to paint a "window" of 3D graphics on the screen ?
The following could be used to have a Viewport with a fixed size of 480x480 which is placed on the bottom left corner. If you supply a PerspectiveCamera to it, everything will be rendered in this area.
public class CustomViewport extends Viewport {
public CustomViewport (Camera camera) {
this.camera = camera;
}
#Override
public void update (int screenWidth, int screenHeight, boolean centerCamera) {
viewportX = 0;
viewportY = 0;
viewportWidth = 480;
viewportHeight = 480;
worldWidth = 480;
worldHeight = 480;
super.update(screenWidth, screenHeight, false);
}
}
If you want to render somewhere else after that, you have to "reset" the glViewport() via Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
Now you are free to render whereever you want, for example in the top and right areas which were left blank.
This test shows another example of how to render in those areas.

Libgdx: screen resize and ClickListener (libgdx)

I develope a 2D game and use OrthographicCamera and Viewport to resize virtaul board to real display size. I add images to stage and use ClickListener to detect clicks. It works fine, but when I change resolution it works incorrent(can't detect correct actor, I think the problem with new and original x and y). Is there any way to fix this?
You will need to translate the screen coordinates to world coordinates.
Your camera can do that. You can do both ways, cam.project(...) and cam.unproject(...)
Or if you are already using Actors, don't initialize a camera yourself, but use a Stage. Create a Stage and add the actors to it. The Stage will then do coordinate translation for you.
Once me too suffered from this problem but at end i got the working solution, for drawing anything using SpriteBatch or Stage in libgdx. Using orthogrphic camera we can do this.
first choose one constant resolution which is best for game. Here i have taken 1280*720(landscape).
class ScreenTest implements Screen{
final float appWidth = 1280, screenWidth = Gdx.graphics.getWidth();
final float appHeight = 720, screenHeight = Gdx.graphics.getHeight();
OrthographicCamera camera;
SpriteBatch batch;
Stage stage;
Texture img1;
Image img2;
public ScreenTest(){
camera = new OrthographicCamera();
camera.setToOrtho(false, appWidth, appHeight);
batch = new SpriteBatch();
batch.setProjectionMatrix(camera.combined);
img1 = new Texture("your_image1.png");
img2 = new Image(new Texture("your_image2.png"));
img2.setPosition(0, 0); // drawing from (0,0)
stage = new Stage(new StretchViewport(appWidth, appHeight, camera));
stage.addActor(img2);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(img, 0, 0);
batch.end();
stage.act();
stage.act(delta);
stage.draw();
// Also You can get touch input according to your Screen.
if (Gdx.input.isTouched()) {
System.out.println(" X " + Gdx.input.getX() * (appWidth / screenWidth));
System.out.println(" Y " + Gdx.input.getY() * (appHeight / screenHeight));
}
}
//
:
:
//
}
run this code in Any type of resolution it will going to adjust in that resolution without any disturbance.
I just think Stage is easy to use.
If there are some wrong,i consider you should check your code:
public Actor hit(float x, float y)

AS3 draws bigger Sprite than i have set (padding/margin ?)

i created my own Button which simply extends from Sprite.
Its able to show 3 different text fading in and out using a timer.
In my draw function i first draw a rectangle with the Sprites graphics object representing the background of the button.
I added a function to set the button width. This property is used to draw the rectangle. I know that the sprites's size is updated after the rectangle drawing. But for some reason the sprite's width is always more than what i have set via my "setButtonWidth" function.
Now i have a simple sprite acting as a button having a graphics.drawRectangle part drawing a simple rect. with lets say 500px width. But when i trace the width of that button it is always about 10% more. Where are these 10% coming from?
I read about calling validateNow(). But this is only for Labels, or Checkboxes. For some reason i cannot access the library for Label. This must work somehow with TextFields. But how?
// this function is part of MyButtonClass.as file
function drawButton()
{
this.graphics.clear();
this.graphics.beginFill( currentBackColor);
this.graphics.drawRoundRect(0, 0, int(this.buttonWidth)+20, 30, 10, 10);
this.graphics.endFill();
}
// this code is in main action code frame
// the buttonWidth is set this way
stage.addEventListener( Event.RESIZE, updateBtn);
function updateBtn( event:Event)
{
// access the container in which the buttons are in like ...
for( var i = 0; i < buttonContainer.numChildren; i++) {
var btn = buttonContainer.getChildAt( i) as MyButtonClass;
// MyButtonClass is the class which extends from Sprite drawing my button
// and using buttonWidth to draw the backgrounds width.
btn.setButtonWidth( (stage.stageWidth / 2) - 20);
// i set half of stageWidth because i have two columns with a list of buttons
// after setButtonWidth is called in MyButtonClass, the draw function is called
// which does the graphics stuff above.
}
}
this.buttonWidth is set to 500. There is nothing special done on that sprite. No children to be added, only this drawing stuff. But this sets the sprite's width to 550 or something.
Define Button like this
package {
import flash.display.Sprite;
public class Button extends Sprite {
private var _buttonWith: int = 0;
private var _buttonHeight: int = 0;
public function Button() {
// constructor code
}
public function set buttonWidth(w: int): void {
_buttonWith = w;
updateButton();
}
public function get buttonWidth(): int {
return _buttonWith;
}
public function set buttonHeight(h: int): void {
_buttonHeight = h;
updateButton();
}
public function get buttonHeight(): int {
return _buttonHeight;
}
protected function updateButton() {
graphics.clear();
graphics.beginFill(0xff00ff);
graphics.drawRoundRect(0, 0, buttonWidth, buttonHeight, 10, 10);
graphics.endFill();
}
}
}
And create instance like this
var button:Button = new Button();
addChild(button);
button.buttonWidth = 100;
button.buttonHeight = 30;

how to draw a circle using ActionScript

how to draw a circle using action script (as a component) i tried some xample did not work....i need to add this circle in a panel
Create a class derived from UIComponent
Override the updateDisplayList() method inside your component and draw the circle
Add an instance of your component in the panel;
Component class:
class MyCircle extends UIComponent
{
public function MyCircle()
{
super();
}
override protected function updateDisplayList(width:Number, height:Number):void
{
super.updateDisplaylist(width,height);
this.graphics.clear();
this.graphics.beginFill(0xff0000);
this.graphics.drawCircle(width/2, height/2, Math.min(width/2,height/2));
}
}
Panel component:
<mx:Panel width = "400" height
= "400">
<local:MyCircle
width = "100%"
height = "100%"/>
</mx:Panel>
// Draw a simple circle, gray, with a radius of 24 px
var circleColor:uint = 0xCCCCCC;
var radius:uint = 24;
var circle:Shape = new Shape();
circle.graphics.beginFill(circleColor);
circle.graphics.drawCircle(radius, radius, radius);
circle.graphics.endFill();
addChild(circle);
You can substitute beginLine and endLine instead of beginFill and endFill if you just want the circle's outer edge.