cocos2d-x How To Use External Instances? - cocos2d-x

As mentioned on the title, I'm trying to use an instance out of its function.
There is a spr sprite instance in the Helloworld::init()
I want to use it inside the HelloWorld::menuCallback1(Ref* sender)
so once the menu is clicked, the instance spr will rotate.
Help me please!!!
void HelloWorld::menuCallback1(Ref* sender) {
auto item = (MenuItemFont*)sender;
auto actionRotation = RotateBy::create(3.0, 1080);
spr->runAction(actionRotation);
}
bool HelloWorld::init() {
if (!Layer::init()) return false;
Size winSize = Director::getInstance()->getWinSize();
auto spr = Sprite::create("ch.png");
spr->setPosition(Point(winSize.width / 2, 70));
spr->setAnchorPoint(Point(0.5, 0));
this->addChild(spr);
// 메뉴(Menu)
auto item_1 = MenuItemFont::create("MOVE UP RIGHT", CC_CALLBACK_0(HelloWorld::menuCallback1, this));
auto menu = Menu::create(item_1, NULL);
menu->alignItemsVertically();
this->addChild(menu);
return true;
}

According to the documentation menuCallback looks like this:
typedef std::function<void(Ref*)> ccMenuCallback;
So it doesn't have any params.
But you have 2 other ways to achieve that:
1) make Sprite* spr instance in .h file,
2) use item_1->setUserObject(spr) and extract it in menuCallback1 function using item->getUserObject.

You can also pass in a lambda for any callbacks in cocos2d-x:
[&](Ref* const ref){menuCallback1(ref);}

Related

How can I translate keyword prototype in AS3 to Haxe?

I have the below AS3 code, and I want to translate it to Haxe. But I don't know how to deal with the keyword prototype. Who can help me? Thanks.
var style = new CSSStyleDeclaration();
style.defaultFactory = function():void
{
this.disabledOverlayAlpha = 0;
this.borderStyle = "controlBar";
this.paddingTop = 10;
this.verticalAlign = "middle";
this.paddingLeft = 10;
this.paddingBottom = 10;
this.paddingRight = 10;
};
if(chain == null) chain = {};
style.defaultFactory.prototype = chain;
chain = new style.defaultFactory();
style.defaultFactory = function():void
{
this.fontWeight = "bold";
};
style.defaultFactory.prototype = chain;
chain = new style.defaultFactory();
style.defaultFactory = function():void
{
this.backgroundSize = "100%";
this.paddingTop = 24;
this.backgroundColor = 8821927;
this.backgroundImage = ApplicationBackground;
this.horizontalAlign = "center";
this.backgroundGradientAlphas = [1,1];
this.paddingLeft = 24;
this.paddingBottom = 24;
this.paddingRight = 24;
};
style.defaultFactory.prototype = chain;
chain = new style.defaultFactory();
Ok, I poked this a bit, and now I kind of figured out, what that piece of code does. This knowledge won't help you to port your code to HAXE, but it will help you understand what it is about and to compose a decent HAXE-style alternative.
First, the part about instantiating, functions and working with prototypes. As it turned out, if you invoke the new operator on an unbound function (does not work on class methods):
The new empty class-less generic Object is created.
Its reference is passed to the said function as this.
The function can add and modify the object's fields and methods.
Ultimately, the reference to that Object is returned.
Then, it works (as I mentioned in my comments above) very much the way classes worked back then in AS1 and Flash 6.
If that function has a prototype and it is too a generic Object, then it is added to the newly created one as a... how to put it... a bottom layer Object which adds its fields to the top layer Object.
I understand that it sounds difficult, so there's an explanatory example that somehow sheds some light on it all:
public class Proton extends Sprite
{
public function Proton()
{
super();
var P:Function;
// Empty.
P = new Function;
create("First:", P);
// Empty with prototype.
P.prototype = {c:3, d:4};
create("Second:", P);
// Non-empty.
P = function():void
{
this.a = 1;
this.b = 2;
};
create("Third:", P);
// Non-empty with prototype.
P.prototype = {a:5, f:6};
create("Fourth:", P);
}
// Instantiates the F and outputs the result.
private function create(prefix:String, F:Function):void
{
var A:Object = new F;
trace(prefix + "\nJSON:" + JSON.stringify(A) + "\nREAL:" + explore(A) + "\n");
}
// Same as JSON.stringify, but also looks into the prototype.
private function explore(O:Object):String
{
var result:Array = new Array;
for (var akey:String in O)
{
result.push('"' + akey + '":' + O[akey]);
}
return "{" + result.join(",") + "}";
}
}
So, the output is:
First:
JSON:{}
REAL:{}
Second:
JSON:{}
REAL:{"d":4,"c":3}
Third:
JSON:{"b":2,"a":1}
REAL:{"b":2,"a":1}
Fourth:
JSON:{"b":2,"a":1}
REAL:{"b":2,"a":1,"f":6,"a":1}
As you can see, JSON.stringify exports only the top layer object, while direct for iteration goes through all the layers, top to bottom, and even processes the duplicate keys (but the top layer value shadows what's below).
Second, how it all is related to your code. These factory and defaultFactory functions are used in some CSS-related class to form an Object representation of the style: https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/styles/CSSStyleDeclaration.html
So, you can use that prototype hack to form a generic Object with a chain of layers upon layers of CSS declarations... probably. You saw that JSON doesn't perceive anything but the top layer, I have no idea if CSS classes act differently or not.
I think, working with CSS should be less hack-y and more straightforward.
Good luck figuring it out.

Chipmunk collisions not happening when moving sprite using actions

Really a basic question, but I am moving a sprite A with a physics body over another kind of sprites B having another physics body. I expect the collision callback oncontact to be called for these bodies. They have their respective category bitmasks set using setCategoryBitmask() and also respectively have each other's categories set using setContactTestBitmask().
The collision works as long as I do not move sprite A. I assume the problem is that I move sprite A using cocos2d actions, and I need to do something else. But using cocos2d actions for scripting things like these look so much simpler to me than anything else I can think of.
Move sprite A using physics calls. (looks like a lot of work, and it looks like it's hard to achieve exact scripting perfection)
Do my own collision detection in update() instead. (looks like a bunch of work too, especially if the sprites are rotated etc)
Is there any other shortcut? Or did I miss something else?
I ended up doing "Do my own collision detection in update() instead". It wasn't too problematic.
Something like this in update()...
const Rect RECT_A = spriteA->getBoundingBox();
for (auto spriteB : someparent->getChildren()) {
const Rect RECT_B = spriteB->getBoundingBox();
if (RECT_A.intersectsRect(RECT_B)) {
// Hit
}
}
Contaction detection should be fine while collion doesn't work.
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::createWithPhysics();
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
scene->getPhysicsWorld()->setGravity(Vec2::ZERO);
// return the scene
return scene;
}
bool HelloWorld::init()
{
if ( !Layer::init() )
{
return false;
}
auto createSprite = [this](const Vec2& pos) {
auto sprite = Sprite::create();
auto bodyA = PhysicsBody::createCircle(20);
sprite->setPhysicsBody(bodyA);
sprite->setPosition(pos);
bodyA->setCollisionBitmask(0xff);
bodyA->setCategoryBitmask(0xff);
bodyA->setContactTestBitmask(0xff);
return sprite;
};
auto spriteA = createSprite(Vec2(300, 300));
auto moveBy = MoveBy::create(1.f, Vec2(200, 200));
spriteA->runAction(moveBy);
auto spriteB = createSprite(Vec2(350, 350));
addChild(spriteA);
addChild(spriteB);
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = [=](PhysicsContact& contact) {
auto a = contact.getShapeA()->getBody()->getNode();
auto b = contact.getShapeB()->getBody()->getNode();
assert((a == spriteA && b == spriteB) || (a == spriteB && b == spriteA));
log("It is working");
return false;
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
return true;
}

Collision Detection not working in cocos2dx v3 using Physics

I want to collide 2 sprites using Physics Engine.
But my contact listener is not responding. and no warning/error on log or runtime.
So here is what i did :
Declaration
1)cocos2d::PhysicsWorld* m_world;
2)void setPhyWorld(cocos2d::PhysicsWorld* world){m_world = world;}
3)bool onContactBegin(cocos2d::PhysicsContact& contact);
Implementation
For PhysicsWorld:
Scene ->
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
auto layer = HelloWorld::create();
layer->setPhyWorld(scene->getPhysicsWorld());
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
PhysicsWorld->
void HelloWorld::createPhysicsWorld(){
auto body = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3);
auto edgeNode = Node::create();
edgeNode->setPosition(Point(visibleSize.width/2,visibleSize.height/2));
edgeNode->setPhysicsBody(body);
this->addChild(edgeNode);
}
Creating Sprite->
void HelloWorld::createCar(){
car = Sprite::create("car.png");
auto body3 = PhysicsBody::createBox(car->getContentSize());
body3->setDynamic(false);
body3->setCategoryBitmask(2);
body3->setCollisionBitmask(2);
body3->setContactTestBitmask(true);
car->setPhysicsBody(body3);
// position the sprite on the center of the screen
car->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
// add the sprite as a child to this layer
this->addChild(car, 1);
car->setAnchorPoint(Vec2(0.5, 0));
car->setFlippedX(true);
}
void HelloWorld::createRocket(){
rocket = Sprite::create("rocket.png");
auto body2 = PhysicsBody::createBox(rocket->getContentSize());
body2->setDynamic(false);
body2->setCategoryBitmask(1);
body2->setCollisionBitmask(1);
body2->setContactTestBitmask(true);
rocket->setPhysicsBody(body2);
// position the sprite on the center of the screen
rocket->setPosition(Vec2(visibleSize.width/2 + origin.x,origin.y));
// add the sprite as a child to this layer
this->addChild(rocket, 1);
}
Collision->
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener,this);
ContactListner->
bool HelloWorld::onContactBegin(cocos2d::PhysicsContact& contact)
{
CCLOG("onContactBegin -------> ");
return true;
}
Well it is tricky thing that you miss in your code.one body should be setDynamic to true.
body->setDynamic(true);
cheers!
Well, it turned out that it was bit ugly mistake.
body3->setContactTestBitmask(true);
this method's argument is a bitmask not 'true'/'false' field, so your 'true' mask was treated as it was 1 while your bodies mask is 2. The solution is:
body3->setCategoryBitmask(1);
body3->setCollisionBitmask(3);
body3->setContactTestBitmask(1);
body2->setCategoryBitmask(3);
body2->setCollisionBitmask(1);
body2->setContactTestBitmask(1);
I Just Comment out body2->setDynamic(false); inside createRocket Method and setGravityEnable(false); and it works now.
void HelloWorld::createRocket(){
rocket = Sprite::create("rocket.png");
rocket->setPosition(Vec2(visibleSize.width/2 + origin.x,origin.y - 50));
rocket->setTag(3);
auto body2 = PhysicsBody::createBox(rocket->getContentSize());
//body2->setDynamic(false);
body2->setTag(3);
body2->setGravityEnable(false);
body2->setCollisionBitmask(3);
body2->setContactTestBitmask(true);
rocket->setPhysicsBody(body2);
this->addChild(rocket, 1);
}

Changing x and y values of a Sprite Actionscript 3

I'm attempting to change the x and y value of a sprite.
public var panContainer:Sprite = new Sprite();
public var xVal:Number;
public var yVal:Number;
I've created the function:
public function moveContainer(xVal,yVal):void
{
xVal = panContainer.x;
yVal = panContainer.y;
}
Both the variable and function are created within an .as file. I'm attempting to make the function call within a class file called test2.as using a case statement. When the user selects an item from a list box the sprite's x and y values need to change:
switch (event.target.selectedItem.data)
{
case 1 :
panZoomMap.moveContainer(30,30);
break;
The function call, however does nothing at this point. Is this a scope issue? Am I not executing this properly? Thanks in advance for any advise.
It appears that you have your variable assignments backwards, what you want to do is assign the values you get in moveContainer to the x and y properties of panContainer:
public function moveContainer(xVal,yVal):void
{
panContainer.x = xVal;
panContainer.y = yVal;
}
Unless I am reading your question wrong (it is not worded well), you have this backwards
public function moveContainer(xVal,yVal):void
{
panContainer.x = xVal;
panContainer.y = yVal;
}
You were setting your variables to the x,y coords of your object, when you should have been setting your x,y coords to your variables.
I think you are very close, just have it reversed. You are passing in the xVal and yVal into the moveContainer method. so xVal and yVal are the new values. Below should be your function:
public function moveContainer(xVal,yVal):void
{
panContainer.x = xVal;
panContainer.y = yVal;
}
A simple rule of thumb I go by is: values always get assigned into a container to the left of the = sign.
So in the method will assign passed xVal to the panContainer.x property, and yVal to panContainer.y property.

AS3 OOP Principal, Structure & Organization

Refining my OOP structure, and trying to make the display of code as intuitive as possible,
using basic OOP principals this definitely helps but my craft has only gone so far. I am looking to improve upon my practice:
package
{
import flash.display.*;
import flash.text.*;
public class Button extends Sprite
{
protected var _spr:Sprite = new Sprite();
protected var _tf :TextField = new TextField();
protected var c :Number;
protected var xx :Number;
protected var yy :Number;
protected var w :Number;
protected var h :Number;
protected var t :String;
protected var a :Number;
protected var l :Number;
protected var lC :Number;
function Button
(
_col:Number, //beginFill
_x:Number, _y:Number, _w:Number, _h:Number, //drawRect
_t:String = "", //TextField (optional)
_a:Number = 1, //beginFill (optional)
_l:Number = 0, _lC:Number = 0xFFFFFF //lineStyle (optional)
)
{
c = _col;
xx = _x;
yy = _y;
w = _w;
h = _h;
t = _t;
a = _a;
l = _l;
lC = _lC;
_spr.addChild(_tf);
draw();
}
public function draw ():void
{
_spr.graphics.clear ();
_spr.graphics.lineStyle(l, lC);
_spr.graphics.beginFill(c);
_spr.graphics.drawRect (xx, yy, w, h);
var f:TextFormat = new TextFormat;
f.font = "Arial";
_tf.text = t;
_tf.autoSize = TextFieldAutoSize.LEFT;
_tf.x = xx + w/2 - _tf.textWidth / 2;
_tf.y = yy + h/2 - _tf.textHeight / 1.5;
_tf.width = w - 2;
_tf.height = h - 2;
_tf.alpha = 0.75;
_tf.setTextFormat(f);
_tf.selectable = false;
_tf.mouseEnabled = false;
_spr.graphics.endFill ();
}
/* ----------------------- *
* GETTERS *
* ----------------------- */
//OVERRIDE
override public function get x () :Number {return (xx)}
override public function get y () :Number {return (yy)}
override public function get width () :Number {return (w)}
override public function get height () :Number {return (h)}
//SUPPLEMENTARY
public function get col () :Number {return (c)}
public function get text () :String {return (t)}
public function get line () :Number {return (l)}
public function get lineC () :Number {return (lC)}
public function get getObj () :Sprite {return (_spr)}
/* ----------------------- *
* SETTERS *
* ----------------------- */
//OVERRIDE
override public function set x (_n:Number) :void
{ xx = getObj.x = Math.round(_n - xx) }
override public function set y (_n:Number) :void
{ yy = getObj.y = Math.round(_n - yy) }
override public function set width (_n:Number) :void
{ w = Math.round(_n) }
override public function set height (_n:Number) :void
{ h = Math.round(_n) }
//SUPPLEMENTARY
public function set col (_n:Number) :void
{
c = _n;
draw();
}
public function set text (_s:String) :void
{
t = _s;
draw();
}
public function set line (_n:Number) :void
{
l = _n;
draw();
}
public function set lineC(_n:Number) :void
{
lC = _n;
draw();
}
}
}
From the above Button class, what interpretations can you make about my structure & organization? I have read and followed many articles on how you should perform OOP logically and I think I am ready for some tuning, or criticism rather on my understanding of how a class should be in AS3 (circumstantial i know.)
Some specific questions:
When I instantiate 'Button' from my Main class, should I add it to the stage there or
within the Button Class itself using Super?
Will the "1047" Error ever be fixed? What is a sustainable (or more efficient) work-around besides the ones already mentioned here?: http://curtismorley.com/2008/10/15/actionscript-error-1047-parameter-initializer-unknown-or-is-not-a-compile-time-constant/
In order to update width/height changes, I must call my draw function after modification from outside the Override function for width & height specifically. Is there a proper way to call draw() through the Override functions? No error output was provided, it seems doing so is against the rules though so I am just calling draw() from Main as a hack fix.. Possibly write a function within button tethered to event of a changed property?
If anyone bothered to parse this wall of text, thanks for reading and I appreciate any criticism you may have, harsh or otherwise :)
First, your variable names are not decriptive. If you're going to name your variables "c", "t", "lc", etc., at least put inline comments that describe what they're for. Even if you comment the parameters that populate them lower down, there's unnecessary overhead with what you've done.
If you've done that because of the historically poor code completion in the IDE, use Flash Builder or one of the excellent code editing tools that can help you type out lineColor, textField, etc.
On closer inspection, it looks like you've done this at least partially because you've reversed the normal convention, which is to have parameters to functions not use underscores, whereas private/protected storage should use underscores, but otherwise should have the same name as the public property. Changing your conventions to match the rest of the AS3 world would go a long way to making your code more readable.
If you don't want to lose the underscores in your function parameters, you could use a snippet in FB to make setting the instance variable to a parameter of the same name.
Invalidation is very well understood in ActionScript, so I'm not sure why you have an issue. It looks something like this:
protected function invalidate():void {
_isInvalid = true;
addEventListener(Event.ENTER_FRAME, validate);
}
protected function validate(e:Event):void {
removeEventListener(Event.ENTER_FRAME, validate);
if (_isInvalid) {
draw();
}
_isInvalid = false;
}
Call this everywhere you're now calling draw(), and it will reduce the number of times you have to update the display list.
MPO is that you should not have constructor arguments for View Classes, as this makes it impossible to use them from the timeline.
You'll probably find that if you're open to using the timeline, a lot of this hard work goes away--you simply add the behavior via an AS Class and draw the graphics in the IDE (using things like 9-slice scaling, filters, etc., to minimize maintenance hassle). If you want a button that looks different, you draw a different one, attach your behavior Class, and done.
A lot of people don't realize that it's possible to maintain good OOP while allowing the timeline to take over much of the heavy lifting. Hope this gives you what you want, or at least gives you some search terms you can move forward with. Note if you're interested in knowing more about leveraging the timeline, post back. The links to the source code on that one were eaten when the post was archived.