mirror of https://github.com/axmolengine/axmol.git
Add Anchored Sprite Class (#1040)
* add anchored sprite class * Add feature tests
This commit is contained in:
parent
d444937358
commit
63263e09d2
|
@ -0,0 +1,210 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2008-2010 Ricardo Quesada
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2011 Zynga Inc.
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
Copyright (c) 2020 C4games Ltd.
|
||||
Copyright (c) 2021-2022 Bytedance Inc.
|
||||
|
||||
https://axmolengine.github.io/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#include "2d/CCAnchoredSprite.h"
|
||||
#include "renderer/backend/Device.h"
|
||||
|
||||
NS_AX_BEGIN
|
||||
|
||||
// FIXME: HACK: optimization
|
||||
#define SET_DIRTY_RECURSIVELY() \
|
||||
{ \
|
||||
if (!_recursiveDirty) \
|
||||
{ \
|
||||
_recursiveDirty = true; \
|
||||
setDirty(true); \
|
||||
if (!_children.empty()) \
|
||||
setDirtyRecursively(true); \
|
||||
} \
|
||||
}
|
||||
|
||||
// MARK: create, init, dealloc
|
||||
AnchoredSprite* AnchoredSprite::createWithTexture(Texture2D* texture)
|
||||
{
|
||||
AnchoredSprite* asprite = new AnchoredSprite();
|
||||
if (asprite->initWithTexture(texture))
|
||||
{
|
||||
asprite->autorelease();
|
||||
return asprite;
|
||||
}
|
||||
AX_SAFE_DELETE(asprite);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AnchoredSprite* AnchoredSprite::createWithTexture(Texture2D* texture, const Rect& rect, bool rotated)
|
||||
{
|
||||
AnchoredSprite* asprite = new AnchoredSprite();
|
||||
if (asprite->initWithTexture(texture, rect, rotated))
|
||||
{
|
||||
asprite->autorelease();
|
||||
return asprite;
|
||||
}
|
||||
AX_SAFE_DELETE(asprite);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AnchoredSprite* AnchoredSprite::create(std::string_view filename)
|
||||
{
|
||||
return AnchoredSprite::create(filename, Texture2D::getDefaultAlphaPixelFormat());
|
||||
}
|
||||
|
||||
AnchoredSprite* AnchoredSprite::create(std::string_view filename, PixelFormat format)
|
||||
{
|
||||
AnchoredSprite* asprite = new AnchoredSprite();
|
||||
if (asprite->initWithFile(filename, format))
|
||||
{
|
||||
asprite->autorelease();
|
||||
return asprite;
|
||||
}
|
||||
AX_SAFE_DELETE(asprite);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AnchoredSprite* AnchoredSprite::create(const PolygonInfo& info)
|
||||
{
|
||||
AnchoredSprite* asprite = new AnchoredSprite();
|
||||
if (asprite->initWithPolygon(info))
|
||||
{
|
||||
asprite->autorelease();
|
||||
return asprite;
|
||||
}
|
||||
AX_SAFE_DELETE(asprite);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AnchoredSprite* AnchoredSprite::create(std::string_view filename, const Rect& rect)
|
||||
{
|
||||
AnchoredSprite* asprite = new AnchoredSprite();
|
||||
if (asprite->initWithFile(filename, rect))
|
||||
{
|
||||
asprite->autorelease();
|
||||
return asprite;
|
||||
}
|
||||
AX_SAFE_DELETE(asprite);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AnchoredSprite* AnchoredSprite::createWithSpriteFrame(SpriteFrame* spriteFrame)
|
||||
{
|
||||
AnchoredSprite* asprite = new AnchoredSprite();
|
||||
if (spriteFrame && asprite->initWithSpriteFrame(spriteFrame))
|
||||
{
|
||||
asprite->autorelease();
|
||||
return asprite;
|
||||
}
|
||||
AX_SAFE_DELETE(asprite);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AnchoredSprite* AnchoredSprite::createWithSpriteFrameName(std::string_view spriteFrameName)
|
||||
{
|
||||
SpriteFrame* frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(spriteFrameName);
|
||||
|
||||
#if _AX_DEBUG > 0
|
||||
char msg[256] = {0};
|
||||
snprintf(msg, sizeof(msg), "Invalid spriteFrameName: %s", spriteFrameName.data());
|
||||
AXASSERT(frame != nullptr, msg);
|
||||
#endif
|
||||
|
||||
return createWithSpriteFrame(frame);
|
||||
}
|
||||
|
||||
AnchoredSprite* AnchoredSprite::create()
|
||||
{
|
||||
AnchoredSprite* asprite = new AnchoredSprite();
|
||||
if (asprite->init())
|
||||
{
|
||||
asprite->autorelease();
|
||||
return asprite;
|
||||
}
|
||||
AX_SAFE_DELETE(asprite);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AnchoredSprite::setVertexCoords(const Rect& rect, V3F_C4B_T2F_Quad* outQuad)
|
||||
{
|
||||
float relativeOffsetX = _unflippedOffsetPositionFromCenter.x - getContentSize().x * _spriteVertexAnchor.x;
|
||||
float relativeOffsetY = _unflippedOffsetPositionFromCenter.y - getContentSize().y * _spriteVertexAnchor.y;
|
||||
|
||||
// issue #732
|
||||
if (_flippedX)
|
||||
relativeOffsetX = -relativeOffsetX;
|
||||
if (_flippedY)
|
||||
relativeOffsetY = -relativeOffsetY;
|
||||
|
||||
_offsetPosition.x = relativeOffsetX + (_originalContentSize.width - _rect.size.width) / 2;
|
||||
_offsetPosition.y = relativeOffsetY + (_originalContentSize.height - _rect.size.height) / 2;
|
||||
|
||||
// FIXME: Stretching should be applied to the "offset" as well
|
||||
// but probably it should be calculated in the caller function. It will be tidier
|
||||
if (_renderMode == RenderMode::QUAD)
|
||||
{
|
||||
_offsetPosition.x *= _stretchFactor.x;
|
||||
_offsetPosition.y *= _stretchFactor.y;
|
||||
}
|
||||
|
||||
// rendering using batch node
|
||||
if (_renderMode == RenderMode::QUAD_BATCHNODE)
|
||||
{
|
||||
// update dirty_, don't update recursiveDirty_
|
||||
setDirty(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// self rendering
|
||||
|
||||
// Atlas: Vertex
|
||||
const float x1 = 0.0f + _offsetPosition.x + rect.origin.x;
|
||||
const float y1 = 0.0f + _offsetPosition.y + rect.origin.y;
|
||||
const float x2 = x1 + rect.size.width;
|
||||
const float y2 = y1 + rect.size.height;
|
||||
|
||||
// Don't update Z.
|
||||
outQuad->bl.vertices.set(x1, y1, 0.0f);
|
||||
outQuad->br.vertices.set(x2, y1, 0.0f);
|
||||
outQuad->tl.vertices.set(x1, y2, 0.0f);
|
||||
outQuad->tr.vertices.set(x2, y2, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void AnchoredSprite::setAnchorPoint(const Vec2& anchor)
|
||||
{
|
||||
_spriteVertexAnchor = anchor;
|
||||
SET_DIRTY_RECURSIVELY();
|
||||
updatePoly();
|
||||
}
|
||||
|
||||
const Rect& AnchoredSprite::getTouchRect()
|
||||
{
|
||||
Size s = getContentSize();
|
||||
Size a = _spriteVertexAnchor * s;
|
||||
return Rect(-a.x, -a.y, s.width, s.height);
|
||||
}
|
||||
|
||||
NS_AX_END
|
|
@ -0,0 +1,153 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2008-2010 Ricardo Quesada
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2011 Zynga Inc.
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
Copyright (c) 2020 C4games Ltd.
|
||||
Copyright (c) 2021-2022 Bytedance Inc.
|
||||
|
||||
https://axmolengine.github.io/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "2d/CCSprite.h"
|
||||
|
||||
NS_AX_BEGIN
|
||||
|
||||
/**
|
||||
* @addtogroup _2d
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Anchored Sprite
|
||||
*
|
||||
* This node follows the same rules as the normal Sprite.
|
||||
* but instead of anchoring the node with its children,
|
||||
* it instead moves the vertices and anchors them without
|
||||
* altering the node's children positions
|
||||
*
|
||||
* The default anchorPoint of Anchored Sprite is (0.5, 0.5).
|
||||
*/
|
||||
class AX_DLL AnchoredSprite : public Sprite
|
||||
{
|
||||
public:
|
||||
/// @name Creators
|
||||
/// @{
|
||||
|
||||
/**
|
||||
* Creates an empty anchored sprite without texture. You can call setTexture method subsequently.
|
||||
*
|
||||
* @memberof Sprite
|
||||
* @return An autoreleased sprite object.
|
||||
*/
|
||||
static AnchoredSprite* create();
|
||||
|
||||
/**
|
||||
* Creates an anchored sprite with an image filename.
|
||||
*
|
||||
* After creation, the rect of sprite will be the size of the image,
|
||||
* and the offset will be (0,0).
|
||||
*
|
||||
* @param filename A path to image file, e.g., "scene1/monster.png".
|
||||
* @return An autoreleased sprite object.
|
||||
*/
|
||||
static AnchoredSprite* create(std::string_view filename);
|
||||
static AnchoredSprite* create(std::string_view filename, PixelFormat format);
|
||||
|
||||
/**
|
||||
* Creates an anchored polygon sprite with a polygon info.
|
||||
*
|
||||
* After creation, the rect of sprite will be the size of the image,
|
||||
* and the offset will be (0,0).
|
||||
*
|
||||
* @param polygonInfo A path to image file, e.g., "scene1/monster.png".
|
||||
* @return An autoreleased sprite object.
|
||||
*/
|
||||
static AnchoredSprite* create(const PolygonInfo& info);
|
||||
|
||||
/**
|
||||
* Creates an anchored sprite with an image filename and a rect.
|
||||
*
|
||||
* @param filename A path to image file, e.g., "scene1/monster.png".
|
||||
* @param rect A subrect of the image file.
|
||||
* @return An autoreleased sprite object.
|
||||
*/
|
||||
static AnchoredSprite* create(std::string_view filename, const Rect& rect);
|
||||
|
||||
/**
|
||||
* Creates an anchored sprite with a Texture2D object.
|
||||
*
|
||||
* After creation, the rect will be the size of the texture, and the offset will be (0,0).
|
||||
*
|
||||
* @param texture A pointer to a Texture2D object.
|
||||
* @return An autoreleased sprite object.
|
||||
*/
|
||||
static AnchoredSprite* createWithTexture(Texture2D* texture);
|
||||
|
||||
/**
|
||||
* Creates an anchored sprite with a texture and a rect.
|
||||
*
|
||||
* After creation, the offset will be (0,0).
|
||||
*
|
||||
* @param texture A pointer to an existing Texture2D object.
|
||||
* You can use a Texture2D object for many sprites.
|
||||
* @param rect Only the contents inside the rect of this texture will be applied for this sprite.
|
||||
* @param rotated Whether or not the rect is rotated.
|
||||
* @return An autoreleased sprite object.
|
||||
*/
|
||||
static AnchoredSprite* createWithTexture(Texture2D* texture, const Rect& rect, bool rotated = false);
|
||||
|
||||
/**
|
||||
* Creates an anchored sprite with an sprite frame.
|
||||
*
|
||||
* @param spriteFrame A sprite frame which involves a texture and a rect.
|
||||
* @return An autoreleased sprite object.
|
||||
*/
|
||||
static AnchoredSprite* createWithSpriteFrame(SpriteFrame* spriteFrame);
|
||||
|
||||
/**
|
||||
* Creates an anchored sprite with an sprite frame name.
|
||||
*
|
||||
* A SpriteFrame will be fetched from the SpriteFrameCache by spriteFrameName param.
|
||||
* If the SpriteFrame doesn't exist it will raise an exception.
|
||||
*
|
||||
* @param spriteFrameName The name of sprite frame.
|
||||
* @return An autoreleased sprite object.
|
||||
*/
|
||||
static AnchoredSprite* createWithSpriteFrameName(std::string_view spriteFrameName);
|
||||
|
||||
/* This function will reposition the sprite's vertices itself instead of the node */
|
||||
virtual void setAnchorPoint(const Vec2& anchor) override;
|
||||
/* Gets the hit area of the anchored sprite, this requires special calculations for shifted vertices and should be used with touch event listeners */
|
||||
virtual const Rect& getTouchRect();
|
||||
|
||||
protected:
|
||||
virtual void setVertexCoords(const Rect& rect, V3F_C4B_T2F_Quad* outQuad) override;
|
||||
Vec2 _spriteVertexAnchor = Vec2::ANCHOR_MIDDLE;
|
||||
};
|
||||
|
||||
// end of sprite_nodes group
|
||||
/// @}
|
||||
|
||||
NS_AX_END
|
|
@ -9,6 +9,7 @@ set(_AX_2D_HEADER
|
|||
2d/CCActionCamera.h
|
||||
2d/CCParticleExamples.h
|
||||
2d/CCSprite.h
|
||||
2d/CCAnchoredSprite.h
|
||||
2d/CCNode.h
|
||||
2d/CCComponentContainer.h
|
||||
2d/CCActionProgressTimer.h
|
||||
|
@ -125,6 +126,7 @@ set(_AX_2D_SRC
|
|||
2d/CCScene.cpp
|
||||
2d/CCSpriteBatchNode.cpp
|
||||
2d/CCSprite.cpp
|
||||
2d/CCAnchoredSprite.cpp
|
||||
2d/CCSpriteFrameCache.cpp
|
||||
2d/CCSpriteFrame.cpp
|
||||
2d/CCAutoPolygon.cpp
|
||||
|
|
|
@ -226,6 +226,7 @@ THE SOFTWARE.
|
|||
#include "2d/CCAnimation.h"
|
||||
#include "2d/CCAnimationCache.h"
|
||||
#include "2d/CCSprite.h"
|
||||
#include "2d/CCAnchoredSprite.h"
|
||||
#include "2d/CCAutoPolygon.h"
|
||||
#include "2d/CCSpriteBatchNode.h"
|
||||
#include "2d/CCSpriteFrame.h"
|
||||
|
|
|
@ -61,6 +61,8 @@ SpriteTests::SpriteTests()
|
|||
ADD_TEST_CASE(Sprite1);
|
||||
ADD_TEST_CASE(SpriteBatchNode1);
|
||||
ADD_TEST_CASE(SpriteAnchorPoint);
|
||||
ADD_TEST_CASE(SpriteWithoutVertexAnchorPoint);
|
||||
ADD_TEST_CASE(SpriteVertexAnchorPoint);
|
||||
ADD_TEST_CASE(SpriteBatchNodeAnchorPoint);
|
||||
ADD_TEST_CASE(SpriteAnchorPointFromFile);
|
||||
ADD_TEST_CASE(SpriteOffsetAnchorRotation);
|
||||
|
@ -1175,6 +1177,120 @@ std::string SpriteAnchorPoint::subtitle() const
|
|||
return "anchor point";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
// SpriteWithoutVertexAnchorPoint
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
|
||||
SpriteWithoutVertexAnchorPoint::SpriteWithoutVertexAnchorPoint()
|
||||
{
|
||||
auto s = Director::getInstance()->getWinSize();
|
||||
|
||||
auto rotate = RotateBy::create(10, 360);
|
||||
auto action = RepeatForever::create(rotate);
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
auto sprite = Sprite::create("Images/grossini_dance_atlas.png", Rect(85 * i, 121 * 1, 85, 121));
|
||||
sprite->setPosition(Vec2(s.width / 4 * (i + 1), s.height / 2));
|
||||
|
||||
auto point = Sprite::create("Images/r1.png");
|
||||
point->setScale(0.25f);
|
||||
point->setPosition(sprite->getPosition());
|
||||
addChild(point, 10);
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
sprite->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
|
||||
break;
|
||||
case 1:
|
||||
sprite->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
|
||||
break;
|
||||
case 2:
|
||||
sprite->setAnchorPoint(Vec2::ANCHOR_TOP_RIGHT);
|
||||
break;
|
||||
}
|
||||
|
||||
point->setPosition(sprite->getPosition());
|
||||
|
||||
sprite->runAction(action->clone());
|
||||
addChild(sprite, i);
|
||||
|
||||
auto lb = Label::createWithSystemFont("This is a text", "", 16);
|
||||
lb->setColor(Color3B::WHITE);
|
||||
sprite->addChild(lb, i);
|
||||
}
|
||||
}
|
||||
|
||||
std::string SpriteWithoutVertexAnchorPoint::title() const
|
||||
{
|
||||
return "Testing Sprite";
|
||||
}
|
||||
|
||||
std::string SpriteWithoutVertexAnchorPoint::subtitle() const
|
||||
{
|
||||
return "anchor point without using Anchored Sprite (default node anchoring) with children attached";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
// SpriteVertexAnchorPoint
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
|
||||
SpriteVertexAnchorPoint::SpriteVertexAnchorPoint()
|
||||
{
|
||||
auto s = Director::getInstance()->getWinSize();
|
||||
|
||||
auto rotate = RotateBy::create(10, 360);
|
||||
auto action = RepeatForever::create(rotate);
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
auto sprite = AnchoredSprite::create("Images/grossini_dance_atlas.png", Rect(85 * i, 121 * 1, 85, 121));
|
||||
sprite->setPosition(Vec2(s.width / 4 * (i + 1), s.height / 2));
|
||||
|
||||
auto point = Sprite::create("Images/r1.png");
|
||||
point->setScale(0.25f);
|
||||
point->setPosition(sprite->getPosition());
|
||||
addChild(point, 10);
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
sprite->setAnchorPoint(Vec2::ANCHOR_BOTTOM_LEFT);
|
||||
break;
|
||||
case 1:
|
||||
sprite->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
|
||||
break;
|
||||
case 2:
|
||||
sprite->setAnchorPoint(Vec2::ANCHOR_TOP_RIGHT);
|
||||
break;
|
||||
}
|
||||
|
||||
point->setPosition(sprite->getPosition());
|
||||
|
||||
sprite->runAction(action->clone());
|
||||
addChild(sprite, i);
|
||||
|
||||
auto lb = Label::createWithSystemFont("This is a text", "", 16);
|
||||
lb->setColor(Color3B::WHITE);
|
||||
sprite->addChild(lb, i);
|
||||
}
|
||||
}
|
||||
|
||||
std::string SpriteVertexAnchorPoint::title() const
|
||||
{
|
||||
return "Testing Sprite";
|
||||
}
|
||||
|
||||
std::string SpriteVertexAnchorPoint::subtitle() const
|
||||
{
|
||||
return "anchor point using Anchored Sprite with children attached";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
// SpriteBatchNodeAnchorPoint
|
||||
|
|
|
@ -213,6 +213,26 @@ public:
|
|||
virtual std::string subtitle() const override;
|
||||
};
|
||||
|
||||
class SpriteWithoutVertexAnchorPoint : public SpriteTestDemo
|
||||
{
|
||||
public:
|
||||
CREATE_FUNC(SpriteWithoutVertexAnchorPoint);
|
||||
|
||||
SpriteWithoutVertexAnchorPoint();
|
||||
virtual std::string title() const override;
|
||||
virtual std::string subtitle() const override;
|
||||
};
|
||||
|
||||
class SpriteVertexAnchorPoint : public SpriteTestDemo
|
||||
{
|
||||
public:
|
||||
CREATE_FUNC(SpriteVertexAnchorPoint);
|
||||
|
||||
SpriteVertexAnchorPoint();
|
||||
virtual std::string title() const override;
|
||||
virtual std::string subtitle() const override;
|
||||
};
|
||||
|
||||
class SpriteBatchNodeAnchorPoint : public SpriteTestDemo
|
||||
{
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue